Supporto delle decorazioni di sistema

Gli aggiornamenti apportati a queste aree specifiche per la visualizzazione sono disponibili in questa pagina.

Decorazioni di sistema

Android 10 aggiunge il supporto per la configurazione di display secondari per mostrare determinate decorazioni di sistema, come sfondo, barra di navigazione e launcher. Per impostazione predefinita, il display principale mostra tutte le decorazioni del sistema, mentre i display secondari mostrano quelle attivate facoltativamente. Puoi impostare il supporto per un editor del metodo di input (IME) separatamente dalle altre decorazioni di sistema.

Utilizza DisplayWindowSettings#setShouldShowSystemDecorsLocked per aggiungere il supporto per le decorazioni di sistema su un display specifico o fornire un valore predefinito in /data/system/display_settings.xml. Per alcuni esempi, vedi Impostazioni della finestra di visualizzazione.

Implementazione

DisplayWindowSettings#setShouldShowSystemDecorsLocked è esposto anche in WindowManager#setShouldShowSystemDecors a scopo di test. L'attivazione di questo metodo con l'intento di abilitare le decorazioni di sistema non aggiunge finestre di decorazione precedentemente mancanti né le rimuove se erano presenti in precedenza. Nella maggior parte dei casi, la modifica del supporto delle decorazioni di sistema ha effetto solo dopo il riavvio del dispositivo.

I controlli per il supporto delle decorazioni di sistema nella codebase di WindowManager di solito passano attraverso DisplayContent#supportsSystemDecorations, mentre i controlli per i servizi esterni (come la UI di sistema per verificare se la barra di navigazione deve essere mostrata) utilizzano WindowManager#shouldShowSystemDecors. Per capire cosa viene controllato da questa impostazione, esplora i punti di chiamata di questi metodi.

Finestre di decorazione dell'UI di sistema

Android 10 aggiunge il supporto della finestra di decorazione del sistema solo per la barra di navigazione perché è essenziale per navigare tra attività e app. Per impostazione predefinita, la barra di navigazione mostra i pulsanti Indietro e Home. La barra di navigazione è inclusa solo se il display di destinazione supporta le decorazioni di sistema (vedi DisplayWindowSettings).

La barra di stato è una finestra di sistema più complessa, perché contiene anche l'area notifiche, le Impostazioni rapide e la schermata di blocco. In Android 10, la barra di stato non è supportata sui display secondari. Pertanto, notifiche, impostazioni e tastierino completo sono disponibili solo sul display principale.

La finestra di sistema Panoramiche o Recenti non è supportata sugli schermi secondari. In Android 10, AOSP mostra Recenti solo sul display predefinito e contiene attività di tutti i display. Quando viene avviata da Recenti, un'attività che si trovava su un display secondario viene portata in primo piano su quel display, per impostazione predefinita. Questo approccio presenta alcuni problemi noti, ad esempio l'aggiornamento non immediato quando le app vengono visualizzate su altre schermate.

Implementazione

Per implementare funzionalità aggiuntive della UI di sistema, i produttori di dispositivi devono utilizzare un unico componente della UI di sistema che ascolta l'aggiunta o la rimozione di display e presenta contenuti appropriati.

Un componente della UI di sistema che supporta il multi-display (MD) deve gestire i seguenti casi:

  • Inizializzazione di più display all'avvio
  • Display aggiunto in fase di runtime
  • Visualizzazione rimossa in fase di runtime

Quando l'UI di sistema rileva l'aggiunta di un display prima di WindowManager, crea una race condition. Puoi evitare questo problema implementando un callback personalizzato da WindowManager a UI di sistema quando viene aggiunto un display, anziché abbonarti agli eventi DisplayManager.DisplayListener. Per un'implementazione di riferimento, vedi CommandQueue.Callbacks#onDisplayAddSystemDecorations per il supporto della barra di navigazione e WallpaperManagerInternal#onDisplayAddSystemDecorations per gli sfondi.

