系統裝飾支援

本頁面會提供這些顯示專用區域的更新資訊。

系統裝飾

Android 10 新增支援功能,可設定次要螢幕顯示特定系統裝飾,例如桌布、導覽列和啟動器。根據預設,主要螢幕會顯示所有系統裝飾,次要螢幕則會顯示選擇性啟用的裝飾。您可以為輸入法編輯器 (IME) 設定支援,與其他系統裝飾項目分開。

使用 DisplayWindowSettings#setShouldShowSystemDecorsLocked() 在特定螢幕上新增系統裝飾支援功能,或在 /data/system/display_settings.xml 中提供預設值。如需範例,請參閱「顯示視窗設定」。

實作

DisplayWindowSettings#setShouldShowSystemDecorsLocked() 也會在 WindowManager#setShouldShowSystemDecors() 中公開,以供測試。如果觸發這個方法是為了啟用系統裝飾,先前缺少的裝飾視窗不會新增,先前存在的裝飾視窗也不會移除。在大多數情況下,系統裝飾支援的變更必須重新啟動裝置才會完全生效。

WindowManager 程式碼庫中對系統裝飾項的支援檢查通常會經過 DisplayContent#supportsSystemDecorations(),而對外部服務的檢查 (例如系統 UI 檢查是否應顯示導覽列) 則會使用 WindowManager#shouldShowSystemDecors()。如要瞭解這項設定控管的內容,請探索這些方法的呼叫點。

系統 UI 裝飾視窗

Android 10 僅為導覽列新增系統裝飾視窗支援功能,因為導覽列是活動和應用程式之間導覽的必要功能。根據預設,導覽列會顯示「返回」和「首頁」功能。只有在目標螢幕支援系統裝飾時,才會加入這項屬性 (請參閱DisplayWindowSettings)。

狀態列是較為複雜的系統視窗,因為它也包含通知欄、快速設定和螢幕鎖定畫面。Android 10 不支援在第二螢幕上顯示狀態列。因此,通知、設定和完整鍵盤鎖僅適用於主螢幕。

次要螢幕不支援「總覽/最近」系統視窗。在 Android 10 中,AOSP 只會在預設螢幕上顯示「最近」畫面,並包含所有螢幕的活動。從「最近」啟動活動時,系統預設會將次要螢幕上的活動移到該螢幕的前景。這種做法會導致一些已知問題,例如應用程式出現在其他螢幕上時,不會立即更新。

實作

如要實作其他系統 UI 功能,裝置製造商應使用單一系統 UI 元件,監聽螢幕的加入或移除作業,並呈現適當內容。

支援多螢幕 (MD) 的系統 UI 元件應處理下列情況:

  • 啟動時初始化多個螢幕
  • 在執行階段新增的螢幕
  • 在執行階段移除的螢幕

如果系統 UI 在 WindowManager 之前偵測到新增的螢幕,就會產生競爭條件。如要避免這種情況,請在新增螢幕時,從 WindowManager 實作自訂回呼至 System UI,而不是訂閱 DisplayManager.DisplayListener 事件。如需參考實作方式,請參閱CommandQueue.Callbacks#onDisplayAddSystemDecorations導覽列支援功能和WallpaperManagerInternal#onDisplayAddSystemDecorations桌布。

此外,Android 10 還提供下列更新:

  • NavigationBarController 類別會控管導覽列的所有特定功能。
  • 如要查看自訂導覽列,請參閱CarStatusBar
  • TYPE_NAVIGATION_BAR 不再僅限於單一執行個體,可供每個螢幕使用。
  • IWindowManager#hasNavigationBar() 已更新,僅適用於系統 UI 的 displayId 參數。

啟動器

在 Android 10 中,預設情況下,每個設定為支援系統裝飾的螢幕,都會為類型為 WindowConfiguration#ACTIVITY_TYPE_HOME 的啟動器活動提供專屬的主畫面堆疊。每個螢幕都會使用不同的啟動器活動執行個體:

圖 1. 平台/開發/samples/MultiDisplay 的多螢幕啟動器範例。

現有的大多數啟動器都不支援多個執行個體,且未針對大螢幕尺寸進行最佳化。此外,次要/外部螢幕通常會提供不同的體驗。為第二螢幕提供專屬活動,Android 10 在意圖篩選器中導入了 SECONDARY_HOME 類別。活動執行個體會在支援系統裝飾的所有螢幕上使用,每個螢幕上擁有一個執行個體。

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

