Architettura delle informazioni

Android 8.0 ha introdotto una nuova architettura delle informazioni per l'app Impostazioni per semplificare il modo in cui le impostazioni sono organizzate e consentire agli utenti di trovarle più facilmente per personalizzare i propri dispositivi Android. Android 9 ha introdotto alcuni miglioramenti per fornire maggiori funzionalità Impostazioni e un'implementazione più semplice.

Esempi e origine

Al momento, la maggior parte delle pagine in Impostazioni è implementata utilizzando il nuovo framework. Un buon esempio è DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

Di seguito sono riportati i percorsi dei file per i componenti importanti:

  • 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 (introdotto in Android 9): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implementazione

I produttori di dispositivi sono invitati ad adattare l'architettura esistente delle informazioni delle Impostazioni e ad inserire altre pagine di impostazioni in base alle esigenze per supportare le funzionalità specifiche dei partner. Lo spostamento delle preferenze dalla pagina precedente (implementata come SettingsPreferencePage) a una nuova pagina (implementata utilizzando DashboardFragment) può essere complicato. È probabile che la preferenza della pagina precedente non sia implementata con un PreferenceController.

Pertanto, quando sposti le preferenze da una pagina precedente a una nuova, devi creare un PreferenceController e spostare il codice nel controller prima di inizializarlo nel nuovo DashboardFragment. Le API richieste da PreferenceController sono descritte nel nome e documentate in Javadoc.

Ti consigliamo vivamente di aggiungere un test unitario per ogni PreferenceController. Se la modifica viene inviata ad AOSP, è necessario un test unitario. Per ulteriori informazioni su come scrivere test basati su Robolectric, consulta il file readme packages/apps/Settings/tests/robotests/README.md.

Architettura delle informazioni stile plug-in

Ogni elemento delle impostazioni è implementato come preferenza. Una preferenza può essere facilmente trasferita da una pagina all'altra.

Per semplificare lo spostamento di più impostazioni, Android 8.0 ha introdotto un frammento host in stile plug-in che contiene le voci delle impostazioni. Gli elementi delle impostazioni sono modellati come controller in stile plug-in. Di conseguenza, una pagina delle impostazioni è costituita da un singolo frammento host e da più controller di impostazioni.

DashboardFragment

DashboardFragment è l'host dei controller delle preferenze di tipo plug-in. Il frammento eredita da PreferenceFragment e ha hook per espandere e aggiornare gli elenchi di preferenze statici e quelli dinamici.

Preferenze statiche

Un elenco di preferenze statiche è definito in XML utilizzando il tag <Preference>. Un'implementazione di DashboardFragment utilizza il metodo getPreferenceScreenResId() per definire quale file XML contiene l'elenco statico delle preferenze da visualizzare.

Preferenze dinamiche

Un elemento dinamico rappresenta un riquadro con intent che rimanda a un'attività interna o esterna. In genere, l'intent porta a una pagina di impostazioni diversa. Ad esempio, l'elemento di impostazione "Google" nella home page delle Impostazioni è un elemento dinamico. Gli elementi dinamici vengono definiti in AndroidManifest (descritto di seguito) e caricati tramite un FeatureProvider (definito come DashboardFeatureProvider).

Le impostazioni dinamiche hanno un peso maggiore rispetto a quelle configurate staticamente, pertanto gli sviluppatori dovrebbero implementarla normalmente. Tuttavia, l'impostazione dinamica può essere utile quando si verifica una delle seguenti condizioni:

  • L'impostazione non è implementata direttamente nell'app Impostazioni (ad esempio, l'inserimento di un'impostazione implementata dalle app OEM/operatore).
  • L'impostazione dovrebbe essere visualizzata nella home page delle Impostazioni.
  • Hai già un'attività per l'impostazione e non vuoi implementare la configurazione statica aggiuntiva.

Per configurare un'attività come impostazione dinamica:

  • Contrassegna l'attività come impostazione dinamica aggiungendo un filtro per intent.
  • Indica all'app Impostazioni a quale categoria appartiene. La categoria è una costante, definita in CategoryKey.
  • (Facoltativo) Aggiungi il testo del riepilogo quando viene visualizzata l'impostazione.

