diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb6e56b..51b72b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ * New options under `android-integration`, offer some of the tools familiar to Termux users. - Currently it's just `am`. + Currently only `am` and `termux-setup-storage` are provided. ### Compatibility considerations diff --git a/modules/environment/android-integration.nix b/modules/environment/android-integration.nix index 06f8ebb8..621d4154 100644 --- a/modules/environment/android-integration.nix +++ b/modules/environment/android-integration.nix @@ -7,6 +7,10 @@ let termux-am = pkgs.callPackage (import ../../pkgs/android-integration/termux-am.nix) { }; + termux-tools = + pkgs.callPackage (import ../../pkgs/android-integration/termux-tools.nix) { + inherit termux-am; + }; in { @@ -25,12 +29,35 @@ in ''; }; + termux-setup-storage.enable = lib.mkOption { + type = lib.types.bool; + default = false; + example = "true"; + description = lib.mdDoc '' + Provide a `termux-setup-storage` command + that makes the app request storage permission, + and then creates a $HOME/storage symlink. + ''; + }; + + unsupported.enable = lib.mkOption { + type = lib.types.bool; + default = false; + example = "true"; + description = lib.mdDoc '' + Provide several more unsupported and untested commands. + For testing and for brave souls only. + ''; + }; + }; ###### implementation - config = { + config = let ifD = cond: pkg: if cond then [ pkg ] else [ ]; in { environment.packages = - lib.mkIf cfg.am.enable [ termux-am ]; + (ifD cfg.am.enable termux-am) ++ + (ifD cfg.termux-setup-storage.enable termux-tools.setup-storage) ++ + (ifD cfg.unsupported.enable termux-tools.out); }; } diff --git a/pkgs/android-integration/termux-tools.nix b/pkgs/android-integration/termux-tools.nix new file mode 100644 index 00000000..10cf66a2 --- /dev/null +++ b/pkgs/android-integration/termux-tools.nix @@ -0,0 +1,93 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE. + +{ stdenv +, fetchFromGitHub +, autoreconfHook +, makeWrapper +, gnused +, getopt +, pandoc +, termux-am +}: + +stdenv.mkDerivation rec { + name = "termux-tools"; + version = "1.42.4"; + src = fetchFromGitHub { + owner = "termux"; + repo = "termux-tools"; + rev = "v${version}"; + sha256 = "sha256-LkkeaEQcY8HgunBYAg3Ymn5xYPvrGqGNCZTd/NyIOKY="; + }; + nativeBuildInputs = [ autoreconfHook makeWrapper pandoc ]; + propagatedInputs = [ termux-am ]; + + # https://github.com/termux/termux-tools/pull/95 + patches = [ ./termux-tools.patch ]; + postPatch = '' + substituteInPlace scripts/* --replace @TERMUX_APP_PACKAGE@/ com.termux.nix/ + substituteInPlace scripts/termux-setup-storage.in \ + --replace @TERMUX_APP_PACKAGE@ com.termux.nix + substituteInPlace scripts/* --replace "getopt " "${getopt}/bin/getopt " + ${gnused}/bin/sed -i 's|^am |${termux-am}/bin/am |' scripts/* + ''; + + outputs = [ + "out" # all the unsupported unsorted stuff + "setup_storage" # termux-setup-storage + ]; + postInstall = '' + rm $out/etc/termux-login.sh + rm $out/etc/profile.d/init-termux-properties.sh + rm -r $out/etc/termux/mirrors + rm -d $out/etc/termux + rm -d $out/etc/profile.d + rm $out/etc/motd.sh $out/etc/motd $out/etc/motd-playstore + rm -d $out/etc + + rm $out/bin/chsh # we offer a declarative way to change your shell + rm $out/bin/cmd # doesn't work because we overlay /system/bin + rm $out/bin/dalvikvm # doesn't work because we overlay /system/bin + rm $out/bin/df # works without the magic + rm $out/bin/getprop # doesn't work because we overlay /system/bin + rm $out/bin/logcat # doesn't work because we overlay /system/bin + rm $out/bin/login # we have our own, very complex login + rm $out/bin/ping # doesn't work because we overlay /system/bin + rm $out/bin/ping6 # doesn't work because we overlay /system/bin + rm $out/bin/pkg # we use Nix + rm $out/bin/pm # doesn't work because we overlay /system/bin + rm $out/bin/settings # doesn't work because we overlay /system/bin + rm $out/bin/su # doesn't work because we overlay /bin + rm $out/bin/top # doesn't work because we overlay /system/bin + + rm $out/bin/termux-change-repo # we use Nix + rm $out/bin/termux-fix-shebang # we use Nix + rm $out/bin/termux-info # Termux-specific. write our own? + rm $out/bin/termux-reset # untested and dangerous + rm $out/bin/termux-restore # untested and dangerous + rm $out/bin/termux-setup-package-manager # we use Nix + + mkdir -p $setup_storage/bin + mv $out/bin/termux-setup-storage $setup_storage/bin/ + + # check that we didn't package we didn't want to + find $out | ${gnused}/bin/sed "s|^$out|.|" | sort > effective + echo . >> expected + echo ./bin >> expected + echo ./bin/termux-backup >> expected # entirely untested + echo ./bin/termux-open >> expected # good candidate for fixing + echo ./bin/termux-open-url >> expected # good candidate for fixing + echo ./bin/termux-reload-settings >> expected # good candidate for fixing + echo ./bin/termux-wake-lock >> expected # good candidate for fixing + echo ./bin/termux-wake-unlock >> expected # good candidate for fixing + echo ./bin/xdg-open >> expected # good candidate for fixing + echo ./share >> expected + echo ./share/examples >> expected + echo ./share/examples/termux >> expected + echo ./share/examples/termux/termux.properties >> expected # useful + echo ./share/man >> expected + echo ./share/man/man1 >> expected + echo ./share/man/man1/termux.1 >> expected # 50/50 useful/misleading + diff -u expected effective + ''; +} diff --git a/pkgs/android-integration/termux-tools.patch b/pkgs/android-integration/termux-tools.patch new file mode 100644 index 00000000..26e0427e --- /dev/null +++ b/pkgs/android-integration/termux-tools.patch @@ -0,0 +1,87 @@ +From 6d72b44d90347ddce8473b604c38f352e6773f8d Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Sat, 1 Jun 2024 17:14:22 +0200 +Subject: [PATCH] scripts: replace com.termux with @TERMUX_APP_PACKAGE@ + +--- + scripts/termux-open.in | 2 +- + scripts/termux-reload-settings.in | 2 +- + scripts/termux-reset.in | 2 +- + scripts/termux-setup-storage.in | 4 ++-- + scripts/termux-wake-lock.in | 4 ++-- + scripts/termux-wake-unlock.in | 4 ++-- + 6 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/scripts/termux-open.in b/scripts/termux-open.in +index 9c81630..9a04e7b 100644 +--- a/scripts/termux-open.in ++++ b/scripts/termux-open.in +@@ -44,7 +44,7 @@ case "${TERMUX__USER_ID:-}" in ''|*[!0-9]*|0[0-9]*) TERMUX__USER_ID=0;; esac + + am broadcast --user "$TERMUX__USER_ID" \ + -a $ACTION \ +- -n com.termux/com.termux.app.TermuxOpenReceiver \ ++ -n @TERMUX_APP_PACKAGE@/@TERMUX_APP_PACKAGE@.app.TermuxOpenReceiver \ + $EXTRAS \ + -d "$FILE" \ + > /dev/null +diff --git a/scripts/termux-reload-settings.in b/scripts/termux-reload-settings.in +index 4e71f8a..ef8b0f4 100644 +--- a/scripts/termux-reload-settings.in ++++ b/scripts/termux-reload-settings.in +@@ -11,4 +11,4 @@ fi + + case "${TERMUX__USER_ID:-}" in ''|*[!0-9]*|0[0-9]*) TERMUX__USER_ID=0;; esac + +-am broadcast --user "$TERMUX__USER_ID" -a com.termux.app.reload_style com.termux > /dev/null ++am broadcast --user "$TERMUX__USER_ID" -a @TERMUX_APP_PACKAGE@.app.reload_style @TERMUX_APP_PACKAGE@ > /dev/null +diff --git a/scripts/termux-reset.in b/scripts/termux-reset.in +index 6f807a7..2161d1f 100644 +--- a/scripts/termux-reset.in ++++ b/scripts/termux-reset.in +@@ -45,6 +45,6 @@ else + /system/bin/killall -9 "$SHELL" + else + export CLASSPATH="@TERMUX_CACHE_DIR@/termux-am/am.apk" +- /system/bin/app_process / com.termux.termuxam.Am stopservice com.termux/.app.TermuxService ++ /system/bin/app_process / @TERMUX_APP_PACKAGE@.termuxam.Am stopservice @TERMUX_APP_PACKAGE@/.app.TermuxService + fi + fi +diff --git a/scripts/termux-setup-storage.in b/scripts/termux-setup-storage.in +index c621234..a086159 100644 +--- a/scripts/termux-setup-storage.in ++++ b/scripts/termux-setup-storage.in +@@ -27,5 +27,5 @@ fi + case "${TERMUX__USER_ID:-}" in ''|*[!0-9]*|0[0-9]*) TERMUX__USER_ID=0;; esac + + am broadcast --user "$TERMUX__USER_ID" \ +- --es com.termux.app.reload_style storage \ +- -a com.termux.app.reload_style com.termux > /dev/null ++ --es @TERMUX_APP_PACKAGE@.app.reload_style storage \ ++ -a @TERMUX_APP_PACKAGE@.app.reload_style @TERMUX_APP_PACKAGE@ > /dev/null +diff --git a/scripts/termux-wake-lock.in b/scripts/termux-wake-lock.in +index ba4b899..f3fd59e 100644 +--- a/scripts/termux-wake-lock.in ++++ b/scripts/termux-wake-lock.in +@@ -10,6 +10,6 @@ case "${TERMUX__USER_ID:-}" in ''|*[!0-9]*|0[0-9]*) TERMUX__USER_ID=0;; esac + + am startservice \ + --user "$TERMUX__USER_ID" \ +- -a com.termux.service_wake_lock \ +- com.termux/com.termux.app.TermuxService \ ++ -a @TERMUX_APP_PACKAGE@.service_wake_lock \ ++ @TERMUX_APP_PACKAGE@/@TERMUX_APP_PACKAGE@.app.TermuxService \ + > /dev/null +diff --git a/scripts/termux-wake-unlock.in b/scripts/termux-wake-unlock.in +index a4b1f57..d53ce31 100644 +--- a/scripts/termux-wake-unlock.in ++++ b/scripts/termux-wake-unlock.in +@@ -10,6 +10,6 @@ case "${TERMUX__USER_ID:-}" in ''|*[!0-9]*|0[0-9]*) TERMUX__USER_ID=0;; esac + + am startservice \ + --user "$TERMUX__USER_ID" \ +- -a com.termux.service_wake_unlock \ +- com.termux/com.termux.app.TermuxService \ ++ -a @TERMUX_APP_PACKAGE@.service_wake_unlock \ ++ @TERMUX_APP_PACKAGE@/@TERMUX_APP_PACKAGE@.app.TermuxService \ + > /dev/null diff --git a/tests/emulator/android_integration.py b/tests/emulator/android_integration.py index dc696e9c..7271cd75 100644 --- a/tests/emulator/android_integration.py +++ b/tests/emulator/android_integration.py @@ -6,12 +6,17 @@ def run(d): nod = bootstrap_channels.run(d) + # Verify that android-integration tools aren't installed by default d('input text "am"') d.ui.press('enter') wait_for(d, 'bash: am: command not found') screenshot(d, 'no-am') + d('input text "termux-setup-storage"') + d.ui.press('enter') + wait_for(d, 'bash: termux-setup-storage: command not found') + screenshot(d, 'no-termux-setup-storage') - # Apply a config that enables am + # Apply a config that enables android-integration tools cfg = ('/data/local/tmp/n-o-d/unpacked/tests/on-device/' 'config-android-integration.nix') d(f'input text \'cp {cfg} .config/nixpkgs/nix-on-droid.nix\'') @@ -51,3 +56,27 @@ def run(d): d('input text "am | head -n2"') d.ui.press('enter') wait_for(d, 'termux-am is a wrapper script') + + # Verify termux-setup-storage is there + d('input text "termux-setup-storage"') + d.ui.press('enter') + screenshot(d, 'termux-setup-storage-invoked') + wait_for(d, 'Allow Nix to access') + screenshot(d, 'permission-requested') + d.ui(text='Allow').click() + screenshot(d, 'permission-granted') + + d('input text "ls -l storage"') + screenshot(d, 'storage-listed') + wait_for(d, 'downloads -> /storage/emulated/Download') + wait_for(d, 'shared -> /storage/emulated/0') + screenshot(d, 'storage-listed-ok') + + # Invoke termux-setup-storage again + d('input text "termux-setup-storage"') + d.ui.press('enter') + screenshot(d, 'termux-setup-storage-invoked-again') + wait_for(d, 'already exists') + wait_for(d, 'Do you want to continue?') + d.ui.press('enter') + wait_for(d, 'Aborting configuration and leaving') diff --git a/tests/on-device/config-android-integration.bats b/tests/on-device/config-android-integration.bats index b588241a..69a5aa82 100644 --- a/tests/on-device/config-android-integration.bats +++ b/tests/on-device/config-android-integration.bats @@ -4,6 +4,7 @@ load lib @test 'android-integration options can be used' { run ! command -v am + run ! command -v termux-setup-storage cp \ "$ON_DEVICE_TESTS_DIR/config-android-integration.nix" \ @@ -11,6 +12,7 @@ load lib nix-on-droid switch command -v am + command -v termux-setup-storage switch_to_default_config } diff --git a/tests/on-device/config-android-integration.nix b/tests/on-device/config-android-integration.nix index 5c852395..b04a6320 100644 --- a/tests/on-device/config-android-integration.nix +++ b/tests/on-device/config-android-integration.nix @@ -4,5 +4,6 @@ _: system.stateVersion = "23.11"; android-integration = { am.enable = true; + termux-setup-storage.enable = true; }; }