系統裝飾支援

以下是針對這些特定顯示區域所做的更新:

系統裝飾

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 中,次要顯示器不支援狀態列。因此,通知、設定和完整鍵盤鎖僅適用於主要螢幕。

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

實作

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

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

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

當系統 UI 偵測到在 WindowManager 之前新增顯示畫面時,就會建立競爭狀態。如要避免這種情況,請在新增螢幕時,實作從 WindowManager 到 System UI 的自訂回呼,而不是訂閱 DisplayManager.DisplayListener 事件。如需參考實作,請參閱 CommandQueue.Callbacks#onDisplayReady 支援導覽列和桌布的 WallpaperManagerInternal#onDisplayReady

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

  • NavigationBarController 類別可控管導覽列特有的所有功能。
  • 如要查看自訂導覽列,請參閱 CarStatusBar
  • TYPE_NAVIGATION_BAR 不再限於單一例項,可用於每個顯示畫面。
  • IWindowManager#hasNavigationBar() 已更新,加入僅限系統 UI 的 displayId 參數。

發射器

在 Android 10 中,每個設定為支援系統裝飾的螢幕,預設都會為類型為 WindowConfiguration#ACTIVITY_TYPE_HOME 的啟動器活動提供專屬的主畫面堆疊。每個螢幕都會使用獨立的啟動器活動例項。

圖 1. platform/development/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 API 設定桌布。
  2. WallpaperManager 是從 Context 物件取得,而每個 Context 物件都包含對應顯示畫面 (Context#getDisplay()/getDisplayId()) 的資訊。因此,您可以從 WallpaperManager 例項取得 displayId,而無需新增任何方法。
  3. 在架構端,請使用從 Context 物件取得的 displayId,並將其對應至靜態 ID (例如實體螢幕的連接埠)。使用靜態 ID 保留所選桌布。

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

如果需要為目前螢幕以外的螢幕設定桌布,請為目標螢幕 (Context#createDisplayContext) 建立新的 Context 物件,然後從該螢幕取得 WallpaperManager 例項。

安全性限制

系統不會在虛擬螢幕上顯示非自有的桌布。 這是因為惡意應用程式可能會建立支援系統裝飾功能的虛擬螢幕,並讀取途徑中的使用者私密資訊 (例如個人相片),造成了一些安全疑慮。

實作

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

部分公開 WallpaperManager 方法實作方式 (例如 WallpaperManager#getDesiredMinimumWidth()) 已更新為運算作業並提供對應螢幕的資訊。WallpaperInfo#supportsMultipleDisplays() 和對應的資源屬性已新增,讓應用程式開發人員能夠回報哪些桌布可用於多個螢幕。

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

圖 3. 次要螢幕的桌布備用邏輯