Repurposing an old Android phone as a USB-driven text display

January 19, 2023

Over the years I’ve ended up with an assortment of phones that are no longer fit for purpose – maybe the touchscreen is held together with tape, or they stopped getting security updates years ago, or the camera lens is shattered. But that doesn’t mean they aren’t still useful for other things!

Depending on what model of phone it is and what exactly is wrong with it, you can use them as webcams, wireless repeaters, sensor platforms, status displays, remote controls…there are lots of possibilities. This post, however, looks at turning a phone into a USB-connected ancillary screen that you can push text to from a computer.

As always this post is focused on Linux, but once it’s set up you should be able to drive it from any computer with ssh and, optionally, adb.

For my example setup I’m using an old Nexus 5X with a busted camera.

Overview

The general course of events is:

  1. Reflash the phone with LineageOS. This is optional but it gives you a freshly installed OS with no cruft and which is generally supported for longer than the manufacturer supports the stock image.
  2. Install Termux. This gives you a Linux shell environment on the phone, and the ability to install the packages we’ll need to remote control it.
  3. Install and set up an SSH server. This is what lets us log into the phone over wifi or USB and drive it remotely.
  4. Wire up all the shell scripts needed to actually use the phone remotely for things.

Installing LineageOS

This part is optional, but if you’re using an older phone this will often let you get a more up to date Android version on it, and one without lots of manufacturer-added cruft. LOS generally supports devices for longer than the manufacturer does, and even once official support is ended you can often find LOS maintainers releasing unofficial builds, like this backport of Android 10 to the Nexus 5X, which is what I used.

If you’re doing this step, start by heading over to the LineageOS website and reading the instructions for your device; even for discontinued devices using unofficial builds you’ll generally be following the official install instructions. I’m summarizing the instructions for my device here as an example, but do not blindly follow them — yours may be different!

For the 5X, the process was:

  • Go into android settings and enable USB Debugging and OEM Unlocking
  • Plug it into the computer
  • adb reboot bootloader
  • Download the latest TWRP recovery mode for the device and fastboot flash recovery to install it
  • Boot the device into recovery mode (which should now be TWRP)
  • Wipe the internal storage
  • Sideload LineageOS
  • Reboot into Lineage

Initial Setup

This assumes that you have a working, ready to go Android device, whether newly flashed with LineageOS or just using whatever Android build it came with.

First, if you plan to control it over USB instead of wifi, open the developer settings up and (re-)enable USB debugging.

Then, download and install Termux, Termux:Boot, and Termux:API. You can either download and install the APKs directly, or download F-Droid and install Termux through that. Do not install it through Google Play – that version is badly outdated.

Once installed, you need to give the various Termux components the permissions they need:

  • Open up Termux:Boot once. You don’t need to do anything with it, but this will let it register itself to start automatically on boot.
  • Go to Apps -> Termux -> Advanced and turn on Display Over Other Apps. This lets you use Termux to launch other apps and control which app has focus remotely.
  • Go to Apps -> Termux:API -> Advanced and turn on Modify System Settings. This lets you use Termux to do things like adjust the backlight settings.

Finally, open Termux and run the following commands to install all the packages we’ll need:

@phone $ pkg update
@phone $ pkg upgrade
@phone $ pkg install openssh

SSH Access

We do this first so that subsequent steps can be done remotely rather than needing to type in all the commands on the phone.

First of all, you’ll need to set a password and start the ssh server. So open up Termux and run:

@phone $ passwd
@phone $ sshd

The server is now running and should stay running until next time you restart the phone. To access it over wifi, get the phone’s address (from the settings menu or by running ifconfig in Termux) and then run:

@host $ ssh -p 8022 [phone IP address]

If you want to talk to it over USB, plug it into the host computer and then run:

@host $ adb forward tcp:8022 tcp:8022
@host $ ssh -p 8022 localhost

In either case, it should prompt you for a password. Enter the one you just set on the phone and you should have a shell.

Automatic ssh server on boot

It’s nice to not have to manually open Termux and type in sshd every time you start up the phone, so let’s get it running on boot automatically.

Any script you put in ~/.termux/boot/ on the phone will be found automatically by Termux:Boot, so ssh into the phone and create a script there to start the ssh server:

@phone $ mkdir -p ~/.termux/boot/
@phone $ cd ~/.termux/boot/
@phone $ echo "sshd" > ssh-server
@phone $ chmod a+x ssh-server

This trivial one-liner starts the ssh server, and will run anywhere from five seconds to five minutes (depending on android version and phone model) after you unlock the screen for the first time after booting.

Passwordless ssh login

This is the same as any other passwordless login setup. First of all, generate a user ssh key if you haven’t already:

@host $ ssh-keygen

Then copy it to the phone:

