diff --git a/.github/workflows/emulator.yml b/.github/workflows/emulator.yml index 16a88f47..490c17ed 100644 --- a/.github/workflows/emulator.yml +++ b/.github/workflows/emulator.yml @@ -108,6 +108,7 @@ jobs: # below 28: bootstrap didn't start, IDK why # 34: sometimes work, but doesn't seem stable, even w/o caching images script: + - android_integration - bootstrap_flakes - bootstrap_channels - poke_around diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae6ecb1..9cb6e56b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Release 24.05 (unreleased) +### New Options + +* New options under `android-integration`, + offer some of the tools familiar to Termux users. + Currently it's just `am`. + ### Compatibility considerations * `nixOnDroidConfigurations` `pkgs` argument is now mandatory. diff --git a/modules/environment/android-integration.nix b/modules/environment/android-integration.nix new file mode 100644 index 00000000..06f8ebb8 --- /dev/null +++ b/modules/environment/android-integration.nix @@ -0,0 +1,36 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE. + +{ config, lib, pkgs, ... }: + +let + cfg = config.android-integration; + + termux-am = + pkgs.callPackage (import ../../pkgs/android-integration/termux-am.nix) { }; +in +{ + + ###### interface + + options.android-integration = { + + am.enable = lib.mkOption { + type = lib.types.bool; + default = false; + example = "true"; + description = lib.mdDoc '' + Provide an `am` (activity manager) command. + Is not guaranteed to be a real deal, could be of limited compatibility + with real `am` (like `termux-am`). + ''; + }; + + }; + + ###### implementation + + config = { + environment.packages = + lib.mkIf cfg.am.enable [ termux-am ]; + }; +} diff --git a/modules/module-list.nix b/modules/module-list.nix index 20dfdd00..14003530 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -9,6 +9,7 @@ [ ./build/activation.nix ./build/config.nix + ./environment/android-integration.nix ./environment/ca.nix ./environment/etc ./environment/links.nix diff --git a/pkgs/android-integration/termux-am.nix b/pkgs/android-integration/termux-am.nix new file mode 100644 index 00000000..e3d15492 --- /dev/null +++ b/pkgs/android-integration/termux-am.nix @@ -0,0 +1,32 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE. + +{ stdenv, fetchFromGitHub, cmake }: + +let + appPath = "/data/data/com.termux.nix/files/apps/com.termux.nix"; + socketPath = "${appPath}/termux-am/am.sock"; +in +stdenv.mkDerivation rec { + name = "termux-am"; + version = "1.5.0"; + src = fetchFromGitHub { + owner = "termux"; + repo = "termux-am-socket"; + rev = version; + sha256 = "sha256-6pCv2HMBRp8Hi56b43mQqnaFaI7y5DfhS9gScANwg2I="; + }; + nativeBuildInputs = [ cmake ]; + patchPhase = '' + # Header generation doesn't seem to work on android + echo "#define SOCKET_PATH \"${socketPath}\"" > termux-am.h + + cat termux-am.h + # Fix the bash link so that nix can patch it + substituteInPlace termux-am.sh.in --replace @TERMUX_PREFIX@ "" + head termux-am.sh.in + ''; + postInstall = '' + # Scripts use 'am' as an alias. + ln -s $out/bin/termux-am $out/bin/am + ''; +} diff --git a/tests/emulator/android_integration.py b/tests/emulator/android_integration.py new file mode 100644 index 00000000..dc696e9c --- /dev/null +++ b/tests/emulator/android_integration.py @@ -0,0 +1,53 @@ +import bootstrap_channels + +from common import screenshot, wait_for + + +def run(d): + nod = bootstrap_channels.run(d) + + d('input text "am"') + d.ui.press('enter') + wait_for(d, 'bash: am: command not found') + screenshot(d, 'no-am') + + # Apply a config that enables am + 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\'') + d.ui.press('enter') + screenshot(d, 'pre-switch') + d('input text "nix-on-droid switch"') + d.ui.press('enter') + screenshot(d, 'post-switch') + + # Verify am is there + d('input text "am | head -n2"') + d.ui.press('enter') + wait_for(d, 'termux-am is a wrapper script') + screenshot(d, 'am-appears') + + # Smoke-test that am doesn't work yet + d('input text "am start -a android.settings.SETTINGS 2>&1 | head -n5"') + d.ui.press('enter') + screenshot(d, 'am-invoked for the first time') + wait_for(d, 'Nix requires "Display over other apps" permission') + wait_for(d, 'https://dontkillmyapp.com') + screenshot(d, 'am-wants-permission') + + # Grant nix app 'Draw over other apps' permission + nod.permissions += 'android.permission.SYSTEM_ALERT_WINDOW' + + # Smoke-test that am works + d('input text "am start -a android.settings.SETTINGS"') + d.ui.press('enter') + screenshot(d, 'settings-opening') + wait_for(d, 'Search settings') + wait_for(d, 'Network') + d.ui.press('back') + screenshot(d, 'back-from-settings') + + # Verify we're back + d('input text "am | head -n2"') + d.ui.press('enter') + wait_for(d, 'termux-am is a wrapper script') diff --git a/tests/emulator/bootstrap_channels.py b/tests/emulator/bootstrap_channels.py index d108fd21..6890cda4 100644 --- a/tests/emulator/bootstrap_channels.py +++ b/tests/emulator/bootstrap_channels.py @@ -42,3 +42,5 @@ def run(d): wait_for(d, 'c21va2UtdGVzdAo=') screenshot(d, 'success-bootstrap-channels') + + return nod diff --git a/tests/emulator/bootstrap_flakes.py b/tests/emulator/bootstrap_flakes.py index 348e590d..695a13ce 100644 --- a/tests/emulator/bootstrap_flakes.py +++ b/tests/emulator/bootstrap_flakes.py @@ -42,3 +42,5 @@ def run(d): wait_for(d, 'c21va2UtdGVzdAo=') screenshot(d, 'success-bootstrap-flakes') + + return nod diff --git a/tests/on-device/config-android-integration.bats b/tests/on-device/config-android-integration.bats new file mode 100644 index 00000000..b588241a --- /dev/null +++ b/tests/on-device/config-android-integration.bats @@ -0,0 +1,16 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE. + +load lib + +@test 'android-integration options can be used' { + run ! command -v am + + cp \ + "$ON_DEVICE_TESTS_DIR/config-android-integration.nix" \ + ~/.config/nixpkgs/nix-on-droid.nix + nix-on-droid switch + + command -v am + + switch_to_default_config +} diff --git a/tests/on-device/config-android-integration.nix b/tests/on-device/config-android-integration.nix new file mode 100644 index 00000000..5c852395 --- /dev/null +++ b/tests/on-device/config-android-integration.nix @@ -0,0 +1,8 @@ +_: + +{ + system.stateVersion = "23.11"; + android-integration = { + am.enable = true; + }; +}