#!/bin/sh
# adb_uiautomator.sh
# 2026-03-29
# by Gernot Walzl
# Up to now, this is just an idea on
# how to tap buttons of various apps over adb.
# The device needs to be in unlocked state.
# Requirements:
# apt install adb libxml2-utils
# Notice: The position in xpath is 1-based, not 0-based.
set -e
restart_app () {
APP=$1
adb shell "am stop-app '$APP'"
adb shell "am start '$APP'"
}
stop_app () {
APP=$1
adb shell "am stop-app '$APP'"
}
input_tap () {
XPATH=$1
read X_MIN Y_MIN X_MAX Y_MAX <<EOF
$(adb exec-out "uiautomator dump /dev/tty > /dev/null" \
| xmllint --xpath "$XPATH/@bounds" - \
| sed 's/.*\[\(.*\),\(.*\)\]\[\(.*\),\(.*\)\].*/\1 \2 \3 \4/')
EOF
if [ -z "$Y_MAX" ]; then
echo "WARNING: '$XPATH' not found."
return 1
else
adb shell "input tap $((($X_MIN + $X_MAX)/2)) $((($Y_MIN + $Y_MAX)/2))"
fi
}
input_text () {
adb shell "input text '$1'"
}
export_contacts () {
FILENAME="contacts-$(date '+%Y-%m-%d').vcf"
adb shell "rm '/sdcard/$FILENAME'"
restart_app 'com.android.contacts'
input_tap '//node[@resource-id="com.android.contacts:id/toolbar"]/node[1]'
input_tap '//node[@resource-id="com.android.contacts:id/nav_settings"]'
input_tap '//node[@package="com.android.contacts" and @resource-id="android:id/list"]/node[9]'
input_tap '//node[@package="com.android.contacts" and @resource-id="android:id/select_dialog_listview"]/node[1]'
input_tap '//node[@resource-id="com.android.documentsui:id/horizontal_breadcrumb"]/node[1]/node[1]'
input_tap '//node[@resource-id="com.android.documentsui:id/container_save"]/node[1]/node[2]'
input_text "$FILENAME"
input_tap '//node[@resource-id="com.android.documentsui:id/container_save"]/node[1]/node[3]'
sleep 5
adb pull "/sdcard/$FILENAME"
stop_app 'com.android.contacts'
}
export_contacts