Search

Ubuntu - Take Screen capture of your Android device even from Recovery

Contents[Hide]

dropcap ubuntu android

With ADB, a lot of possibilities are open to administrate and tweak your Android device. A tool like QtADB is a good example of what can be done.

Some time back, I discovered that you can take some screenshots of your Android device thru ADB with a inbuilt utility called screencap. But it only works when you are running a normal android session, not when you are in recovery mode.

After some searches, I found that many devices, depending on their hardware, can provide some screen capture thru a frame buffer.

Both these approaches open some nice possibilities to take screenshot of your device while running any type of application (tutorials, games, …) or even running a recent version of recovery like TWRP where ADB is activated by default.

This article explains how to take a screenshot of an android device in ADB mode thru some simple console commands by using both screencap or frame buffer methods.

It also provides a GUI tool to take sreenshot of your android device with a single click from the comfort of your linux desktop.

It has been written and tested on Ubuntu 14.04 LTS, but it should be applicable to any modern Linux flavor. Frame buffer capture under TWRP recovery has been tested on Nexus S, Nexus 7 2012 and Nexus 5.

1. Pre-requisite

1.1. YAD

The screenshot GUI described later in this article uses YAD (Yet Another Dialog).

YAD is a powerful fork of Zenity with many improvements, but it is not available in Ubuntu official repositories. So, we need to install it thru PPA WebUpd8.

Terminal
# sudo add-apt-repository ppa:webupd8team/y-ppa-manager
# sudo apt-get update
# sudo apt-get install yad

1.2. ADB

Before being able to make any screen capture of your android device, you should make sure that :

  • adb client is installed on your computer
  • adb is enabled on your android device
  • your device is recognised by your computer

You can follow this guide Ubuntu 14.04 - Install Android Tools (ADB, Fastboot, ... & QtADB) to get everything ready.

If everything is ok, your device should be detected thru ADB :

Terminal
# adb devices
List of devices attached
015d2d426d640c1a device

2. Screenshot with screencap

Screencap is a small screen capture utility available with any modern Android build.

It is very simple to use and you don't need a rooted device to use it.

Because of that, this should be the prefered method when available.

First thing is to test that screencap is available on your device :

Terminal
# adb shell "screencap -h" | grep "usage" | cut -d' ' -f2
screencap

When screencap is available, a screen capture can be done into 2 very simple steps :

  1. run screencap to a local file on sdcard
  2. pull out this file to your computer

These commands will do the job :

Terminal
# adb shell "screencap -p > /sdcard/screenshot.png"
# adb pull /sdcard/screenshot.png screenshot.png

Your screenshot is now available.

android nexus7 boot android nexus7 desktop android nexus7 contrejour

3.  Screenshot thru framebuffer

This method is very interesting when screencap is not available (running a very old Android version or running a modern recovery like TWRP).

On many android devices, your screen content may be accessible thru a frame buffer file named /dev/graphics/fb0.

This file may or may not be used on your device depending on its hardware. So this method may fail depending on your device's hardware.

If framebufer file is used, it contains your raw screen content. But this file is only accessible to root user.

So your device needs to be rooted (which is obviously the case when you run a recovery like TWRP).

The first time you'll access your framebuffer content, you may be asked to grant root access to adb process.

A screenshot thru framebuffer is done into 3 simple steps :

  1. copy framebuffer content to a local file on sdcard
  2. pull out this file to your computer
  3. convert it from raw to png format with avconv

Before converting the raw framebuffer, you need to know 2 things :

  • your screen resolution
  • the encoding used (rgb565, rgba, …)

Screen resolution can be retrieved thru adb when running a normal Android session :

Terminal
# adb shell "wm size"
Physical size: 800x1280

Color encoding is not available as such. But here are the main rules :

  • If your device is using 65536 colors with 16bits pixel (most devices), its framebuffer should be encoded using rgb565, bgr565, …
  • If your device is using 16M colors with 24bits pixel, its framebuffer should be encoded using rgba or bgra.

All different encoding should be tried to find the right one for a specific device.

Raw framebuffer conversion is done using avconv with following options :

  • input format forced to raw (-vcodec rawvideo)
  • first frame only (-vframes 1)
  • color space forced to whichever decided (-pix_fmt rgb565)
  • transparency forced to 255 (-filter lutrgb=a=255)

Here are the commands to run to extract a screenshot using framebuffer on a Nexus 7 2012 running TWRP recovery :

