8 Commits
1.1 ... v1.2

44 changed files with 297 additions and 12 deletions

30
CHANGELOG.md Normal file
View File

@@ -0,0 +1,30 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2] - 2025-03-10
### Changed
- Fix app name displaying as "ISO Drive" instead of "ISO Droid" in some places
## [1.1] - 2025-03-10
### Changed
- New app icon
## [1.0] - 2025-03-10
### Added
- Mount ISO/IMG files as USB mass storage or CD-ROM
- Create blank IMG files for writable USB drives
- Read-only or read-write mount options
- Persistent notification with quick unmount button
- OS-specific icons for popular distributions (Linux, BSD, etc.)
- Download links to popular operating systems (Linux, BSD, Windows, Recovery tools)
- Rename and delete files
- Material 3 dynamic theming with dark mode support
- Support for Magisk, KernelSU, and APatch root solutions
- Bundled isodrive binary for all architectures (arm64-v8a, armeabi-v7a, x86_64, x86)

View File

@@ -13,7 +13,7 @@ android {
minSdk = 26 minSdk = 26
targetSdk = 36 targetSdk = 36
versionCode = 1 versionCode = 1
versionName = "1.1" versionName = "1.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid package sh.sar.isodroid
import android.app.Application import android.app.Application

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid package sh.sar.isodroid
import android.content.Context import android.content.Context

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.data package sh.sar.isodroid.data
import java.io.File import java.io.File

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.data package sh.sar.isodroid.data
data class MountOptions( data class MountOptions(

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.data package sh.sar.isodroid.data
enum class MountType { enum class MountType {

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.isodrive package sh.sar.isodroid.isodrive
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.isodrive package sh.sar.isodroid.isodrive
import android.content.Context import android.content.Context

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.isodrive package sh.sar.isodroid.isodrive
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.notification package sh.sar.isodroid.notification
import android.content.BroadcastReceiver import android.content.BroadcastReceiver

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.notification package sh.sar.isodroid.notification
import android.app.NotificationChannel import android.app.NotificationChannel

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.notification package sh.sar.isodroid.notification
import android.content.BroadcastReceiver import android.content.BroadcastReceiver

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.root package sh.sar.isodroid.root
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.components package sh.sar.isodroid.ui.components
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.components package sh.sar.isodroid.ui.components
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.components package sh.sar.isodroid.ui.components
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.components package sh.sar.isodroid.ui.components
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.components package sh.sar.isodroid.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.screens package sh.sar.isodroid.ui.screens
import android.content.Context import android.content.Context

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.screens package sh.sar.isodroid.ui.screens
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -84,7 +89,7 @@ fun MainScreen(
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("ISO Drive") }, title = { Text("ISO Droid") },
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer, containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.screens package sh.sar.isodroid.ui.screens
import android.Manifest import android.Manifest
@@ -226,11 +231,11 @@ fun SettingsScreen(
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
Column { Column {
Text( Text(
text = "ISO Drive", text = "ISO Droid",
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
) )
Text( Text(
text = "Version 1.0", text = "Version 1.2",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
@@ -254,13 +259,13 @@ fun SettingsScreen(
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
Text( Text(
text = "git.shihaam.dev/shihaam/ISODrive", text = "git.shihaam.dev/shihaam/ISODroid",
style = MaterialTheme.typography.bodySmall.copy( style = MaterialTheme.typography.bodySmall.copy(
textDecoration = TextDecoration.Underline textDecoration = TextDecoration.Underline
), ),
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
modifier = Modifier.clickable { modifier = Modifier.clickable {
openUrl("https://git.shihaam.dev/shihaam/ISODrive") openUrl("https://git.shihaam.dev/shihaam/ISODroid")
} }
) )
} }
@@ -301,7 +306,7 @@ fun SettingsScreen(
} }
} }
Text( Text(
text = "The CLI tool that powers ISO Drive. Mounts ISO/IMG files as bootable USB devices using configfs.", text = "The CLI tool that powers ISO Droid. Mounts ISO/IMG files as bootable USB devices using configfs.",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 8.dp) modifier = Modifier.padding(top = 8.dp)

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.screens package sh.sar.isodroid.ui.screens
import android.Manifest import android.Manifest
@@ -92,7 +97,7 @@ private fun WelcomeStep(
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
Text( Text(
text = "Welcome to ISO Drive", text = "Welcome to ISO Droid",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
@@ -147,7 +152,7 @@ private fun RootAccessStep(
title = "Root Access", title = "Root Access",
description = when (hasRoot) { description = when (hasRoot) {
false -> "Root access was denied. The app requires root to mount ISO files. You can try again or skip and grant access later from your root manager." false -> "Root access was denied. The app requires root to mount ISO files. You can try again or skip and grant access later from your root manager."
else -> "ISO Drive needs superuser (root) access to mount ISO files as USB devices. This is required because mounting USB gadgets is a system-level operation." else -> "ISO Droid needs superuser (root) access to mount ISO files as USB devices. This is required because mounting USB gadgets is a system-level operation."
}, },
granted = hasRoot granted = hasRoot
) )
@@ -253,7 +258,7 @@ private fun NotificationStep(
description = when { description = when {
permanentlyDenied -> "Notification permission was denied. You can enable it later in system settings if you change your mind." permanentlyDenied -> "Notification permission was denied. You can enable it later in system settings if you change your mind."
wasDenied -> "Notification permission was denied. You can try again or continue without notifications." wasDenied -> "Notification permission was denied. You can try again or continue without notifications."
else -> "ISO Drive shows a notification when an ISO is mounted, with a quick unmount button. This helps you keep track of the mount status." else -> "ISO Droid shows a notification when an ISO is mounted, with a quick unmount button. This helps you keep track of the mount status."
}, },
granted = if (wasDenied) false else if (hasPermission) true else null granted = if (wasDenied) false else if (hasPermission) true else null
) )
@@ -318,7 +323,7 @@ private fun CompleteStep(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = "ISO Drive is ready to use. Place your ISO or IMG files in the isodrive folder and start mounting.", text = "ISO Droid is ready to use. Place your ISO or IMG files in the isodrive folder and start mounting.",
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -339,7 +344,7 @@ private fun CompleteStep(
onClick = onFinish, onClick = onFinish,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Text("Start Using ISO Drive") Text("Start Using ISO Droid")
} }
} }

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.theme package sh.sar.isodroid.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.theme package sh.sar.isodroid.ui.theme
import android.app.Activity import android.app.Activity

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.ui.theme package sh.sar.isodroid.ui.theme
import androidx.compose.material3.Typography import androidx.compose.material3.Typography

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 Shiham Abdul Rahman <shihaam@shihaam.dev>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package sh.sar.isodroid.viewmodel package sh.sar.isodroid.viewmodel
import android.app.Application import android.app.Application

77
build_isodrive.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -euo pipefail
# Build isodrive from source for all Android architectures
# Requires: Android NDK (or runs via nix-shell on NixOS)
SCRIPT_DIR=$(dirname "$(realpath "$0")")
ISODRIVE_DIR="/tmp/isodrive"
OUTPUT_DIR="$SCRIPT_DIR/app/src/main/assets/bin"
# Clone isodrive source
if [[ -d "$ISODRIVE_DIR" ]]; then
echo "Updating isodrive source..."
git -C "$ISODRIVE_DIR" pull
else
echo "Cloning isodrive..."
git clone --depth 1 https://github.com/nitanmarcel/isodrive "$ISODRIVE_DIR"
fi
SRCS="$ISODRIVE_DIR/src/util.cpp $ISODRIVE_DIR/src/configfsisomanager.cpp $ISODRIVE_DIR/src/androidusbisomanager.cpp $ISODRIVE_DIR/src/main.cpp"
CFLAGS="-I$ISODRIVE_DIR/src/include -static-libstdc++ -Os -s"
build_all() {
local NDK="$1"
local TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
echo "Building arm64-v8a..."
"$TOOLCHAIN/aarch64-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/arm64-v8a/isodrive"
echo "Building armeabi-v7a..."
"$TOOLCHAIN/armv7a-linux-androideabi26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/armeabi-v7a/isodrive"
echo "Building x86_64..."
"$TOOLCHAIN/x86_64-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/x86_64/isodrive"
echo "Building x86..."
"$TOOLCHAIN/i686-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/x86/isodrive"
echo "Done! Built isodrive for all architectures."
ls -la "$OUTPUT_DIR"/*/isodrive
}
# On NixOS, prefer nix-shell (local Android SDK has /bin/bash issues)
if command -v nix-shell &>/dev/null; then
echo "Using nix-shell to get Android NDK..."
export SRCS CFLAGS OUTPUT_DIR
NIXPKGS_ALLOW_UNFREE=1 nix-shell -p androidenv.androidPkgs.ndk-bundle --run '
SDK_ROOT=$(find /nix/store -maxdepth 1 -name "*android-sdk-ndk*" -type d 2>/dev/null | head -1)
NDK=$(ls -d "$SDK_ROOT/libexec/android-sdk/ndk/"* | head -1)
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
echo "Using NDK: $NDK"
echo "Building arm64-v8a..."
"$TOOLCHAIN/aarch64-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/arm64-v8a/isodrive"
echo "Building armeabi-v7a..."
"$TOOLCHAIN/armv7a-linux-androideabi26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/armeabi-v7a/isodrive"
echo "Building x86_64..."
"$TOOLCHAIN/x86_64-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/x86_64/isodrive"
echo "Building x86..."
"$TOOLCHAIN/i686-linux-android26-clang++" $CFLAGS $SRCS -o "$OUTPUT_DIR/x86/isodrive"
echo "Done!"
ls -la "$OUTPUT_DIR"/*/isodrive
'
elif [[ -n "${ANDROID_NDK_HOME:-}" ]]; then
build_all "$ANDROID_NDK_HOME"
elif [[ -n "${ANDROID_NDK:-}" ]]; then
build_all "$ANDROID_NDK"
else
echo "Error: Android NDK not found."
echo "Set ANDROID_NDK_HOME or ANDROID_NDK, or install nix-shell."
exit 1
fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -0,0 +1,9 @@
* New app icon
* Mount ISO/IMG files as USB mass storage or CD-ROM
* Create blank IMG files for writable USB drives
* Read-only or read-write mount options
* Persistent notification with quick unmount button
* OS-specific icons for popular distributions
* Download links to popular operating systems
* Rename and delete files
* Material 3 dynamic theming with dark mode support

View File

@@ -0,0 +1,24 @@
ISO Droid lets you mount ISO and IMG files as USB mass storage or CD-ROM devices on rooted Android devices. Connect your phone to any PC and it will appear as a bootable USB drive or CD-ROM.
Features:
* Mount ISO/IMG files as USB mass storage or CD-ROM
* Create blank IMG files for writable USB drives
* Read-only or read-write mount options
* Persistent notification with quick unmount button
* OS-specific icons for popular distributions (Linux, BSD, etc.)
* Download links to popular operating systems
* Rename and delete files
* Material 3 dynamic theming with dark mode support
Requirements:
* Rooted Android device (Magisk, KernelSU, APatch, etc.)
* USB gadget support (configfs or sysfs)
* Android 8.0+ (API 26)
Usage:
1. Place your ISO/IMG files in /sdcard/isodrive/
2. Select an ISO/IMG file from the list
3. Choose mount options (Mass Storage or CD-ROM)
4. Tap Mount
5. Connect your phone to a PC via USB
6. Unmount via the app or notification when done

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1 @@
Mount ISO/IMG files as USB drives on rooted Android

View File

@@ -0,0 +1 @@
ISO Droid

18
get_isodrive.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Get the directory where this script lives
SCRIPT_DIR=$(dirname "$(realpath "$0")")
ISODRIVE_VERSION=$(curl -sI https://github.com/nitanmarcel/isodrive-magisk/releases/latest | grep -i ^location | grep -oP 'v\K[\d.]+')
curl -sL https://github.com/nitanmarcel/isodrive-magisk/releases/download/v$ISODRIVE_VERSION/isodrive-magisk-v$ISODRIVE_VERSION.zip -o /tmp/isodrive-magisk.zip
unzip -q /tmp/isodrive-magisk.zip -d /tmp/isodrive-magisk
# Move the isodrive binary for each architecture
mv /tmp/isodrive-magisk/libs/arm64-v8a/isodrive $SCRIPT_DIR/app/src/main/assets/bin/arm64-v8a/
mv /tmp/isodrive-magisk/libs/armeabi-v7a/isodrive $SCRIPT_DIR/app/src/main/assets/bin/armeabi-v7a/
mv /tmp/isodrive-magisk/libs/x86/isodrive $SCRIPT_DIR/app/src/main/assets/bin/x86/
mv /tmp/isodrive-magisk/libs/x86_64/isodrive $SCRIPT_DIR/app/src/main/assets/bin/x86_64/
# Clean up temp files
rm -rf /tmp/isodrive-magisk /tmp/isodrive-magisk.zip