Skip to content

Instantly share code, notes, and snippets.

@emilwojcik93
Last active September 1, 2025 18:10
Show Gist options
  • Save emilwojcik93/3ca0b063055d37a2fb1af10ab2a4aa2b to your computer and use it in GitHub Desktop.
Save emilwojcik93/3ca0b063055d37a2fb1af10ab2a4aa2b to your computer and use it in GitHub Desktop.
This Termux script automatically detects and sets the optimal resolution for virtual displays based on connected external displays. It handles the entire process including dependency installation, ADB pairing/connection, external display detection, and resolution configuration.
#!/data/data/com.termux/files/usr/bin/env bash
# filepath: /data/data/com.termux/files/home/termux_display_resolution.sh
# Set Termux-specific paths
TERMUX_PREFIX="/data/data/com.termux/files/usr"
TERMUX_HOME="/data/data/com.termux/files/home"
TEMP_DIR="$TERMUX_HOME/.temp"
# Create temp directory if it doesn't exist
mkdir -p "$TEMP_DIR"
# Function to show colored output
print_colored() {
local color="$1"
local message="$2"
case "$color" in
"red") echo -e "\033[1;31m$message\033[0m" ;;
"green") echo -e "\033[1;32m$message\033[0m" ;;
"yellow") echo -e "\033[1;33m$message\033[0m" ;;
"blue") echo -e "\033[1;34m$message\033[0m" ;;
*) echo -e "$message" ;;
esac
}
# Function to print header
print_header() {
print_colored "blue" "====================================="
print_colored "blue" " Display Resolution Optimizer Tool "
print_colored "blue" "====================================="
echo ""
}
# Function to print usage
print_usage() {
echo "Usage: $0"
echo "This script sets virtual display resolution to match external displays."
echo "Works from Termux environment and handles dependencies installation."
exit 1
}
# Function to install dependencies
install_dependencies() {
print_colored "yellow" "Checking for required packages..."
# Ensure package lists are up to date
pkg update -y
# Check for and install required packages
for package in android-tools grep coreutils sed; do
if ! dpkg -s "$package" >/dev/null 2>&1; then
print_colored "yellow" "Installing $package..."
pkg install -y "$package"
if [ $? -ne 0 ]; then
print_colored "red" "Failed to install $package. Exiting."
exit 1
fi
fi
done
print_colored "green" "All dependencies are installed."
}
# Function to handle ADB pairing
handle_adb_pairing() {
# Check if any devices are already connected
if adb devices | grep -q "device$"; then
print_colored "green" "ADB device already connected."
return 0
fi
# Function to get the local IP address
get_local_ip() {
# Try using ifconfig first for wlan0 (WiFi)
ifconfig wlan0 2>/dev/null | grep -oP 'inet addr:\K\d+(\.\d+){3}' || \
ifconfig wlan0 2>/dev/null | grep -oP 'inet\s+\K\d+(\.\d+){3}' || \
# Then try any interface except lo (loopback)
ifconfig 2>/dev/null | grep -v '127.0.0.1' | grep -oP 'inet addr:\K\d+(\.\d+){3}' || \
ifconfig 2>/dev/null | grep -v '127.0.0.1' | grep -oP 'inet\s+\K\d+(\.\d+){3}'
}
local_ip=$(get_local_ip)
# Check if local_ip is in valid IP format
if [[ -n "$local_ip" && $local_ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
print_colored "blue" "Your device IP address appears to be: $local_ip"
# Ask for target device IP with the local IP as default
print_colored "blue" "Enter target device IP address [$local_ip]:"
read device_ip
# If user pressed enter without typing, use the local_ip as default
if [ -z "$device_ip" ]; then
device_ip="$local_ip"
print_colored "yellow" "Using local IP address: $device_ip"
fi
else
# If no valid local IP was found
print_colored "yellow" "Could not determine your local IP address."
print_colored "blue" "Enter target device IP address:"
read device_ip
# Ensure the user entered something
while [ -z "$device_ip" ]; do
print_colored "red" "IP address cannot be empty."
print_colored "blue" "Enter target device IP address:"
read device_ip
done
fi
# Default ports
connect_port=5555
pair_port=5555 # Most devices use 5555 for pairing too but internally subtract 1
print_colored "blue" "Enter ADB connection port [5555]:"
read port_input
if [ -n "$port_input" ]; then
connect_port=$port_input
fi
# Try to connect first
print_colored "yellow" "Trying to connect to $device_ip:$connect_port..."
adb connect "$device_ip:$connect_port"
# Check if connection was successful
if adb devices | grep -q "$device_ip:$connect_port.*device$"; then
print_colored "green" "Successfully connected to device."
return 0
fi
# If connection failed, try pairing
print_colored "yellow" "Connection failed. Need to pair first."
# Ask for pairing port (often different from connect port)
print_colored "blue" "Enter ADB pairing port [Typically $((connect_port-1))]:"
read pair_port_input
if [ -n "$pair_port_input" ]; then
pair_port=$pair_port_input
else
pair_port=$((connect_port-1))
fi
# Ask for pairing code
print_colored "blue" "Enter pairing code (shown on device):"
read pairing_code
# Pairing process
print_colored "yellow" "Pairing with device at $device_ip:$pair_port using code: $pairing_code"
adb pair "$device_ip:$pair_port" "$pairing_code"
# Try connecting again after pairing
print_colored "yellow" "Trying to connect after pairing..."
adb connect "$device_ip:$connect_port"
# Final check
if adb devices | grep -q "$device_ip:$connect_port.*device$"; then
print_colored "green" "Successfully connected to device after pairing."
return 0
else
print_colored "red" "Failed to connect to ADB device after pairing attempts."
return 1
fi
}
# Function to check for external display
check_external_display() {
print_colored "yellow" "Checking for external displays..."
# Get display information
adb shell dumpsys display > "$TEMP_DIR/display_info.txt"
# Check for HDMI or external display
if grep -q "HDMI\|EXTERNAL\|local:[^0]\|uniqueId=\"local:" "$TEMP_DIR/display_info.txt"; then
print_colored "green" "External display detected."
return 0
else
print_colored "red" "No external display detected. Please connect an external display first."
return 1
fi
}
# Function to find max resolution for external displays
find_max_resolution() {
print_colored "yellow" "Finding maximum resolution for external displays..."
# First try direct HDMI search
display_name="HDMI"
hdmi_max_res=$(adb shell dumpsys display | grep -m 1 "${display_name}" | awk -F' |=' '/width/ && /height/ {for(i=1;i<=NF;i++) if($i=="width") print $(i+1) "x" $(i+3)}' | tr -d ',' | sort -nr -k1,1 -k2,2 | head -n 1)
if [[ -n "$hdmi_max_res" ]]; then
print_colored "green" "Found max resolution from HDMI display: $hdmi_max_res"
max_resolution=$hdmi_max_res
return 0
fi
# If HDMI search fails, try more extensive parsing
print_colored "yellow" "Checking all external display modes..."
max_width=0
max_height=0
max_resolution=""
# Get all external display modes
while IFS= read -r line; do
if [[ $line =~ DisplayDeviceInfo && ! $line =~ virtual && ! $line =~ displayId=0 ]]; then
# Check for supported modes
if [[ $line =~ supportedModes\ \[\{([^]]+)\}\] ]]; then
modes_info="${BASH_REMATCH[1]}"
# Process each mode
while IFS= read -r mode; do
if [[ $mode =~ width=([0-9]+),\ height=([0-9]+) ]]; then
width="${BASH_REMATCH[1]}"
height="${BASH_REMATCH[2]}"
# Calculate area
current_area=$((width * height))
max_area=$((max_width * max_height))
if [[ $max_width -eq 0 ]] || (( current_area > max_area )); then
max_width=$width
max_height=$height
max_resolution="${width}x${height}"
print_colored "yellow" "Found resolution: ${width}x${height} (new max)"
fi
fi
done < <(echo "$modes_info" | tr '{' '\n')
fi
fi
done < "$TEMP_DIR/display_info.txt"
# If we found a resolution
if [[ -n "$max_resolution" ]]; then
print_colored "green" "Found max resolution from modes: $max_resolution"
return 0
fi
# Last attempt - check basic width/height attributes
while IFS= read -r line; do
if [[ $line =~ "DisplayDeviceInfo" && ! $line =~ "virtual" && ! $line =~ "displayId=0" ]]; then
if [[ $line =~ width=([0-9]+) && $line =~ height=([0-9]+) ]]; then
width=$(echo "$line" | grep -oP "width=\K[0-9]+")
height=$(echo "$line" | grep -oP "height=\K[0-9]+")
current_area=$((width * height))
max_area=$((max_width * max_height))
if (( current_area > max_area )); then
max_width=$width
max_height=$height
max_resolution="${width}x${height}"
fi
fi
fi
done < "$TEMP_DIR/display_info.txt"
if [[ -n "$max_resolution" ]]; then
print_colored "green" "Found max resolution: $max_resolution"
return 0
else
print_colored "red" "Could not determine external display resolution."
return 1
fi
}
# Function to find virtual display
find_virtual_display() {
print_colored "yellow" "Looking for virtual displays..." >&2
# Multiple strategies to find virtual display ID
virtual_display_id=""
# First strategy: search for uniqueId with virtual
grep -E "uniqueId=.*virtual" "$TEMP_DIR/display_info.txt" > "$TEMP_DIR/virtual_displays.txt"
while IFS= read -r line; do
if [[ $line =~ displayId[=\ ]+([0-9]+) ]]; then
virtual_display_id="${BASH_REMATCH[1]}"
print_colored "green" "Found virtual display ID: $virtual_display_id" >&2
break
fi
done < "$TEMP_DIR/virtual_displays.txt"
# Second strategy: search for mUniqueDisplayId=virtual
if [[ -z "$virtual_display_id" ]]; then
while IFS= read -r line; do
if [[ $line == *"mUniqueDisplayId=virtual"* ]]; then
display_section=$(grep -A 5 "$line" "$TEMP_DIR/display_info.txt")
if [[ $display_section =~ displayId[\ =]+([0-9]+) ]]; then
virtual_display_id="${BASH_REMATCH[1]}"
print_colored "green" "Found virtual display ID from mUniqueDisplayId: $virtual_display_id" >&2
break
fi
fi
done < "$TEMP_DIR/display_info.txt"
fi
# Third strategy: look for "virtual" and "displayId" together
if [[ -z "$virtual_display_id" ]]; then
display_line=$(grep -m 1 -E 'virtual.*displayId|displayId.*virtual' "$TEMP_DIR/display_info.txt")
if [[ $display_line =~ displayId[\ =]+([0-9]+) ]]; then
virtual_display_id="${BASH_REMATCH[1]}"
print_colored "green" "Found virtual display ID via direct search: $virtual_display_id" >&2
fi
fi
# Fourth strategy: Look for "Desktop" display which is usually virtual
if [[ -z "$virtual_display_id" ]]; then
desktop_line=$(grep -m 1 -B 3 -A 3 '"Desktop"' "$TEMP_DIR/display_info.txt")
if [[ $desktop_line =~ displayId[\ =]+([0-9]+) ]]; then
virtual_display_id="${BASH_REMATCH[1]}"
print_colored "green" "Found Desktop virtual display ID: $virtual_display_id" >&2
fi
fi
# Fifth strategy: try ID=2 as fallback (common for virtual displays)
if [[ -z "$virtual_display_id" ]]; then
virtual_display_id="2"
print_colored "yellow" "Using fallback virtual display ID: $virtual_display_id" >&2
fi
# Only output the raw ID number without any extra text or formatting
echo "$virtual_display_id"
}
# Function to set resolution for virtual display
set_virtual_resolution() {
local display_id="$1"
local resolution="$2"
width=${resolution%x*}
height=${resolution#*x}
print_colored "yellow" "Setting virtual display (ID: $display_id) to resolution: $resolution..."
# Set the resolution
adb shell wm size $width\x$height -d $display_id
# Check result
if [ $? -eq 0 ]; then
# Verify the change
current_res=$(adb shell wm size -d $display_id)
print_colored "green" "Resolution set successfully!"
print_colored "blue" "Current configuration:\n$current_res"
return 0
else
print_colored "red" "Failed to set resolution."
return 1
fi
}
# Function to clean up unreachable ADB connections
clean_unreachable_adb_connections() {
print_colored "yellow" "Checking existing ADB connections..."
# Get list of connected devices, excluding the header and empty lines
adb_devices=$(adb devices | grep -v "List" | sed '/^$/d')
if [ -z "$adb_devices" ]; then
# No devices connected, nothing to clean
print_colored "yellow" "No ADB devices currently connected."
return 0
fi
print_colored "yellow" "Found connected devices, checking their status..."
has_unreachable=false
# Check each device
while IFS= read -r line; do
device=$(echo "$line" | awk '{print $1}')
status=$(echo "$line" | awk '{print $2}')
# Only process network devices (with IP:port format)
if [[ "$device" == *":"* ]]; then
print_colored "blue" "Testing connection to $device..."
# Try a simple command with a short timeout
if ! timeout 2 adb -s "$device" shell echo "test" &>/dev/null; then
print_colored "yellow" "Device $device is unreachable, disconnecting..."
adb disconnect "$device"
has_unreachable=true
else
print_colored "green" "Device $device is responsive."
fi
fi
done <<< "$adb_devices"
if [ "$has_unreachable" = true ]; then
print_colored "green" "Cleaned up unreachable connections."
else
print_colored "green" "All connections are healthy."
fi
return 0
}
# Main function
main() {
print_header
# Check if adb is available
if ! command -v adb &> /dev/null; then
print_colored "red" "ADB not found even after installing dependencies."
# Install dependencies
install_dependencies
exit 1
fi
# Clean up any stale ADB connections before proceeding
clean_unreachable_adb_connections
# Handle ADB pairing and connection
handle_adb_pairing
if [ $? -ne 0 ]; then
print_colored "red" "Failed to establish ADB connection. Exiting."
exit 1
fi
# Check for external display
check_external_display
if [ $? -ne 0 ]; then
exit 1
fi
# Find maximum resolution
find_max_resolution
if [ $? -ne 0 ] || [ -z "$max_resolution" ]; then
print_colored "red" "Failed to determine maximum resolution. Exiting."
exit 1
fi
# Find virtual display
print_colored "yellow" "Finding virtual display..."
virtual_display_id=$(find_virtual_display)
print_colored "blue" "Using virtual display ID: $virtual_display_id"
if [ -z "$virtual_display_id" ]; then
print_colored "red" "Failed to identify virtual display. Exiting."
exit 1
fi
# Set resolution
set_virtual_resolution "$virtual_display_id" "$max_resolution"
if [ $? -ne 0 ]; then
print_colored "red" "Failed to set virtual display resolution. Exiting."
exit 1
fi
# Clean up
rm -f "$TEMP_DIR/display_info.txt" "$TEMP_DIR/virtual_displays.txt"
print_colored "green" "Operation completed successfully!"
exit 0
}
# Run the main function
main
@emilwojcik93
Copy link
Author

emilwojcik93 commented Apr 13, 2025

Android External Display Resolution Optimizer

This script automatically detects external displays connected to your Android device and sets the virtual display resolution to the optimal supported resolution. It works from Termux and handles all necessary ADB connections, pairing, and configuration.

Features

  • Automatically detects external HDMI/USB-C displays
  • Finds and sets maximum supported resolution
  • Handles ADB wireless connection and pairing
  • Cleans up stale connections
  • Works as a convenient widget shortcut

Prerequisites

  1. Install Termux and Termux:Widget from GitHub (F-Droid versions recommended):

  2. Install required packages:

    pkg update && pkg install android-tools wget curl

Installation

One-Step Installation (Widget Ready)

Run this command in Termux to download the script and create necessary directories:

# Create required directories
mkdir -p ~/.termux/widget/dynamic_shortcuts ~/.shortcuts

# Set permissions
chmod -R 755 ~/.termux/widget/dynamic_shortcuts ~/.shortcuts

# Download script to widget shortcut folder
curl -sL "https://gist.githubusercontent.com/emilwojcik93/3ca0b063055d37a2fb1af10ab2a4aa2b/raw/termux_display_resolution.sh?$(date +%s)" -o ~/.termux/widget/dynamic_shortcuts/termux_display_resolution.sh && chmod +x ~/.termux/widget/dynamic_shortcuts/termux_display_resolution.sh

# Create symbolic link for alternative access method
ln -sf ~/.termux/widget/dynamic_shortcuts/termux_display_resolution.sh ~/.shortcuts/termux_display_resolution.sh

Usage

Running Directly in Termux

~/.termux/widget/dynamic_shortcuts/termux_display_resolution.sh

Using the Widget Shortcuts (Two Methods)

Method 1: Via Termux:Widget on home screen

  1. Long-press on your home screen
  2. Select "Widgets"
  3. Find and add "Termux:Widget" to your home screen
  4. Tap the widget and select "termux_display_resolution.sh"

Method 2: Via Termux Context Menu

  1. Long-press on the Termux app icon
  2. Select "termux_display_resolution.sh" from the context menu

Example Output

=====================================
  Display Resolution Optimizer Tool
=====================================

Checking existing ADB connections...
Found connected devices, checking their status...
Testing connection to 192.168.0.12:45249...
Device 192.168.0.12:45249 is responsive.
ADB device already connected.
Checking for external displays...
External display detected.
Finding maximum resolution for external displays...
Found max resolution from HDMI display: 5120x1440
Finding virtual display...
Looking for virtual displays...
Found virtual display ID via direct search: 2
Setting virtual display (ID: 2) to resolution: 5120x1440...
Resolution set successfully!
Current configuration:
Physical size: 2560x1080
Override size: 5120x1440
Operation completed successfully!

Troubleshooting

  • If the script fails to connect via ADB, make sure:

    1. USB debugging is enabled in Developer Options
    2. Wireless debugging is enabled with pairing code visible
    3. Your device and Termux are on the same network
  • If resolution doesn't change, try manually entering your device IP and port when prompted

  • If shortcuts don't appear, check directory permissions with:

    ls -la ~/.termux/widget/dynamic_shortcuts ~/.shortcuts

Requirements

  • Android device with external display support
  • Termux and Termux:Widget installed
  • ADB debugging enabled on device

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment