Di seguito sono riportati gli aggiornamenti apportati a queste aree specifiche per il display:
- Ridimensionamento di attività e display
- Dimensioni e proporzioni del display
- Norme per i display
- Impostazioni della finestra di visualizzazione
- Identificatori di visualizzazione statica
- Utilizzare più di due display
- Messa a fuoco per display
Ridimensionare attività e display
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 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 input assolute (anziché quelle relative alla posizione della finestra), il che potrebbe interrompere l'input in modalità multi-finestra.
In Android 7 (e versioni successive), un'app può essere impostata
resizeableActivity=false
per essere sempre eseguita in modalità a schermo intero. In
questo caso, la piattaforma impedisce alle attività non ridimensionabili di passare alla modalità
schermo diviso. Se l'utente tenta di richiamare un'attività non ridimensionabile dal launcher
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à:
- Al processo viene applicata la stessa configurazione, che contiene tutte le attività e i componenti non 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à Split Screen, 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 le seguenti norme:
Quando un'attività dichiarata incompatibile con il multi-window tramite l'utilizzo dell'attributo android:resizeableActivity
e quando questa 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'opportunità per 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 un livello API o dichiara le proporzioni in modo esplicito
Questa figura mostra un'attività non ridimensionabile con proporzioni dichiarate. Quando pieghi il dispositivo, la finestra viene ridimensionata per adattarsi all'area mantenendo le proporzioni utilizzando il 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 apri il dispositivo, la configurazione, le dimensioni e le proporzioni dell'attività non cambiano, ma viene visualizzata l'opzione per riavviarla.
Quando resizeableActivity
non è impostato (o è impostato su
true
), l'app supporta completamente il ridimensionamento.
Implementazione
Un'attività non ridimensionabile con orientamento o proporzioni fissi è denominata
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 corretta nella configurazione di override richiesta, quindi 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 dell'attività vengono calcolati da
AppWindowToken#calculateCompatBoundsTransformation()
.
Quando un'attività SCM utilizza una configurazione dello schermo diversa dal 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 pulsante di riavvio del processo.
Dimensioni e proporzioni del display
Android 10 supporta nuovi formati
dalle proporzioni elevate di schermi lunghi e sottili a proporzioni 1:1. Le app possono definire
ApplicationInfo#maxAspectRatio
e il ApplicationInfo#minAspectRatio
dello schermo che sono
in grado di gestire.
Figura 1. Esempio di proporzioni delle app supportate in Android 10
Le implementazioni dei dispositivi possono avere display secondari con dimensioni e
risoluzioni inferiori a quelle richieste da Android 9 e versioni precedenti (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 posizionate
lì.
Le app possono attivare questa funzionalità dichiarando una dimensione minima supportata inferiore o uguale
alla dimensione del display di destinazione. Utilizza gli attributi di layout dell'attività android:minHeight
e android:minWidth
in AndroidManifest.xml.
Norme per gli annunci display
Android 10 separa e sposta alcuni criteri di visualizzazione
dall'implementazione WindowManagerPolicy
predefinita in
PhoneWindowManager
a classi per display, ad esempio:
- Stato e rotazione del display
- Alcuni tasti e il monitoraggio degli eventi di movimento
- Finestre di decorazione e UI di sistema
In Android 9 (e versioni precedenti), la classe PhoneWindowManager
gestiva
le norme di visualizzazione, lo stato e le impostazioni, la rotazione, il monitoraggio
del frame della finestra di decorazione 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 finestre configurabile per display è stata ampliata per includere:
- Modalità di visualizzazione predefinita
- Valori di overscan
- Rotazione degli utenti e modalità di rotazione
- Modalità di ridimensionamento, densità e dimensioni forzate
- Modalità di rimozione dei contenuti (quando viene rimosso il display)
- Supporto per decorazioni di sistema e IME
La classe DisplayWindowSettings
contiene le impostazioni per queste
opzioni. Vengono salvati su disco nella partizione /data
in
display_settings.xml
ogni volta che viene modificata un'impostazione. Per i dettagli, vedi 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 è stato cancellato da una pulizia.
Per impostazione predefinita, Android 10 utilizza
DisplayInfo#uniqueId
come identificatore per un display durante il salvataggio
delle impostazioni. uniqueId
deve essere compilato per tutti i display. 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, quindi è sicuro aggiornare la chiave utilizzata per una voce di visualizzazione
nello spazio di archiviazione. Per maggiori dettagli, vedi
Identificatori di visualizzazione statici.
Le impostazioni vengono mantenute nella directory /data
per motivi storici. In origine, venivano utilizzate per conservare le impostazioni impostate dall'utente, ad esempio
la rotazione del display.
Identificatori di visualizzazione statica
Android 9 (e versioni precedenti) non forniva identificatori stabili per i display nel
framework. Quando un display è stato aggiunto al sistema,
Display#mDisplayId
o DisplayInfo#displayId
è stato
generato per quel display incrementando un contatore statico. Se il sistema
ha aggiunto e rimosso lo stesso display, è stato generato un ID diverso.
Se un dispositivo aveva più display disponibili all'avvio, ai display potrebbero essere
assegnati identificatori diversi, a seconda della tempistica. Sebbene Android 9 (e versioni precedenti) includa DisplayInfo#uniqueId
, non contiene informazioni sufficienti per distinguere i display perché i display fisici sono stati 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 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 del display stabile durante i riavvii. In Android
10, DisplayAddress
supporta display
fisici e di rete. DisplayAddress.Physical
contiene un ID
display stabile (lo stesso di 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 nelle configurazioni statiche
multi-display e di configurare diverse impostazioni e funzionalità di sistema
utilizzando identificatori di display statici, come le porte per i display fisici. Questi
metodi sono nascosti e sono destinati all'uso 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 su produttore o modello dall'EDID per
generare gli ID display stabili a 64 bit esposti al framework. Se questo metodo
non è supportato o genera errori, SurfaceFlinger torna alla modalità MD legacy,
in cui DisplayInfo#address
è null e
DisplayInfo#uniqueId
è hardcoded, come descritto in precedenza.
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 al massimo due display fisici con ID hardcoded 0
e 1.
A partire da Android 10, SurfaceFlinger può utilizzare 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 display 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 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, i display interni aggiuntivi vengono trattati come esterni.
Come soluzione alternativa, il codice specifico del dispositivo può fare ipotesi su
DisplayAddress.Physical#getPort
se l'HWC è noto e la logica di allocazione delle porte
è prevedibile.
Questa limitazione viene 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. Tuttavia, rimane vero che il display principale non può essere disconnesso e di conseguenza deve essere un display interno. Tieni presente che alcuni smartphone pieghevoli hanno più display interni.
- I display secondari sono classificati correttamente come
Display.TYPE_INTERNAL
oDisplay.TYPE_EXTERNAL
(precedentemente noti comeDisplay.TYPE_BUILT_IN
eDisplay.TYPE_HDMI
, rispettivamente) a seconda del tipo di connessione.
Implementazione
In Android 9 e versioni precedenti, i display vengono 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 persistenti, il che consente a SurfaceFlinger e DisplayManagerService
di monitorare più di due display e riconoscere quelli già visti. 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 sono 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 al massimo due display fisici.
Focus per display
Per supportare diverse origini di input che hanno come target singoli display contemporaneamente, Android 10 può essere configurato per supportare più finestre attive, 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, ad esempio Android Automotive.
È vivamente consigliato di non attivare questa funzionalità per i dispositivi normali, inclusi quelli multi-schermo o quelli utilizzati per esperienze <x0A>simili a quelle desktop. Ciò è dovuto principalmente a un problema di sicurezza che potrebbe indurre gli utenti a chiedersi quale finestra abbia lo stato attivo.
Immagina l'utente che inserisce informazioni sicure in un campo di input di testo, magari accedendo a un'app di servizi bancari o inserendo un testo che contiene informazioni sensibili. Un'app dannosa potrebbe creare un display virtuale fuori schermo con cui eseguire un'attività, anche con un campo di input di testo. Le attività legittime e malicious hanno il focus e mostrano entrambe un indicatore di input attivo (cursore lampeggiante).
Tuttavia, poiché l'input da una tastiera (hardware o software) viene inserito solo nell'attività in primo piano (l'app avviata 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.
Utilizza com.android.internal.R.bool.config_perDisplayFocusEnabled
per impostare la messa a fuoco per display.
Compatibilità
Problema: in Android 9 e versioni precedenti, al massimo una finestra del sistema è attiva alla volta.
Soluzione: nel raro caso in cui due finestre dello stesso processo vengano messe a fuoco, il sistema mette a fuoco solo la finestra più in alto nell'ordine Z. Questa limitazione viene rimossa per le app che hanno come target Android 10, a quel punto è previsto che possano supportare più finestre su cui concentrarsi contemporaneamente.
Implementazione
WindowManagerService#mPerDisplayFocusEnabled
controlla la
disponibilità di questa funzionalità. In ActivityManager
,
ora viene utilizzato ActivityDisplay#getFocusedStack()
anziché il monitoraggio globale in una variabile. ActivityDisplay#getFocusedStack()
determina lo stato attivo in base all'ordine Z anziché memorizzare il valore nella cache. In questo modo,
solo un'origine, WindowManager, deve tenere traccia dell'ordine Z delle attività.
ActivityStackSupervisor#getTopDisplayFocusedStack()
adotta un approccio simile per i casi in cui deve essere identificato lo stack più in primo piano nel sistema. Gli stack vengono attraversati dall'alto verso il basso, alla ricerca
del primo stack idoneo.
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 inviato
alla finestra attiva nel display attivo, ovvero il display con cui l'utente
ha interagito più di recente.
Vedi InputDispatcher::mFocusedWindowHandlesByDisplay
e
InputDispatcher::setFocusedDisplay()
. Anche le app mirate 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
della messa a fuoco correlata sono stati spostati da
WindowManagerService
a DisplayContent
.