Architecture de l'information

Android 8.0 a introduit une nouvelle architecture d'informations pour l'application Paramètres afin de simplifier l'organisation des paramètres et de permettre aux utilisateurs de trouver plus facilement les paramètres pour personnaliser leurs appareils Android. Android 9 a introduit des améliorations pour offrir davantage de fonctionnalités de paramètres et faciliter l'implémentation.

Exemples et source

La plupart des pages de paramètres sont actuellement implémentées à l'aide du nouveau framework. Un bon exemple est DisplaySettings : packages/apps/Settings/src/com/android/settings/DisplaySettings.java

Vous trouverez ci-dessous les chemins d'accès aux fichiers des composants importants :

  • CategoryKey: packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
  • DashboardFragmentRegistry : packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
  • DashboardFragment : packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
  • AbstractPreferenceController : frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
  • BasePreferenceController (introduit dans Android 9) : packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implémentation

Les fabricants d'appareils sont encouragés à adapter l'architecture des informations sur les paramètres existants et à insérer des pages de paramètres supplémentaires si nécessaire pour prendre en charge les fonctionnalités spécifiques aux partenaires. Il peut être compliqué de transférer les préférences de l'ancienne page (implémentée en tant que SettingsPreferencePage) vers une nouvelle page (implémentée à l'aide de DashboardFragment). Il est probable que la préférence de l'ancienne page ne soit pas implémentée avec un PreferenceController.

Ainsi, lorsque vous déplacez une préférence d'une ancienne page vers une nouvelle page, vous devez créer un PreferenceController et déplacer le code dans le contrôleur avant de l'instancier dans le nouveau DashboardFragment. Les API requises par PreferenceController sont décrites dans leur nom et documentées dans Javadoc.

Nous vous recommandons vivement d'ajouter un test unitaire pour chaque PreferenceController. Si la modification est envoyée à l'AOSP, un test unitaire est requis. Pour savoir comment écrire des tests basés sur Robolectric, consultez le fichier Readme packages/apps/Settings/tests/robotests/README.md.

Architecture de l'information de type plug-in

Chaque élément de paramètre est implémenté en tant que préférence. Il est facile de déplacer une préférence d'une page à une autre.

Pour faciliter le déplacement de plusieurs paramètres, Android 8.0 a introduit un fragment hôte de style plug-in contenant des éléments de paramètres. Les éléments de paramètres sont modélisés en tant que contrôleurs de style plug-in. Par conséquent, une page de paramètres est construite par un seul fragment hôte et plusieurs contrôleurs de paramètres.

DashboardFragment

DashboardFragment est l'hôte des contrôleurs de préférences de type plug-in. Le fragment hérite de PreferenceFragment et comporte des hooks permettant de développer et de mettre à jour les listes de préférences statiques et dynamiques.

Préférences statiques

Une liste de préférences statique est définie en XML à l'aide de la balise <Preference>. Une implémentation DashboardFragment utilise la méthode getPreferenceScreenResId() pour définir le fichier XML contenant la liste statique des préférences à afficher.

Préférences dynamiques

Un élément dynamique représente un bloc avec une intention, qui mène à une activité externe ou interne. En général, l'intention mène à une autre page de paramètres. Par exemple, l'élément de paramètre "Google" sur la page d'accueil des paramètres est un élément dynamique. Les éléments dynamiques sont définis dans AndroidManifest (voir ci-dessous) et chargés via un FeatureProvider (défini comme DashboardFeatureProvider).

