Displayunterstützung

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

Größe von Aktivitäten und Displays ändern

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 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 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, bei denen dieses Attribut im Manifest explizit auf false festgelegt ist, 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 Multiwindow-Bildschirmen kompatibel erklärt wurde und diese Aktivität eine der unten beschriebenen Bedingungen erfüllt, muss sich die angewendete Bildschirmkonfiguration ändern. Aktivität und 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, weil 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 Sie das Gerät zusammenklappen, wird das Fenster so skaliert, dass es in den Bereich passt. Dabei wird das Seitenverhältnis durch entsprechendes 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 ist (oder auf true gesetzt ist), unterstützt die App das Ändern der Größe 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. 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 das Display neu skaliert 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.

App-Verhältnisse in Android 10

Abbildung 1: Beispiel für App-Verhältnisse, die in Android 10 unterstützt werden

Geräteimplementierungen können sekundäre Displays mit Größen und Auflösungen haben, die kleiner als die von Android 9 geforderten sind (mindestens 6,4 cm Breite oder Höhe, mindestens 320 dp für smallestScreenWidth). Dort können jedoch nur Aktivitäten platziert werden, die die Unterstützung dieser kleinen Displays aktivieren.

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

Unter Android 10 werden bestimmte Displayrichtlinien aus der standardmäßigen WindowManagerPolicy-Implementierung in PhoneWindowManager in Klassen pro Display verschoben, z. B.:

  • Displaystatus und -ausrichtung
  • Einige 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 dieser Funktionen 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 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 DisplayWindowSettings-Klasse enthält Einstellungen für diese Optionen. Sie werden jedes Mal, wenn eine Einstellung geändert wird, auf der Festplatte in der Partition /data unter 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 sollte für alle Displays 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 Displayeintrag verwendet wird, sicher im Speicher 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 zu speichern.

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 für dieses Display Display#mDisplayId oder DisplayInfo#displayId 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 wird 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. Unter Android 10 unterstützt DisplayAddress physische 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 von statischen 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, wechselt SurfaceFlinger zum alten MD-Modus, 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 es höchstens zwei physische Displays mit den hartcodierten IDs 0 und 1 gibt.

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 kann. 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 Sie in Gerätecode Annahmen über DisplayAddress.Physical#getPort treffen, 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 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 Daten zur Displayidentifikation bereitstellt, analysiert SurfaceFlinger die EDID-Struktur und weist physischen und HWC-virtuellen Displays stabile 64‑Bit-Display-IDs zu. Die IDs werden mit einem Optionstyp angegeben, wobei der Nullwert für ein ungültiges Display oder ein nicht HWC-virtuelles Display steht. Ohne HWC-Unterstützung wechselt SurfaceFlinger zum bisherigen Verhalten mit maximal zwei physischen Displays.

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. 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, sich beispielsweise in einer Banking-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 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 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 stehen können.

Implementierung

Mit WindowManagerService#mPerDisplayFocusEnabled wird die Verfügbarkeit dieser Funktion gesteuert. In ActivityManager wird jetzt ActivityDisplay#getFocusedStack() anstelle des globalen Trackings 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 aktive Fenster auf dem aktiven Display gesendet, also an das Display, 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 aktive Fenster separat erfasst. Weitere Informationen finden Sie unter DisplayContent#mCurrentFocus und DisplayContent#mFocusedApp. Die zugehörigen Methoden zum Fokus-Tracking und -Aktualisieren wurden von WindowManagerService zu DisplayContent verschoben.