Unterstützung für Systemdesigns

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

Systemdekorationen

In Android 10 wird die Konfiguration von sekundären Displays unterstützt, um bestimmte Systemdesigns wie Hintergründe, Navigationsleisten und Launcher anzeigen zu lassen. Auf dem primären Display werden standardmäßig alle Systemdekorationen angezeigt, auf sekundären Displays nur die optional aktivierten. Die Unterstützung für einen Eingabemethoden-Editor (IME) kann getrennt von anderen Systemdekorationen festgelegt werden.

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

Implementierung

DisplayWindowSettings#setShouldShowSystemDecorsLocked() ist auch in WindowManager#setShouldShowSystemDecors() für Tests verfügbar. Durch das Auslösen dieser Methode mit der Absicht, Systemdesigns zu aktivieren, werden keine zuvor fehlenden Dekorfenster hinzugefügt oder entfernt, falls sie zuvor vorhanden waren. In den meisten Fällen werden die Änderungen an der Unterstützung von Systemdekorationen erst nach einem Neustart des Geräts vollständig wirksam.

Prüfungen zur 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. die System-UI, um zu prüfen, ob die Navigationsleiste angezeigt werden soll) WindowManager#shouldShowSystemDecors() verwenden. Um zu verstehen, was von dieser Einstellung gesteuert wird, sehen Sie sich die Aufrufpunkte dieser Methoden an.

Dekorfenster der System-UI

In Android 10 wird das Fenster für die Systemeinrichtung nur für die Navigationsleiste unterstützt, da die Navigationsleiste für die Navigation zwischen Aktivitäten und Apps unerlässlich ist. Standardmäßig werden in der Navigationsleiste „Zurück“- und „Startseite“-Angebote angezeigt. Dies ist nur enthalten, wenn die Zielanzeige die Systemgestaltung unterstützt (siehe DisplayWindowSettings).

Die Statusleiste ist ein komplizierteres 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 Bildschirm verfügbar.

Das Systemfenster Übersicht/Letzte wird auf sekundären Bildschirmen nicht unterstützt. In Android 10 zeigt AOSP nur die letzten Aktivitäten auf dem Standarddisplay an und enthält Aktivitäten von allen Displays. Wenn Sie die App über „Letzte Aktivitäten“ starten, wird eine Aktivität, die sich auf einem sekundären Display befand, standardmäßig auf diesem Display angezeigt. Bei diesem Ansatz sind einige bekannte Probleme aufgetreten, z. B. wird nicht sofort aktualisiert, wenn Apps auf anderen Bildschirmen angezeigt werden.

Implementierung

Wenn Gerätehersteller zusätzliche System-UI-Funktionen implementieren möchten, sollten sie eine einzelne System-UI-Komponente verwenden, die auf das Hinzufügen oder Entfernen von Displays achtet und entsprechende Inhalte präsentiert.

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

  • Mehrere Bildschirme beim Start initialisieren
  • Zur Laufzeit hinzugefügtes Display
  • Anzeige wird bei 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 vom WindowManager an die System-UI implementieren, wenn ein Display hinzugefügt wird, anstatt DisplayManager.DisplayListener-Ereignisse zu abonnieren. Eine Referenzimplementierung finden Sie unter CommandQueue.Callbacks#onDisplayReady für die Navigationsleiste und WallpaperManagerInternal#onDisplayReady für Hintergründe.

Außerdem bietet Android 10 folgende Updates:

  • Die Klasse NavigationBarController steuert alle Funktionen für Navigationsleisten.
  • Eine benutzerdefinierte 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, um den Parameter displayId nur für die Systemoberfläche zu enthalten.

Werfer

In Android 10 hat jedes Display, das für die Unterstützung von Systemdekorationen konfiguriert ist, standardmäßig einen eigenen Start-Stack für Launcher-Aktivitäten vom Typ WindowConfiguration#ACTIVITY_TYPE_HOME. Für jeden Bildschirm wird eine separate Instanz der Launcher-Aktivität verwendet.

Abbildung 1: Beispiel für einen Multi-Display-Launcher für platform/development/samples/MultiDisplay

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

<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 sich an unterschiedliche Bildschirmgrößen anpassen kann. Der Startmodus darf nicht singleInstance oder singleTask sein.

Implementierung

