Di seguito sono riportati gli aggiornamenti apportati a queste aree specifiche per i display:
- Modificare le dimensioni di attività e display
- Dimensioni e proporzioni del display
- Norme relative alla visualizzazione
- 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à multifinestra 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 dal programma di avvio mentre è già in modalità schermo diviso, la piattaforma esce da questa modalità 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à
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 ancora alle attività non ridimensionabili di passare alla modalità schermo diviso, ma possono essere ridimensionate temporaneamente se l'attività ha dichiarato un orientamento o un formato fisso. In caso contrario, l'attività viene ridimensionata per riempire l'intero schermo come in Android 9 e versioni precedenti.
L'implementazione predefinita applica la seguente norma:
Quando un'attività è dichiarata incompatibile con il multi-finestra tramite
l'utilizzo 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.
- L'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 un'area visibile dichiarata. Quando il dispositivo viene piegato, la finestra viene ridotta in base all'area mantenendo le proporzioni utilizzando il letterbox appropriato. Inoltre, ogni volta che l'area di visualizzazione dell'attività viene modificata, all'utente viene fornita un'opzione per riavviare l'attività.
Quando apri 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 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 (ad esempio le dimensioni o la densità) viene fissata nella configurazione di override richiesta, pertanto l'attività non dipende più dalla configurazione di visualizzazione corrente.
Se l'attività SCM non può riempire l'intero schermo, viene 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 degli schermi lunghi e sottili alle proporzioni 1:1. Le app possono definire
ApplicationInfo#maxAspectRatio
e il ApplicationInfo#minAspectRatio
dello schermo che sono in grado di 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 solo le attività che attivano il supporto di questi piccoli display possono essere posizionate lì.
Le app possono attivare questa funzionalità dichiarando una dimensione minima supportata inferiore o uguale alle dimensioni del display target. A tale scopo, utilizza gli attributi di layout dell'attività android:minHeight
e android:minWidth
in AndroidManifest.
Norme relative alla visualizzazione
Android 10 separa e sposta determinati criteri di visualizzazione dall'implementazione predefinita di WindowManagerPolicy
in PhoneWindowManager
a classi per display, ad esempio:
- Stato e rotazione del display
- Alcune chiavi e il monitoraggio degli eventi di movimento
- UI di sistema e finestre di decorazione
In Android 9 (e versioni precedenti), la classe PhoneWindowManager
gestiva i criteri di visualizzazione, lo stato e le impostazioni, la rotazione, il monitoraggio del riquadro della finestra di decorazione e altro ancora. In Android 10 la maggior parte di questi dati viene trasferita alla 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 di overscan
- Rotazione dell'utente e modalità di rotazione
- 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 memorizzati sul 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 utilizzaDisplayInfo#uniqueId
come identificatore di una visualizzazione quando mantiene le impostazioni. uniqueId
deve essere compilato per tutti i display. Inoltre, è stabile per i display fisici e di rete. È anche possibile usare 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 vengono mantenute nella directory /data
per motivi storici. In origine, venivano utilizzati per mantenere le impostazioni impostate dall'utente, ad esempio la rotazione del display.
Identificatori di visualizzazione statici
Android 9 (e versioni precedenti) non forniva identificatori stabili per le visualizzazioni nel
framework. Quando un display è stato aggiunto 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 ha 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 modifica DisplayInfo#uniqueId
per aggiungere un identificatore stabile e per distinguere tra 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 i display fisici
e di rete. DisplayAddress.Physical
contiene un ID visualizzato stabile (come in uniqueId
) e può essere creato con DisplayAddress#fromPhysicalDisplayId()
.
Android 10 fornisce anche un comodo metodo per ottenere informazioni sulla porta (Physical#getPort()
). Questo metodo può essere utilizzato nel framework per identificare in modo statico le visualizzazioni. 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 sono destinati solo all'uso in system_server
.
IComposerClient
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 display a 64 bit stabili 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 potrebbe sfruttare un'API Hardware Composer (HWC) per generare ID display stabili, il che gli 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 un display fisico tramite SurfaceControl#getPhysicalDisplayToken
dopo aver ottenuto l'ID display a 64 bit da SurfaceControl#getPhysicalDisplayIds
o da un evento DisplayEventReceiver
hotplug.
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 è rilevante. Tuttavia, rimane vero che il display principale non può essere scollegato e ne consegue che deve essere un display interno. Tieni presente che alcuni smartphone pieghevoli hanno più display interni.
- Le visualizzazioni secondarie sono classificate correttamente come
Display.TYPE_INTERNAL
oDisplay.TYPE_EXTERNAL
(precedentementeDisplay.TYPE_BUILT_IN
eDisplay.TYPE_HDMI
, rispettivamente) 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 un display virtuale 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 l'HWC supporta IComposerClient.getDisplayIdentificationData
e fornisce dati di identificazione del display, SurfaceFlinger analizza la struttura EDID e alloca ID display 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 HWC, SurfaceFlinger torna al comportamento precedente con un massimo di due display fisici.
Messa a fuoco 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 input 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 portare gli utenti a chiedersi su quale finestra è attivo l'input.
Immagina un utente che inserisce informazioni protette in un campo di immissione di testo, magari accedendo a un'app bancaria o inserendo 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 e mostrano entrambe un indicatore di input attivo (cursore lampeggiante).
Tuttavia, poiché l'input di una tastiera (hardware o software) viene inserito solo nell'attività più in alto (l'app lanciata più di recente), creando un display virtuale nascosto, un'app dannosa potrebbe acquisire l'input dell'utente, anche quando si utilizza una tastiera software sul display del dispositivo principale.
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, che dovrebbero supportare il passaggio di più finestre in primo piano contemporaneamente.
Implementazione
WindowManagerService#mPerDisplayFocusEnabled
controlla la
disponibilità di questa funzionalità. In ActivityManager
,
ActivityDisplay#getFocusedStack()
viene ora utilizzato 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 serie vengono attraversate dall'alto verso il basso, cercando la prima serie idonea.
InputDispatcher
ora può avere più finestre attive (una per display). Se un evento di input è specifico per il display, viene inviato alla finestra attiva nel display corrispondente. In caso contrario, viene inviata alla finestra attiva nel display attivo, ovvero 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
.