Konubinix' opinionated web of thoughts

Android

Fleeting

tools

adb screenrecord

to play with apk: aapt

install the sdk

It can be downloaded from https://developer.android.com/studio (go to the bottom of the page)

https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip

I prefer using nixos and a custom flake to download what I need automatically.

missing the avd folder

the avdmanager respects the XDG_CONFIG HOME but the emulator does not. This leads to avdmanager create putting avds in some path and emulator not finding it.

test graphical interfaces

Permission Denial

java.lang.SecurityException: Permission Denial: starting Intent The full error description usually looks like ‘java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.mypackage/.myactivity.MainActivity launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 } } from null (pid=11366, uid=2000) not exported from uid 10191. Such error might be the indication of the fact that the combination of application package and activity name, which has been passed to Appium as appPackage/appActivity (or auto detected implicitly), is not the correct one to start the application under test

https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/android/activity-startup.md

appium

appium driver install uiautomator2

http://appium.io/docs/en/2.4/quickstart/uiauto2-driver/#prepare-the-device

npm i -g appium

http://appium.io/docs/en/2.4/quickstart/install/

ANDROID_SERIAL=emulator-5554 appium
pip install Appium-Python-Client
speed up the starting
additional_options = {
    "skipDeviceInitialization": not self.first_time,
    "skipServerInstallation": not self.first_time,
    "disableWindowAnimation": self.first_time,
}

It still takes some time to kill the previous run of the uiautomator2 server and start it again.

start session calls this.cleanupAutomationLeftovers

https://github.com/appium/appium-uiautomator2-driver/blob/25eeea068a1928dec32af5ac7744a967b385bf3a/lib/uiautomator2.js#L225

that in turn stops the server https://github.com/appium/appium-uiautomator2-driver/blob/25eeea068a1928dec32af5ac7744a967b385bf3a/lib/uiautomator2.js#L376

before starting it again https://github.com/appium/appium-uiautomator2-driver/blob/25eeea068a1928dec32af5ac7744a967b385bf3a/lib/uiautomator2.js#L241

socket hang up error

uiautomator2

Needs at least android 5

A lot of sites say that some uiautomatorviewer tool exist. But so far, I could not find any proof of its existence, even downloading the sdk and android studio for linux and windows.

uiautomatorviewer

uiautomatorviewer

Developer Assistant APK

Developer Assistant_1.2.2_apkcombo.com.apk

(
    TMP="$(mktemp -d)"
    trap "rm -rf '${TMP}'" 0
    ipfs get -o "${TMP}/assistant.apk" https://konubinix.eu/ipfs/bafybeialb27i7yjaqdh2g4hswv4vqc5o7cl4gr5ubk7vkpelc275lqhs7u
    adb -s emulator-5554 install "${TMP}/assistant.apk"
)

sdkmanager

The sdkmanager is quite touchy. It needs to be called in a specific directory and specifying the root.

cd ~/.buildozer/android/platform/android-sdk/tools
./bin/sdkmanager --list --sdk_root=..

avdmanager

avdmanager list

To find the possible package to give to avd create

sdkmanager --list | gi system-images
[...]

  system-images;android-34;google_apis;x86_64                                              | 12            | Google APIs Intel x86_64 Atom System Image

[...]

Then

sdkmanager --install 'system-images;android-34;google_apis;x86_64
avdmanager create avd --device 9 --name test --package "system-images;android-34;google_apis;x86_64"

L’émulateur opère de manière optimale s’il peut utiliser le matériel de votre ordinateur, tel que le processeur, le GPU et le modem, au lieu de fonctionner comme un logiciel pur

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

appareils Android ont recours à OpenGL for Embedded Systems (OpenGL ES ou GLES) pour le rendu des graphismes 2D et 3D à l’écran.

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

L’accélération matérielle, qui est généralement plus rapide, est recommandée. Toutefois, vous devrez peut-être recourir à l’accélération logicielle si votre ordinateur utilise des pilotes graphiques non compatibles avec l’émulateur.

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

Si vous démarrez l’émulateur à partir de la ligne de commande, vous pouvez forcer le paramètre d’accélération graphique de l’AVD correspondant à cette instance d’appareil virtuel

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

Pour spécifier un type d’accélération graphique lorsque vous exécutez un AVD à partir de la ligne de commande, incluez l’option -gpu, comme illustré dans l’exemple suivant :

emulator -avd avd_name -gpu mode [{-option [value]} … ]

La valeur de

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

Lorsque vous utilisez des images pour le niveau d’API 27 ou supérieur, l’émulateur peut afficher l’UI Android avec Skia. Skia aide l’émulateur à afficher les graphiques de manière plus fluide et plus efficace.

