Displayunterstützung

Im Folgenden finden Sie die Änderungen an diesen anzeigespezifischen Bereichen:

Größe von Aktivitäten und Displays anpassen

Um anzugeben, dass eine App den Mehrfenstermodus oder die Größenänderung möglicherweise nicht unterstützt, verwenden Aktivitäten das Attribut resizeableActivity=false. Zu den häufigsten Problemen, die bei Apps auftreten, wenn Aktivitäten angepasst werden, gehören:

  • Die Konfiguration einer Aktivität kann sich von der App oder einer anderen nicht visuellen Komponente unterscheiden. Ein häufiger Fehler besteht darin, 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 App kann versuchen, absolute Eingabekoordinaten zu verwenden (anstelle von Koordinaten, die sich auf die Fensterposition beziehen). Dies kann die Eingabe in einem Mehrfenstermodus beeinträchtigen.

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 Aktivitäten ohne Größenanpassung im Splitscreen-Modus erscheinen. Wenn der Nutzer versucht, über den Launcher eine Aktivität aufzurufen, deren Größe nicht angepasst werden kann, während er sich bereits im geteilten Bildschirmmodus befindet, wird der Splitscreen-Modus von der Plattform beendet und die Aktivität mit nicht anpassbarer Größe im Vollbildmodus gestartet.

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.

Auch in Android 10 verhindert die Plattform, dass Aktivitäten ohne Größenanpassung in den Splitscreen-Modus wechseln. Sie können jedoch vorübergehend skaliert werden, wenn die Aktivität eine feste Ausrichtung oder ein festes Seitenverhältnis deklariert hat. Andernfalls wird die Aktivität wie in Android 9 und niedriger so angepasst, dass sie den gesamten Bildschirm ausfüllt.

Bei der Standardimplementierung wird die folgende Richtlinie angewendet:

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 über android:screenOrientation eine feste Ausrichtung.
  • 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. Beim Falten des Geräts wird das Fenster verkleinert, damit es in den Bereich passt und das Seitenverhältnis mit dem entsprechenden Letterbox-Format beibehalten wird. Außerdem wird dem Nutzer jedes Mal eine Option für den Neustart der Aktivität zur Verfügung gestellt, wenn sich der Anzeigebereich für die Aktivität ändert.

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 Aktivität mit nicht anpassbarer Größe mit fester Ausrichtung oder festem Seitenverhältnis wird im Code als Größenkompatibilitätsmodus (Size Compatibility Mode, SCM) bezeichnet. Die Bedingung ist in ActivityRecord#shouldUseSizeCompatMode() definiert. Wenn eine SCM-Aktivität gestartet wird, wird die bildschirmbezogene Konfiguration (z. B. Größe oder Dichte) in der angeforderten Überschreibungskonfiguration festgelegt. Die Aktivität ist dann nicht mehr von der aktuellen Displaykonfiguration abhängig.

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 Verhältnissen bei langen und dünnen Bildschirmen bis zu Seitenverhältnissen von 1:1. Apps können die ApplicationInfo#maxAspectRatio und die ApplicationInfo#minAspectRatio des Bildschirms definieren, die sie verarbeiten können.

App-Verhältnisse in Android 10

Abbildung 1: Beispiele für unter Android 10 unterstützte App-Seitenverhältnisse

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.

Apps können durch Deklarieren einer unterstützten Mindestgröße aktiviert werden, die kleiner oder gleich der Zielanzeigegröße ist. Verwenden Sie dazu die Aktivitätslayoutattribute android:minHeight und android:minWidth im AndroidManifest.

Displayrichtlinien

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

Unter Android 9 und niedriger wurden in der Klasse PhoneWindowManager unter anderem Displayrichtlinien, Status und Einstellungen, Drehung und das Tracking des Dekorationsfensterrahmens verarbeitet. In Android 10 wurde der Großteil davon in die Klasse DisplayPolicy verschoben, mit Ausnahme des Drehungs-Trackings, das in DisplayRotation verschoben wurde.

Einstellungen für das Anzeigefenster

