Prise en charge des décorations système

Les mises à jour apportées à ces zones spécifiques à l'affichage sont fournies ci-dessous :

Décorations système

Android 10 ajoute la prise en charge de la configuration des écrans secondaires pour afficher certaines décorations du système, telles que le fond d'écran, la barre de navigation et le lanceur. Par défaut, l'écran principal affiche toutes les décorations du système et les écrans secondaires affichent celles qui sont facultativement activées. La prise en charge d'un éditeur de méthode d'entrée (IME) peut être définie séparément des autres décorations du système.

Utilisez DisplayWindowSettings#setShouldShowSystemDecorsLocked() pour ajouter la prise en charge des décorations système sur un écran spécifique ou fournir une valeur par défaut dans /data/system/display_settings.xml . Pour des exemples, voir Paramètres de la fenêtre d'affichage .

Mise en œuvre

DisplayWindowSettings#setShouldShowSystemDecorsLocked() est également exposé dans WindowManager#setShouldShowSystemDecors() pour les tests. Le déclenchement de cette méthode dans le but d'activer les décors du système n'ajoute pas de fenêtres de décor qui manquaient auparavant, ni ne les supprime si elles étaient auparavant présentes. Dans la plupart des cas, le changement de prise en charge des décorations système ne prend pleinement effet qu'après le redémarrage de l'appareil.

Les vérifications de la prise en charge des décorations système dans la base de code WindowManager passent généralement par DisplayContent#supportsSystemDecorations() tandis que les vérifications des services externes (tels que l'interface utilisateur système pour vérifier si la barre de navigation doit être affichée) utilisent WindowManager#shouldShowSystemDecors() . Pour comprendre ce qui est contrôlé par ce paramètre, explorez les points d’appel de ces méthodes.

Fenêtres de décoration de l'interface utilisateur du système

Android 10 ajoute la prise en charge de la fenêtre de décoration du système pour la barre de navigation uniquement , car la barre de navigation est essentielle pour naviguer entre les activités et les applications. Par défaut, la barre de navigation affiche les options Retour et Accueil. Ceci n'est inclus que si l'affichage cible prend en charge les décorations système (voir DisplayWindowSettings ).

La barre d'état est une fenêtre système plus compliquée, car elle contient également un volet de notification, des paramètres rapides et un écran de verrouillage. Sous Android 10, la barre d'état n'est pas prise en charge sur les écrans secondaires. Par conséquent, les notifications, les paramètres et un clavier complet ne sont disponibles que sur l'écran principal.

La fenêtre système Présentation/Récents n’est pas prise en charge sur les écrans secondaires. Dans Android 10, AOSP affiche uniquement les événements récents sur l'écran par défaut et contient les activités de tous les écrans. Lorsqu'elle est lancée à partir de Récents, une activité qui se trouvait sur un écran secondaire est placée au premier plan sur cet écran, par défaut. Cette approche présente certains problèmes connus, tels que le fait de ne pas se mettre à jour immédiatement lorsque les applications apparaissent sur d'autres écrans.

Mise en œuvre

Pour implémenter des fonctionnalités supplémentaires de l'interface utilisateur système, les fabricants d'appareils doivent utiliser un seul composant d'interface utilisateur système qui écoute l'ajout/la suppression d'affichages et présente le contenu approprié.

Un composant de l'interface utilisateur système prenant en charge le multi-affichage (MD) doit gérer les cas suivants :

  • Initialisation de plusieurs affichages au démarrage
  • Affichage ajouté au moment de l'exécution
  • Affichage supprimé au moment de l'exécution

Lorsque l'interface utilisateur système détecte l'ajout d'un affichage avant WindowManager, elle crée une condition de concurrence critique. Cela peut être évité en implémentant un rappel personnalisé de WindowManager vers l'interface utilisateur système lorsqu'un affichage est ajouté au lieu de s'abonner aux événements DisplayManager .DisplayListener . Pour une implémentation de référence, consultez CommandQueue.Callbacks#onDisplayReady pour la prise en charge de la barre de navigation et WallpaperManagerInternal#onDisplayReady pour les fonds d'écran.

De plus, Android 10 fournit ces mises à jour :

  • La classe NavigationBarController contrôle toutes les fonctionnalités spécifiques aux barres de navigation.
  • Pour afficher une barre de navigation personnalisée, consultez CarStatusBar .
  • TYPE_NAVIGATION_BAR n'est plus limité à une seule instance et peut être utilisé par affichage.
  • IWindowManager#hasNavigationBar() est mis à jour pour inclure le paramètre displayId pour l'interface utilisateur système uniquement.

Lanceur

Dans Android 10, chaque écran configuré pour prendre en charge les décorations système dispose d'une pile d'accueil dédiée aux activités du lanceur de type WindowConfiguration#ACTIVITY_TYPE_HOME , par défaut. Chaque affichage utilise une instance distincte d'activité du lanceur.

Figure 1. Exemple de lanceur multi-affichage pour platform/development/samples/MultiDisplay

La plupart des lanceurs existants ne prennent pas en charge plusieurs instances et ne sont pas optimisés pour les grands écrans. En outre, un type d’expérience différent est souvent attendu sur les écrans secondaires/externes. Pour fournir une activité dédiée aux écrans secondaires, Android 10 introduit la catégorie SECONDARY_HOME dans les filtres d'intention. Des instances de cette activité sont utilisées sur tous les écrans prenant en charge les décorations système, une par écran.

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