Pour activer le rendu Skia, utilisez les commandes suivantes dans le shell adb : su setprop debug.hwui.renderer skiagl stop start

https://developer.android.com/studio/run/emulator-acceleration?hl=fr

emulator

sdkmanager --install emulator

May need to sudo apt install libx11-dev to get libx11.so

Using the name of the avd installed with avdmanager (see above).

emulator -avd test -qemu -enable-kvm -gpu host
INFO    | Android emulator version 33.1.24.0 (build_id 11237101) (CL:N/A)
INFO    | AVD test has path /home/sam/.android/avd/../avd/test.avd
INFO    | trying to check whether /home/sam/.buildozer/android/platform/android-sdk is a valid sdk root
WARNING | /home/sam/.buildozer/android/platform/android-sdk/android-sdk/system-images/android-34/google_apis/x86_64/ is not a valid directory.
WARNING | emulator has searched the above paths but found no valid sdk root directory.
PANIC: Broken AVD system path. Check your ANDROID_SDK_ROOT value [/home/sam/.buildozer/android/platform/android-sdk]!

Strange. Hopefully, this can be easily circumvented

ln -s ~/.buildozer/android/platform/android-sdk ~/.buildozer/android/platform/android-sdk/android-sdk

Also, to enable keyboard in the avd

sed -i 's/hw.keyboard = no/hw.keyboard = yes/' ~/.android/avd/test.avd/config.ini

If the emulator restarted

adb disconnect emulator-5554

run in x11vnc

x11vnc -create -nopw -gone 'pkill -f "qemu-system-x86_64 -avd test" -SIGTERM' -env X11VNC_FINDDISPLAY_ALWAYS_FAILS=1 -env FD_PROG="emulator -avd test"

Then, on the remote side

xtightvncviewer localhost:5900

This uses xvfb under the hood

The good thing here is that the application starts only when connecting to the vnc server, not before.

This is not enough, as closing the window won’t send SIGTERM to the running emulator.

run in xvfb

apktool to play with the content of an apk

Extract some apk with

apktool d my.apk

It creates the folder my

Then, make some changes, then

apktool b my

The new apk is in the my/dist/ folder

Connect Android to PC using debian and udev :

  • Get the code of the constructor
    • either get the code from http://developer.android.com/tools/device.html
    • or find the line [.] usb .: New USB device found, idVendor=04e8, . in the output of dmesg when you plug the phone. (for the example, my samsung phone indicates the vendor 04e8)
  • create an udev rule for the android phone when it plugs in
    • edit the new file /etc/udev/rules.d/50-android.rules and put into it SUBSYSTEM==“usb”, ATTR{idVendor}==“04e8”, MODE=“0666”, GROUP=“plugdev”
    • restart udev with
      service udev restart
      
  • re plug the phone

4

5

7

8.1

mindthegapps > 8.1

10

Android 10 (codenamed Android Q during development)

https://en.wikipedia.org/wiki/Android_10

11

13

automation (with adb)

adb exec-out screencap -p > screen.png adb shell input keyevent keycode # voir les keycodes ici https://developer.android.com/reference/android/view/KeyEvent adb shell input tap x y adb shell input text letexte adb shell getevent -l # pour récup une macro adb shell sendevent <periph de getevent> adb shell input swipe 224 548 $((0x000001dd)) $((0x00000206)) # some times you have to reverse x and y

scrcpy

use the developer option to see the interraction on the screen then try and error with several swipes adb shell input swipe 200 200 200 300

adb shell input keyevent KEYCODE_POWER adb shell input keyevent KEYCODE_BACK

https://stackoverflow.com/questions/17259809/can-anyone-explain-this-command-fully-adb-shell-sendevent-device-type-code

A method to get what I want

https://stackoverflow.com/questions/25363526/fire-a-pinch-in-out-command-to-android-phone-using-adb

kill an active application

launch activity

am start -n yourpackagename/.activityname

https://stackoverflow.com/questions/13380590/is-it-possible-to-start-activity-through-adb-shell

find available activities

adb shell pm list packages -f Then you can use adb pull:

adb pull <APK path from previous command> and then aapt to get the information you want:

aapt dump badging <pulledfile.apk>

https://stackoverflow.com/questions/12698814/get-launchable-activity-name-of-package-from-adb

example with slightbackup

clk android adb shell pm list packages -f|gi slightba
package:/data/app/de.shandschuh.slightbackup-AtJUMUgaD889KHasQ8QaKg==/base.apk=de.shandschuh.slightbackup
TMP="$(mktemp -d)"
trap "rm -rf '${TMP}'" 0

cd "${TMP}"

