Unterstützung von Systemdekorationen

Aktualisierungen dieser anzeigenspezifischen Bereiche werden auf dieser Seite bereitgestellt.

Systemverzierungen

Unter Android 10 können sekundäre Displays so konfiguriert werden, dass bestimmte Systemdekorationen wie Hintergrund, Navigationsleiste und Launcher angezeigt werden. Standardmäßig werden auf dem primären Display alle Systemdekorationen angezeigt, auf sekundären Displays nur die optional aktivierten. Sie können die Unterstützung für einen Eingabemethoden-Editor (IME) separat von anderen Systemdekorationen festlegen.

Verwende DisplayWindowSettings#setShouldShowSystemDecorsLocked(), um Unterstützung für Systemdekorationen auf einem bestimmten Display hinzuzufügen oder einen Standardwert in /data/system/display_settings.xml anzugeben. Beispiele finden Sie unter Einstellungen für das Displayfenster.

Implementierung

DisplayWindowSettings#setShouldShowSystemDecorsLocked() ist auch in WindowManager#setShouldShowSystemDecors() für Tests verfügbar. Wenn Sie diese Methode mit der Absicht auslösen, Systemdekorationen zu aktivieren, werden keine Dekorfenster hinzugefügt, die zuvor gefehlt haben, und keine entfernt, die zuvor vorhanden waren. In den meisten Fällen wird die Änderung der Unterstützung für Systemdekorationen erst nach einem Neustart des Geräts vollständig wirksam.

Prüfungen auf Unterstützung von Systemdekorationen in der WindowManager-Codebasis erfolgen in der Regel über DisplayContent#supportsSystemDecorations(), während Prüfungen für externe Dienste (z. B. System-UI, um zu prüfen, ob die Navigationsleiste angezeigt werden soll) WindowManager#shouldShowSystemDecors() verwenden. Um zu verstehen, was durch diese Einstellung gesteuert wird, sehen Sie sich die Aufrufstellen dieser Methoden an.

Dekorfenster der System-UI

In Android 10 wird die Unterstützung von Systemdekorfenstern nur für die Navigationsleiste hinzugefügt, da die Navigationsleiste für die Navigation zwischen Aktivitäten und Apps unerlässlich ist. Standardmäßig werden in der Navigationsleiste die Schaltflächen „Zurück“ und „Startseite“ angezeigt. Dieser Wert ist nur enthalten, wenn das Zieldisplay Systemdekorationen unterstützt (siehe DisplayWindowSettings).

Die Statusleiste ist ein komplexeres Systemfenster, da sie auch die Benachrichtigungsleiste, die Schnelleinstellungen und den Sperrbildschirm enthält. In Android 10 wird die Statusleiste auf sekundären Displays nicht unterstützt. Daher sind Benachrichtigungen, Einstellungen und ein vollständiger Keyguard nur auf dem primären Display verfügbar.

Das Systemfenster Übersicht/Letzte wird auf sekundären Bildschirmen nicht unterstützt. In Android 10 werden in AOSP nur die zuletzt verwendeten Apps auf dem Standarddisplay angezeigt und Aktivitäten von allen Displays sind enthalten. Wenn eine Aktivität, die auf einem sekundären Display angezeigt wurde, über „Letzte“ gestartet wird, wird sie standardmäßig auf diesem Display in den Vordergrund geholt. Dieser Ansatz hat einige bekannte Probleme, z. B. dass er nicht sofort aktualisiert wird, wenn Apps auf anderen Bildschirmen angezeigt werden.

Implementierung

Um zusätzliche Funktionen der System-UI zu implementieren, sollten Gerätehersteller eine einzelne System-UI-Komponente verwenden, die auf das Hinzufügen oder Entfernen von Displays reagiert und entsprechende Inhalte präsentiert.

Eine System-UI-Komponente, die Multi-Display (MD) unterstützt, sollte die folgenden Fälle abdecken:

  • Initialisierung mehrerer Displays beim Start
  • Display zur Laufzeit hinzugefügt
  • Display zur Laufzeit entfernt

