1. 背景

由于公司的办公电脑也用于深度学习的模型训练,该电脑就不能同时大型软件(连Chrome也不能多开标签),避免影响训练。于是就想把新手机“红米Note 12 Turbo”利用起来,处理一些“轻办公”的工作。

找到方案是:

  • 方案1:Android系统利用chroot安装完整Linux系统,运行基于X11的图形化软件(例如Chrome),PC端运行X server
  • 方案2:手机运行Android桌面模式,并投屏到PC。

由于方案1运行不流畅、不能方便利用GPU加速、软件兼容不佳等,只能放弃。方案2整理了一下,能达到比较高的实用性。

2. 原理

据说从Android 10开始,Android系统内置了桌面模式。该模式下,App可以自由拖动显示位置,并调整窗口大小(跟PC操作系统一样)。

有趣的是,“开发者选项”里开启了“模拟辅助显示设备”,就可以启用桌面模式,而且基本不影响手机正常显示模式。可以认为同一个Android手机上同时运行“手机模式”和“桌面模式”,App能在这两个模式之间显示。

最后,利用scrcpy把“模拟辅助显示设备”投屏到PC端,就可以使用大屏幕显示“桌面模式”,并且利用鼠标键盘进行输入。

据说手机直连显示器(需要手机直接输出HDMI功能),或者无线连接Miracast,都可以显示“桌面模式”。但是手上没有相关设备,不能验证。

3. 配置

3.1. PC端软件

3.2. Android必要配置

  • 启用“开发者模式”。
  • 进入“设置” -> “系统” -> “开发者选项”,勾选“启用可自由调整的窗口”、“强制使用桌面模式”。

    • 其中“强制使用桌面模式”,就是“模拟辅助显示设备”启用桌面模式。

3.3. 启动命令

在PC端的命令窗口执行以下命令即可启动。Linux Shell脚本参考如下:

#!/bin/bash

CMD_ADB=/opt/android-sdk/platform-tools/adb
CMD_SCRCPY=/opt/scrcpy/scrcpy
PHONE_NAME=MyPhone

# Turn on Simulate secondary displays of android phone
"${CMD_ADB}" shell settings put global overlay_display_devices 1920x1080/180

# Get display-id of Simulate secondary displays
DISPLAY_ID=$("${CMD_SCRCPY}" --list-displays | "${CMD_ADB}" shell "grep -o 'display-id=[1-9][0-9]*' | sed 's/display-id=\([1-9][0-9]*\)/\1/'")
echo Display ID: ${DISPLAY_ID}

# Cast screen
"${CMD_SCRCPY}" --display-id=${DISPLAY_ID} --keyboard=uhid --mouse=sdk --no-audio --power-off-on-close --shortcut-mod="lctrl,rctrl" --stay-awake --turn-screen-off --window-title="${PHONE_NAME} - Android Desktop Mode" --window-x=0 --window-y=25

# Turn off Simulate secondary displays of android phone
${CMD_ADB} shell settings put global overlay_display_devices null

说明:

  • CMD_ADB设置adb命令所在位置。
  • CMD_SCRCPY设置scrcpy命令所在位置。
  • PHONE_NAME设置手机名称,作为投屏窗口的标题。
  • adb shell settings put global overlay_display_devices用于开启或关闭Android上“模拟辅助显示设备”。

    • 如果在“开发者选项”中开启“模拟辅助显示设备”,没有DPI选项,所以这里通过命令开启。
    • 值为1920x1080/180,设置“模拟辅助显示设备”的分辨率为1920x1080,DPI为180。此值适合针对20吋左右的屏幕。DPI的值,主要影响“模拟辅助显示设备”UI效果,包括字体大小,但不影响手机正常模式。
    • 值为"1920x1080/180\;1920x1080/180",显示两个“模拟辅助显示设备”。多个“模拟辅助显示设备”的配置,需要用双引号(")包裹,并以\;分隔。
    • 值为null,关闭“模拟辅助显示设备”。
  • 获取“模拟辅助显示设备”的“display-id”,用于scrcpy投屏。

    • 这里利用了Android自带的grepsed实现字符串匹配提取,避免操作系统缺乏相关命令(例如Windows的CMD)。
    • 如果PC端是Linux设备,可以改为“DISPLAY_ID=$(${CMD_SCRCPY} --list-displays | grep -oP '(?<=display-id=)1-9*')”,简化命令。
  • 启动scrcpy

    • 相关参数可以通过scrcpy --help查阅。
  • 关闭“模拟辅助显示设备”。

    • 由于scrcpy运行时,会占着终端,同时暂停了Shell脚本的运行。那么scrcpy停止后,就可以自动执行关闭“模拟辅助显示设备”。

Windows的CMD批处理脚本,参考如下:

@echo off

set PHONE_NAME=MyPhone
set CMD_ADB=D:\Program Files\android-sdk\platform-tools\adb.exe
set CMD_SCRCPY_PATH=D:\Program Files\scrcpy
set CMD_SCRCPY=scrcpy.exe
set TEMP_FILE="C:\Users\%username%\AppData\Local\Temp\scrcpy_display_id_%RANDOM%.txt"

rem Turn on auxiliary display device
"%CMD_ADB%" shell settings put global overlay_display_devices 1920x1080/180

rem Get display id of auxiliary display device
"%CMD_SCRCPY_PATH%\%CMD_SCRCPY%" --list-displays | "%CMD_ADB%" shell "grep -o 'display-id=[1-9][0-9]*' | sed 's/display-id=\([1-9][0-9]*\)/\1/'" > %TEMP_FILE%
set /p DISPLAY_ID=<%TEMP_FILE%
del %TEMP_FILE%
echo Display id: %DISPLAY_ID%

rem adb shell am start-activity --display %DISPLAY_ID% cu.axel.smartdock/cu.axel.smartdock.activities.MainActivity
rem adb shell am stack list | adb shell "grep 'cu.axel.smartdock/cu.axel.smartdock.activities.MainActivity' | sed 's/^[[:space:]]*taskId=\([1-9][0-9]*\).*/\1/i'"

rem Run scrcpy
"%CMD_SCRCPY_PATH%\%CMD_SCRCPY%" --display-id=%DISPLAY_ID% --keyboard=uhid --mouse=sdk --no-audio --power-off-on-close --shortcut-mod="lctrl,rctrl" --stay-awake --turn-screen-off --window-title="%PHONE_NAME% - Android Desktop Mode" --window-x=0 --window-y=25

rem Turn off auxiliary display device
"%CMD_ADB%" shell settings put global overlay_display_devices null

标签: scrcpy

添加新评论