clk android adb pull /data/app/de.shandschuh.slightbackup-AtJUMUgaD889KHasQ8QaKg==/base.apk
aapt dump badging base.apk | gi launchable-activity
/data/app/de.shandschuh.slightbackup-AtJUMUgaD889KHasQ8QaKg==/base.apk: 1 file pulled, 0 skipped. 1.9 MB/s (78433 bytes in 0.040s)
launchable-activity: name='de.shandschuh.slightbackup.BackupActivity'  label='Slight backup' icon=
clk android adb shell am start -n 'de.shandschuh.slightbackup/.BackupActivity
Starting: Intent { cmp=de.shandschuh.slightbackup/.BackupActivity }

keep my screen unlocked during USB debugging?

change display brightness using adb

get the Android device screen size from the adb command line?

hacks

provide permissions (like camera or sdcard)

clk android -d klipad adb shell pm grant eu.konubinix.konixpoc android.permission.CAMERA clk android -d klipad adb shell pm grant eu.konubinix.konixpoc android.permission.WRITE_EXTERNAL_STORAGE

note that with android 11 scoped storage, sdcard storage is granted using

clk android adb shell appops set –uid eu.konubinix.konixpoc MANAGE_EXTERNAL_STORAGE allow

change fullscreen settings

see doing again, with old python2 kivy, to reuse my wiko cink peax apktool d app.apk change in ./app/AndroidManifest.xml the android theme to be android:theme="@android:style/Theme.NoTitleBar.Fullscreen" apktool b app keytool -genkeypair -keystore your-keystore.jks -storepass 000000 -keypass 000000 -alias your-alias -dname “CN=Your Name, OU=Your Unit, O=Your Organization, L=Your City, ST=Your State, C=Your Country” -keyalg RSA -keysize 2048 -validity 10000 apksigner sign –ks your-keystore.jks –ks-key-alias your-alias –ks-pass pass:000000 ./app/dist/app.apk now, ./app/dist/app.apk is ready

Alternatively, from the code

from jnius import autoclass
from android import mActivity
from android.runnable import run_on_ui_thread

View = autoclass('android.view.View')

option = View.SYSTEM_UI_FLAG_FULLSCREEN

@run_on_ui_thread
def fs():
    mActivity.getWindow().getDecorView().setSystemUiVisibility(option)

fs()

Quit it using the SYSTEM_UI_FLAG_VISIBLE option

permanent adb over wifi by adding “service.adb.tcp.port=5555” into “/system/build.prop”

enable wakelock

see a legacy from another lifetime <meta-data android:name=“wakelock” android:value=“1”/>

from jnius import autoclass
from android import mActivity
# in a service, use instead of mActivity
# PythonService = autoclass('org.kivy.android.PythonService')
# PythonService.mService
PowerManager = autoclass('android.os.PowerManager')
Context = autoclass('android.content.Context')
WindowManager = autoclass('android.view.WindowManager')

pm = mActivity.getSystemService(Context.POWER_SERVICE)
self.wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 'simplecamera:screen-awake')
self.wl.acquire()

And later, self.wl.release()

SCREEN_DIM_WAKE_LOCK (and supposedly deprecated for FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) to simply dim, worked well on android 4

<<enable-wakelock>>

record audio

def record(self):
    plyer.audio.file_path = "/sdcard/truc.3gp"
    plyer.audio.start()
    Clock.schedule_once(lambda a: plyer.audio.stop(), 5)

keep screen on

All wakelock that keep the screen on have been deprecated a long time ago, in favor of this way of doing.

from android import mActivity
from jnius import autoclass
from android.runnable import run_on_ui_thread
LayoutParams = autoclass('android.view.WindowManager$LayoutParams')

@run_on_ui_thread
def do():
    mActivity.getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON)

do()
# clear with
mActivity.getWindow().clearFlags(LayoutParams.FLAG_KEEP_SCREEN_ON)

wake up the screen from a service

A service cannot access the window, hence cannot use keep screen on

But it can make use of SCREEN_BRIGHT_WAKE_LOCK and ACQUIRE_CAUSES_WAKEUP

from jnius import autoclass

PythonService = autoclass('org.kivy.android.PythonService')
PowerManager = autoclass('android.os.PowerManager')
Context = autoclass('android.content.Context')
WindowManager = autoclass('android.view.WindowManager')

pm = PythonService.mService.getSystemService(Context.POWER_SERVICE)
wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 'simple awakening')
wl.acquire()
wl.release() # I can release it as soon as it was acquired, because it was only to wake the phone

That way, anything that needs the UI to be refreshed can still work.

keep doing something even when the screen is off

Tested on android 4. Even with a PARTIAL_WAKE_LOCK, the front application will stop its processing when the screen goes off.

It apparently does not impact stuff that already run when the screen goes of, for instance

while True:
        time.sleep(2)
        print("a")

Will continue working, same if ran in threading.Thread(target=myfunction).start

But the Clock.schedule_interval and anything related to the UI will stop working, until the screen gets back on.

Also, I don’t know if I need to enable a wake lock here, but doing it in the service would look like this

from jnius import autoclass

PowerManager = autoclass('android.os.PowerManager')
Context = autoclass('android.content.Context')
PythonService = autoclass('org.kivy.android.PythonService')

pm = PythonService.mService.getSystemService(Context.POWER_SERVICE)
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 'do something')
wl.acquire()

access the camera to record a video

using MediaRecorder and CamcorderProfile

from jnius import autoclass
MediaRecorder = autoclass('android.media.MediaRecorder')
Camera = autoclass("android.hardware.Camera")
AudioSource = autoclass('android.media.MediaRecorder$AudioSource')
VideoSource = autoclass('android.media.MediaRecorder$VideoSource')
OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')
AudioEncoder = autoclass('android.media.MediaRecorder$AudioEncoder')
VideoEncoder = autoclass('android.media.MediaRecorder$VideoEncoder')
CamcorderProfile = autoclass('android.media.CamcorderProfile')
# see https://developer.android.com/reference/android/media/CamcorderProfile
from kivy.core.camera import Camera
camera = Camera(
                 resolution=(640, 480),
                 index=0, # index=1 for front camera (in general)
             )
recorder = MediaRecorder()
camera._android_camera.unlock()
recorder.setCamera(camera._android_camera)

recorder.setAudioSource(AudioSource.MIC)
recorder.setVideoSource(VideoSource.CAMERA)

profile = CamcorderProfile.get(CamcorderProfile.QUALITY_VGA)
recorder.setProfile(profile)
# or
#recorder.setOutputFormat(OutputFormat.DEFAULT)
#recorder.setAudioEncoder(AudioEncoder.DEFAULT)
#recorder.setVideoEncoder(VideoEncoder.DEFAULT)

recorder.setOutputFile("/sdcard/v.mp4")
recorder.prepare()
recorder.start()
print("started")
import time
time.sleep(5)
print("done")
recorder.stop()
recorder.release()

access the camera to take pictures

see digging a bit the old phone idea: create a timelapse

tested on android 4 : it cannot be done in a service and needs the screen to be on, even very dimmed

also on android 4, the camera returns bad images when the screen is off, even if using PARTIAL_WAKE_LOCK and a thread to get the images.

A compromise to take photos continuously, but save battery by keeping the screen off most of the time can be to

  1. create a wakelock of type PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
  2. run the routine in a thread that
    1. acquire the wakelock
    2. grab the frame
    3. release the wakelock

see digging a bit the old phone idea: create a timelapse to see an example of this.

keep the the screen on, but very dimmed

If for some reason you need to keep the screen on, but at the lowest brightness

Supposedly you should be able to keep screen on with FLAG_ALLOW_LOCK_WHILE_SCREEN_ON to simply dim, but did not work on android 4

Combine the SCREEN_DIM_WAKE_LOCK wakelock and set the brightness

from jnius import autoclass
from android import mActivity
from android.runnable import run_on_ui_thread
WindowManagerLayoutParams = autoclass('android.view.WindowManager$LayoutParams')
window = mActivity.getWindow()

# Adjust the brightness level (0.0 to 1.0, where 0.0 is the minimum)
layout_params = window.getAttributes()
layout_params.screenBrightness = 0.01  # Minimum brightness
@run_on_ui_thread
def do():
    window.setAttributes(layout_params)

do()

Tested only on android 4, where brightness == 0 actually put the application to sleep

Also, you can try plyer.brightness.set_level(1)

change the orientation

from plyer import orientation

orientation.set_landscape()

Put this at the root boxlayout of you application

With a legacy from another lifetime, it tends to often freeze the application. Prefer editing the manifest

android:screenOrientation="portrait" and repackage the application (see from the python android runtime to a custom app)

useful apks

termux

connectbot

simplesshd

https://www.galexander.org/software/simplesshd/ (https://f-droid.org/en/packages/org.galexander.sshd/)

TMP="$(mktemp -d)"
trap "rm -rf '${TMP}'" 0

gpg --export-ssh-key konubinix > "${TMP}/authorized_keys"
scp -P 2222 "${TMP}/authorized_keys" 192.168.1.192:

sshdroid

https://apkpure.com/sshdroid/berserker.android.apps.sshdroid/downloading (/ipfs/bafybeigwd4nxu7xwd34la5ce3jzu43ezbie7fp7p3cw3q22zaqjukucul4?filename=SSHDroid_2.1.2_APKPure.apk) in case simplesshd is not possible (android 4)

ssh -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group14-sha1 root@192.168.1.36 does not deal with authorized_keys, but works with “sshpass -p admin ssh cinkpeax”

Notes linking here