Di seguito sono riportati gli aggiornamenti apportati a queste aree specifiche per i display:
- Ridimensionare attività e display
- Dimensioni e proporzioni del display
- Norme della Rete Display
- Impostazioni della finestra di visualizzazione
- Identificatori di visualizzazione statici
- Utilizzare più di due display
- Messa a fuoco per display
Ridimensionare attività e display
Per indicare che un'app potrebbe non supportare la modalità a più finestre 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 aggiustati in base alle metriche dell'area visibile in cui viene visualizzata un'attività.
- Un'attività potrebbe non gestire il ridimensionamento e arrestarsi in modo 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 immissione assolute (anziché quelle relative alla posizione della finestra), il che potrebbe interrompere l'immissione in modalità multi-finestra.
In Android 7 (e versioni successive), è possibile impostare un'appresizeableActivity=false
in modo che venga eseguita sempre in modalità a schermo intero. In questo caso, la piattaforma impedisce alle attività non ridimensionabili di passare allo schermo diviso. Se l'utente tenta di richiamare un'attività non ridimensionabile dall'Avvio app 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
file 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 correlati alle attività.
- La configurazione applicata soddisfa i requisiti CDD per i display compatibili con le app.
In Android 10, la piattaforma impedisce comunque alle attività non ridimensionabili di passare alla modalità schermo diviso, ma possono essere scalate temporaneamente se l'attività ha dichiarato un orientamento o proporzioni fisse. In caso contrario, l'attività si ridimensiona per occupare l'intero schermo come in Android 9 e inferiori.
L'implementazione predefinita applica le seguenti norme:
Quando un'attività è dichiarata incompatibile con il multi-finestra tramite
l'uso dell'attributo android:resizeableActivity
e quando quell'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 un'opzione per riavviare il processo dell'app in modo da utilizzare la configurazione dello schermo aggiornata.
- È con orientamento fisso tramite l'applicazione di
android:screenOrientation
- L'app ha proporzioni massime o minime predefinite in base al livello API di destinazione o dichiara le proporzioni esplicitamente
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 letterbox appropriato. Inoltre, viene fornita un'opzione di riavvio dell'attività all'utente ogni volta che l'area di visualizzazione dell'attività viene modificata.
Quando apri il dispositivo, la configurazione, le dimensioni e le proporzioni dell'attività non cambiano, ma viene visualizzata l'opzione per riavviare l'attività.
Se il criterio resizeableActivity
non è configurato (o è impostato su
true
), l'app supporta completamente il ridimensionamento.
Implementazione
Un'attività non ridimensionabile con orientamento o proporzioni fisse è chiamata
in codice modalità di compatibilità delle dimensioni (SCM). 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 override richiesta, quindi l'attività non dipende più dall'attuale configurazione del display.
Se l'attività SCM non può occupare l'intero schermo, è allineata in alto e centrata orizzontalmente. I limiti di attività vengono calcolati da
AppWindowToken#calculateCompatBoundsTransformation()
.
Quando un'attività SCM utilizza una configurazione dello schermo diversa rispetto al suo contenitore (ad esempio, le dimensioni del display vengono modificate 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 pulsante di riavvio del processo.
Dimensioni e proporzioni del display
Android 10 supporta nuove proporzioni,
dalle proporzioni elevate di schermi lunghi e sottili alle proporzioni 1:1. Le app possono definire l'ApplicationInfo#maxAspectRatio
e il ApplicationInfo#minAspectRatio
dello schermo che possono gestire.
Figura 1. Rapporti di app di esempio supportati in Android 10
Le implementazioni dei dispositivi possono avere display secondari con dimensioni e risoluzioni inferiori a quelle richieste da Android 9 e versioni successive (minima di 6,3 cm di larghezza o altezza, minima di 320 DP per smallestScreenWidth
), ma possono essere inserite solo le attività che attivano il supporto di questi display di piccole dimensioni.
Le app possono essere attivate dichiarando una dimensione minima supportata inferiore o uguale alla dimensione di visualizzazione di destinazione. A tale scopo, utilizza gli attributi di layout delle attività android:minHeight
e
android:minWidth
in
AndroidManifest.
Norme relative alla visualizzazione
Android 10 separa e sposta alcuni criteri di visualizzazione
dall'implementazione predefinita di WindowManagerPolicy
in
PhoneWindowManager
alle classi per display, ad esempio:
- Stato e rotazione del display
- Alcuni tasti e rilevamento degli eventi di movimento
- UI di sistema e finestre decorative
In Android 9 (e versioni precedenti), la classe PhoneWindowManager
ha gestito
i criteri di visualizzazione, lo stato e le impostazioni, la rotazione, il monitoraggio della cornice
della finestra decorativa e altro ancora. Android 10 sposta la maggior parte di questi elementi
nella classe DisplayPolicy
, ad eccezione del monitoraggio della rotazione, che
è stato spostato in DisplayRotation
.
Impostazioni della finestra di visualizzazione
In Android 10, l'impostazione di gestione delle finestre configurabile per display è stata ampliata per includere:
- Modalità di visualizzazione della finestra predefinita
- Valori overscan
- Modalità di rotazione e rotazione utenti
- Dimensioni, densità e modalità di ridimensionamento forzati
- Modalità di rimozione dei contenuti (quando la visualizzazione viene rimossa)
- Supporto per le decorazioni di sistema e l'IME
La classe DisplayWindowSettings
contiene le impostazioni per queste opzioni. Vengono mantenuti nel disco nella partizione /data
in display_settings.xml
ogni volta che viene modificata un'impostazione. Per maggiori dettagli, consulta 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 ripristinarlo se viene cancellato da un azzeramento.
Per impostazione predefinita, Android 10 utilizza
DisplayInfo#uniqueId
come identificatore per un display quando vengono mantenute
le impostazioni. uniqueId
deve essere compilato per tutte le visualizzazioni. Inoltre, è stabile per i 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, tutte le impostazioni vengono scritte in modo da poter aggiornare in sicurezza la chiave utilizzata per una voce di visualizzazione nello spazio di archiviazione. Per maggiori dettagli, consulta
Identificatori di visualizzazione statici.
Le impostazioni sono rese persistenti nella directory /data
per motivi
cronologici. In origine, venivano utilizzati per mantenere le impostazioni impostate dall'utente, come la rotazione dello schermo.
Identificatori di visualizzazione statici
Android 9 (e versioni precedenti) non forniva identificatori stabili per i display nel
framework. Quando una visualizzazione è stata aggiunta al sistema, è stato generato Display#mDisplayId
o DisplayInfo#displayId
per quel display incrementando un contatore statico. Se il sistema ha aggiunto e rimosso la stessa visualizzazione, è stato generato un ID diverso.
Se un dispositivo dispone di più display disponibili dall'avvio, a questi display potrebbero essere assegnati identificatori diversi, a seconda dei tempi. Sebbene Android 9 (e versioni precedenti) includesse DisplayInfo#uniqueId
, non conteneva informazioni sufficienti per distinguere i display perché i display fisici erano identificati come local:0
o local:1
per rappresentare il display integrato e quello esterno.
Android 10 cambia DisplayInfo#uniqueId
per aggiungere un identificatore stabile e per distinguere display locali, di rete e
virtuali.
Tipo di display | Formato |
---|---|
Locale | local:<stable-id> |
Rete | network:<mac-address> |
Virtuale | virtual:<package-name-and-name> |
Oltre agli aggiornamenti di 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 visualizzato stabile (come in uniqueId
) e può essere creato con DisplayAddress#fromPhysicalDisplayId()
.
Android 10 offre anche un metodo pratico per ottenere
informazioni sulle porte (Physical#getPort()
), che può essere utilizzato nel
framework per identificare i display in modo statico. 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 nelle configurazioni statiche con più display e di configurare diverse impostazioni e funzionalità di sistema utilizzando identificatori di display statici, ad esempio le porte per i display fisici. Questi metodi sono nascosti e possono 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'uscita 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 genera errori, SurfaceFlinger passa alla modalità MD precedente, dove DisplayInfo#address
è nullo e DisplayInfo#uniqueId
è hardcoded, come descritto sopra.
Per verificare che questa funzionalità sia supportata, esegui:
$ 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 massimo due display fisici con ID hardcoded 0
e 1.
A partire da Android 10, SurfaceFlinger ha potuto sfruttare un'API HWC (Hardware Composer) per generare ID display stabili, il che consente di gestire un numero arbitrario di display fisici. Per scoprire di più, consulta Identificatori di visualizzazione statici.
Il framework può cercare il token IBinder
per trovare una visualizzazione fisica tramite SurfaceControl#getPhysicalDisplayToken
dopo aver recuperato l'ID display a 64 bit da SurfaceControl#getPhysicalDisplayIds
o da un evento hotplug DisplayEventReceiver
.
In Android 10 (e versioni precedenti), il display interno principale è TYPE_INTERNAL
e tutti i display secondari sono contrassegnati come TYPE_EXTERNAL
, indipendentemente dal tipo di connessione. Pertanto, gli altri display interni vengono considerati esterni.
Come soluzione alternativa, il codice specifico del dispositivo può fare supposizioni 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) non è pertinente. Tuttavia, rimane vero che il display principale non può essere scollegato e ne consegue che deve essere un display interno. Alcuni smartphone pieghevoli hanno più display interni.
- I display secondari sono classificati correttamente come
Display.TYPE_INTERNAL
oDisplay.TYPE_EXTERNAL
(precedentemente noti rispettivamente comeDisplay.TYPE_BUILT_IN
eDisplay.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.
A partire da Android 10, ai display vengono assegnati ID stabili e permanenti, che consentono a SurfaceFlinger e DisplayManagerService
di monitorare più di due display e di riconoscere quelli visti in precedenza. Se HWC supporta IComposerClient.getDisplayIdentificationData
e fornisce dati di identificazione dei display, SurfaceFlinger analizza la struttura EDID e alloca ID di visualizzazione stabili a 64 bit per i display fisici e virtuali HWC. Gli ID vengono espressi utilizzando un tipo di opzione, in cui il valore nullo rappresenta un display non valido o un display virtuale non HWC. Senza il supporto di HWC, SurfaceFlinger utilizza il comportamento precedente con al massimo due display fisici.
Focus per display
Per supportare più origini di input che hanno come target singoli display contemporaneamente, Android 10 può essere configurato per supportare più finestre in primo piano, al massimo una per display. Questa opzione è pensata solo per tipi speciali di dispositivi quando più utenti interagiscono con lo stesso dispositivo contemporaneamente e utilizzano dispositivi o metodi di inserimento diversi, ad esempio Android Automotive.
È vivamente sconsigliato attivare questa funzionalità per i dispositivi normali, inclusi i dispositivi multischermo o quelli utilizzati per esperienze simili a quelle dei computer. Ciò è dovuto principalmente a un problema di sicurezza che potrebbe indurre gli utenti a chiedersi quale finestra ha lo stato attivo dell'input.
Immagina un utente che inserisce informazioni sicure in un campo di immissione di testo, ad esempio accedendo a un'app di online banking o inserendo del testo contenente informazioni sensibili. Un'app dannosa potrebbe creare un display virtuale off-screen con cui eseguire un'attività, anche con un campo di immissione di testo. Le attività legittime e dannose sono attive ed entrambe mostrano un indicatore di input attivo (cursore lampeggiante).
Tuttavia, poiché l'input da una tastiera (hardware o software) viene inserito solo nell'attività principale (l'app lanciata più di recente), creando un display virtuale nascosto, un'app dannosa potrebbe acquisire l'input dell'utente, anche utilizzando una tastiera software sul display principale del dispositivo.
Usa com.android.internal.R.bool.config_perDisplayFocusEnabled
per impostare lo stato attivo per display.
Compatibilità
Problema: in Android 9 e versioni precedenti, al massimo una finestra del sistema ha il fuoco alla volta.
Soluzione: nel raro caso in cui due finestre dello stesso processo siano messe a fuoco, il sistema mette a fuoco solo la finestra più alta nell'ordine Z. Questa limitazione viene rimossa per le app destinate ad Android 10, quindi è previsto che possano supportare più finestre contemporaneamente.
Implementazione
WindowManagerService#mPerDisplayFocusEnabled
controlla la disponibilità di questa funzionalità. In ActivityManager
, ora viene utilizzato ActivityDisplay#getFocusedStack()
al posto del monitoraggio globale in una variabile. ActivityDisplay#getFocusedStack()
determina lo stato attivo in base all'ordine Z anziché memorizzare nella cache il valore. In questo modo, soltanto una sorgente, WindowManager, deve monitorare l'ordine Z delle attività.
ActivityStackSupervisor#getTopDisplayFocusedStack()
adotta un approccio simile per i casi in cui è necessario identificare la pila più in primo piano nel sistema. Le pila vengono attraversate dall'alto verso il basso, alla ricerca
della prima pila idonea.
Ora InputDispatcher
può avere più finestre con stato attivo
(una per display). Se un evento di input è specifico per la visualizzazione, viene inviato
alla finestra attiva nella visualizzazione corrispondente. Altrimenti, viene inviato
alla finestra con lo stato attivo, che è il display con cui l'utente
ha interagito più di recente.
Leggi InputDispatcher::mFocusedWindowHandlesByDisplay
e
InputDispatcher::setFocusedDisplay()
. Anche le app in primo piano vengono aggiornate
separatamente in InputManagerService tramite
NativeInputManager::setFocusedApplication()
.
In WindowManager
, anche le finestre attive vengono monitorate separatamente.
Consulta DisplayContent#mCurrentFocus
e
DisplayContent#mFocusedApp
e i rispettivi utilizzi. I metodi di monitoraggio e aggiornamento correlati ai focus sono stati spostati da WindowManagerService
a DisplayContent
.