Inoltre, Android 10 fornisce questi aggiornamenti:

  • La classe NavigationBarController controlla tutte le funzionalità specifiche delle barre di navigazione.
  • Per visualizzare una barra di navigazione personalizzata, vedi CarStatusBar.
  • TYPE_NAVIGATION_BAR non è più limitato a una singola istanza e può essere utilizzato per ogni display.
  • IWindowManager#hasNavigationBar viene aggiornato per includere il parametro displayId solo per la UI di sistema.

Avvio applicazioni

In Android 10, ogni display configurato per supportare le decorazioni di sistema ha una home stack dedicata per le attività di avvio con tipo WindowConfiguration#ACTIVITY_TYPE_HOME, per impostazione predefinita. Ogni display utilizza un'istanza separata dell'attività di avvio:

Figura 1. Esempio di avvio di più display per platform/development/samples/MultiDisplay.

La maggior parte dei launcher esistenti non supporta più istanze e non è ottimizzata per le dimensioni dello schermo grandi. Inoltre, spesso ci si aspetta un'esperienza diversa sui display secondari/esterni. Per fornire un'attività dedicata per gli schermi secondari, Android 10 ha introdotto la categoria SECONDARY_HOME nei filtri degli intent. Le istanze di questa attività vengono utilizzate su tutti i display che supportano le decorazioni di sistema, una per display.

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

L'attività deve avere una modalità di avvio che non impedisca più istanze e deve adattarsi a diverse dimensioni dello schermo. La modalità di avvio non può essere singleInstance o singleTask.

Implementazione

In Android 10, RootActivityContainer#startHomeOnDisplay seleziona automaticamente il componente e l'intent desiderati a seconda del display in cui viene avviata la schermata Home. RootActivityContainer#resolveSecondaryHomeActivity contiene la logica per cercare il componente dell'attività di avvio a seconda dell'avvio app attualmente selezionato e può utilizzare quello predefinito del sistema, se necessario (vedi ActivityTaskManagerService#getSecondaryHomeIntent).

Limitazioni di sicurezza

Oltre alle limitazioni che si applicano alle attività sui display secondari, per evitare la possibilità che un'app dannosa crei un display virtuale con le decorazioni di sistema attive e legga informazioni sensibili dell'utente dalla superficie, il launcher viene visualizzato solo sui display virtuali di proprietà del sistema. Il launcher non mostra contenuti su display virtuali non di sistema.

Sfondi

In Android 10 e versioni successive, gli sfondi sono supportati sui display secondari:

Figura 2. Sfondo animato sui display interno (in alto) ed esterno (in basso).

Gli sviluppatori possono dichiarare il supporto della funzionalità di sfondo fornendo android:supportsMultipleDisplays="true" nella definizione XML WallpaperInfo. Gli sviluppatori di sfondi devono anche caricare gli asset utilizzando il contesto di visualizzazione in WallpaperService.Engine#getDisplayContext.

Il framework crea un'istanza WallpaperService.Engine per display, quindi ogni motore ha la propria superficie e il proprio contesto di visualizzazione. Lo sviluppatore deve assicurarsi che ogni motore possa disegnare in modo indipendente, a frame rate diversi, rispettando la sincronizzazione verticale.

Selezionare sfondi per singoli schermi

Android 10 non fornisce supporto diretto della piattaforma per la selezione di sfondi per singoli schermi. Per farlo, è necessario un identificatore di visualizzazione stabile per mantenere le impostazioni dello sfondo per ogni display. Display#getDisplayId è dinamico, quindi non è garantito che un display fisico abbia lo stesso ID dopo il riavvio.

