modules/android-integration: add am command

This commit is contained in:
Alexander Sosedkin 2024-06-01 17:51:25 +02:00
parent b7e7cd423d
commit c4c4f09e3d
10 changed files with 175 additions and 0 deletions

View file

@ -108,6 +108,7 @@ jobs:
# below 28: bootstrap didn't start, IDK why # below 28: bootstrap didn't start, IDK why
# 34: sometimes work, but doesn't seem stable, even w/o caching images # 34: sometimes work, but doesn't seem stable, even w/o caching images
script: script:
- android_integration
- bootstrap_flakes - bootstrap_flakes
- bootstrap_channels - bootstrap_channels
- poke_around - poke_around

View file

@ -2,6 +2,12 @@
## Release 24.05 (unreleased) ## 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 ### Compatibility considerations
* `nixOnDroidConfigurations` `pkgs` argument is now mandatory. * `nixOnDroidConfigurations` `pkgs` argument is now mandatory.

View file

@ -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 ];
};
}

View file

@ -9,6 +9,7 @@
[ [
./build/activation.nix ./build/activation.nix
./build/config.nix ./build/config.nix
./environment/android-integration.nix
./environment/ca.nix ./environment/ca.nix
./environment/etc ./environment/etc
./environment/links.nix ./environment/links.nix

View file

@ -0,0 +1,33 @@
# 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
# Fix the bash link so that nix can patch it + path to termux-am-socket
substituteInPlace termux-am.sh.in \
--replace @TERMUX_PREFIX@/bin/bash /bin/bash \
--replace \
"termux-am-socket \"\$am_command_string\"" \
"$out/bin/termux-am-socket \"\$am_command_string\""
'';
postInstall = ''
# Scripts use 'am' as an alias.
ln -s $out/bin/termux-am $out/bin/am
'';
}

View file

@ -0,0 +1,69 @@
import time
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 && echo integration tools installed"')
d.ui.press('enter')
wait_for(d, 'integration tools installed')
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')
# ... there might be a notification now, get rid of it
time.sleep(3)
screenshot(d, 'am-wants-permission-3-seconds-later')
if 'text="TermuxAm Socket Server Error"' in d.ui.dump_hierarchy():
d.ui.open_notification()
time.sleep(1)
screenshot(d, 'notification-opened')
d.ui(text='TermuxAm Socket Server Error').swipe('right')
screenshot(d, 'error-notification-swiped-right')
d.ui.press('back')
screenshot(d, 'back')
# 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')
screenshot(d, 'settings-awaited')
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')

View file

@ -52,3 +52,5 @@ def run(d):
wait_for(d, 'c21va2UtdGVzdAo=') wait_for(d, 'c21va2UtdGVzdAo=')
screenshot(d, 'success-bootstrap-channels') screenshot(d, 'success-bootstrap-channels')
return nod

View file

@ -52,3 +52,5 @@ def run(d):
wait_for(d, 'c21va2UtdGVzdAo=') wait_for(d, 'c21va2UtdGVzdAo=')
screenshot(d, 'success-bootstrap-flakes') screenshot(d, 'success-bootstrap-flakes')
return nod

View file

@ -0,0 +1,17 @@
# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE.
load lib
@test 'android-integration options can be used' {
bats_require_minimum_version 1.5.0
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
}

View file

@ -0,0 +1,8 @@
_:
{
system.stateVersion = "23.11";
android-integration = {
am.enable = true;
};
}