In Android 10 wurde die konfigurierbare Windowing-Einstellung pro Anzeige um Folgendes erweitert:

  • Standardfenstermodus
  • Overscan-Werte
  • Nutzerrotation und Rotationsmodus
  • Erzwungene Größe, Dichte und Skalierungsmodus
  • Modus zum Entfernen von Inhalten (wenn die Anzeige entfernt wird)
  • Unterstützung für Systemdesigns 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äteverwaltung 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.

Standardmäßig verwendet Android 10 beim Speichern der Einstellungen DisplayInfo#uniqueId als Kennung für eine Anzeige. uniqueId sollte für alle Bildschirme ausgefüllt sein. Außerdem ist er für physische und Netzwerkbildschirme stabil. Es ist auch möglich, den Anschluss eines physischen Displays als Kennung zu verwenden. Diese kann in DisplayWindowSettings#mIdentifier festgelegt werden. Bei jedem Schreibvorgang werden alle Einstellungen geschrieben. Daher kann der Schlüssel, der für einen Anzeigeeintrag im Speicher verwendet wird, sicher aktualisiert werden. Weitere Informationen finden Sie unter Statische Anzeigen-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.

Statische Display-IDs

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 Start mehrere Bildschirme verfügbar waren, können den Bildschirmen 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 Anzeige-ID, die auch nach einem Neustart stabil ist. Unter Android 10 unterstützt DisplayAddress physische und Netzwerkbildschirme. DisplayAddress.Physical enthält eine stabile Display-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. Er 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 Anzeige-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 wird ab Android 11 aufgehoben.

  • In Android 11 ist der erste Bildschirm, der beim Start gemeldet wird, der primäre Bildschirm. 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 oder Display.TYPE_EXTERNAL (früher Display.TYPE_BUILT_IN und Display.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 erhalten Displays stabile und persistente IDs, sodass SurfaceFlinger und DisplayManagerService mehr als zwei Displays erfassen und zuvor gesehene Displays erkennen können. 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 ausgedrückt, wobei der Nullwert eine ungültige Anzeige oder eine virtuelle Anzeige ohne HWC darstellt. Ohne HWC-Unterstützung wechselt SurfaceFlinger zum bisherigen Verhalten mit maximal zwei physischen Displays.

Fokus pro Display

Android 10 kann so konfiguriert werden, dass mehrere fokussierte Fenster unterstützt werden, und zwar maximal ein Fenster pro Display, um mehrere Eingabequellen zu unterstützen, die auf einzelne Bildschirme ausgerichtet sind. 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. Das liegt vor allem an Sicherheitsbedenken, die Nutzer dazu bringen könnten, sich zu fragen, welches Fenster den Eingabefokus hat.

Stellen Sie sich einen Nutzer vor, der vertrauliche Informationen in ein Textfeld eingibt, z. B. wenn er sich in einer Banking-App anmeldet oder Text mit vertraulichen Informationen eingibt. Eine schädliche App könnte ein virtuelles Off-Screen-Display erstellen, mit dem eine Aktivität ausgeführt werden kann, 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 die Eingabe über eine Tastatur (Hardware oder Software) jedoch nur in die oberste Aktivität (die zuletzt gestartete App) eingegeben wird, kann eine schädliche App durch das Erstellen eines versteckten virtuellen Displays die Nutzereingabe abfangen, auch wenn eine Softwaretastatur auf dem primären Gerätedisplay verwendet wird.

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 aus demselben Prozess fokussiert werden, fokussiert das System nur das Fenster, das in der Z-Reihenfolge weiter oben liegt. Diese Einschränkung wird für Apps entfernt, die auf Android 10 ausgerichtet sind. Ab diesem Zeitpunkt können sie voraussichtlich mehrere Fenster gleichzeitig unterstützen.

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. Auf diese Weise 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 Stacks werden von oben nach unten durchlaufen, wobei nach dem ersten zulässigen Stack gesucht wird.

InputDispatcher kann jetzt mehrere fokussierte Fenster haben (eines pro Anzeige). 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(). Fokussierte Apps werden außerdem separat in 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.