Display-Unterstützung

Nachfolgend finden Sie Aktualisierungen, die an diesen anzeigespezifischen Bereichen vorgenommen wurden:

Ändern Sie die Größe von Aktivitäten und Anzeigen

Um anzuzeigen, 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 der Größenänderung von Aktivitäten bei Apps auftreten, gehören:

  • Eine Aktivität kann eine andere Konfiguration haben als die App oder eine andere nicht-visuelle Komponente. Ein häufiger Fehler besteht darin, Anzeigemetriken aus dem App-Kontext abzulesen. Die zurückgegebenen Werte werden nicht an die Metriken des sichtbaren Bereichs angepasst, in denen eine Aktivität angezeigt wird.
  • Eine Aktivität verträgt möglicherweise keine Größenänderung und stürzt ab, zeigt eine verzerrte Benutzeroberfläche an oder verliert den Status aufgrund eines Neustarts, ohne den Instanzstatus zu speichern.
  • Eine App versucht möglicherweise, absolute Eingabekoordinaten zu verwenden (anstelle derer, die sich auf die Fensterposition beziehen), wodurch die Eingabe in mehreren Fenstern möglicherweise unterbrochen wird.

In Android 7 (und höher) kann eine App so eingestellt werden resizeableActivity=false immer im Vollbildmodus ausgeführt wird. In diesem Fall verhindert die Plattform, dass nicht veränderbare Aktivitäten in den geteilten Bildschirm gelangen. Wenn der Benutzer versucht, eine nicht veränderbare Aktivität über den Launcher aufzurufen, während er sich bereits im Split-Screen-Modus befindet, verlässt die Plattform den Split-Screen-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:

  • Dieselbe Konfiguration wird auf den Prozess angewendet, der alle Aktivitäten und Nichtaktivitätskomponenten enthält.
  • Die angewandte Konfiguration erfüllt die CDD-Anforderungen für App-kompatible Displays.

In Android 10 verhindert die Plattform immer noch, dass nicht veränderbare Aktivitäten in den Split-Screen-Modus wechseln, sie können jedoch vorübergehend skaliert werden, wenn die Aktivität eine feste Ausrichtung oder ein festes Seitenverhältnis angegeben hat. Wenn nicht, wird die Größe der Aktivität so angepasst, dass sie den gesamten Bildschirm ausfüllt, wie in Android 9 und niedriger.

Die Standardimplementierung wendet die folgende Richtlinie an:

Wenn eine Aktivität durch die Verwendung des Attributs android:resizeableActivity als mit Multi-Window nicht kompatibel erklärt wird und diese Aktivität eine der unten beschriebenen Bedingungen erfüllt und sich die angewendete Bildschirmkonfiguration ändern muss, werden die Aktivität und der Prozess mit der ursprünglichen Konfiguration gespeichert und dem Benutzer wird die Möglichkeit geboten, den App-Prozess neu zu starten, um die aktualisierte Bildschirmkonfiguration zu verwenden.

  • Ist eine feste Ausrichtung über die Anwendung von android:screenOrientation
  • Die App verfügt über ein standardmäßiges maximales oder minimales Seitenverhältnis, indem sie auf die API-Ebene abzielt oder das Seitenverhältnis explizit deklariert

Diese Abbildung zeigt eine nicht veränderbare Aktivität mit einem angegebenen Seitenverhältnis. Beim Zusammenklappen des Geräts wird das Fenster entsprechend der Fläche verkleinert, wobei das Seitenverhältnis durch die entsprechende Letterbox beibehalten wird. Darüber hinaus wird dem Benutzer jedes Mal, wenn der Anzeigebereich für die Aktivität geändert wird, eine Option zum Neustarten der Aktivität bereitgestellt.

Beim Aufklappen des Geräts ändern sich Konfiguration, Größe und Seitenverhältnis der Aktivität nicht, es wird jedoch die Option zum Neustarten der Aktivität angezeigt.

Wenn resizeableActivity nicht festgelegt ist (oder auf true festgelegt ist), unterstützt die App die Größenänderung vollständig.

Implementierung

