Supporto per visualizzazione

Gli aggiornamenti apportati a queste aree specifiche del display sono forniti di seguito:

Ridimensiona attività e visualizzazioni

Per indicare che un'app potrebbe non supportare la modalità multi-finestra o il ridimensionamento, le attività utilizzano l'attributo resizeableActivity=false . I problemi comuni riscontrati dalle app quando le attività vengono ridimensionate includono:

  • Un'attività può avere una configurazione diversa dall'app o da un altro componente non visivo. Un errore comune è leggere le metriche di visualizzazione dal contesto dell'app. I valori restituiti non verranno adattati alle metriche dell'area visibile in cui viene visualizzata un'attività.
  • Un'attività potrebbe non gestire il ridimensionamento e l'arresto anomalo, visualizzare un'interfaccia utente distorta o perdere lo stato a causa del riavvio senza salvare lo stato dell'istanza.
  • Un'app potrebbe tentare di utilizzare coordinate di input assolute (invece di quelle relative alla posizione della finestra), che potrebbero interrompere l'input in più finestre.

In Android 7 (e versioni successive), è possibile impostare resizeableActivity=false un'app in modo che venga sempre eseguita in modalità a schermo intero. In questo caso, la piattaforma impedisce che le attività non ridimensionabili vengano visualizzate sullo schermo diviso. Se l'utente tenta di richiamare un'attività non ridimensionabile dal programma di avvio mentre è già in modalità schermo diviso, la piattaforma esce dalla modalità schermo diviso e avvia l'attività non ridimensionabile in modalità a schermo intero.

Le app che impostano esplicitamente questo attributo su false nel manifest non devono essere avviate in modalità multi-finestra, a meno che non venga applicata la modalità di compatibilità:

  • La stessa configurazione viene applicata al processo, che contiene tutte le attività e i componenti non attività.
  • La configurazione applicata soddisfa i requisiti CDD per i display compatibili con l'app.

In Android 10, la piattaforma impedisce ancora alle attività non ridimensionabili di passare alla modalità schermo diviso, ma possono essere ridimensionate temporaneamente se l'attività ha dichiarato un orientamento o proporzioni fissi. In caso contrario, l'attività si ridimensiona per riempire l'intero schermo come in Android 9 e versioni precedenti.

L'implementazione predefinita applica la seguente policy:

Quando un'attività viene dichiarata incompatibile con multi-finestra tramite l'uso dell'attributo android:resizeableActivity e quando tale attività soddisfa una delle condizioni descritte di seguito, quando la configurazione dello schermo applicata deve cambiare, l'attività e il processo vengono salvati con la configurazione originale e all'utente viene fornita la possibilità di riavviare il processo dell'app per utilizzare la configurazione dello schermo aggiornata.

  • L'orientamento è fisso tramite l'applicazione di android:screenOrientation
  • L'app ha proporzioni massime o minime predefinite scegliendo come target il livello API o dichiara esplicitamente le proporzioni

Questa figura mostra un'attività non ridimensionabile con proporzioni dichiarate. Quando si piega il dispositivo, la finestra viene ridimensionata per adattarsi all'area mantenendo le proporzioni utilizzando il formato letterbox appropriato. Inoltre, all'utente viene fornita un'opzione di riavvio dell'attività ogni volta che viene modificata l'area di visualizzazione dell'attività.

Quando si apre il dispositivo, la configurazione, le dimensioni e le proporzioni dell'attività non cambiano, ma viene visualizzata l'opzione per riavviare l'attività.

Quando resizeableActivity non è impostato (o è impostato su true ), l'app supporta completamente il ridimensionamento.

Implementazione

Un'attività non ridimensionabile con orientamento o proporzioni fissi viene chiamata modalità di compatibilità delle dimensioni (SCM) nel codice. La condizione è definita in ActivityRecord#shouldUseSizeCompatMode() . Quando viene avviata un'attività SCM, la configurazione relativa allo schermo (come dimensioni o densità) viene fissata nella configurazione di sostituzione richiesta, quindi l'attività non dipende più dalla configurazione di visualizzazione corrente.

Se l'attività SCM non può riempire l'intero schermo, è allineata in alto e centrata orizzontalmente. I limiti dell'attività vengono calcolati da AppWindowToken#calculateCompatBoundsTransformation() .