Terminal
# adb shell "cat /dev/graphics/fb0 > /sdcard/screenshot.raw"
# adb pull /sdcard/screenshot.raw
# avconv -vframes 1 -vcodec rawvideo -f image2 -pix_fmt rgb565 -s 800x1280 -i screenshot.raw -filter lutrgb=a=255 screenshot.png
avconv version 9.18-6:9.18-0ubuntu0.14.04.1, Copyright (c) 2000-2014 the Libav developers
built on Mar 16 2015 13:19:10 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
Input #0, image2, from 'screenshot.raw':
Duration: 00:00:00.04, start: 0.000000, bitrate: N/A
Stream #0.0: Video: rawvideo, rgb565le, 800x1280, 25 tbn
Output #0, image2, to 'screenshot.png':
Metadata:
encoder : Lavf54.20.4
Stream #0.0: Video: png, rgb24, 800x1280, q=2-31, 200 kb/s, 90k tbn, 25 tbc
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo -> png)
Press ctrl-c to stop encoding
frame= 1 fps= 0 q=0.0 Lsize= 0kB time=0.04 bitrate= 0.0kbits/s
video:26kB audio:0kB global headers:0kB muxing overhead -100.000000%

You screenshot should be available under screenshot.png.

android nexus7 recovery android nexuss recovery

4.  GUI tool

Now that we know how to take screenshots thru screencap or thru frame buffer, next step is to write a simple GUI tool to do the job.

ubuntu android screenshot

4.1. Main tool

This tool handles connexion of multiple devices (thru their serial number) and is in charge  of following tasks :

  1. detect new devices at startup
  2. if device is detected, extract its hardware screen size and its commercial name to simplify selection
  3. read and save data from the configuration file
  4. detect if connected devices need screencap or frame buffer method
  5. propose a list of all detected devices to do screenshot
  6. process screenshot extraction and convert it with the right method

It is provided by /usr/local/bin/android-screenshot script.

/usr/local/bin/android-screenshot
#!/bin/bash
# --------------------------------------------
# Takes screenshot from android devices
# connected thru ADB
#
# More explainations are available at
#   http://bernaerts.dyndns.org/...
# Depends on :
#   * adb
#   * avconv
#   * yad
# Revision history :
#   05/04/2015, V1.0 - Creation by Nicolas Bernaerts
# ---------------------------------------------------

# configuration file localisation
FILE_CONF="$HOME/.android-screenshot.conf"

# set title
TITLE="Android Screenshot"

# check tools availability
command -v adb >/dev/null 2>&1 || { zenity --error --title="${TITLE}" --text="Please install adb [android-tools-adb]"; exit 1; }
command -v avconv >/dev/null 2>&1 || { zenity --error --title="${TITLE}" --text="Please install avconv"; exit 1; }
command -v yad >/dev/null 2>&1 || { zenity --error --title="${TITLE}" --text="Please install yad"; exit 1; }

# check configuration file
[ -f "${FILE_CONF}" ] || { zenity --error --title="${TITLE}" --text="Please install configuration file"; exit 1; }

# directory to hold screenshot
FILE_DIR=$(grep "directory=" "${FILE_CONF}" | cut -d'=' -f2)
[ "${FILE_DIR}" == "" ] && FILE_DIR=$HOME

# set choice possibilities
CHOICE_SCREEN=0
CHOICE_EXIT=1

# separator is line feed
IFS=$'\n'

# -----------------------------------------------------------
#  detection of connected devices
# -----------------------------------------------------------

# ensure adb server is started
adb start-server

# check if device is connected
ARR_DETECTED=( $(adb devices | head -n -1 | tail -n +2 | tr '\t' '|') )

# if no device connected, error message
[ "${#ARR_DETECTED[@]}" -eq "0" ] && { zenity --error --title="${TITLE}" --text="There isn't any device connected in ADB mode"; exit 1; }

