Im Folgenden finden Sie die Änderungen an diesen anzeigespezifischen Bereichen:
- Größe von Aktivitäten und Displays anpassen
- Displaygrößen und Seitenverhältnisse
- Richtlinien für Displayanzeigen
- Anzeigefenster-Einstellungen
- Statische Anzeigen-IDs
- Mehr als zwei Bildschirme verwenden
- Fokus pro Display
Größe von Aktivitäten und Displays anpassen
Wenn eine App möglicherweise keinen Multifenstermodus oder keine Größenänderung unterstützt, wird in Aktivitäten das Attribut resizeableActivity=false
verwendet. Häufige Probleme bei Apps, wenn Aktivitäten die Größe ändern:
- Eine Aktivität kann eine andere Konfiguration als die App oder eine andere nicht visuelle Komponente haben. Ein häufiger Fehler ist es, Displaymesswerte aus dem App-Kontext zu lesen. Die zurückgegebenen Werte werden nicht an die Messwerte für den sichtbaren Bereich angepasst, in dem eine Aktivität angezeigt wird.
- Eine Aktivität kann das Ändern der Größe möglicherweise nicht verarbeiten und abstürzen, eine verzerrte Benutzeroberfläche anzeigen oder den Status verlieren, weil sie neu gestartet wird, ohne den Instanzstatus zu speichern.
- Eine Anwendung kann versuchen, absolute Eingabekoordinaten zu verwenden (anstelle von Koordinaten relativ zur Fensterposition), was die Eingabe im Mehrfenstermodus beeinträchtigen kann.
Unter Android 7 und höher kann eine App soresizeableActivity=false
eingerichtet werden, dass sie immer im Vollbildmodus ausgeführt wird. In diesem Fall verhindert die Plattform, dass nicht skalierbare Aktivitäten im Splitscreen angezeigt werden. Wenn der Nutzer versucht, eine nicht veränderbare Aktivität über den Launcher aufzurufen, während er sich bereits im Splitscreen-Modus befindet, beendet die Plattform den Splitscreen-Modus und startet die nicht veränderbare Aktivität im Vollbildmodus.
Apps, die dieses Attribut im Manifest explizit auf false
setzen, dürfen nicht im Mehrfenstermodus gestartet werden, es sei denn, der Kompatibilitätsmodus wird angewendet:
- Die gleiche Konfiguration wird auf den Prozess angewendet, der alle Aktivitäten und nicht aktivitätsbezogenen Komponenten enthält.
- Die angewendete Konfiguration erfüllt die CDD-Anforderungen für App-kompatible Displays.
Unter Android 10 verhindert die Plattform weiterhin, dass nicht skalierbare Aktivitäten in den Splitscreen-Modus wechseln. Sie können jedoch vorübergehend skaliert werden, wenn für die Aktivität eine feste Ausrichtung oder ein festes Seitenverhältnis festgelegt wurde. Andernfalls wird die Aktivität so skaliert, dass sie den gesamten Bildschirm ausfüllt, wie unter Android 9 und niedriger.
Bei der Standardimplementierung gilt die folgende Richtlinie:
Wenn eine Aktivität mithilfe des Attributs android:resizeableActivity
als nicht mit dem Multifenstermodus kompatibel erklärt wurde und diese Aktivität eine der unten beschriebenen Bedingungen erfüllt, muss sich die angewendete Bildschirmkonfiguration ändern. Die Aktivität und der Prozess werden dann mit der ursprünglichen Konfiguration gespeichert und der Nutzer kann den App-Prozess neu starten, um die aktualisierte Bildschirmkonfiguration zu verwenden.
- Ist die Ausrichtung durch die Anwendung von
android:screenOrientation
festgelegt? - Die App hat ein standardmäßiges maximales oder minimales Seitenverhältnis, da sie auf API-Level ausgerichtet ist oder das Seitenverhältnis explizit deklariert.
Diese Abbildung zeigt eine nicht skalierbare Aktivität mit einem angegebenen Seitenverhältnis. Wenn das Gerät zusammengeklappt wird, wird das Fenster so skaliert, dass es in den Bereich passt. Dabei wird das Seitenverhältnis mithilfe des entsprechenden Letterboxing beibehalten. Außerdem wird dem Nutzer jedes Mal, wenn der Anzeigebereich für die Aktivität geändert wird, die Option zum Neustarten der Aktivität angezeigt.
Wenn Sie das Gerät aufklappen, ändern sich Konfiguration, Größe und Seitenverhältnis der Aktivität nicht, aber die Option zum Neustarten der Aktivität wird angezeigt.
Wenn resizeableActivity
nicht festgelegt oder auf true
gesetzt ist, unterstützt die App die Größenanpassung vollständig.
Implementierung
Eine nicht skalierbare Aktivität mit fester Ausrichtung oder festem Seitenverhältnis wird im Code als „SCM“ (Size Compatibility Mode) bezeichnet. Die Bedingung ist in ActivityRecord#shouldUseSizeCompatMode()
definiert. Beim Start einer SCM-Aktivität wird die bildschirmbezogene Konfiguration (z. B. Größe oder Dichte) in der angeforderten Überschreibungskonfiguration festgelegt. Die Aktivität hängt also nicht mehr von der aktuellen Anzeigekonfiguration ab.
Wenn die SCM-Aktivität nicht den gesamten Bildschirm ausfüllen kann, wird sie oben ausgerichtet und horizontal zentriert. Die Aktivitätsgrenzen werden von AppWindowToken#calculateCompatBoundsTransformation()
berechnet.
Wenn für eine SCM-Aktivität eine andere Bildschirmkonfiguration als die des Containers verwendet wird (z. B. wenn die Größe des Displays geändert oder die Aktivität auf ein anderes Display verschoben wird), ist ActivityRecord#inSizeCompatMode()
wahr und SizeCompatModeActivityController
(in der System-UI) erhält den Rückruf, um die Schaltfläche zum Neustarten des Prozesses anzuzeigen.
Displaygrößen und Seitenverhältnisse
Android 10 unterstützt neue Seitenverhältnisse, von hohen Seitenverhältnissen bei langen und schmalen Displays bis hin zu 1:1. Apps können die ApplicationInfo#maxAspectRatio
und die ApplicationInfo#minAspectRatio
des Bildschirms definieren, die sie verarbeiten können.
Abbildung 1. Beispiel für App-Verhältnisse, die unter Android 10 unterstützt werden
Geräteimplementierungen können sekundäre Bildschirme mit Größen und Auflösungen haben, die kleiner als die für Android 9 erforderlichen und niedrigeren (mindestens 2,5 Zoll Breite oder Höhe, mindestens 320 DP für smallestScreenWidth
) sind.Es dürfen jedoch nur Aktivitäten platziert werden, die diese kleinen Displays unterstützen.
Sie können die Funktion aktivieren, indem Sie eine Mindestgröße angeben, die kleiner als die Zieldisplaygröße ist oder mit dieser übereinstimmt. Verwenden Sie dazu die Aktivitätslayoutattribute android:minHeight
und android:minWidth
im AndroidManifest.
Displayanzeigenrichtlinien
In Android 10 werden bestimmte Anzeigerichtlinien von der standardmäßigen WindowManagerPolicy
-Implementierung in PhoneWindowManager
in Klassen pro Display getrennt und verschoben. Dazu gehören:
- Displaystatus und -ausrichtung
- Tracking einiger Tasten und Bewegungsereignisse
- System-UI und Dekorationsfenster
In Android 9 (und niedriger) wurde die Klasse PhoneWindowManager
für Anzeigerichtlinien, den Status und die Einstellungen, die Drehung, das Tracking von Weihnachtsfensterrahmen und mehr verwendet. Android 10 verschiebt den Großteil davon in die DisplayPolicy
-Klasse, mit Ausnahme des Rotationstrackings, das in DisplayRotation
verschoben wurde.
Einstellungen für das Anzeigefenster
In Android 10 wurde die konfigurierbare Einstellung für die Fenstergröße pro Display um folgende Optionen erweitert:
- Standardfenstermodus
- Werte für Overscan
- Nutzerrotation und Rotationsmodus
- Erzwungene Größe, Dichte und Skalierungsmodus
- Modus zur Entfernung von Inhalten (wenn das Display entfernt wird)
- Unterstützung für Systemdekorationen und IME
Die Klasse DisplayWindowSettings
enthält Einstellungen für diese Optionen. Sie werden jedes Mal, wenn eine Einstellung geändert wird, auf der Festplatte in der Partition /data
in display_settings.xml
gespeichert. Weitere Informationen finden Sie unter DisplayWindowSettings.AtomicFileStorage
und DisplayWindowSettings#writeSettings()
. Gerätehersteller können in display_settings.xml
Standardwerte für ihre Gerätekonfiguration angeben. Da die Datei jedoch in /data
gespeichert ist, ist möglicherweise zusätzliche Logik erforderlich, um sie wiederherzustellen, wenn sie durch ein Löschen gelöscht wurde.
In Android 10 wird standardmäßig DisplayInfo#uniqueId
als Kennung für ein Display verwendet, wenn die Einstellungen gespeichert werden. uniqueId
muss für alle Displays ausgefüllt sein. Außerdem ist er für physische und Netzwerkbildschirme stabil. Sie können auch den Port eines physischen Bildschirms als Kennung verwenden, die in DisplayWindowSettings#mIdentifier
festgelegt werden kann. Bei jedem Schreibvorgang werden alle Einstellungen geschrieben. Daher kann der Schlüssel, der für einen Displayeintrag verwendet wird, sicher im Speicher aktualisiert werden. Weitere Informationen finden Sie unter Statische Anzeige-IDs.
Einstellungen werden aus historischen Gründen im Verzeichnis /data
gespeichert. Ursprünglich wurden sie verwendet, um von Nutzern festgelegte Einstellungen wie die Displaydrehung beizubehalten.
Static display identifiers
Android 9 (und niedriger) bot keine stabilen IDs für Displays im Framework. Wenn dem System ein Display hinzugefügt wurde, wurde Display#mDisplayId
oder DisplayInfo#displayId
für dieses Display generiert, indem ein statischer Zähler erhöht wurde. Wenn das System dasselbe Display hinzugefügt und wieder entfernt hat, wurde eine andere ID zugewiesen.
Wenn bei einem Gerät beim Starten mehrere Displays verfügbar sind, können den Displays je nach Zeitpunkt unterschiedliche IDs zugewiesen werden. Android 9 (und niedriger) enthielt zwar DisplayInfo#uniqueId
, aber nicht genügend Informationen, um zwischen Displays zu unterscheiden, da physische Displays entweder als local:0
oder local:1
gekennzeichnet wurden, um das integrierte und das externe Display zu repräsentieren.
Unter Android 10 wurde DisplayInfo#uniqueId
geändert, um eine stabile Kennung hinzuzufügen und zwischen lokalen, Netzwerk- und virtuellen Displays zu unterscheiden.
Displaytyp | Format |
---|---|
Lokal | local:<stable-id> |
Netz | network:<mac-address> |
Virtuell | virtual:<package-name-and-name> |
Zusätzlich zu den Aktualisierungen von uniqueId
enthält DisplayInfo.address
DisplayAddress
, eine Display-ID, die nach einem Neustart unverändert bleibt. In Android 10 unterstützt DisplayAddress
physische Displays und Netzwerkbildschirme. DisplayAddress.Physical
enthält eine stabile Anzeigen-ID (wie in uniqueId
) und kann mit DisplayAddress#fromPhysicalDisplayId()
erstellt werden.
Android 10 bietet auch eine praktische Methode zum Abrufen von Anschlussinformationen (Physical#getPort()
). Diese Methode kann im Framework verwendet werden, um Displays statisch zu identifizieren. Sie wird beispielsweise in DisplayWindowSettings
verwendet. DisplayAddress.Network
enthält die MAC-Adresse und kann mit DisplayAddress#fromMacAddress()
erstellt werden.
Mit diesen Ergänzungen können Gerätehersteller Displays in statischen Mehrfach-Display-Konfigurationen identifizieren und verschiedene Systemeinstellungen und -funktionen mithilfe statischer Display-IDs wie Ports für physische Displays konfigurieren. Diese Methoden sind ausgeblendet und dürfen nur innerhalb von system_server
verwendet werden.
Wenn eine HWC-Display-ID angegeben wird (die undurchsichtig und nicht immer stabil sein kann), gibt diese Methode die (plattformspezifische) 8‑Bit-Portnummer zurück, die einen physischen Anschluss für die Displayausgabe identifiziert, sowie den EDID-Blob des Displays.
SurfaceFlinger extrahiert Hersteller- oder Modellinformationen aus der EDID, um stabile 64‑Bit-Display-IDs zu generieren, die für das Framework freigegeben werden. Wenn diese Methode nicht unterstützt wird oder Fehler auftritt, greift SurfaceFlinger auf den alten MD-Modus zurück, in dem DisplayInfo#address
null und DisplayInfo#uniqueId
hartcodiert ist, wie oben beschrieben.
So prüfen Sie, ob diese Funktion unterstützt wird:
$ 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"
Mehr als zwei Displays verwenden
In Android 9 (und niedriger) gingen SurfaceFlinger und DisplayManagerService
davon aus, dass maximal zwei physische Displays mit den hartcodierten IDs 0 und 1 vorhanden sind.
Ab Android 10 konnte SurfaceFlinger eine Hardware Composer API (HWC) nutzen, um stabile Display-IDs zu generieren, wodurch eine beliebige Anzahl physischer Displays verwaltet werden konnte. Weitere Informationen finden Sie unter Statische Anzeigen-IDs.
Das Framework kann das IBinder
-Token für ein physisches Display über SurfaceControl#getPhysicalDisplayToken
abrufen, nachdem es die 64‑Bit-Display-ID von SurfaceControl#getPhysicalDisplayIds
oder aus einem DisplayEventReceiver
-Hotplug-Ereignis abgerufen hat.
Unter Android 10 (und niedriger) ist das primäre interne Display TYPE_INTERNAL
und alle sekundären Displays werden unabhängig vom Verbindungstyp als TYPE_EXTERNAL
gekennzeichnet. Daher werden zusätzliche interne Displays als extern behandelt.
Als Problemumgehung können in Gerätecode Annahmen über DisplayAddress.Physical#getPort
getroffen werden, wenn der HWC bekannt ist und die Logik der Portzuweisung vorhersehbar ist.
Diese Einschränkung wurde in Android 11 und höher aufgehoben.
- In Android 11 ist das erste Display, das beim Start gemeldet wird, das primäre Display. Der Verbindungstyp (intern oder extern) ist irrelevant. Das primäre Display kann jedoch nicht getrennt werden, sodass es sich in der Praxis um ein internes Display handeln muss. Einige faltbare Smartphones haben mehrere interne Displays.
- Sekundäre Anzeigen werden je nach Verbindungstyp korrekt als
Display.TYPE_INTERNAL
oderDisplay.TYPE_EXTERNAL
(früherDisplay.TYPE_BUILT_IN
undDisplay.TYPE_HDMI
) kategorisiert.
Implementierung
Unter Android 9 und niedriger werden Displays anhand von 32‑Bit-IDs identifiziert. Dabei steht 0 für das interne Display, 1 für das externe Display, [2, INT32_MAX]
für virtuelle HWC-Displays und -1 für ein ungültiges Display oder ein virtuelles Display ohne HWC.
Ab Android 10 werden Displays stabile und dauerhafte IDs zugewiesen. Dadurch können SurfaceFlinger und DisplayManagerService
mehr als zwei Displays erfassen und zuvor gesehene Displays erkennen. Wenn die HWC IComposerClient.getDisplayIdentificationData
unterstützt und Anzeige-Identifikationsdaten bereitstellt, parst SurfaceFlinger die EDID-Struktur und weist stabile 64-Bit-Anzeige-IDs für physische und virtuelle HWC-Displays zu. Die IDs werden mit einem Optionstyp angegeben, wobei der Nullwert für ein ungültiges Display oder ein virtuelles Display ohne HWC steht. Ohne HWC-Unterstützung greift SurfaceFlinger auf das Legacy-Verhalten von höchstens zwei physischen Bildschirmen zurück.
Fokus pro Display
Um mehrere Eingabequellen zu unterstützen, die gleichzeitig auf einzelne Displays ausgerichtet sind, kann Android 10 so konfiguriert werden, dass mehrere fokussierte Fenster unterstützt werden, maximal eines pro Display. Diese Funktion ist nur für spezielle Gerätetypen vorgesehen, bei denen mehrere Nutzer gleichzeitig mit demselben Gerät interagieren und dabei unterschiedliche Eingabemethoden oder Geräte verwenden, z. B. Android Automotive.
Wir empfehlen dringend, diese Funktion nicht für normale Geräte zu aktivieren, einschließlich Geräte mit mehreren Bildschirmen oder Geräten, die für eine Desktop-ähnliche Nutzung verwendet werden. Dies ist in erster Linie auf Sicherheitsbedenken zurückzuführen, durch die sich Nutzer möglicherweise fragen, welches Fenster einen Eingabefokus hat.
Stellen Sie sich den Nutzer vor, der sichere Informationen in ein Texteingabefeld eingibt, z. B. sich in einer Bank-App anmeldet oder Text mit vertraulichen Informationen eingibt. Eine schädliche App kann ein virtuelles Off-Screen-Display erstellen, mit dem eine Aktivität ausgeführt wird, auch mit einem Texteingabefeld. Sowohl legitime als auch schädliche Aktivitäten sind im Fokus und beide zeigen einen aktiven Eingabeindikator (blinkenden Cursor) an.
Da Eingaben über eine Tastatur (Hardware oder Software) jedoch nur in die oberste Aktivität (die zuletzt gestartete App) einfließen, kann eine schädliche App durch die Erstellung einer verborgenen virtuellen Anzeige Nutzereingaben erfassen, selbst wenn sie eine Softwaretastatur auf dem primären Bildschirm des Geräts verwenden.
Mit com.android.internal.R.bool.config_perDisplayFocusEnabled
können Sie den Fokus für jedes Display festlegen.
Kompatibilität
Problem: Bei Android 9 und niedriger hat jeweils nur ein Fenster im System den Fokus.
Lösung:In dem seltenen Fall, dass zwei Fenster desselben Prozesses im Fokus sind, legt das System den Fokus nur auf das Fenster, das in der Z-Reihenfolge höher ist. Diese Einschränkung gilt nicht für Apps, die auf Android 10 ausgerichtet sind. Bei diesen Apps kann dann erwartet werden, dass mehrere Fenster gleichzeitig im Fokus sind.
Implementierung
WindowManagerService#mPerDisplayFocusEnabled
steuert die Verfügbarkeit dieser Funktion. In ActivityManager
wird jetzt ActivityDisplay#getFocusedStack()
anstelle von globalem Tracking in einer Variablen verwendet. ActivityDisplay#getFocusedStack()
legt den Fokus anhand der Z-Reihenfolge fest, anstatt den Wert im Cache zu speichern. So muss nur eine Quelle, WindowManager, die Z-Reihenfolge der Aktivitäten verfolgen.
ActivityStackSupervisor#getTopDisplayFocusedStack()
verwendet einen ähnlichen Ansatz für Fälle, in denen der oberste Stack im System identifiziert werden muss. Die Stapel werden von oben nach unten durchsucht, um den ersten geeigneten Stapel zu finden.
InputDispatcher
kann jetzt mehrere Fenster im Fokus haben (jeweils eines pro Bildschirm). Wenn ein Eingabeereignis displayspezifisch ist, wird es an das Fenster mit der Fokussierung auf dem entsprechenden Display gesendet. Andernfalls wird die Benachrichtigung an das Fenster auf dem Display gesendet, mit dem der Nutzer zuletzt interagiert hat.
Weitere Informationen finden Sie unter InputDispatcher::mFocusedWindowHandlesByDisplay
und InputDispatcher::setFocusedDisplay()
. Aktive Apps werden auch separat im InputManagerService über NativeInputManager::setFocusedApplication()
aktualisiert.
In WindowManager
werden auch Fenster, die gerade aktiv sind, separat erfasst.
Weitere Informationen finden Sie unter DisplayContent#mCurrentFocus
und DisplayContent#mFocusedApp
sowie die jeweiligen Verwendungszwecke. Die zugehörigen Methoden zum Fokus-Tracking und -Aktualisieren wurden von WindowManagerService
zu DisplayContent
verschoben.