Quando un'attività SCM utilizza una configurazione dello schermo diversa rispetto al relativo contenitore (ad esempio, il display viene ridimensionato o l'attività viene spostata su un altro display), ActivityRecord#inSizeCompatMode() è true e SizeCompatModeActivityController (nell'interfaccia utente di sistema) riceve il callback per mostrare il processo pulsante di riavvio.

Visualizza dimensioni e proporzioni

Android 10 fornisce supporto per nuove proporzioni, da rapporti elevati di schermi lunghi e sottili a rapporti 1:1. Le app possono definire ApplicationInfo#maxAspectRatio e ApplicationInfo#minAspectRatio dello schermo che sono in grado di gestire.

rapporti delle app in Android 10

Figura 1. Esempio di rapporti di app supportati in Android 10

Le implementazioni dei dispositivi possono avere display secondari con dimensioni e risoluzioni inferiori a quelle richieste da Android 9 e inferiori (minimo 2,5 pollici di larghezza o altezza, minimo 320 DP per smallestScreenWidth ), ma solo le attività che accettano di supportare questi piccoli display possono essere messo lì.

Le app possono aderire dichiarando una dimensione minima supportata inferiore o uguale alla dimensione di visualizzazione di destinazione. A tale scopo, utilizza gli attributi di layout dell'attività android:minHeight e android:minWidth nel file AndroidManifest.

Visualizza le politiche

Android 10 separa e sposta alcuni criteri di visualizzazione dall'implementazione WindowManagerPolicy predefinita in PhoneWindowManager alle classi per display, come:

  • Stato di visualizzazione e rotazione
  • Alcuni tasti e tracciamento degli eventi di movimento
  • Interfaccia utente del sistema e finestre decorative

In Android 9 (e versioni precedenti), la classe PhoneWindowManager gestiva criteri di visualizzazione, stato e impostazioni, rotazione, tracciamento dei frame delle finestre decorative e altro ancora. Android 10 ne sposta la maggior parte nella classe DisplayPolicy , ad eccezione del tracciamento della rotazione, che è stato spostato in DisplayRotation .

Visualizza le impostazioni della finestra

In Android 10, l'impostazione configurabile delle finestre per display è stata ampliata per includere:

  • Modalità di visualizzazione a finestre predefinita
  • Valori di overscan
  • Rotazione utente e modalità di rotazione
  • Dimensioni forzate, densità e modalità di ridimensionamento
  • Modalità di rimozione del contenuto (quando il display viene rimosso)
  • Supporto per decorazioni di sistema e IME

La classe DisplayWindowSettings contiene le impostazioni per queste opzioni. Vengono mantenuti sul disco nella partizione /data in display_settings.xml ogni volta che viene modificata un'impostazione. Per i dettagli, vedere DisplayWindowSettings.AtomicFileStorage e DisplayWindowSettings#writeSettings() . I produttori di dispositivi possono fornire valori predefiniti in display_settings.xml per la configurazione del dispositivo. Tuttavia, poiché il file è archiviato in /data , potrebbe essere necessaria una logica aggiuntiva per ripristinare il file se cancellato tramite cancellazione.

Per impostazione predefinita, Android 10 utilizza DisplayInfo#uniqueId come identificatore per un display quando si mantengono le impostazioni. uniqueId deve essere popolato per tutti i display. Inoltre, è stabile per display fisici e di rete. È anche possibile utilizzare la porta di un display fisico come identificatore, che può essere impostato in DisplayWindowSettings#mIdentifier . A ogni scrittura, vengono scritte tutte le impostazioni, quindi è sicuro aggiornare la chiave utilizzata per una voce visualizzata nell'archivio. Per maggiori dettagli, consulta Identificatori di visualizzazione statici .

Le impostazioni vengono mantenute nella directory /data per motivi storici. Originariamente venivano utilizzati per rendere persistenti le impostazioni impostate dall'utente, come la rotazione del display.

Identificatori di visualizzazione statici

Android 9 (e versioni precedenti) non forniva identificatori stabili per i display nel framework. Quando uno schermo veniva aggiunto al sistema, veniva generato Display#mDisplayId o DisplayInfo#displayId per quello schermo incrementando un contatore statico. Se il sistema aggiungeva e rimuoveva lo stesso display, risultava un ID diverso.