Tuttavia, Android 10 ha aggiunto DisplayInfo.mAddress, che contiene identificatori stabili per i display fisici e può essere utilizzato per un'implementazione completa in futuro. Purtroppo è troppo tardi per implementare la logica per Android 10. La soluzione suggerita:

  1. Utilizza la classe WallpaperManager per impostare gli sfondi.

    WallpaperManager viene ottenuto da un oggetto Context e ogni oggetto Context contiene informazioni sul display corrispondente (Context#getDisplay/getDisplayId). Pertanto, puoi ottenere displayId da un'istanza WallpaperManager senza aggiungere nuovi metodi.

  2. Sul lato framework, utilizza displayId ottenuto da un oggetto Context e mappalo a un identificatore statico (ad esempio una porta di un display fisico). Utilizza l'identificatore statico per mantenere lo sfondo scelto.

Questa soluzione alternativa utilizza le implementazioni esistenti per i selettori di sfondi. Se è stata aperta su un display specifico e utilizza il contesto giusto, quando chiama per impostare uno sfondo, il sistema può identificare automaticamente il display.

Se è necessario impostare lo sfondo per un display diverso da quello attuale, crea un nuovo oggetto Context per il display di destinazione (Context#createDisplayContext) e ottieni l'istanza WallpaperManager da quel display.

Limitazioni di sicurezza

Il sistema non mostrerà sfondi su display virtuali che non sono di sua proprietà. Ciò è dovuto a un problema di sicurezza: un'app dannosa potrebbe creare un display virtuale con il supporto delle decorazioni di sistema abilitato e leggere informazioni sensibili dell'utente dalla superficie (ad esempio una foto personale).

Implementazione

In Android 10, le interfacce IWallpaperConnection#attachEngine e IWallpaperService#attach accettano il parametro displayId per creare connessioni per display. WallpaperManagerService.DisplayConnector incapsula un motore e una connessione per ogni display. In WindowManager, i controller dello sfondo vengono creati per ogni oggetto DisplayContent durante la costruzione anziché un singolo WallpaperController per tutti i display.

Alcune implementazioni del metodo pubblico WallpaperManager (ad esempio WallpaperManager#getDesiredMinimumWidth) sono state aggiornate per calcolare e fornire informazioni per le visualizzazioni corrispondenti. Sono stati aggiunti WallpaperInfo#supportsMultipleDisplays e un attributo risorsa corrispondente, in modo che gli sviluppatori di app possano segnalare quali sfondi sono pronti per più schermi.

Se il servizio di sfondi mostrato sul display predefinito non supporta più display, il sistema mostra lo sfondo predefinito sui display secondari:

Figura 3. Logica di fallback dello sfondo per i display secondari.

Attivare il supporto degli sfondi animati

In Android 10 e versioni successive (API 29), gli sviluppatori possono utilizzare l'attributo android:supportsMultipleDisplays per indicare se lo sfondo può estendersi su più display. Negli ambienti con finestre delle app, dove il multitasking è intenso, il rendering degli sfondi animati su display esterni può influire in modo significativo sul sovraccarico di GPU e memoria.

Per preservare le risorse di sistema, il sistema non esegue il rendering degli sfondi animati sui display collegati per impostazione predefinita. Quando uno sfondo animato è limitato dalla configurazione del sistema o dal manifest dell'app, il sistema esegue il rendering di uno sfondo statico di riserva.

Gli OEM possono ottimizzare questa esperienza attivando il supporto degli sfondi animati per hardware di fascia alta o personalizzando il fallback statico per un look brandizzato.

Se l'hardware può eseguire il rendering di più istanze di sfondi animati, esegui l'override della seguente configurazione:

Percorso della risorsa frameworks/base/core/res/res/values/config.xml
Nome configurazione config_isLiveWallpaperSupportedInDesktopExperience

Personalizzare lo sfondo di riserva

Se gli sfondi animati sono disattivati o non supportati dal fornitore, il sistema utilizza un componente predefinito. Puoi indirizzare questo intent al tuo provider di sfondi statici:

Percorso della risorsa frameworks/base/core/res/res/values/config.xml
Nome configurazione fallback_wallpaper_component

Implementare il supporto degli sfondi

Per applicare queste modifiche, utilizza una sovrapposizione delle risorse in fase di compilazione nella cartella specifica del dispositivo, che in genere è device/<vendor>/<product>/overlay/frameworks/base/core/res/res/values/.