# -----------------------------------------------------------
#  loop thru connected devices to :
#   - select screenshot method
#   - if needed, update configuration file
# -----------------------------------------------------------
for ADB_DEVICE in "${ARR_DETECTED[@]}"
do
  # get serial number
  DEVICE_SERIAL=$(echo ${ADB_DEVICE} | cut -d'|' -f1)

  # check if device is in the configuration
  DEVICE_CONF=$(grep "${DEVICE_SERIAL}=" "${FILE_CONF}")

  # if device is not in the configuration file, detect parameters and add them to the file
  if [ "${DEVICE_CONF}" == "" ]
  then
    # get device brand
    DEVICE_BRAND=$(adb -s ${DEVICE_SERIAL} shell "cat /system/build.prop" | grep "ro.product.brand" | cut -d'=' -f2- | tr -d '\r\n')

    # get device name
    DEVICE_NAME=$(adb -s ${DEVICE_SERIAL} shell "cat /system/build.prop" | grep "ro.product.model" | cut -d'=' -f2- | tr -d '\r\n')

    # get device screen size
    DEVICE_SIZE=$(adb -s ${DEVICE_SERIAL} shell "wm size" | grep "size" | cut -d':' -f2 | tr -d ' \r\n')

    # if device name is defined, add device to database
    if [ "${DEVICE_BRAND} ${DEVICE_NAME}" != "" ]
    then
      # generate configuration line
      DEVICE_CONF="${DEVICE_SERIAL}=${DEVICE_BRAND} ${DEVICE_NAME};${DEVICE_SIZE};"
  
      # write back configuration file
      echo "${DEVICE_CONF}" >> "${FILE_CONF}"
    fi
  fi

  # if device configuration exists, add device to the current list
  if [ "${DEVICE_CONF}" != "" ]
  then
    # detect screenshot method
    DEVICE_SCREENCAP=$(adb -s ${DEVICE_SERIAL} shell "screencap -h" | grep "usage" | cut -d' ' -f2)

    # add device to displayed list
    ARR_DEVICE=("${ARR_DEVICE[@]}" "${DEVICE_CONF};${DEVICE_SCREENCAP}")
 fi
done

# -----------------------------------------------------------
#  loop to do screenshots
# -----------------------------------------------------------
SELECTED_DEVICE=""
while [ "$CHOICE" != "$CHOICE_EXIT" ]
do
  # generate devices list
  LST_DEVICE="${SELECTED_DEVICE}"
  for DEVICE in "${ARR_DEVICE[@]}"
  do
    # get current device size and name
    DEVICE_SERIAL=$(echo ${DEVICE} | cut -d'=' -f1)
    DEVICE_NAME=$(echo ${DEVICE} | cut -d'=' -f2 | cut -d';' -f1)

    # add it to the list with | separator
    DEVICE_DESCRIPTION="${DEVICE_NAME} (s/n ${DEVICE_SERIAL})"
    if [ "${DEVICE_DESCRIPTION}" != "${SELECTED_DEVICE}" ]
    then
      [ "$LST_DEVICE" == "" ] && LST_DEVICE="${DEVICE_DESCRIPTION}" || LST_DEVICE="${LST_DEVICE}|${DEVICE_DESCRIPTION}"
    fi
  done
  
  # display dialog box
  SELECTION=$(yad --title "${TITLE}" --text "${TEXT}" --center --window-icon "phone" --image "phone" --width 500 \
  --button="Close:$CHOICE_EXIT" --button="Screenshot:$CHOICE_SCREEN" \
  --form --item-separator='|' --field="Device:CB" "${LST_DEVICE}" )
  CHOICE=$?

  # if selected, do the screenshot
  if [ "${CHOICE}" == "${CHOICE_SCREEN}" ]
  then
    # start extraction
    JOB_DONE=""

    # get selected device and retrieve device data
    SELECTED_DEVICE=$(echo ${SELECTION} | cut -d"|" -f1)
    DEVICE_SERIAL=$(echo ${SELECTED_DEVICE} | sed 's/^.*s\/n \(.*\).$/\1/')
    for DEVICE in "${ARR_DEVICE[@]}"
    do
      [[ "${DEVICE}" == "${DEVICE_SERIAL}"* ]] && DEVICE_DATA="${DEVICE}"
    done

    # get device data
    DEVICE_NAME="$(echo ${DEVICE_DATA} | cut -d'=' -f2 | cut -d';' -f1)"
    DEVICE_SIZE="$(echo ${DEVICE_DATA} | cut -d'=' -f2 | cut -d';' -f2)"
    DEVICE_COLOR="$(echo ${DEVICE_DATA} | cut -d'=' -f2 | cut -d';' -f3)"
    DEVICE_METHOD="$(echo ${DEVICE_DATA} | cut -d'=' -f2 | cut -d';' -f4)"

    # generate timestamped filename
    FILE="${FILE_DIR}/${DEVICE_NAME}_$(date '+%y%m%d-%I%M%S')"

    # if detected method is screencap
    if [ "${DEVICE_METHOD}" != "" ] 
    then
      (
      # send screencap command thru adb
      echo "# Capture screenshot ..."
      adb -s ${DEVICE_SERIAL} shell "screencap -p > /sdcard/screenshot.png"    

      # pull screenshot back to computer
      echo "# Pull screenshot to computer ..."
      adb -s ${DEVICE_SERIAL} pull /sdcard/screenshot.png "${FILE}.png"
      ) | yad --center --window-icon "phone" --image "phone" --width 500 --progress --pulsate --auto-close --title "${TITLE} thru Screencap" 

      # extraction is over
      JOB_DONE="ok"
    fi

    # no screencap, start framebuffer extraction
    if [ "${JOB_DONE}" != "ok" ]
    then
      (
      # check if su is available
      echo "# Check su ..."
      SU_OK=$(adb -s ${DEVICE_SERIAL} shell "which su")

      # extract framebuffer using su or not
      echo "# Extract frame buffer ..."
      [ "${SU_OK}" != "" ] && FRAME_RESULT=$(adb -s ${DEVICE_SERIAL} shell "su -c 'cat /dev/graphics/fb0 > /sdcard/screenshot.raw'") \
                           || FRAME_RESULT=$(adb -s ${DEVICE_SERIAL} shell "cat /dev/graphics/fb0 > /sdcard/screenshot.raw")

      # pull screenshot back to computer
      echo "# Pull raw file to computer ..."
      adb -s ${DEVICE_SERIAL} pull /sdcard/screenshot.raw "${FILE}.raw"
      ) | yad --center --window-icon "phone" --image "phone" --width 500 --progress --pulsate --auto-close --title "${TITLE} thru Frame Buffer" 

      # if screen size is unknown, extraction is over
      [ "${DEVICE_SIZE}" == "" ] && JOB_DONE="ok"
    fi

    # size is known, convert to png
    if [ "${JOB_DONE}" != "ok" ]
    then
      # if device colorspace is not defined, collect all declared colorspace
      [ "${DEVICE_COLOR}" == "" ] && DEVICE_COLOR=$(grep "colorspace=" "${FILE_CONF}" | cut -d'=' -f2)

      # generate colorspace to conversion array
      IFS=',' read -a ARR_COLOR <<< "${DEVICE_COLOR}"

      # loop thru colorspace array to convert raw file
      for COLORSPACE in "${ARR_COLOR[@]}"
      do
        # convert it to png
        avconv -vframes 1 -vcodec rawvideo -f image2 -pix_fmt ${COLORSPACE} -s ${DEVICE_SIZE} -i "${FILE}.raw" -filter lutrgb=a=255 "${FILE}-${COLORSPACE}.png"
      done

      # remove raw file
      rm "${FILE}.raw"
    fi
  fi