Les paramètres dynamiques sont plus lourds que les paramètres configurés de manière statique. Les développeurs doivent donc normalement implémenter le paramètre en tant que paramètre statique. Toutefois, le paramètre dynamique peut être utile dans les cas suivants :

  • Le paramètre n'est pas directement implémenté dans l'application Paramètres (par exemple, en injectant un paramètre implémenté par les applications OEM/d'opérateur).
  • Le paramètre doit apparaître sur la page d'accueil des paramètres.
  • Vous disposez déjà d'une activité pour le paramètre et vous ne souhaitez pas implémenter la configuration statique supplémentaire.

Pour configurer une activité en tant que paramètre dynamique, procédez comme suit :

  • Marquez l'activité comme paramètre dynamique en ajoutant un filtre d'intent à l'activité.
  • Indiquez à l'application Paramètres à quelle catégorie il appartient. La catégorie est une constante, définie dans CategoryKey.
  • Facultatif : Ajoutez un texte récapitulatif lorsque le paramètre s'affiche.

Voici un exemple tiré de l'application Paramètres pour DisplaySettings.

<activity android:name="Settings$DisplaySettingsActivity"
                   android:label="@string/display_settings"
                   android:icon="@drawable/ic_settings_display">
             <!-- Mark the activity as a dynamic setting -->
              <intent-filter>
                     <action android:name="com.android.settings.action.IA_SETTINGS" />
              </intent-filter>
             <!-- Tell Settings app which category it belongs to -->
              <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.homepage" />
             <!-- Add a summary text when the setting is displayed -->
              <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/display_dashboard_summary"/>
             </activity>

Au moment du rendu, le fragment demandera une liste de préférences à partir du fichier XML statique et des paramètres dynamiques définis dans AndroidManifest. Que les PreferenceController soient définis dans le code Java ou en XML, DashboardFragment gère la logique de gestion de chaque paramètre via PreferenceController (décrit ci-dessous). Ils sont ensuite affichés dans l'UI sous forme de liste mixte.

PreferenceController

Il existe des différences entre l'implémentation de PreferenceController dans Android 9 et Android 8.x, comme décrit dans cette section.

PreferenceController dans la version Android 9

Un PreferenceController contient toute la logique permettant d'interagir avec la préférence, y compris l'affichage, la mise à jour, l'indexation pour la recherche, etc.

L'interface de PreferenceController est définie comme BasePreferenceController. Par exemple, consultez le code dans packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java.

Il existe plusieurs sous-classes de BasePreferenceController, chacune correspondant à un style d'interface utilisateur spécifique que l'application Paramètres prend en charge par défaut. Par exemple, TogglePreferenceController dispose d'une API qui correspond directement à la façon dont l'utilisateur doit interagir avec une UI de préférence basée sur un bouton bascule.

BasePreferenceController comporte des API telles que getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(),, etc. La documentation détaillée de chaque API se trouve dans la classe d'interface.

Une restriction concernant l'implémentation de BasePreferenceController (et de ses sous-classes telles que TogglePreferenceController) est que la signature du constructeur doit correspondre à l'une des suivantes :

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

Lors de l'installation d'une préférence dans le fragment, le tableau de bord fournit une méthode pour associer un PreferenceController avant l'heure d'affichage. Au moment de l'installation, le contrôleur est câblé au fragment afin que tous les événements pertinents futurs soient envoyés au contrôleur.

DashboardFragment conserve une liste des PreferenceController à l'écran. Au niveau du onCreate() du fragment, tous les contrôleurs sont appelés pour la méthode getAvailabilityStatus(). Si elle renvoie "true", displayPreference() est appelé pour traiter la logique d'affichage. getAvailabilityStatus() est également important pour indiquer au framework Settings quels éléments sont disponibles lors de la recherche.

PreferenceController dans les versions Android 8.x

Un PreferenceController contient toute la logique permettant d'interagir avec la préférence, y compris l'affichage, la mise à jour, l'indexation de recherche, etc.

En lien avec les interactions de préférences, l'interface de PreferenceController comporte les API isAvailable(), displayPreference(), handlePreferenceTreeClicked(), etc. Vous trouverez une documentation détaillée sur chaque API dans la classe d'interface.

Lors de l'installation d'une préférence dans le fragment, le tableau de bord fournit une méthode pour associer un PreferenceController avant l'heure d'affichage. Au moment de l'installation, le contrôleur est câblé au fragment afin que tous les événements pertinents futurs soient envoyés au contrôleur.

DashboardFragment conserve une liste de PreferenceControllers à l'écran. Au niveau de onCreate() du fragment, tous les contrôleurs sont appelés pour la méthode isAvailable(). Si elle renvoie la valeur "true", displayPreference() est appelé pour traiter la logique d'affichage.

Utiliser DashboardFragment

Déplacer une préférence de la page A vers la page B

Si la préférence est listée de manière statique dans le fichier XML de préférences de la page d'origine, suivez la procédure de déplacement statique pour votre version d'Android ci-dessous. Sinon, suivez la procédure de déplacement dynamique pour votre version d'Android.

Déplacement statique dans Android 9

  1. Recherchez les fichiers XML de préférences pour la page d'origine et la page de destination. Vous trouverez ces informations dans la méthode getPreferenceScreenResId() de la page.
  2. Supprimez la préférence du fichier XML de la page d'origine.
  3. Ajoutez la préférence au fichier XML de la page de destination.
  4. Supprimez PreferenceController pour cette préférence de l'implémentation Java de la page d'origine. Il se trouve généralement dans createPreferenceControllers(). Le contrôleur peut être déclaré directement dans le fichier XML.

    Remarque : Il est possible que la préférence n'ait pas de PreferenceController.

  5. Instanciez PreferenceController dans le createPreferenceControllers() de la page de destination. Si PreferenceController est défini en XML dans l'ancienne page, définissez-le également en XML pour la nouvelle page.

Déplacement dynamique dans Android 9

  1. Déterminez la catégorie à laquelle appartiennent les pages d'origine et de destination. Vous trouverez ces informations dans DashboardFragmentRegistry.
  2. Ouvrez le fichier AndroidManifest.xml contenant le paramètre que vous devez déplacer, puis recherchez l'entrée d'activité correspondant à ce paramètre.
  3. Définissez la valeur des métadonnées de l'activité pour com.android.settings.category sur la clé de catégorie de la nouvelle page.

Déplacement statique dans les versions Android 8.x

  1. Recherchez les fichiers XML de préférences pour la page d'origine et la page de destination.
  2. Vous trouverez ces informations dans la méthode getPreferenceScreenResId() de la page.
  3. Supprimez la préférence dans le fichier XML de la page d'origine.
  4. Ajoutez la préférence au fichier XML de la page de destination.
  5. Supprimez le PreferenceController pour cette préférence dans l'implémentation Java de la page d'origine. Il se trouve généralement dans getPreferenceControllers().
  6. Remarque : Il est possible que la préférence n'ait pas de PreferenceController.

  7. Instanciez PreferenceController dans le getPreferenceControllers() de la page de destination.

Déplacement dynamique dans les versions Android 8.x

  1. Déterminez la catégorie à laquelle appartiennent les pages d'origine et de destination. Vous trouverez ces informations dans DashboardFragmentRegistry.
  2. Ouvrez le fichier AndroidManifest.xml contenant le paramètre que vous devez déplacer, puis recherchez l'entrée d'activité correspondant à ce paramètre.
  3. Modifiez la valeur des métadonnées de l'activité pour com.android.settings.category et définissez la valeur de manière à ce qu'elle pointe vers la clé de catégorie de la nouvelle page.

Créer une préférence sur une page

Si la préférence est listée de manière statique dans le fichier XML des préférences de la page d'origine, suivez la procédure statique ci-dessous. Sinon, suivez la procédure dynamique.

Créer une préférence statique

  1. Recherchez les fichiers XML de préférences pour la page. Vous trouverez ces informations à partir de la méthode getPreferenceScreenResId() de la page.
  2. Ajoutez un élément "Preference" dans le fichier XML. Assurez-vous qu'il possède un android:key unique.
  3. Définissez un PreferenceController pour cette préférence dans la méthode getPreferenceControllers() de la page.
    • Dans Android 8.x et éventuellement dans Android 9, instanciez un PreferenceController pour cette préférence dans la méthode createPreferenceControllers() de la page.

      Si cette préférence existait déjà ailleurs, il est possible qu'il existe déjà un PreferenceController pour celle-ci. Vous pouvez réutiliser le PreferenceController sans en créer un autre.

    • À partir d'Android 9, vous pouvez choisir de déclarer PreferenceController en XML à côté de la préférence. Exemple :
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

Créer une préférence dynamique

  1. Déterminez la catégorie à laquelle appartiennent les pages d'origine et de destination. Vous trouverez ces informations dans DashboardFragmentRegistry.
  2. Créer une activité dans AndroidManifest
  3. Ajoutez les métadonnées nécessaires à la nouvelle activité pour définir le paramètre. Définissez la valeur des métadonnées pour com.android.settings.category sur la même valeur définie à l'étape 1.

Créer une page

  1. Créez un fragment en héritant de DashboardFragment.
  2. Définissez sa catégorie dans DashboardFragmentRegistry.

    Remarque : Cette étape est facultative. Si vous n'avez besoin d'aucune préférence dynamique sur cette page, vous n'avez pas besoin de fournir de clé de catégorie.

  3. Suivez la procédure pour ajouter les paramètres nécessaires à cette page. Pour en savoir plus, consultez la section Implémentation.

Validation

  • Exécutez les tests Robolectric dans les paramètres. Tous les tests existants et nouveaux doivent réussir.
  • Créez et installez les paramètres, puis ouvrez manuellement la page en cours de modification. La page devrait s'actualiser immédiatement.