Wenn die System-UI das Hinzufügen eines Displays vor dem WindowManager erkennt, entsteht eine Race Condition. Sie können dies vermeiden, indem Sie einen benutzerdefinierten Callback von WindowManager zur System-UI implementieren, wenn ein Display hinzugefügt wird, anstatt DisplayManager.DisplayListener-Ereignisse zu abonnieren. Eine Referenzimplementierung finden Sie unter CommandQueue.Callbacks#onDisplayAddSystemDecorations für die Unterstützung der Navigationsleiste und unter WallpaperManagerInternal#onDisplayAddSystemDecorations für Hintergrundbilder.

Außerdem bietet Android 10 die folgenden Updates:

  • Die Klasse NavigationBarController steuert alle Funktionen, die für Navigationsleisten spezifisch sind.
  • Informationen zum Anpassen der Navigationsleiste finden Sie unter CarStatusBar.
  • TYPE_NAVIGATION_BAR ist nicht mehr auf eine einzelne Instanz beschränkt und kann pro Display verwendet werden.
  • IWindowManager#hasNavigationBar() wird aktualisiert und enthält nur für die System-UI den Parameter displayId.

Launcher

In Android 10 hat jeder Bildschirm, der für die Unterstützung von Systemdekorationen konfiguriert ist, standardmäßig einen dedizierten Home-Stack für Launcher-Aktivitäten mit dem Typ WindowConfiguration#ACTIVITY_TYPE_HOME. Für jeden Bildschirm wird eine separate Instanz der Launcher-Aktivität verwendet:

Abbildung 1: Beispiel für einen Launcher für mehrere Displays für platform/development/samples/MultiDisplay.

Die meisten vorhandenen Launcher unterstützen keine mehreren Instanzen und sind nicht für große Displays optimiert. Außerdem wird auf sekundären/externen Displays oft eine andere Art von Nutzung erwartet. In Android 10 wurde die Kategorie SECONDARY_HOME in Intent-Filtern eingeführt, um eine spezielle Aktivität für sekundäre Displays bereitzustellen. Instanzen dieser Aktivität werden auf allen Displays verwendet, die Systemdekorationen unterstützen, eine pro Display.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

Die Aktivität muss einen Startmodus haben, der mehrere Instanzen nicht verhindert, und sie muss sich an verschiedene Bildschirmgrößen anpassen. Der Startmodus darf nicht singleInstance oder singleTask sein.

Implementierung

In Android 10 wählt RootActivityContainer#startHomeOnDisplay() automatisch die gewünschte Komponente und den gewünschten Intent aus, je nachdem, auf welchem Display der Startbildschirm gestartet wird. RootActivityContainer#resolveSecondaryHomeActivity() enthält die Logik zum Suchen der Launcher-Aktivitätskomponente in Abhängigkeit vom aktuell ausgewählten Launcher und kann bei Bedarf den Systemstandard verwenden (siehe ActivityTaskManagerService#getSecondaryHomeIntent()).

Sicherheitseinschränkungen

Zusätzlich zu den Einschränkungen, die für Aktivitäten auf sekundären Displays gelten, wird der Launcher nur auf virtuellen Displays angezeigt, die dem System gehören. So soll verhindert werden, dass eine schädliche App ein virtuelles Display mit aktivierten Systemdekorationen erstellt und nutzersensible Informationen von der Oberfläche liest. Der Launcher zeigt keine Inhalte auf virtuellen Displays an, die nicht zum System gehören.

Hintergründe

In Android 10 und höher werden Hintergrundbilder auf sekundären Displays unterstützt:

Abbildung 2: Live-Hintergrund auf dem inneren (oben) und äußeren (unten) Display.

Entwickler können die Unterstützung für das Hintergrundbild-Feature deklarieren, indem sie android:supportsMultipleDisplays="true" in der XML-Definition WallpaperInfo angeben. Hintergrundbildentwickler müssen Assets auch über den Anzeige-Kontext in WallpaperService.Engine#getDisplayContext() laden.