# USB
@host $ ssh-copy-id -p 8022 localhost
# Wifi
@host $ ssh-copy-id -p 8022 [phone IP]

And you should be good to go. Test afterwards by logging in and it should use the key automatically rather than prompting you for the phone password.

Termux:API Features

Termux:API lets us do a bunch of cool things already with the phone. You need to install the command line tools to access them:

@phone $ pkg install termux-api
@phone $ echo 'termux-api-start' > ~/.termux/boot/termux-api
@phone $ chmod a+x ~/.termux/boot/termux-api
@phone $ termux-api-start

Now there’s a bunch of cool things you can do:

  • Take photos with termux-camera-photo and download them with scp
  • Display notifications with termux-toast
  • Remote control IR devices with termux-infrared-transmit (if the phone has an IR transmitter)
  • Make noises with termux-vibrate, termux-tts-speak, and termux-media-player
  • Receive text messages with termux-sms-list, and send them with termux-sms-send (if it has a SIM)
  • Do speech-to-text conversion with termux-speech-to-text
  • Monitor the local environment with termux-sensor
  • Open URLs on the phone with termux-open-url

and probably a bunch of other things I haven’t thought of! Some of these require additional permissions; if so, check the phone screen for a permissions popup for Termux:API.

Also, while not part of Termux:API, you can bring termux to the forground remotely with: am start --user 0 -n com.termux/com.termux.app.TermuxActivity.

tmux Integration

The simplest way to change what is being displayed remotely is to run tmux on the phone; then you can connect to it over ssh, connect to the tmux session, run a command, then detach from the session and leave the phone showing the output of that command (which may be, for example, something long-running that continually updates its display, e.g. fetching log messages or dashboard metrics from somewhere).

The easiest way to enable this is to start tmux automatically when termux opens on the phone; I did this with the following ~/.bashrc file:

# Skip noninteractive mode or when connecting over ssh or already inside tmux
[[ $- != *i* ]] && return
[[ $SSH_TTY ]] && return
[[ $TMUX ]] && return

if tmux has-session;
  then tmux -2u attach
  else tmux -2u
fi

Which will connect to an existing tmux session if there is one, or start a new one if there is not.

I also like to set some tmux options in ~/.tmux.conf; the particular settings people might be interested in for cell phone usage are:

# Override TERM.
set -g default-terminal tmux-256color
# Disable status bar at the bottom.
set -g status off
# Shrink to the size of the smallest attached client (which is almost certainly
# the phone) even if a larger client is connected.
setw -g window-size smallest

With all this set up, you can then do, for example:

@host $ ssh phone
@phone $ tmux attach
@phone $ watch -t -n 300 'curl -s wttr.in | head -n17'

and now the phone displays an ASCII-art weather forecast, updating every five minutes. Replace with the monitoring command of your choice.

Pushing text to the phone directly

The tmux client running on the phone is connected to a ptr (“pseudoterminal”, a virtual serial terminal), so by writing to the pty you can push text directly to the phone screen. (Indeed, this is true even without tmux, but using tmux makes it easy to figure out which pty.)

@phone $ tmux list-clients
/dev/pts/0: 0 [56x46 xterm-256color] (attached,focused,UTF-8)

That tells you that the tmux displayed on the phone’s screen is attached to /dev/pts/0 and is 56 columns wide and 46 lines high.

This means that if you want to skip the whole “run a monitoring command on the phone” rigamarole and just push text to it directly, you can do that by writing the text to /dev/pts/0; it will behave as if a program running in that terminal had output the text, including handling escape sequences, etc.

So, for example, this will clear the screen and display the host system’s uptime on the phone screen in bold:

@host $ printf '\x1B[2J\x1B[1m %s \x1B[0m' "$(uptime)" | ssh phone dd of=/dev/pts/0

More generally, you can run any command on the host system and push the output to the phone just by piping it to ssh phone dd of=/dev/pts/0 (or whatever pty tmux on the phone is attached to). For commands that need to know the terminal size for correct output (e.g. task), you can use tmux list-clients or stty -a -F /dev/pts/0 to get the terminal size. It’s not a good solution for anything interactive, but for an automatic data push to the phone, it’s pretty handy.

Practical Uses

I originally set this up as a tertiary screen for my work computer; too small for interactive usage, it displays a filtered list of my most urgent TODOs and informational messages when long-running commands like unit test suites complete. One thing I want to try, but have not yet attempted, is reconfiguring my desktop notifications to generate popups on the phone screen instead. I think this is the sort of task at which it excels; moving either (a) something you want to continuously monitor or (b) something you want to be informed of when it happens from the main desktop to a dedicated display. You can even have it vibrate or make a noise when this happens!

I’m sure there are many more uses for this that I haven’t yet thought of; experiment and come up with your own!