Supporto per le decorazioni del sistema

Di seguito sono riportati gli aggiornamenti apportati a queste aree specifiche per i display:

Decorazioni di sistema

Android 10 aggiunge il supporto per la configurazione dei display secondari in modo da mostrare determinate decorazioni di sistema, come sfondo, barra di navigazione e Avvio app. Per impostazione predefinita, il display principale mostra tutte le decorazioni di sistema, mentre quelle facoltative vengono mostrate sui display secondari. Il supporto di un editor di metodi di inserimento (IME) può essere impostato separatamente da altre decorazioni di sistema.

Utilizza DisplayWindowSettings#setShouldShowSystemDecorsLocked() per aggiungere il supporto per le decorazioni di sistema su un display specifico o fornisci un valore predefinito in /data/system/display_settings.xml. Per alcuni esempi, consulta Impostazioni delle finestre di visualizzazione.

Implementazione

DisplayWindowSettings#setShouldShowSystemDecorsLocked() è disponibile anche in WindowManager#setShouldShowSystemDecors() per i test. L'attivazione di questo metodo con l'intento di attivare 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 viene applicata completamente solo dopo il riavvio del dispositivo.

I controlli per il supporto delle decorazioni di sistema nella base di codice di WindowManager solitamente passano per DisplayContent#supportsSystemDecorations(), mentre i controlli per i servizi esterni (come l'interfaccia utente di sistema per verificare se la barra di navigazione deve essere visualizzata) utilizzano WindowManager#shouldShowSystemDecors(). Per capire cosa viene controllato da questa impostazione, esplora i punti di chiamata di questi metodi.

Finestre di decorazione dell'interfaccia utente di sistema

Android 10 aggiunge il supporto delle finestre di arredamento del sistema solo per la barra di navigazione, perché quest'ultima è essenziale per navigare tra attività e app. Per impostazione predefinita, la barra di navigazione mostra le affordance Indietro e Home. Questo valore viene incluso solo se il display di destinazione supporta le decorazioni di sistema (vedi DisplayWindowSettings).

La barra di stato è una finestra di sistema più complicata, in quanto 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, le notifiche, le impostazioni e un blocco tastiera completo sono disponibili solo sul display principale.

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

Implementazione

Per implementare funzionalità aggiuntive dell'interfaccia utente di sistema, i produttori di dispositivi devono utilizzare un singolo componente dell'interfaccia utente di sistema che monitora l'aggiunta/rimozione di display e presenta contenuti appropriati.

Un componente dell'interfaccia utente di sistema che supporta il multi-display (MD) deve gestire i seguenti casi:

  • Inizializzazione di più display all'avvio
  • Display aggiunto in fase di esecuzione
  • Display rimosso in fase di esecuzione

Quando l'interfaccia utente di sistema rileva l'aggiunta di un display prima di WindowManager, viene creata una condizione di gara. Questo problema può essere evitato implementando un callback personalizzato da WindowManager all'interfaccia utente di sistema quando viene aggiunto un display anziché iscriversi agli eventi DisplayManager.DisplayListener. Per un'implementazione di riferimento, consulta CommandQueue.Callbacks#onDisplayReady per il supporto della barra di navigazione e WallpaperManagerInternal#onDisplayReady 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 display.
  • IWindowManager#hasNavigationBar() viene aggiornato per includere il parametro displayId solo per l'interfaccia utente di sistema.

Avvio app

In Android 10, per impostazione predefinita ogni display configurato per supportare le decorazioni di sistema ha una serie di app Home dedicata per le attività di Avvio app di tipoWindowConfiguration#ACTIVITY_TYPE_HOME. Ogni display utilizza un'istanza separata dell'attività del programma di avvio.

Figura 1. Esempio di Avvio app multi-display per platform/development/samples/MultiDisplay

La maggior parte dei lanci esistenti non supporta più istanze e non è ottimizzata per schermi di grandi dimensioni. Inoltre, su display secondari/esterni spesso è prevista un'esperienza diversa. Per fornire un'attività dedicata per le schermate secondarie, Android 10 introduce la categoria SECONDARY_HOME nei filtri di intent. Le istanze di questa attività vengono utilizzate su tutti i display che supportano le decorazioni del 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 lancio che non impedisca l'esecuzione di più istanze e che debba adattarsi a schermi di dimensioni diverse. La modalità di lancio non può essere singleInstance o singleTask.

Implementazione

In Android 10, RootActivityContainer#startHomeOnDisplay() seleziona automaticamente il componente e lo scopo desiderati in base al display in cui viene lanciata la schermata Home. RootActivityContainer#resolveSecondaryHomeActivity() contiene la logica per cercare il componente dell'attività del programma di avvio a seconda del programma di avvio selezionato al momento 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 programma di avvio viene visualizzato solo sui display virtuali di proprietà del sistema. Il programma di avvio non mostra contenuti su display virtuali non di sistema.

Sfondi

In Android 10 (e versioni successive), gli sfondi sono supportati su display secondari:

Figura 2. Sfondo animato sui display interno (sopra) ed esterno (sotto)

Gli sviluppatori possono dichiarare il supporto per la funzionalità sfondo fornendo android:supportsMultipleDisplays="true" nella definizione XML di 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 il proprio contesto di superficie e visualizzazione. Lo sviluppatore deve assicurarsi che ogni motore possa disegnare in modo indipendente, a frequenze diverse, rispettando VSYNC.

Selezionare gli sfondi per le singole schermate

Android 10 non fornisce il supporto diretto della piattaforma per la selezione degli sfondi per le singole schermate. Per farlo, è necessario un identificatore dello schermo stabile per mantenere le impostazioni dello sfondo per ogni display. Display#getDisplayId() è dinamico, quindi non vi è alcuna garanzia 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 l'API WallpaperManager per impostare gli sfondi.
  2. WallpaperManager viene ottenuto da un oggetto Context e ogni oggetto Context contiene informazioni sulla visualizzazione corrispondente (Context#getDisplay()/getDisplayId()). Pertanto, puoi ottenere displayId da un'istanza WallpaperManager senza aggiungere nuovi metodi.
  3. A livello di 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 corretto, quando viene chiamata per impostare uno sfondo, il sistema può identificare automaticamente il display.

Se è necessario impostare lo sfondo per un display diverso da quello corrente, 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 sui display virtuali che non sono di sua proprietà. Ciò è dovuto al fatto che un'app dannosa potrebbe creare un display virtuale con funzionalità di supporto delle decorazioni di sistema attive e leggere dalla piattaforma informazioni sensibili agli utenti (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 di sfondo e una connessione per display. In WindowManager, i controller di sfondo vengono creati per ogni oggetto DisplayContent al momento della 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. WallpaperInfo#supportsMultipleDisplays() e un attributo corrispondente risorsa sono stati aggiunti in modo che gli sviluppatori di app possano segnalare quali sfondi sono pronti per più schermi.

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

Figura 3. Logica di riserva per lo sfondo per i display secondari