Das Framework erstellt eine WallpaperService.Engine-Instanz pro Display. Jede Engine hat also eine eigene Oberfläche und einen eigenen Displaykontext. Der Entwickler muss dafür sorgen, dass jede Engine unabhängig voneinander mit unterschiedlichen Framerates zeichnen kann und dabei VSync berücksichtigt wird.

Hintergründe für einzelne Displays auswählen

Android 10 bietet keine direkte Plattformunterstützung für die Auswahl von Hintergrundbildern für einzelne Bildschirme. Dazu ist eine stabile Display-Kennung erforderlich, um die Hintergrundeinstellungen für jedes Display beizubehalten. Display#getDisplayId() ist dynamisch. Es gibt also keine Garantie, dass ein physisches Display nach einem Neustart dieselbe ID hat.

Mit Android 10 wurde jedoch DisplayInfo.mAddress eingeführt, das stabile IDs für physische Displays enthält und in Zukunft für eine vollständige Implementierung verwendet werden kann. Leider ist es zu spät, die Logik für Android 10 zu implementieren. Vorgeschlagene Lösung:

  1. Verwenden Sie die Klasse WallpaperManager, um die Hintergrundbilder festzulegen.

    WallpaperManager wird aus einem Context-Objekt abgerufen und jedes Context-Objekt enthält Informationen zum entsprechenden Display (Context#getDisplay()/getDisplayId()). Daher können Sie displayId aus einer WallpaperManager-Instanz abrufen, ohne neue Methoden hinzuzufügen.

  2. Verwenden Sie auf der Framework-Seite displayId, das von einem Context-Objekt abgerufen wird, und ordnen Sie es einer statischen Kennung zu (z. B. einem Port eines physischen Displays). Verwenden Sie die statische Kennung, um den ausgewählten Hintergrund beizubehalten.

Bei dieser Problemumgehung werden vorhandene Implementierungen für die Auswahl von Hintergrundbildern verwendet. Wenn die App auf einem bestimmten Display geöffnet wurde und den richtigen Kontext verwendet, kann das System das Display automatisch erkennen, wenn es aufgerufen wird, um ein Hintergrundbild festzulegen.

Wenn Sie das Hintergrundbild für ein anderes Display als das aktuelle festlegen müssen, erstellen Sie ein neues Context-Objekt für das Zieldisplay (Context#createDisplayContext) und rufen Sie die WallpaperManager-Instanz von diesem Display ab.

Sicherheitseinschränkungen

Das System zeigt keine Hintergrundbilder auf virtuellen Displays an, die nicht zum System gehören. Dies ist auf ein Sicherheitsrisiko zurückzuführen, da eine schädliche App ein virtuelles Display mit aktivierter Unterstützung für Systemdekorationen erstellen und vertrauliche Nutzerinformationen von der Oberfläche lesen könnte, z. B. ein persönliches Foto.

Implementierung

In Android 10 akzeptieren die Schnittstellen IWallpaperConnection#attachEngine() und IWallpaperService#attach() den Parameter displayId, um Verbindungen pro Display zu erstellen. WallpaperManagerService.DisplayConnector kapselt eine Wallpaper-Engine und ‑Verbindung pro Display. In WindowManager werden Wallpaper-Controller für jedes DisplayContent-Objekt bei der Erstellung erstellt, anstatt ein einzelnes WallpaperController für alle Displays.

Einige der öffentlichen WallpaperManager-Methodenimplementierungen (z. B. WallpaperManager#getDesiredMinimumWidth()) wurden aktualisiert, um Informationen für entsprechende Anzeigen zu berechnen und bereitzustellen. WallpaperInfo#supportsMultipleDisplays() und ein entsprechendes Ressourcenattribut wurden hinzugefügt, damit App-Entwickler angeben können, welche Hintergrundbilder für mehrere Bildschirme geeignet sind.

Wenn der auf dem Standarddisplay angezeigte Hintergrunddienst keine Unterstützung für mehrere Displays bietet, wird auf den sekundären Displays der Standardhintergrund angezeigt:

Abbildung 3. Fallback-Logik für Hintergrundbilder für sekundäre Displays.