Unter Android 10 wird die gewünschte Komponente und Intent von RootActivityContainer#startHomeOnDisplay() automatisch ausgewählt, je nachdem, auf welchem Display der Startbildschirm gestartet wird. RootActivityContainer#resolveSecondaryHomeActivity() enthält die Logik zum Abrufen der Launcher-Aktivitätskomponente je nach aktuell ausgewähltem Launcher und kann bei Bedarf die Standardeinstellung des Systems verwenden (siehe ActivityTaskManagerService#getSecondaryHomeIntent()).

Sicherheitseinschränkungen

Zusätzlich zu den Einschränkungen für Aktivitäten auf sekundären Displays wird der Launcher nur auf virtuellen Displays angezeigt, die dem System gehören. Damit soll verhindert werden, dass eine schädliche App eine virtuelle Anzeige mit aktivierten Systemdesigns erstellt und nutzerspezifische Informationen von der Oberfläche liest. Der Launcher zeigt keine Inhalte auf nicht systemeigenen virtuellen Displays an.

Hintergründe

Unter Android 10 und höher werden Hintergründe auf sekundären Displays unterstützt:

Abbildung 2. Live-Hintergrund auf dem internen (oben) und externen Display (unten)

Entwickler können die Unterstützung für die Hintergrundfunktion angeben, indem sie android:supportsMultipleDisplays="true" in der WallpaperInfo-XML-Definition angeben. Entwickler von Hintergründen müssen außerdem Assets mit dem Displaykontext in WallpaperService.Engine#getDisplayContext() laden.

Das Framework erstellt eine WallpaperService.Engine-Instanz pro Display, sodass jede Engine eine eigene Oberfläche und einen eigenen Displaykontext hat. Der Entwickler muss dafür sorgen, dass jede Engine unabhängig und mit unterschiedlichen Frameraten gezeichnet werden kann, wobei VSYNC berücksichtigt werden muss.

Hintergründe für einzelne Bildschirme auswählen

Android 10 bietet keine direkte Plattformunterstützung für die Auswahl von Hintergründen für einzelne Bildschirme. Dazu ist eine stabile Display-ID erforderlich, um die Hintergrundeinstellungen pro Display beizubehalten. Display#getDisplayId() ist dynamisch. Es gibt also keine Garantie, dass ein physischer Bildschirm nach dem Neustart die gleiche ID hat.

In Android 10 wurde jedoch DisplayInfo.mAddress hinzugefügt, 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 WallpaperManager API, um die Hintergründe festzulegen.
  2. WallpaperManager wird aus einem Context-Objekt abgerufen und jedes Context-Objekt enthält Informationen zur entsprechenden Anzeige (Context#getDisplay()/getDisplayId()). Daher können Sie displayId aus einer WallpaperManager-Instanz abrufen, ohne neue Methoden hinzufügen zu müssen.
  3. Verwenden Sie auf Framework-Seite displayId, das aus einem Context-Objekt stammt, und ordnen Sie es einer statischen Kennung zu (z. B. einem Anschluss eines physischen Displays). Verwenden Sie die statische Kennung, um den ausgewählten Hintergrund beizubehalten.

Bei dieser Problemumgehung werden vorhandene Implementierungen für Hintergrundauswahlen 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 darum gebeten wird, einen Hintergrund festzulegen.

Wenn Sie den Hintergrund für ein anderes Display als das aktuelle Display festlegen möchten, 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 Hintergründe auf virtuellen Displays an, die es nicht besitzt. Grund dafür sind Sicherheitsbedenken, dass eine schädliche App ein virtuelles Display mit aktivierter Systemgestaltungs-Unterstützung erstellen und nutzerbezogene Informationen (z. B. ein persönliches Foto) von der Oberfläche lesen könnte.

Implementierung

Unter Android 10 akzeptieren die IWallpaperConnection#attachEngine()- und IWallpaperService#attach()-Benutzeroberflächen den Parameter displayId, um pro Display Verbindungen herzustellen. WallpaperManagerService.DisplayConnector umschließt eine pro Display konfigurierte Hintergrund-Engine und -Verbindung. In WindowManager werden Hintergrund-Controller für jedes DisplayContent-Objekt bei der Erstellung erstellt, anstatt eines einzelnen WallpaperController für alle Bildschirme.

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

Wenn der Hintergrunddienst, der auf dem Standarddisplay angezeigt wird, keine mehreren Displays unterstützt, zeigt das System auf den sekundären Displays den Standardhintergrund an.

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