Architettura dell'informazione

Android 8.0 ha introdotto una nuova architettura delle informazioni per l'app Impostazioni per semplificare l'organizzazione delle impostazioni e consentire agli utenti di trovare rapidamente le impostazioni per personalizzare i propri dispositivi Android. Android 9 ha introdotto alcuni miglioramenti per fornire più funzionalità di Impostazioni e semplificare l'implementazione.

Esempi e origine

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

Di seguito sono elencati 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 delle informazioni di Impostazioni esistente e a inserire pagine di impostazioni aggiuntive, se necessario, per ospitare 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 una preferenza da una pagina precedente a una nuova pagina, devi creare un PreferenceController e spostare il codice nel controller prima di istanziarlo nel nuovo DashboardFragment. Le API richieste da PreferenceController sono descritte nel nome e documentate in Javadoc.

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

Architettura delle informazioni in stile plug-in

Ogni elemento di impostazione viene implementato come preferenza. Una preferenza può essere spostata facilmente da una pagina all'altra.

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

DashboardFragment

DashboardFragment è l'host dei controller di preferenza in stile plug-in. Il fragment eredita da PreferenceFragment e dispone di hook per espandere e aggiornare sia gli elenchi di preferenze statici sia quelli dinamici.

Preferenze statiche

Un elenco di preferenze statiche è definito in XML utilizzando il <Preference> tag. 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 porta a un'attività esterna o interna. In genere, l'intent porta a una pagina di impostazioni diversa. Ad esempio, l'elemento di impostazione "Google" nella home page di Impostazioni è un elemento dinamico. Gli elementi dinamici sono definiti in AndroidManifest (descritti di seguito) e caricati tramite un FeatureProvider (definito come DashboardFeatureProvider).

Le impostazioni dinamiche sono più pesanti di quelle configurate staticamente, quindi in genere gli sviluppatori devono implementare l'impostazione come statica. 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 deve essere visualizzata nella home page di 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 all'attività.
  • Indica all'app Impostazioni a quale categoria appartiene. La categoria è una costante, definita in CategoryKey.
  • (Facoltativo) Aggiungi il testo di riepilogo quando viene visualizzata l'impostazione.

Di seguito è riportato 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 fragment chiederà un elenco di preferenze sia dall'XML statico sia dalle impostazioni dinamiche definite in AndroidManifest. Indipendentemente dal fatto che i PreferenceController siano definiti nel codice Java o in XML, DashboardFragment gestisce la logica di gestione di ogni impostazione tramite PreferenceController (descritta di seguito). Vengono poi visualizzati nell'UI come un 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, inclusi la visualizzazione, l'aggiornamento, l'indicizzazione della 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 diverse sottoclassi di BasePreferenceController, ognuna delle quali esegue il mapping a uno stile UI specifico supportato per impostazione predefinita dall'app Impostazioni. Ad esempio, TogglePreferenceController ha un'API che esegue il mapping diretto al modo in cui l'utente deve interagire con un'UI di preferenza basata su attivazione/disattivazione.

BasePreferenceController ha API come getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), e così via. La documentazione dettagliata per ogni API è nella classe di interfaccia.

Una limitazione all'implementazione di BasePreferenceController (e delle relative sottoclassi come TogglePreferenceController) è che la firma del costruttore deve corrispondere a una delle seguenti:

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

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

DashboardFragment mantiene un elenco di PreferenceController sullo schermo. In onCreate() del fragment, tutti i controller vengono richiamati per il metodo getAvailabilityStatus() e, se restituisce true, viene richiamato 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, inclusi la visualizzazione, l'aggiornamento, l'indicizzazione della ricerca e così via.

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

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

DashboardFragment mantiene un elenco di PreferenceControllers sullo schermo. In onCreate() del fragment, tutti i controller vengono richiamati per il metodo isAvailable() e, se restituisce true, viene richiamato displayPreference() per elaborare la logica di visualizzazione.

Utilizzare DashboardFragment

Spostare una preferenza dalla pagina A alla pagina B

Se la preferenza è elencata staticamente nel file XML delle preferenze della pagina originale, segui la procedura di spostamento statico per la tua release di Android riportata di seguito. In caso contrario, segui la procedura di spostamento dinamico per la tua release di 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 dal metodo getPreferenceScreenResId() della pagina.
  2. Rimuovi la preferenza dall'XML della pagina originale.
  3. Aggiungi la preferenza all'XML della pagina di destinazione.
  4. Rimuovi il PreferenceController per questa preferenza dall'implementazione Java della pagina originale. In genere si trova in createPreferenceControllers(). Il controller potrebbe essere dichiarato direttamente in XML.

    Nota: la preferenza potrebbe non avere un PreferenceController.

  5. Crea un'istanza di PreferenceController in della pagina di destinazionecreatePreferenceControllers(). 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 dalla pagina di destinazione. Puoi trovare queste informazioni in DashboardFragmentRegistry.
  2. Apri il file AndroidManifest.xml che contiene l'impostazione che devi spostare e trova la voce Activity che rappresenta questa impostazione.
  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 dal metodo getPreferenceScreenResId() della pagina.
  3. Rimuovi la preferenza dall'XML della pagina originale.
  4. Aggiungi la preferenza all'XML della pagina di destinazione.
  5. Rimuovi il PreferenceController per questa preferenza dall'implementazione Java della pagina originale. In genere si trova in getPreferenceControllers().
  6. Nota:è possibile che la preferenza non abbia un PreferenceController.

  7. Crea un'istanza di PreferenceController in della pagina di destinazionegetPreferenceControllers().

Spostamento dinamico nelle release di Android 8.x

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

Creare una nuova preferenza in una pagina

Se la preferenza è elencata staticamente 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 dal metodo getPreferenceScreenResId() della pagina.
  2. Aggiungi un nuovo elemento Preference in XML. Assicurati che abbia un android:key univoco.
  3. Definisci un PreferenceController per questa preferenza nel metodo getPreferenceControllers() della pagina.
    • In Android 8.x e, facoltativamente, in Android 9, crea un'istanza di PreferenceController per questa preferenza nel metodo createPreferenceControllers() della pagina.

      Se questa preferenza esisteva già in altre posizioni, è possibile che esista già un PreferenceController. Puoi riutilizzare 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 dalla pagina 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.

Creare una nuova pagina

  1. Crea un nuovo fragment, ereditando 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 Robolectric in Impostazioni. Tutti i test esistenti e nuovi devono essere superati.
  • Crea e installa Impostazioni, poi apri manualmente la pagina da modificare. La pagina dovrebbe aggiornarsi immediatamente.