活動的啟動模式不得阻止多個執行個體,且能夠適應不同的螢幕大小。啟動模式不能是 singleInstancesingleTask

實作

在 Android 10 中,RootActivityContainer#startHomeOnDisplay()會根據啟動主畫面的螢幕,自動選取所需元件和意圖。RootActivityContainer#resolveSecondaryHomeActivity() 包含用於查閱啟動器活動元件的邏輯 (視目前選取的啟動器而定),且視需要可使用系統預設值 (請參閱ActivityTaskManagerService#getSecondaryHomeIntent())。

安全限制

除了適用於次要螢幕上活動的限制外,為避免惡意應用程式建立啟用系統裝飾的虛擬螢幕,並從介面讀取使用者私密資訊,啟動器只會顯示在系統擁有的虛擬螢幕上。啟動器不會在非系統虛擬螢幕上顯示內容。

桌布

在 Android 10 以上版本中,第二螢幕支援桌布:

圖 2. 內螢幕 (上圖) 和外螢幕 (下圖) 上的動態桌布。

開發人員可以在 WallpaperInfo XML 定義中提供 android:supportsMultipleDisplays="true",宣告支援桌布功能。桌布開發人員也應使用 WallpaperService.Engine#getDisplayContext() 中的螢幕背景載入素材資源。

架構會為每個螢幕建立一個 WallpaperService.Engine 執行個體,因此每個引擎都有自己的介面和螢幕內容。開發人員必須確保每個引擎都能以不同影格速率獨立繪製,並遵守 VSync。

為個別螢幕選取桌布

Android 10 不會直接提供平台支援,讓使用者為個別螢幕選取桌布。為此,您需要穩定的螢幕 ID,才能為每個螢幕保留桌布設定。Display#getDisplayId() 是動態的,因此無法保證實體螢幕在重新啟動後會具有相同的 ID。

不過,Android 10 新增了 DisplayInfo.mAddress,其中包含實體螢幕的穩定 ID,日後可用於完整實作。很抱歉,現在來不及為 Android 10 實作邏輯。建議解決方案:

  1. 使用 WallpaperManager 類別設定桌布。

    WallpaperManager 是從 Context 物件取得,而每個 Context 物件都有對應顯示器 (Context#getDisplay()/getDisplayId()) 的相關資訊。因此,您可以在不新增方法的情況下,從 WallpaperManager 執行個體取得 displayId

  2. 在架構端,請使用從 Context 物件取得的 displayId,並將其對應至靜態 ID (例如實體螢幕的連接埠)。使用靜態 ID 持續顯示所選桌布。

這項解決方法會使用現有的桌布挑選器實作項目。如果是在特定螢幕上開啟,並使用正確的內容,那麼在呼叫設定桌布時,系統就能自動識別螢幕。

如有需要為目前螢幕以外的螢幕設定桌布,請為目標螢幕建立新的 Context 物件 (Context#createDisplayContext),並從該螢幕取得 WallpaperManager 執行個體。

安全限制

系統不會在不屬於自己的虛擬螢幕上顯示桌布。 這是因為惡意應用程式可能會建立支援系統裝飾的虛擬螢幕,並從表面讀取使用者私密資訊 (例如個人相片),因此有安全疑慮。

實作

在 Android 10 中,IWallpaperConnection#attachEngine()IWallpaperService#attach() 介面會接受 displayId 參數,以建立每個螢幕的連線。WallpaperManagerService.DisplayConnector 封裝每個螢幕的桌布引擎和連線。在 WindowManager 中,系統會為建構時的每個 DisplayContent 物件建立桌布控制器,而不是為所有螢幕建立單一 WallpaperController

部分公開 WallpaperManager 方法實作 (例如 WallpaperManager#getDesiredMinimumWidth()) 已更新,可計算並提供對應顯示畫面的資訊。WallpaperInfo#supportsMultipleDisplays() 和對應的資源屬性已新增完畢,應用程式開發人員可以回報哪些桌布適用於多個螢幕。

如果預設螢幕上顯示的桌布服務不支援多個螢幕,系統會在次要螢幕上顯示預設桌布:

圖 3. 第二螢幕的桌布備援邏輯。