Compatibilité avec les décorations système

Les modifications apportées à ces zones spécifiques à l'affichage sont indiquées sur cette page.

Décorations système

Android 10 permet de configurer les écrans secondaires pour afficher certaines décorations système, telles que le fond d'écran, la barre de navigation et le lanceur d'applications. Par défaut, l'écran principal affiche toutes les décorations système, tandis que les écrans secondaires affichent celles qui sont éventuellement activées. Vous pouvez définir la prise en charge d'un éditeur de méthode de saisie (IME) 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 écran spécifique ou fournissez une valeur par défaut dans /data/system/display_settings.xml. Pour obtenir des exemples, consultez Paramètres de la fenêtre d'affichage.

Implémentation

DisplayWindowSettings#setShouldShowSystemDecorsLocked() est également exposé dans WindowManager#setShouldShowSystemDecors() à des fins de test. Le déclenchement de cette méthode avec l'intention d'activer les décorations système n'ajoute pas les fenêtres de décoration qui manquaient auparavant, ni ne les supprime si elles étaient présentes auparavant. Dans la plupart des cas, la 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'UI 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'UI système

Android 10 ajoute la prise en charge de la fenêtre de décoration système uniquement pour la barre de navigation, car celle-ci est essentielle pour naviguer entre les activités et les applications. Par défaut, la barre de navigation affiche les affordances "Retour" et "Accueil". Cette valeur n'est incluse que si l'écran cible est compatible avec les décorations système (voir DisplayWindowSettings).

La barre d'état est une fenêtre système plus complexe, car elle contient également le volet des notifications, les réglages 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 le verrouillage du clavier complet ne sont disponibles que sur l'écran principal.

La fenêtre système Aperçu/Récents n'est pas compatible avec les écrans secondaires. Dans Android 10, l'AOSP n'affiche les éléments récents que sur l'écran par défaut et contient les activités de tous les écrans. Lorsqu'une activité qui se trouvait sur un écran secondaire est lancée à partir de la liste des applications récentes, elle est placée au premier plan sur cet écran par défaut. Cette approche présente certains problèmes connus, par exemple le fait qu'elle ne se mette pas à jour immédiatement lorsque des applications apparaissent sur d'autres écrans.

Implémentation

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

Un composant d'UI système compatible avec le multi-écran (MD) doit gérer les cas suivants :

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

Lorsque l'UI système détecte l'ajout d'un écran avant WindowManager, elle crée une condition de concurrence. Pour éviter cela, implémentez un rappel personnalisé de WindowManager à l'UI système lorsqu'un écran est ajouté au lieu de vous abonner aux événements DisplayManager.DisplayListener. Pour obtenir une implémentation de référence, consultez CommandQueue.Callbacks#onDisplayAddSystemDecorations pour la prise en charge de la barre de navigation et WallpaperManagerInternal#onDisplayAddSystemDecorations pour les fonds d'écran.

Android 10 propose également les mises à jour suivantes :

  • 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 écran.
  • IWindowManager#hasNavigationBar() est mis à jour pour inclure le paramètre displayId pour l'UI système uniquement.

Lanceur d'applications

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

Figure 1 : Exemple de lanceur multi-écran pour platform/development/samples/MultiDisplay.

La plupart des lanceurs d'applications existants ne sont pas compatibles avec plusieurs instances et ne sont pas optimisés pour les grands écrans. De plus, une expérience différente est souvent attendue sur les écrans secondaires/externes. Pour fournir une activité dédiée aux écrans secondaires, Android 10 a introduit la catégorie SECONDARY_HOME dans les filtres d'intent. Les instances de cette activité sont utilisées sur tous les écrans compatibles avec les décorations système, à raison d'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 qui est censé s'adapter à différentes tailles d'écran. Le mode de lancement ne peut pas être singleInstance ni singleTask.

Implémentation

Dans Android 10, RootActivityContainer#startHomeOnDisplay() sélectionne automatiquement le composant et l'intention souhaités en fonction de l'écran sur lequel l'écran d'accueil est lancé. RootActivityContainer#resolveSecondaryHomeActivity() contient la logique permettant de rechercher le composant d'activité du lanceur d'applications 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 qu'une application malveillante ne crée un écran virtuel avec les décorations système activées et ne lise des informations sensibles de l'utilisateur à partir de la surface, le lanceur n'apparaît que sur les écrans virtuels appartenant au système. Le lanceur d'applications n'affiche pas de contenu sur les écrans virtuels non système.

Fonds d'écran

Dans Android 10 et les versions ultérieures, les fonds d'écran sont compatibles avec les écrans secondaires :

Figure 2. Fond d'écran animé sur les écrans interne (en haut) et externe (en bas).

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

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

Sélectionner des fonds d'écran pour des écrans individuels

Android 10 ne fournit pas d'assistance directe de la plate-forme pour la sélection de fonds d'écran pour des écrans individuels. Pour ce faire, un identifiant d'écran stable est nécessaire pour conserver les paramètres de fond d'écran par écran. Display#getDisplayId() étant dynamique, rien ne garantit qu'un écran physique aura le même ID après un redémarrage.

Toutefois, Android 10 a ajouté DisplayInfo.mAddress, qui contient des identifiants stables pour les écrans 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. Solution suggérée :

  1. Utilisez la classe WallpaperManager pour définir les fonds d'écran.

    WallpaperManager est obtenu à partir d'un objet Context, et chaque objet Context contient des informations sur l'affichage correspondant (Context#getDisplay()/getDisplayId()). Vous pouvez donc obtenir displayId à partir d'une instance WallpaperManager sans ajouter de nouvelles méthodes.

  2. 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 écran 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 fond d'écran. S'il a été ouvert sur un écran spécifique et utilise le bon contexte, le système peut identifier automatiquement l'écran lorsqu'il appelle à définir un fond d'écran.

Si vous devez définir un fond d'écran pour un écran autre que l'écran actuel, créez un objet Context pour l'écran cible (Context#createDisplayContext) et obtenez l'instance WallpaperManager à partir de cet écran.

Restrictions de sécurité

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

Implémentation

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 et une connexion de fond d'écran par écran. Dans WindowManager, les contrôleurs de fond d'écran sont créés pour chaque objet DisplayContent lors de la construction au lieu d'un seul WallpaperController pour tous les écrans.

Certaines implémentations de la méthode WallpaperManager publique (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 pour permettre aux développeurs d'applications d'indiquer quels fonds d'écran sont prêts pour plusieurs écrans.

Si le service de fond d'écran affiché sur l'écran par défaut n'est pas compatible avec plusieurs écrans, le système affiche le fond d'écran par défaut sur les écrans secondaires :

Figure 3. Logique de secours du fond d'écran pour les écrans secondaires.