建議做法

適用於摺疊式和多螢幕裝置的應用程式

一般來說,應用程式不應依賴靜態 ID 或取決於某些螢幕 ID 的邏輯。在大多數情況下,應用程式應調整大小並在不同螢幕上運作,而系統應控管應用程式的位置。舉例來說,您可以為摺疊式裝置打造獨特的新體驗,並在裝置摺疊時,於外部螢幕啟動特殊應用程式。

在這種情況下,SystemUI (或其他系統元件) 應偵測摺疊狀態、判斷是否適合執行動作,然後啟動目標活動,並將外部螢幕 ID 指定為啟動目標。應用程式不應偵測這項動作或執行任何回應動作,然後在特定螢幕上啟動。換句話說,請勿假設在某個裝置上可行的做法,在其他裝置上也能行得通。簡而言之,裝置專用程式碼會增加片段化。

限制螢幕存取權

如果裝置設定需要限制對一或多個螢幕的存取權,建議使用 Display#FLAG_PRIVATE 標記將這類螢幕指定為「私人」。這樣一來,只有擁有者能將內容新增至螢幕,其他人則無法。如果不是擁有者嘗試啟動活動或新增視窗,系統會傳回 SecurityException。如果系統擁有螢幕,系統可以新增視窗及啟動活動。

此外,放置在螢幕上的實體隨時可以存取該螢幕。 如果擁有者在螢幕上啟動活動,該活動就能在該螢幕上啟動其他活動。因此,擁有者有責任限制存取權,允許信任的應用程式存取。

此外,虛擬螢幕會新增更多限制,因為任何應用程式都能建立虛擬螢幕,但不會向使用者顯示。如果虛擬螢幕不屬於系統,則只允許使用 allowEmbedded 的活動,且呼叫端應具備 ACTIVITY_EMBEDDING 權限。

詳情請參閱:

  • ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay()
  • ActivityDisplay#isUidPresent()
  • DisplayManagerService#isUidPresentOnDisplay()

如要有條件地控制活動啟動,請使用 LaunchParamsController,攔截所有活動啟動作業,並允許系統元件修改用於啟動的參數。這項功能適用於 system_server

設定顯示視窗設定和系統裝飾

您可以在 DisplayWindowSettings 中為每個螢幕設定系統裝飾項目。裝置實作項目可以在 /data/system/display_settings.xml 中提供預設設定。

這個值會決定系統裝飾項目 (啟動器、桌布、導覽列和其他裝飾視窗) 和輸入法編輯器是否會顯示在螢幕上。詳情請參閱 DisplayWindowSettings#shouldShowSystemDecorsLocked()DisplayWindowSettings#shouldShowImeLocked()

如要識別螢幕,請使用專屬 ID (預設使用 DisplayInfo#uniqueId) 或硬體螢幕的實體連接埠 ID (請參閱 DisplayInfo#address)。

舉例來說,下列螢幕設定範例會在模擬螢幕上啟用系統裝飾項目和 IME:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="0" />
<display
  name="overlay:1"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>

在上述範例中,uniqueId 用於名稱屬性中的顯示識別,模擬顯示器則為 overlay:1。如果是內建螢幕,範例值可能是 "local:45354385242535243453"。 另一種做法是使用硬體連接埠資訊,將 identifier="1" 設為對應 DisplayWindowSettings#IDENTIFIER_PORT,然後更新名稱以使用 "port:<port_id>" 格式:

<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="1" />
<display
  name="port:12345"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>

詳情請參閱「靜態螢幕 ID」。

詳情請參閱:

在鏡像和主持工作之間切換螢幕

在 Android 17 以上版本中,DisplayManager 會使用 FLAG_ALLOWS_CONTENT_MODE_SWITCH 旗標,控制螢幕是否在執行階段切換鏡像和託管工作。根據預設,這個旗標會針對外部螢幕啟用,並針對所有其他螢幕停用。

如果存在 FLAG_ALLOWS_CONTENT_MODE_SWITCH,DisplayManager 會監控 android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY 安全設定,判斷是否要鏡像或代管工作。這是預設邏輯,但原始設備製造商可以自訂這項行為。

顯示拓撲和指標移動位置

在 Android 17 以上版本中,螢幕拓撲會定義螢幕的相對位置,並將滑鼠游標移動限制在拓撲中的特定螢幕組。

WindowManager 決定在拓撲中加入螢幕,並呼叫 DisplayManagerInternal.onDisplayBelongToTopologyChanged。DisplayManager 會先檢查 DisplayTopologyCoordinator.isDisplayAllowedInTopology,再新增螢幕。根據預設,如果本機螢幕可以執行工作,系統就會新增。

如果有多個可執行工作的公開螢幕,是否要納入預設螢幕的決定,是由傳遞至 DisplayTopologyCoordinatorshouldIncludeDefaultDisplayInTopology 布林值提供者處理。如果預設螢幕是唯一可執行工作的公開螢幕,則一律會出現在拓撲中。在 AOSP 中,只有在預設螢幕支援電腦分割視窗功能,或安全設定 Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGYtrue 時,布林值供應器才會傳回 true

應用程式會使用 DisplayManager.getDisplayTopology 查詢目前的拓撲,並透過向 DisplayManager.registerTopologyListener 註冊事件監聽器,對拓撲的變更做出反應。