Ecco un esempio tratto dall'app Impostazioni per 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>

Al momento del rendering, il frammento richiede un elenco di preferenze sia dall'XML statico che dalle impostazioni dinamiche definite in AndroidManifest. Indipendentemente dal fatto che i parametri PreferenceController siano definiti in codice Java o in XML, DashboardFragment gestisce la logica di gestione di ogni impostazione tramite PreferenceController (descritto di seguito). Poi vengono visualizzati nell'interfaccia utente come elenco misto.

PreferenceController

Esistono differenze tra l'implementazione di PreferenceController in Android 9 e Android 8.x, come descritto in questa sezione.

PreferenceController nella release di Android 9

Un PreferenceController contiene tutta la logica per interagire con la preferenza, inclusa la visualizzazione, l'aggiornamento, l'indicizzazione nella Ricerca e così via.

L'interfaccia di PreferenceController è definita come BasePreferenceController. Ad esempio, consulta il codice in packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java

Esistono diversi sottoclassi di BasePreferenceController, ciascuno associato a uno stile dell'interfaccia utente specifico supportato per impostazione predefinita dall'app Impostazioni. Ad esempio, TogglePreferenceController ha un'API che mappa direttamente al modo in cui l'utente deve interagire con una UI delle preferenze basata su attivazione/disattivazione.

BasePreferenceController include API quali getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), e così via. La documentazione dettagliata per ciascuna API è disponibile nella classe dell'interfaccia.

Una limitazione all'implementazione di BasePreferenceController (e dei suoi sottoclassi come TogglePreferenceController) è che la firma del costruttore deve corrispondere a uno dei seguenti elementi:

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

Durante l'installazione di una preferenza per il frammento, la dashboard fornisce un metodo per collegare un PreferenceController prima del tempo di visualizzazione. Al momento dell'installazione, il controller è collegato al frammento, in modo che tutti gli eventi futuri pertinenti vengano inviati al controller.

DashboardFragment mantiene un elenco di PreferenceController nella schermata. In onCreate() del frammento, vengono invocati tutti i controller per il metodo getAvailabilityStatus() e, se restituisce true, viene invocato displayPreference() per elaborare la logica di visualizzazione. getAvailabilityStatus() è importante anche per indicare al framework Impostazioni quali elementi sono disponibili durante la ricerca.

PreferenceController nelle release di Android 8.x

Un PreferenceController contiene tutta la logica per interagire con la preferenza, inclusa la visualizzazione, l'aggiornamento, l'indicizzazione della ricerca e così via.

In corrispondenza delle interazioni con le preferenze, l'interfaccia di PreferenceController ha le API isAvailable(), displayPreference(), handlePreferenceTreeClicked() e così via. La documentazione dettagliata di ogni API è disponibile nella classe dell'interfaccia.

Durante l'installazione di una preferenza nel frammento, la dashboard fornisce un metodo per collegare un PreferenceController prima del momento di visualizzazione. Al momento dell'installazione, il controller viene collegato al frammento in modo che tutti gli eventi pertinenti futuri vengano inviati al controller.

DashboardFragment mantiene un elenco di PreferenceControllers nella schermata. All'elemento onCreate() del frammento, tutti i controller vengono richiamati per il metodo isAvailable() e, se restituisce true, displayPreference() viene richiamato per elaborare la logica di visualizzazione.

Utilizza DashboardFragment

Spostare una preferenza dalla pagina A alla pagina B

Se la preferenza è elencata in modo statico nel file XML delle preferenze della pagina originale, segui la procedura di spostamento Statica per la release di Android riportata di seguito. In caso contrario, segui la procedura di trasferimento dinamico per la tua release Android.

Spostamento statico in Android 9

  1. Trova i file XML delle preferenze per la pagina originale e la pagina di destinazione. Puoi trovare queste informazioni nel metodo getPreferenceScreenResId() della pagina.
  2. Rimuovi la preferenza dal file XML della pagina originale.
  3. Aggiungi la preferenza al file XML della pagina di destinazione.
  4. Rimuovi PreferenceController per questa preferenza dall'implementazione Java della pagina originale. Di solito si trova in createPreferenceControllers(). Il controller può essere dichiarato direttamente in XML.

    Nota: la preferenza potrebbe non avere un valore PreferenceController.

  5. Crea un'istanza per PreferenceController nel valore createPreferenceControllers() della pagina di destinazione. Se PreferenceController è definito in XML nella pagina precedente, definiscilo anche in XML per la nuova pagina.

Spostamento dinamico in Android 9

  1. Trova la categoria ospitata dalla pagina originale e di destinazione. Puoi trovare queste informazioni in DashboardFragmentRegistry.
  2. Apri il file AndroidManifest.xml contenente l'impostazione da spostare e trova la voce Attività che la rappresenta.
  3. Imposta il valore dei metadati dell'attività per com.android.settings.category sulla chiave della categoria della nuova pagina.

Spostamento statico nelle release di Android 8.x

  1. Trova i file XML delle preferenze per la pagina originale e la pagina di destinazione.
  2. Puoi trovare queste informazioni tramite il metodo getPreferenceScreenResId() della pagina.
  3. Rimuovi la preferenza nel file XML della pagina originale.
  4. Aggiungi la preferenza al file XML della pagina di destinazione.
  5. Rimuovi PreferenceController per questa preferenza nell'implementazione Java della pagina originale. Di solito si trova in getPreferenceControllers().
  6. Nota:è possibile che la preferenza non abbia un valore PreferenceController.

  7. Crea un'istanza di PreferenceController nel getPreferenceControllers() della pagina di destinazione.

Spostamento dinamico nelle release di Android 8.x

  1. Trova la categoria ospitata dalla pagina originale e di destinazione. Puoi trovare queste informazioni in DashboardFragmentRegistry.
  2. Apri il file AndroidManifest.xml contenente l'impostazione da spostare e trova la voce Attività che la rappresenta.
  3. Modifica il valore dei metadati dell'attività per com.android.settings.category, imposta il punto di valore sulla chiave della categoria della nuova pagina.

Creare una nuova preferenza in una pagina

Se la preferenza è elencata in modo statico nel file XML delle preferenze della pagina originale, segui la procedura statica riportata di seguito. In caso contrario, segui la procedura dinamica.

Creare una preferenza statica

  1. Trova i file XML delle preferenze per la pagina. Puoi trovare queste informazioni nel metodo getPreferenceScreenResId() della pagina.
  2. Aggiungi un nuovo elemento Preference nel file XML. Assicurati che abbia un valore android:key univoco.
  3. Definisci un PreferenceController per questa preferenza nel metodo getPreferenceControllers() della pagina.
    • In Android 8.x e, facoltativamente, in Android 9, inizializza un PreferenceController per questa preferenza nel metodo createPreferenceControllers() della pagina.

      Se questa preferenza esisteva già in altri luoghi, è possibile che esista già un PreferenceController. Puoi riutilizzare il PreferenceController senza crearne uno nuovo.

    • A partire da Android 9, puoi scegliere di dichiarare PreferenceController in XML accanto alla preferenza. Ad esempio:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

Creare una preferenza dinamica

  1. Trova la categoria ospitata dalla pagina originale e di destinazione. Puoi trovare queste informazioni in DashboardFragmentRegistry.
  2. Crea una nuova attività in AndroidManifest
  3. Aggiungi i metadati necessari alla nuova attività per definire l'impostazione. Imposta il valore dei metadati per com.android.settings.category sullo stesso valore definito nel passaggio 1.

Crea una nuova pagina

  1. Crea un nuovo frammento ereditandolo da DashboardFragment.
  2. Definisci la relativa categoria in DashboardFragmentRegistry.

    Nota: questo passaggio è facoltativo. Se non hai bisogno di preferenze dinamiche in questa pagina, non devi fornire una chiave di categoria.

  3. Segui i passaggi per aggiungere le impostazioni necessarie per questa pagina. Per ulteriori informazioni, consulta la sezione Implementazione.

Convalida

  • Esegui i test robolectrici nelle Impostazioni. Tutti i test nuovi ed esistenti devono essere superati.
  • Crea e installa le impostazioni, quindi apri manualmente la pagina da modificare. La pagina dovrebbe aggiornarsi immediatamente.