在嵌入式設備、雙顯示終端或定制系統中,Android 多屏幕控制(尤其是屏幕方向旋轉)是一個兼具挑戰與價值的功能模塊。本文將深入分析如何識別多個顯示、如何通過系統 API 控制旋轉,并討論為何某些 displayId
無法旋轉。
📌 一、系統中的多屏幕結構
Android 通過 DisplayManager
和 WindowManagerService
管理顯示設備:
- 每個屏幕對應一個唯一的 Display ID(如 0、2)
- 可使用如下命令查看:
adb shell dumpsys display | grep -E 'DisplayDeviceInfo|mDisplayId='
示例輸出:
DisplayDeviceInfo{"Built-in Screen": ..., uniqueId="local:0", ...}
DisplayDeviceInfo{"HDMI Screen": ..., uniqueId="local:1", ...}
mDisplayId=0
mDisplayId=2
這表明主屏為 ID 0,HDMI 外接屏為 ID 2。
🎛? 二、屏幕旋轉 API 解析
Android 的系統服務 IWindowManager
提供旋轉接口:
freezeRotation(int rotation)
:凍結主屏幕方向freezeDisplayRotation(int displayId, int rotation)
:理論上支持控制任意 Display,但部分實現未生效
?? 這些 API 是隱藏的,僅在系統應用或具有平臺簽名權限下可用。
🧪 三、為什么某些屏幕旋轉無效?
以 Display ID = 2 為例,旋轉指令如下:
wm.freezeDisplayRotation(2, Surface.ROTATION_90);
但實際無效,原因可能包括:
? 1. 不支持旋轉的屏幕標志
通過 dumpsys display
可見:
FLAGS: FLAG_PRESENTATION, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS
但缺少了關鍵的 FLAG_ROTATES_WITH_CONTENT
,說明系統不會主動旋轉它。
? 2. 無實際內容
字段 mHasContent=false
表示該屏幕當前未顯示任何窗口,旋轉調用將無效。
? 3. 非主屏旋轉能力被限制
AOSP 默認僅對主屏做全面旋轉控制,非主屏往往依賴 Presentation 或 VirtualDisplay 機制。
? 四、實踐替代方案
針對不能通過系統旋轉控制的屏幕,可以采取以下方案:
1. 視圖級旋轉(推薦)
在 HDMI 屏幕上的 View 或 SurfaceView 設置旋轉:
yourView.setRotation(90);
適用于 UI 層模擬旋轉效果。
2. 創建旋轉矩陣
如果使用 OpenGL 或 Surface 渲染,可直接應用旋轉矩陣。
3. 修改系統源碼(深度方案)
調整 WindowManagerService
及 DisplayContent
支持非主屏旋轉 —— 適用于 ROM 開發者。
📘 五、推薦架構設計示例
-
啟動時讀取屬性值決定旋轉目標:
int targetDisplayId = SystemProperties.getInt("persist.sys.rotation.screen", 0); int rotation = SystemProperties.getInt("persist.sys.rotation.screen_rotation", 0);
-
根據屬性調用旋轉:
if (targetDisplayId == 0) {wm.freezeRotation(rotation); } else {wm.freezeDisplayRotation(targetDisplayId, rotation); }
-
無屬性時默認控制主屏,避免異常。
🧠 六、總結
項目 | 主屏(displayId=0) | 外接屏(如 displayId=2) |
---|---|---|
旋轉 API 是否生效 | ? 生效 | ? 多數情況無效 |
是否可通過 View 旋轉 | ? 支持 | ? 支持 |
是否具備旋轉標志 | ? FLAG_ROTATES_WITH_CONTENT | ? 通常缺失 |
可行的旋轉方式 | freezeRotation() | View.setRotation() / 自定義渲染 |