Prise en charge des décorations système,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 système, telles que le papier peint, la barre de navigation et le lanceur. Par défaut, l'affichage principal affiche toutes les décorations du système et les affichages secondaires affichent celles qui sont éventuellement 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 système.

Utilisez DisplayWindowSettings#setShouldShowSystemDecorsLocked() pour ajouter la prise en charge des décorations système sur un affichage spécifique ou fournissez 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 avec l'intention d'activer les décors système n'ajoute pas de fenêtres de décor qui manquaient auparavant, ou ne les supprime pas si elles étaient présentes auparavant. Dans la plupart des cas, la modification de la prise en charge des décorations système ne prend pleinement effet qu'après un 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 offres Retour et Accueil. Ceci est inclus uniquement 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 la nuance de notification, les paramètres rapides et l'écran de verrouillage. Dans 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 Aperçu/Récents n'est pas prise en charge sur les écrans secondaires. Dans Android 10, AOSP n'affiche que les Récents sur l'affichage par défaut et contient les activités de tous les écrans. Lorsqu'elle est lancée à partir de Récents, une activité qui était sur un affichage secondaire est mise au premier plan sur cet affichage, par défaut. Cette approche présente certains problèmes connus, tels que la non mise à jour immédiate 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 de l'interface utilisateur système qui écoute l'ajout/la suppression d'affichages et présente le contenu approprié.

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

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

Lorsque l'interface utilisateur système détecte l'ajout d'un affichage avant WindowManager, il crée une condition de concurrence. Cela peut être évité en implémentant un rappel personnalisé de WindowManager à 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, voir 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, voir 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 avec le type WindowConfiguration#ACTIVITY_TYPE_HOME , par défaut. Chaque affichage utilise une instance distincte de l'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 grandes tailles d'écran. 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 plusieurs instances et doit s'adapter à différentes tailles d'écran. Le mode de lancement ne peut pas être singleInstance ou singleTask .

Mise en œuvre

Dans 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 pour 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é

En plus des restrictions qui s'appliquent aux activités sur les écrans secondaires, pour éviter la possibilité qu'une application malveillante crée un écran virtuel avec des décorations système activées et lise des informations sensibles pour l'utilisateur à partir de la surface, le lanceur n'apparaît que 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 les actifs à 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élection de fonds d'écran pour des é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 de WallpaperManager sans ajouter de nouvelles méthodes.
  3. Du côté de la structure, 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 des 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, lorsqu'il appelle pour définir un fond d'écran, le système peut automatiquement identifier 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 les fonds d'écran sur les écrans virtuels qu'il ne possède 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 des décorations système activées et lire des informations sensibles de l'utilisateur à partir de la surface (telles qu'une photo personnelle).

Mise en œuvre

Dans Android 10, les IWallpaperConnection#attachEngine() et IWallpaperService#attach() acceptent le paramètre displayId pour créer des connexions par affichage. WallpaperManagerService.DisplayConnector encapsule un moteur de fond d'écran et une connexion par affichage. 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 pour 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 repli du fond d'écran pour les écrans secondaires