Se un dispositivo avesse più display disponibili all'avvio, ai display potrebbero essere assegnati identificatori diversi, a seconda del momento. Anche se Android 9 (e versioni precedenti) includeva DisplayInfo#uniqueId , non conteneva informazioni sufficienti per distinguere tra i display perché i display fisici erano identificati come local:0 o local:1 , per rappresentare il display integrato ed esterno.

Android 10 modifica DisplayInfo#uniqueId per aggiungere un identificatore stabile e per distinguere tra display locali, di rete e virtuali.

Tipo di visualizzazione Formato
Locale
local:<stable-id>
Rete
network:<mac-address>
Virtuale
virtual:<package-name-and-name>

Oltre agli aggiornamenti a uniqueId , DisplayInfo.address contiene DisplayAddress , un identificatore di visualizzazione stabile dopo i riavvii. In Android 10, DisplayAddress supporta display fisici e di rete. DisplayAddress.Physical contiene un ID di visualizzazione stabile (come in uniqueId ) e può essere creato con DisplayAddress#fromPhysicalDisplayId() .

Android 10 fornisce anche un metodo pratico per ottenere informazioni sulla porta ( Physical#getPort() ). Questo metodo può essere utilizzato nel framework per identificare staticamente i display. Ad esempio, viene utilizzato in DisplayWindowSettings ). DisplayAddress.Network contiene l'indirizzo MAC e può essere creato con DisplayAddress#fromMacAddress() .

Queste aggiunte consentono ai produttori di dispositivi di identificare i display in configurazioni statiche multi-display e di configurare diverse impostazioni e funzionalità di sistema utilizzando identificatori di display statici, come le porte per display fisici. Questi metodi sono nascosti e devono essere utilizzati solo all'interno di system_server .

Dato un ID display HWC (che può essere opaco e non sempre stabile), questo metodo restituisce il numero di porta a 8 bit (specifico della piattaforma) che identifica un connettore fisico per l'output del display, nonché il BLOB EDID del display. SurfaceFlinger estrae le informazioni sul produttore o sul modello dall'EDID per generare gli ID di visualizzazione stabili a 64 bit esposti al framework. Se questo metodo non è supportato o si verificano errori, SurfaceFlinger torna alla modalità MD legacy, dove DisplayInfo#address è null e DisplayInfo#uniqueId è hardcoded, come descritto in precedenza.

Per verificare che questa funzionalità sia supportata, eseguire:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

Utilizzare più di due display

In Android 9 (e versioni precedenti), SurfaceFlinger e DisplayManagerService presupponevano l'esistenza di al massimo due display fisici con ID codificati 0 e 1.

A partire da Android 10, SurfaceFlinger potrebbe sfruttare un'API Hardware Composer (HWC) per generare ID di visualizzazione stabili, che gli consentono di gestire un numero arbitrario di display fisici. Per ulteriori informazioni, consulta Identificatori di visualizzazione statici .

Il framework può cercare il token IBinder per uno schermo fisico tramite SurfaceControl#getPhysicalDisplayToken dopo aver ottenuto l'ID dello schermo a 64 bit da SurfaceControl#getPhysicalDisplayIds o da un evento hotplug DisplayEventReceiver .

In Android 10 (e versioni precedenti), il display interno primario è TYPE_INTERNAL e tutti i display secondari sono contrassegnati come TYPE_EXTERNAL indipendentemente dal tipo di connessione. Pertanto, i display interni aggiuntivi vengono trattati come esterni. Come soluzione alternativa, il codice specifico del dispositivo può formulare ipotesi su DisplayAddress.Physical#getPort se l'HWC è noto e la logica di allocazione delle porte è prevedibile.

Questa limitazione è stata rimossa in Android 11 (e versioni successive).

  • In Android 11, il primo display segnalato durante l'avvio è il display principale. Il tipo di connessione (interna o esterna) è irrilevante. Resta comunque vero che il display principale non può essere scollegato e ne consegue che in pratica deve essere un display interno. Tieni presente che alcuni telefoni pieghevoli dispongono di più display interni.
  • I display secondari sono classificati correttamente come Display.TYPE_INTERNAL o Display.TYPE_EXTERNAL (precedentemente noti rispettivamente come Display.TYPE_BUILT_IN e Display.TYPE_HDMI ) a seconda del tipo di connessione.

Implementazione

In Android 9 e versioni precedenti, i display sono identificati da ID a 32 bit, dove 0 è il display interno, 1 è il display esterno, [2, INT32_MAX] sono display virtuali HWC e -1 rappresenta un display non valido o non HWC visualizzazione virtuale.

A partire da Android 10, ai display vengono assegnati ID stabili e persistenti, che consentono a SurfaceFlinger e DisplayManagerService di tracciare più di due display e riconoscere i display visti in precedenza. Se l'HWC supporta IComposerClient.getDisplayIdentificationData e fornisce dati di identificazione del display, SurfaceFlinger analizza la struttura EDID e assegna ID di visualizzazione stabili a 64 bit per i display fisici e virtuali dell'HWC. Gli ID vengono espressi utilizzando un tipo di opzione, in cui il valore null rappresenta un display non valido o un display virtuale non HWC. Senza il supporto HWC, SurfaceFlinger torna al comportamento legacy con al massimo due display fisici.

Messa a fuoco per display

Per supportare diverse sorgenti di input destinate a singoli display contemporaneamente, Android 10 può essere configurato per supportare più finestre focalizzate, al massimo una per display. Questo è destinato solo a tipi speciali di dispositivi quando più utenti interagiscono con lo stesso dispositivo contemporaneamente e utilizzano metodi o dispositivi di input diversi, come Android Automotive.

Si consiglia vivamente di non abilitare questa funzionalità per i normali dispositivi, inclusi i dispositivi multischermo o quelli utilizzati per esperienze di tipo desktop. Ciò è dovuto principalmente a un problema di sicurezza che potrebbe indurre gli utenti a chiedersi quale finestra abbia lo stato attivo per l'input.

Immagina l'utente che inserisce informazioni protette in un campo di immissione di testo, magari accedendo a un'app bancaria o inserendo un testo che contiene informazioni sensibili. Un'app dannosa potrebbe creare una visualizzazione virtuale fuori schermo con cui eseguire un'attività, dotata anche di un campo per l'immissione di testo. Le attività legittime e dannose sono focalizzate ed entrambe visualizzano un indicatore di input attivo (cursore lampeggiante).

Tuttavia, poiché l'input da una tastiera (hardware o software) viene inserito solo nell'attività più in alto (l'app lanciata più di recente), creando uno schermo virtuale nascosto, un'app dannosa potrebbe catturare l'input dell'utente, anche quando utilizza una tastiera software sul display del dispositivo principale.

Utilizzare com.android.internal.R.bool.config_perDisplayFocusEnabled per impostare la messa a fuoco per display.

Compatibilità

Problema: in Android 9 e versioni precedenti, è attiva al massimo una finestra del sistema alla volta.

Soluzione: nel raro caso in cui vengano attivate due finestre dello stesso processo, il sistema attiva solo la finestra più in alto nell'ordine Z. Questa restrizione viene rimossa per le app destinate ad Android 10, a quel punto si prevede che possano supportare più finestre focalizzate contemporaneamente.

Implementazione

WindowManagerService#mPerDisplayFocusEnabled controlla la disponibilità di questa funzionalità. In ActivityManager , ActivityDisplay#getFocusedStack() viene ora utilizzato al posto del tracciamento globale in una variabile. ActivityDisplay#getFocusedStack() determina il focus in base all'ordine Z invece di memorizzare nella cache il valore. In questo modo è necessario che solo una fonte, WindowManager, tenga traccia dell'ordine Z delle attività.

ActivityStackSupervisor#getTopDisplayFocusedStack() adotta un approccio simile per i casi in cui è necessario identificare lo stack focalizzato più in alto nel sistema. Le pile vengono attraversate dall'alto verso il basso, alla ricerca della prima pila idonea.

InputDispatcher ora può avere più finestre focalizzate (una per display). Se un evento di input è specifico del display, viene inviato alla finestra focalizzata nel display corrispondente. In caso contrario, viene inviato alla finestra focalizzata nel display focalizzato, ovvero il display con cui l'utente ha interagito più recentemente.

Consulta InputDispatcher::mFocusedWindowHandlesByDisplay e InputDispatcher::setFocusedDisplay() . Le app mirate vengono inoltre aggiornate separatamente in InputManagerService tramite NativeInputManager::setFocusedApplication() .

In WindowManager , anche le finestre focalizzate vengono monitorate separatamente. Vedi DisplayContent#mCurrentFocus e DisplayContent#mFocusedApp e i rispettivi usi. I metodi di tracciamento e aggiornamento del focus correlati sono stati spostati da WindowManagerService a DisplayContent .