L'activité doit avoir un mode de lancement qui n'empêche pas les instances multiples et qui doit s'adapter aux différentes tailles d'écran. Le mode de lancement ne peut pas être singleInstance ou singleTask .

Mise en œuvre

Sous Android 10, RootActivityContainer#startHomeOnDisplay() sélectionne automatiquement le composant et l'intention souhaités en fonction de l'affichage sur lequel l'écran d'accueil est lancé. RootActivityContainer#resolveSecondaryHomeActivity() contient la logique permettant de rechercher le composant d'activité du lanceur en fonction du lanceur actuellement sélectionné et peut utiliser la valeur par défaut du système, si nécessaire (voir ActivityTaskManagerService#getSecondaryHomeIntent() ).

Restrictions de sécurité

Outre les restrictions qui s'appliquent aux activités sur les écrans secondaires, pour éviter la possibilité qu'une application malveillante crée un affichage virtuel avec les décorations système activées et lise les informations sensibles de l'utilisateur depuis la surface, le lanceur apparaît uniquement sur les écrans virtuels appartenant au système. Le lanceur n'affiche pas le contenu sur les écrans virtuels non système.

Fonds d'écran

Sous Android 10 (et versions ultérieures), les fonds d'écran sont pris en charge sur les écrans secondaires :

Figure 2. Fond d'écran animé sur les écrans internes (ci-dessus) et externes (ci-dessous)

Les développeurs peuvent déclarer la prise en charge de la fonctionnalité de fond d'écran en fournissant android:supportsMultipleDisplays="true" dans la définition XML WallpaperInfo . Les développeurs de fonds d'écran doivent également charger des ressources à l'aide du contexte d'affichage dans WallpaperService.Engine#getDisplayContext() .

Le framework crée une instance WallpaperService.Engine par affichage, de sorte que chaque moteur a sa propre surface et son propre contexte d'affichage. Le développeur doit s'assurer que chaque moteur peut dessiner indépendamment, à différentes fréquences d'images, en respectant VSYNC.

Sélectionnez des fonds d'écran pour les écrans individuels

Android 10 ne fournit pas de prise en charge directe de la plate-forme pour sélectionner des fonds d'écran pour des écrans individuels. Pour ce faire, un identifiant d'affichage stable est nécessaire pour conserver les paramètres de fond d'écran par affichage. Display#getDisplayId() est dynamique, il n'y a donc aucune garantie qu'un affichage physique aura le même ID après le redémarrage.

Cependant, Android 10 a ajouté DisplayInfo.mAddress , qui contient des identifiants stables pour les affichages physiques et peut être utilisé pour une implémentation complète à l'avenir. Malheureusement, il est trop tard pour implémenter la logique pour Android 10. La solution suggérée :

  1. Utilisez l'API WallpaperManager pour définir les fonds d'écran.
  2. WallpaperManager est obtenu à partir d'un objet Context , et chaque objet Context contient des informations sur l'affichage correspondant ( Context#getDisplay()/getDisplayId() ). Par conséquent, vous pouvez obtenir displayId à partir d’une instance WallpaperManager sans ajouter de nouvelles méthodes.
  3. Du côté du framework, utilisez displayId obtenu à partir d'un objet Context et mappez-le à un identifiant statique (tel qu'un port d'un affichage physique). Utilisez l'identifiant statique pour conserver le fond d'écran choisi.

Cette solution de contournement utilise les implémentations existantes pour les sélecteurs de papier peint. S'il a été ouvert sur un écran spécifique et utilise le bon contexte, alors lorsqu'il appelle pour définir un fond d'écran, le système peut identifier automatiquement l'écran.

S'il est nécessaire de définir un fond d'écran pour un affichage autre que l'affichage actuel, créez un nouvel objet Context pour l'affichage cible ( Context#createDisplayContext ) et obtenez l'instance WallpaperManager à partir de cet affichage.

Restrictions de sécurité

Le système n'affichera pas de fonds d'écran sur des écrans virtuels qui ne lui appartiennent pas. Cela est dû à un problème de sécurité selon lequel une application malveillante pourrait créer un affichage virtuel avec la prise en charge activée des décorations système et lire des informations sensibles pour l'utilisateur depuis la surface (telles qu'une photo personnelle).

Mise en œuvre

Dans Android 10, les interfaces IWallpaperConnection#attachEngine() et IWallpaperService#attach() acceptent le paramètre displayId pour créer des connexions par écran. WallpaperManagerService.DisplayConnector encapsule un moteur de papier peint et une connexion par écran. Dans WindowManager, des contrôleurs de papier peint sont créés pour chaque objet DisplayContent lors de la construction au lieu d'un seul WallpaperController pour tous les affichages.

Certaines des implémentations publiques de la méthode WallpaperManager (telles que WallpaperManager#getDesiredMinimumWidth() ) ont été mises à jour pour calculer et fournir des informations sur les affichages correspondants. WallpaperInfo#supportsMultipleDisplays() et un attribut de ressource correspondant ont été ajoutés, afin que les développeurs d'applications puissent signaler quels fonds d'écran sont prêts pour plusieurs écrans.

Si le service de fond d'écran affiché sur l'écran par défaut ne prend pas en charge plusieurs écrans, le système affiche le fond d'écran par défaut sur les écrans secondaires.

Figure 3. Logique de secours du papier peint pour les affichages secondaires