Emulate scrollable screenshot #29

Open
opened 2025-01-21 21:13:39 +01:00 by Benjamin_Loison · 19 comments

As not possible on Xiaomi Mi A3 stock ROM.

Would help Benjamin_Loison/WhatsApp/issues/15.

+3

As not possible on Xiaomi Mi A3 stock ROM. Would help [Benjamin_Loison/WhatsApp/issues/15](https://codeberg.org/Benjamin_Loison/WhatsApp/issues/15). +3
Author
Owner
Related to [Benjamin-Loison/android/issues/59#issuecomment-2629144502](https://github.com/Benjamin-Loison/android/issues/59#issuecomment-2629144502).
Author
Owner

With Google flavor long press of power button results in voice assistant, see Benjamin_Loison/Voice_assistant/issues/7#issue-1475654.

DuckDuckGo and Google search adb scrolling screenshot.

The Stack Overflow question 72804636 and the Android Stack Exchange question 35012 raise this question, the latter has answers but nothing absolutely clean to me.

scrollscreenshot has 719 stars and last commit was 10 years ago.

With Google flavor long press of power button results in voice assistant, see [Benjamin_Loison/Voice_assistant/issues/7#issue-1475654](https://codeberg.org/Benjamin_Loison/Voice_assistant/issues/7#issue-1475654). DuckDuckGo and Google search *adb scrolling screenshot*. [The Stack Overflow question 72804636](https://stackoverflow.com/q/72804636) and [the Android Stack Exchange question 35012](https://android.stackexchange.com/q/35012) raise this question, the latter has answers but nothing absolutely clean to me. [scrollscreenshot](https://github.com/PGSSoft/scrollscreenshot) has 719 stars and last commit was 10 years ago.
Author
Owner
adb exec-out screencap --help
Output:

usage: screencap [-ahp] [-d display-id] [FILENAME]
   -h: this message
   -a: captures all the active displays. This appends an integer postfix to the FILENAME.
       e.g., FILENAME_0.png, FILENAME_1.png. If both -a and -d are given, it ignores -d.
   -d: specify the display ID to capture (If the id is not given, it defaults to 4619827259835644672)
       see "dumpsys SurfaceFlinger --display-id" for valid display IDs.
   -p: outputs in png format.
   --hint-for-seamless If set will use the hintForSeamless path in SF

If FILENAME ends with .png it will be saved as a png.
If FILENAME is not given, the results will be printed to stdout.
```bash adb exec-out screencap --help ``` <details> <summary>Output:</summary> ``` usage: screencap [-ahp] [-d display-id] [FILENAME] -h: this message -a: captures all the active displays. This appends an integer postfix to the FILENAME. e.g., FILENAME_0.png, FILENAME_1.png. If both -a and -d are given, it ignores -d. -d: specify the display ID to capture (If the id is not given, it defaults to 4619827259835644672) see "dumpsys SurfaceFlinger --display-id" for valid display IDs. -p: outputs in png format. --hint-for-seamless If set will use the hintForSeamless path in SF If FILENAME ends with .png it will be saved as a png. If FILENAME is not given, the results will be printed to stdout. ``` </details>
Author
Owner
adb exec-out screencap --hint-for-seamless -p > test.png

does not have the scrolling aspect, but maybe the Safety app Features tab does not support it.

```bash adb exec-out screencap --hint-for-seamless -p > test.png ``` does not have the scrolling aspect, but maybe the *Safety* app *Features* tab does not support it.
Author
Owner
Should investigate https://www.reddit.com/r/NothingTech/comments/191dix2/how_to_take_scrolling_screenshot/
Author
Owner
Related to [Benjamin_Loison/Backup_Android_apps/issues/26](https://codeberg.org/Benjamin_Loison/Backup_Android_apps/issues/26).
Author
Owner
Related to [Benjamin_Loison/One_UI/issues/2](https://codeberg.org/Benjamin_Loison/One_UI/issues/2).
Author
Owner
adb shell input keyevent KEYCODE_POWER

does not return anything and (un)locks the screen.

```bash adb shell input keyevent KEYCODE_POWER ``` does not return anything and (un)locks the screen.
Author
Owner
adb shell input -h
Output:
Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...]

The sources are: 
      touchnavigation
      touchscreen
      joystick
      stylus
      touchpad
      gamepad
      dpad
      mouse
      keyboard
      trackball

-d: specify the display ID.
      (Default: -1 for key event, 0 for motion event if not specified.)
The commands and default sources are:
      text <string> (Default: touchscreen)
      keyevent [--longpress|--doubletap] <key code number or name> ... (Default: keyboard)
      tap <x> <y> (Default: touchscreen)
      swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      draganddrop <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      press (Default: trackball)
      roll <dx> <dy> (Default: trackball)
      motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)
      keycombination [-t duration(ms)] <key code 1> <key code 2> ... (Default: keyboard, the key order is important here.)

image.png

adb shell input keyevent --longpress KEYCODE_POWER

does not return anything, but works quite as wanted:

image.png

image.png

image.png

image.png

image.png

Related to Benjamin_Loison/YouTube/issues/1.

``` adb shell input -h ``` <details> <summary>Output:</summary> ``` Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...] The sources are: touchnavigation touchscreen joystick stylus touchpad gamepad dpad mouse keyboard trackball -d: specify the display ID. (Default: -1 for key event, 0 for motion event if not specified.) The commands and default sources are: text <string> (Default: touchscreen) keyevent [--longpress|--doubletap] <key code number or name> ... (Default: keyboard) tap <x> <y> (Default: touchscreen) swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen) draganddrop <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen) press (Default: trackball) roll <dx> <dy> (Default: trackball) motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen) keycombination [-t duration(ms)] <key code 1> <key code 2> ... (Default: keyboard, the key order is important here.) ``` </details> ![image.png](/attachments/c8d91bfa-229a-4bb7-b4ed-9008bc7457b5) ```bash adb shell input keyevent --longpress KEYCODE_POWER ``` does not return anything, but works quite as wanted: ![image.png](/attachments/8356147d-1f99-4c73-ad5e-2e76fa85d8fd) ![image.png](/attachments/50e24792-788e-4997-acf4-750384085786) ![image.png](/attachments/6a7009a0-aa6c-4389-b312-c1f2fe777ead) ![image.png](/attachments/b0673564-2245-4dc4-8495-9b4cdbc92a7d) ![image.png](/attachments/8d66b846-5c38-46bb-a686-a5f2750e45fa) Related to [Benjamin_Loison/YouTube/issues/1](https://codeberg.org/Benjamin_Loison/YouTube/issues/1).
Author
Owner
Related to [Benjamin-Loison/android/issues/17](https://github.com/Benjamin-Loison/android/issues/17).
Author
Owner
[Benjamin-Loison/android/issues/310](https://github.com/Benjamin-Loison/android/issues/310) would help.
Author
Owner
xmlstarlet select --template --value-of '//node[@text="Screenshot"]/@bounds' input.xml
[712,415][808,434]

DuckDuckGo and Google search Linux grep to variables and Linux grep groups to variables.

```bash xmlstarlet select --template --value-of '//node[@text="Screenshot"]/@bounds' input.xml ``` ``` [712,415][808,434] ``` DuckDuckGo and Google search *Linux grep to variables* and *Linux grep groups to variables*.
Author
Owner

\d and \\d do not work in the following.

The Stack Overflow answer 1892107 helps.

Bash script:
REGEX="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]"
bounds='[12,34][56,78]'
if [[ $bounds =~ $REGEX ]]
then
    echo $BASH_REMATCH
    for v in "${BASH_REMATCH[@]}"
    do
         echo "|$v|"
    done
    echo "1:|${BASH_REMATCH[1]}|"
    echo "2:|${BASH_REMATCH[2]}|"
    echo "3:|${BASH_REMATCH[3]}|"
    echo "4:|${BASH_REMATCH[4]}|"
fi
Output:
[12,34][56,78]
|[12,34][56,78]|
|12|
|34|
|56|
|78|
1:|12|
2:|34|
3:|56|
4:|78|
`\d` and `\\d` do not work in the following. [The Stack Overflow answer 1892107](https://stackoverflow.com/a/1892107) helps. <details> <summary>Bash script:</summary> ```bash REGEX="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]" bounds='[12,34][56,78]' if [[ $bounds =~ $REGEX ]] then echo $BASH_REMATCH for v in "${BASH_REMATCH[@]}" do echo "|$v|" done echo "1:|${BASH_REMATCH[1]}|" echo "2:|${BASH_REMATCH[2]}|" echo "3:|${BASH_REMATCH[3]}|" echo "4:|${BASH_REMATCH[4]}|" fi ``` </details> <details> <summary>Output:</summary> ``` [12,34][56,78] |[12,34][56,78]| |12| |34| |56| |78| 1:|12| 2:|34| 3:|56| 4:|78| ``` </details>
Author
Owner

DuckDuckGo search Bash function return.

The Stack Overflow answer 17336953 helps.

DuckDuckGo search *Bash function return*. [The Stack Overflow answer 17336953](https://stackoverflow.com/a/17336953) helps.
Author
Owner
/sdcard/Pictures/Screenshots/ CLOSE_WRITE,CLOSE .pending-1763150818-Screenshot_20251107-210658_F-Droid.png
~/.bashrc:
get_ui()
{
    adb exec-out uiautomator dump /dev/tty | sed 's/UI hierchary dumped to: \/dev\/tty//'
}

get_field_value()
{
    ui=$1
    xpath=$2
    field=$3
    echo "$ui" | xmlstarlet select --template --value-of "$xpath/@$field"
}

get_middle()
{
    ui=$1
    xpath=$2
    bounds=`get_field_value "$ui" "$xpath" bounds`
    REGEX="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]"
    if [[ $bounds =~ $REGEX ]]
    then
        middleX=$(((BASH_REMATCH[1] + BASH_REMATCH[3]) / 2))
        middleY=$(((BASH_REMATCH[2] + BASH_REMATCH[4]) / 2))
        echo $middleX $middleY
    fi
}

click_ui()
{
    ui=$1
    text=$2
    middle=`get_middle "$ui" "//node[@text=\"$text\"]"`
    adb shell input tap $middle
}

get_screen_height()
{
    output=`adb shell wm size`
    REGEX="Physical size: [0-9]+x([0-9]+)"
    if [[ $output =~ $REGEX ]]
    then
        screenHeight=${BASH_REMATCH[1]}
        echo $screenHeight
    fi
}

# [Benjamin_Loison/adb/issues/29](https://gitea.lemnoslife.com/Benjamin_Loison/adb/issues/29)
take_scrolling_screenshot()
{
    adb shell input keycombination KEYCODE_POWER KEYCODE_VOLUME_DOWN
    ui=`get_ui`
    click_ui "$ui" 'Capture more'

    ui=`get_ui`
    bottomBoundary=`get_field_value "$ui" '//node[starts-with(@content-desc, "Bottom boundary ")]' 'content-desc'`
    isTopToBottom=`[ "$bottomBoundary" != 'Bottom boundary 100 percent' ] && echo true || echo false`
    contentDesc=`[ $isTopToBottom = true ] && echo Bottom || echo Top`
    startPosition=`get_middle "$ui" "//node[starts-with(@content-desc, \"$contentDesc boundary \")]"`
    endY=`[ $isTopToBottom = true ] && get_screen_height || echo 0`
    adb shell input swipe $startPosition 0 $endY

    SCREENSHOT_FOLDER='/sdcard/Pictures/Screenshots'
    (
        fileName=`adb shell "
            cd /data/local/tmp/ &&
            LD_LIBRARY_PATH=. ./inotifywait -e MOVED_TO $SCREENSHOT_FOLDER
        " | cut -d ' ' -f 3-` && \
        adb pull "$SCREENSHOT_FOLDER/$fileName"
    ) &
    click_ui "$ui" 'Save'
}

adb pull instead of inotifywait ends up with the screenshot taken without scrolling.

``` /sdcard/Pictures/Screenshots/ CLOSE_WRITE,CLOSE .pending-1763150818-Screenshot_20251107-210658_F-Droid.png ``` <details> <summary><code>~/.bashrc</code>:</summary> ```bash get_ui() { adb exec-out uiautomator dump /dev/tty | sed 's/UI hierchary dumped to: \/dev\/tty//' } get_field_value() { ui=$1 xpath=$2 field=$3 echo "$ui" | xmlstarlet select --template --value-of "$xpath/@$field" } get_middle() { ui=$1 xpath=$2 bounds=`get_field_value "$ui" "$xpath" bounds` REGEX="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]" if [[ $bounds =~ $REGEX ]] then middleX=$(((BASH_REMATCH[1] + BASH_REMATCH[3]) / 2)) middleY=$(((BASH_REMATCH[2] + BASH_REMATCH[4]) / 2)) echo $middleX $middleY fi } click_ui() { ui=$1 text=$2 middle=`get_middle "$ui" "//node[@text=\"$text\"]"` adb shell input tap $middle } get_screen_height() { output=`adb shell wm size` REGEX="Physical size: [0-9]+x([0-9]+)" if [[ $output =~ $REGEX ]] then screenHeight=${BASH_REMATCH[1]} echo $screenHeight fi } # [Benjamin_Loison/adb/issues/29](https://gitea.lemnoslife.com/Benjamin_Loison/adb/issues/29) take_scrolling_screenshot() { adb shell input keycombination KEYCODE_POWER KEYCODE_VOLUME_DOWN ui=`get_ui` click_ui "$ui" 'Capture more' ui=`get_ui` bottomBoundary=`get_field_value "$ui" '//node[starts-with(@content-desc, "Bottom boundary ")]' 'content-desc'` isTopToBottom=`[ "$bottomBoundary" != 'Bottom boundary 100 percent' ] && echo true || echo false` contentDesc=`[ $isTopToBottom = true ] && echo Bottom || echo Top` startPosition=`get_middle "$ui" "//node[starts-with(@content-desc, \"$contentDesc boundary \")]"` endY=`[ $isTopToBottom = true ] && get_screen_height || echo 0` adb shell input swipe $startPosition 0 $endY SCREENSHOT_FOLDER='/sdcard/Pictures/Screenshots' ( fileName=`adb shell " cd /data/local/tmp/ && LD_LIBRARY_PATH=. ./inotifywait -e MOVED_TO $SCREENSHOT_FOLDER " | cut -d ' ' -f 3-` && \ adb pull "$SCREENSHOT_FOLDER/$fileName" ) & click_ui "$ui" 'Save' } ``` </details> `adb pull` instead of `inotifywait` ends up with the screenshot taken without scrolling.
Author
Owner
adb: error: failed to stat remote object '/sdcard/Pictures/Screenshots/Screenshot_20251107-211406_Permission': No such file or directory
adb pull "/sdcard/Pictures/Screenshots/Screenshot_20251107-211357_Permission controller.png"
/sdcard/Pictures/Screenshots/Screenshot_20251107-211357_Permission controller.png: 1 file pulled, 0 skipped. 23.2 MB/s (42788 bytes in 0.002s)
``` adb: error: failed to stat remote object '/sdcard/Pictures/Screenshots/Screenshot_20251107-211406_Permission': No such file or directory ``` ```bash adb pull "/sdcard/Pictures/Screenshots/Screenshot_20251107-211357_Permission controller.png" ``` ``` /sdcard/Pictures/Screenshots/Screenshot_20251107-211357_Permission controller.png: 1 file pulled, 0 skipped. 23.2 MB/s (42788 bytes in 0.002s) ```
Author
Owner

I edited above take_scrolling_screenshot to work fine with spaces in file name.

I edited above `take_scrolling_screenshot` to work fine with spaces in file name.
Author
Owner

Could delete the associated screenshot(s) on the device.

Could delete the associated screenshot(s) on the device.
Author
Owner

Let us prefer clicking on Capture more text middle than the associated symbol.

Let us prefer clicking on *Capture more* text middle than the associated symbol.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Benjamin_Loison/adb#29