Eine nicht veränderbare Aktivität mit fester Ausrichtung oder festem Seitenverhältnis wird im Code als Größenkompatibilitätsmodus (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 fixiert, sodass die Aktivität nicht mehr von der aktuellen Anzeigekonfiguration abhängig ist.

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 eine SCM-Aktivität eine andere Bildschirmkonfiguration als ihr Container verwendet (z. B. wird die Größe der Anzeige geändert oder Aktivität in eine andere Anzeige verschoben), ist ActivityRecord#inSizeCompatMode() wahr und SizeCompatModeActivityController (in der System-Benutzeroberfläche) empfängt den Rückruf, um den Prozess anzuzeigen Neustart-Taste.

Displaygrößen und Seitenverhältnisse

Android 10 bietet Unterstützung für neue Seitenverhältnisse von hohen Seitenverhältnissen bei langen und dünnen Bildschirmen bis hin zu 1:1-Verhältnissen. Apps können ApplicationInfo#maxAspectRatio und ApplicationInfo#minAspectRatio des Bildschirms definieren, den sie verarbeiten können.

App-Verhältnisse in Android 10

Abbildung 1. Beispielhafte 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 für Android 9 erforderlichen und niedriger sind (mindestens 2,5 Zoll Breite oder Höhe, mindestens 320 DP für smallestScreenWidth ), aber nur Aktivitäten, die sich für die Unterstützung dieser kleinen Displays entscheiden, können dies tun dort platziert.

Apps können sich dafür entscheiden, indem sie eine unterstützte Mindestgröße angeben, die kleiner als die Zielanzeigegröße ist. Verwenden Sie dazu die Aktivitätslayoutattribute android:minHeight und android:minWidth im AndroidManifest.

Richtlinien anzeigen

Android 10 trennt und verschiebt bestimmte Anzeigerichtlinien von der standardmäßigen WindowManagerPolicy Implementierung in PhoneWindowManager in anzeigespezifische Klassen, wie zum Beispiel:

  • Anzeigestatus und Drehung
  • Einige Tasten und Bewegungsereignisverfolgung
  • System-Benutzeroberfläche und Dekorationsfenster

In Android 9 (und niedriger) verwaltete die PhoneWindowManager Klasse Anzeigerichtlinien, Status und Einstellungen, Drehung, Nachverfolgung von Dekorationsfensterrahmen und mehr. Android 10 verschiebt den größten Teil davon in die DisplayPolicy Klasse, mit Ausnahme der Rotationsverfolgung, die in DisplayRotation verschoben wurde.

Fenstereinstellungen anzeigen

In Android 10 wurde die konfigurierbare Fenstereinstellung pro Anzeige um Folgendes erweitert:

  • Standardmäßiger Anzeigefenstermodus
  • Overscan-Werte
  • Benutzerrotation und Rotationsmodus
  • Erzwungene Größe, Dichte und Skalierungsmodus
  • Modus zum Entfernen 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 in display_settings.xml gespeichert. Einzelheiten finden Sie unter DisplayWindowSettings.AtomicFileStorage und DisplayWindowSettings#writeSettings() . Gerätehersteller können in display_settings.xml Standardwerte für ihre Gerätekonfiguration bereitstellen. Da die Datei jedoch in /data gespeichert ist, ist möglicherweise zusätzliche Logik erforderlich, um die Datei wiederherzustellen, wenn sie durch einen Löschvorgang gelöscht wird.

Standardmäßig verwendet Android 10 DisplayInfo#uniqueId als Kennung für eine Anzeige, wenn die Einstellungen beibehalten werden. uniqueId sollte für alle Anzeigen ausgefüllt werden. Darüber hinaus ist es stabil für physische und Netzwerkanzeigen. Es ist auch möglich, den Port einer physischen Anzeige als Kennung zu verwenden, die in DisplayWindowSettings#mIdentifier festgelegt werden kann. Bei jedem Schreibvorgang werden alle Einstellungen geschrieben, sodass der Schlüssel, der für einen Anzeigeeintrag im Speicher verwendet wird, sicher aktualisiert werden kann. Einzelheiten finden Sie unter Statische Anzeige-IDs .

Aus historischen Gründen werden die Einstellungen im Verzeichnis /data gespeichert. Ursprünglich wurden sie verwendet, um vom Benutzer festgelegte Einstellungen beizubehalten, beispielsweise die Anzeigedrehung.

Statische Anzeigebezeichner

Android 9 (und niedriger) stellte im Framework keine stabilen Identifikatoren für Anzeigen bereit. Wenn dem System eine Anzeige hinzugefügt wurde, wurde Display#mDisplayId oder DisplayInfo#displayId für diese Anzeige durch Erhöhen eines statischen Zählers generiert. Wenn das System dieselbe Anzeige hinzufügte und entfernte, ergab sich eine andere ID.

Wenn einem Gerät beim Booten mehrere Displays zur Verfügung standen, könnten den Displays je nach Timing unterschiedliche Kennungen zugewiesen werden. Während Android 9 (und früher) DisplayInfo#uniqueId enthielt, enthielt es nicht genügend Informationen, um zwischen Anzeigen zu unterscheiden, da physische Anzeigen entweder als local:0 oder local:1 identifiziert wurden, um die integrierte und externe Anzeige darzustellen.

Android 10 ändert DisplayInfo#uniqueId um eine stabile Kennung hinzuzufügen und zwischen lokalen, Netzwerk- und virtuellen Displays zu unterscheiden.

Anzeigetyp Format
Lokal
local:<stable-id>
Netzwerk
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 über Neustarts hinweg stabil bleibt. In Android 10 unterstützt DisplayAddress physische und Netzwerkanzeigen. DisplayAddress.Physical enthält eine stabile Anzeige-ID (wie in uniqueId ) und kann mit DisplayAddress#fromPhysicalDisplayId() erstellt werden.

Android 10 bietet außerdem eine praktische Methode zum Abrufen von Portinformationen ( Physical#getPort() ). Diese Methode kann im Framework verwendet werden, um Displays statisch zu identifizieren. Es wird beispielsweise in DisplayWindowSettings verwendet. DisplayAddress.Network enthält die MAC-Adresse und kann mit DisplayAddress#fromMacAddress() erstellt werden.

Diese Ergänzungen ermöglichen es Geräteherstellern, Displays in statischen Multi-Display-Setups zu identifizieren und verschiedene Systemeinstellungen und Funktionen mithilfe statischer Display-Identifikatoren, wie z. B. Ports für physische Displays, zu konfigurieren. Diese Methoden sind versteckt und nur für die Verwendung innerhalb von system_server vorgesehen.

Bei einer HWC-Display-ID (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 Display-Ausgabe identifiziert, sowie den EDID-Blob des Displays. SurfaceFlinger extrahiert Hersteller- oder Modellinformationen aus der EDID, um die stabilen 64-Bit-Anzeige-IDs zu generieren, die dem Framework zur Verfügung gestellt werden. Wenn diese Methode nicht unterstützt wird oder ein Fehler auftritt, greift SurfaceFlinger auf den alten MD-Modus zurück, in dem DisplayInfo#address null und DisplayInfo#uniqueId hartcodiert ist, wie oben beschrieben.

Um zu überprüfen, ob diese Funktion unterstützt wird, führen Sie Folgendes aus:

$ 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"

Verwenden Sie mehr als zwei Displays

In Android 9 (und niedriger) gingen SurfaceFlinger und DisplayManagerService von der Existenz von höchstens zwei physischen Displays mit den fest codierten IDs 0 und 1 aus.

Ab Android 10 könnte SurfaceFlinger eine Hardware Composer (HWC)-API nutzen, um stabile Display-IDs zu generieren, wodurch eine beliebige Anzahl physischer Displays verwaltet werden kann. Weitere Informationen finden Sie unter Statische Anzeige-IDs .

Das Framework kann das IBinder Token für eine physische Anzeige über SurfaceControl#getPhysicalDisplayToken nachschlagen, nachdem es die 64-Bit-Anzeige-ID von SurfaceControl#getPhysicalDisplayIds oder von einem DisplayEventReceiver Hotplug-Ereignis erhalten hat.

In Android 10 (und niedriger) ist die primäre interne Anzeige TYPE_INTERNAL und alle sekundären Anzeigen werden unabhängig vom Verbindungstyp als TYPE_EXTERNAL gekennzeichnet. Daher werden zusätzliche interne Anzeigen als extern behandelt. Um dieses Problem zu umgehen, kann gerätespezifischer Code Annahmen über DisplayAddress.Physical#getPort treffen, wenn der HWC bekannt und die Portzuweisungslogik vorhersehbar ist.

Diese Einschränkung wird in Android 11 (und höher) entfernt.

  • In Android 11 ist die erste beim Booten gemeldete Anzeige die primäre Anzeige. Der Verbindungstyp (intern versus extern) ist unerheblich. Es bleibt jedoch wahr, dass die primäre Anzeige nicht getrennt werden kann und es sich in der Praxis daher um eine interne Anzeige handeln muss. Beachten Sie, dass einige faltbare Telefone über mehrere interne Displays verfügen.
  • Sekundäre Displays werden je nach Verbindungstyp korrekt als Display.TYPE_INTERNAL oder Display.TYPE_EXTERNAL (früher bekannt als Display.TYPE_BUILT_IN bzw. Display.TYPE_HDMI ) kategorisiert.

Implementierung

In Android 9 und niedriger werden Anzeigen durch 32-Bit-IDs identifiziert, wobei 0 die interne Anzeige, 1 die externe Anzeige, [2, INT32_MAX] virtuelle HWC-Anzeigen und -1 eine ungültige Anzeige oder eine Nicht-HWC darstellt virtuelle Anzeige.

Ab Android 10 erhalten Displays stabile und dauerhafte IDs, die es SurfaceFlinger und DisplayManagerService ermöglichen, mehr als zwei Displays zu verfolgen und zuvor gesehene Displays zu erkennen. Wenn das HWC IComposerClient.getDisplayIdentificationData unterstützt und Anzeigeidentifikationsdaten bereitstellt, analysiert SurfaceFlinger die EDID-Struktur und weist stabile 64-Bit-Anzeige-IDs für physische und virtuelle HWC-Anzeigen zu. Die IDs werden mithilfe eines Optionstyps ausgedrückt, wobei der Nullwert eine ungültige Anzeige oder eine virtuelle Nicht-HWC-Anzeige darstellt. Ohne HWC-Unterstützung greift SurfaceFlinger auf das alte Verhalten mit höchstens zwei physischen Displays zurück.

Fokus pro Anzeige

Um mehrere Eingabequellen zu unterstützen, die gleichzeitig auf einzelne Displays abzielen, kann Android 10 so konfiguriert werden, dass es mehrere fokussierte Fenster unterstützt, höchstens eines pro Display. Dies ist nur für spezielle Gerätetypen gedacht, bei denen mehrere Benutzer gleichzeitig mit demselben Gerät interagieren und unterschiedliche Eingabemethoden oder Geräte verwenden, wie z. B. Android Automotive.

Es wird dringend empfohlen, diese Funktion nicht für normale Geräte zu aktivieren, einschließlich Geräten mit mehreren Bildschirmen oder solchen, die für Desktop-ähnliche Erlebnisse verwendet werden. Dies ist in erster Linie auf ein Sicherheitsrisiko zurückzuführen, das dazu führen kann, dass Benutzer sich fragen, welches Fenster den Eingabefokus hat.

Stellen Sie sich den Benutzer vor, der sichere Informationen in ein Texteingabefeld eingibt, sich vielleicht bei einer Banking-App anmeldet oder Text eingibt, der vertrauliche Informationen enthält. Eine bösartige App könnte eine virtuelle Off-Screen-Anzeige erstellen, mit der eine Aktivität ausgeführt werden kann, auch mit einem Texteingabefeld. Legitime und böswillige Aktivitäten stehen im Fokus und beide zeigen eine aktive Eingabeanzeige (blinkender Cursor).

Da Eingaben über eine Tastatur (Hardware oder Software) jedoch nur in die oberste Aktivität (die App, die zuletzt gestartet wurde) eingegeben werden, könnte eine bösartige App durch die Erstellung einer versteckten virtuellen Anzeige Benutzereingaben erfassen, selbst wenn eine Softwaretastatur verwendet wird auf dem primären Gerätedisplay angezeigt.

Verwenden Sie com.android.internal.R.bool.config_perDisplayFocusEnabled , um den Fokus pro Anzeige festzulegen.

Kompatibilität

Problem: In Android 9 und niedriger ist jeweils höchstens ein Fenster im System im Fokus.

Lösung: In dem seltenen Fall, dass zwei Fenster desselben Prozesses fokussiert sind, fokussiert das System nur das Fenster, das in der Z-Reihenfolge höher liegt. Diese Einschränkung wird für Apps aufgehoben, die auf Android 10 abzielen. Ab diesem Zeitpunkt wird erwartet, dass sie die gleichzeitige Fokussierung mehrerer Fenster unterstützen können.

Implementierung

WindowManagerService#mPerDisplayFocusEnabled steuert die Verfügbarkeit dieser Funktion. Im ActivityManager wird nun ActivityDisplay#getFocusedStack() anstelle der globalen Nachverfolgung in einer Variablen verwendet. ActivityDisplay#getFocusedStack() bestimmt den Fokus basierend auf der Z-Reihenfolge, anstatt den Wert zwischenzuspeichern. Dadurch muss nur eine Quelle, WindowManager, die Z-Reihenfolge der Aktivitäten verfolgen.

ActivityStackSupervisor#getTopDisplayFocusedStack() verfolgt einen ähnlichen Ansatz für die Fälle, in denen der oberste fokussierte Stapel im System identifiziert werden muss. Die Stapel werden von oben nach unten durchlaufen, wobei nach dem ersten geeigneten Stapel gesucht wird.

InputDispatcher kann jetzt mehrere fokussierte Fenster haben (eines pro Anzeige). Wenn ein Eingabeereignis anzeigespezifisch ist, wird es an das fokussierte Fenster in der entsprechenden Anzeige gesendet. Andernfalls wird es an das fokussierte Fenster in der fokussierten Anzeige weitergeleitet, also an die Anzeige, mit der der Benutzer zuletzt interagiert hat.

Siehe InputDispatcher::mFocusedWindowHandlesByDisplay und InputDispatcher::setFocusedDisplay() . Fokussierte Apps werden auch separat in InputManagerService über NativeInputManager::setFocusedApplication() aktualisiert.

Im WindowManager werden fokussierte Fenster auch separat verfolgt. Siehe DisplayContent#mCurrentFocus und DisplayContent#mFocusedApp und die jeweiligen Verwendungen. Zugehörige Methoden zur Fokusverfolgung und -aktualisierung wurden von WindowManagerService nach DisplayContent verschoben.