done

4.2. Configuration file

As this tool detects devices and their characteristics, its reads and saves data from ~/.android-snapshot.conf configuration file.

~/.android-snapshot.conf
[general]
directory=
colorspace=rgb565,bgr565,rgb565be,rgba,bgra

[device]
015d2d426d640c1a=google Nexus 7;800x1280;
3733C7D3FEE900EC=Google Nexus S;480x800;bgra

The [general] section handles general configuration. You can edit it if you need to configure default directory to save screenshots or to modify default color spaces used for raw screenshot conversion.

The [device] section lists each and every detected devices. For every device, a key is created with the serial number and it contains ordered data :

  1. Commercial name
  2. Screen size
  3. Color encoding

Both commercial name and screen size are detected from the device itself when it is connected running a normal Android session (not in recovery mode).

Colorspace encoding can't be detected. You have to configure it when you've determined it.

When running in frame buffer mode, if color encoding is not defined for a specific device, the GUI will extract frame buffer and convert it using all formats listed by the colorspace key. Every filename will include the colorsapce used. This should allow you to detect which colorspace should be used for this device. You can then add it at the end of your device definition. It will then be the only one used while doing raw screenshot conversions.

ubuntu screenshot colorspace

As device detection is automatic, you should first connect it and run the GUI while running a normal Android session (not a recovery).

This will allow the GUI to detect the device and its main characteristics (commercial name and screen resilution). Once detection is done, you can connect the device in recovery mode and restart the GUI. If you are lucky and your device hardware accepts framebuffer mode, you should be able to take some screenshots straight from your desktop.

4.3. Desktop integration

Desktop integration can be done easily thru a android-screenshot.desktop file :

/usr/share/applications/android-screenshot.desktop
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/usr/local/bin/android-screenshot
Name=Android Screenshot
Categories=Graphics;Utility
Icon=phone

You should now be able to start Android Screenshot from the Graphics menu.

4.4. Installation procedure

The complete tool installation can be done with these simple commands :

Terminal
# sudo wget -O /usr/local/bin/android-screenshot https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/android/android-screenshot
# sudo chmod +x /usr/local/bin/android-screenshot
# sudo wget -O /usr/share/applications/android-screenshot.desktop https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/android/android-screenshot.desktop
# wget -O $HOME/.android-screenshot.conf https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/android/android-screenshot.conf

You are now ready to do your first Android Screenshot from the comfort of a GUI.

 

Hope it helps.

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus