Architettura delle informazioni

Android 8.0 ha introdotto una nuova architettura delle informazioni per l'app Impostazioni per semplificare il modo in cui sono organizzate le 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à Impostazioni e un'implementazione più semplice.

Esempi e fonte

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

I percorsi dei file per i componenti importanti sono elencati di seguito:

  • 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 incoraggiati ad adattare l'architettura informativa delle Impostazioni esistente e a inserire pagine di impostazioni aggiuntive secondo necessità per soddisfare le funzionalità specifiche dei partner. Lo spostamento delle preferenze dalla pagina legacy (implementata come SettingsPreferencePage ) a una nuova pagina (implementata utilizzando DashboardFragment ) può essere complicato. La preferenza della pagina legacy probabilmente non è implementata con un PreferenceController .

Pertanto, quando si spostano le preferenze da una pagina legacy a una nuova pagina, è necessario creare un PreferenceController e spostare il codice nel controller prima di crearne un'istanza nel nuovo DashboardFragment . Le API richieste PreferenceController sono descritte nel loro nome e documentate in Javadoc.

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

Architettura dell'informazione in stile plugin

Ciascun elemento delle impostazioni viene implementato come Preferenza. Una preferenza può essere facilmente spostata da una pagina all'altra.

Per facilitare lo spostamento di più impostazioni, Android 8.0 ha introdotto un frammento host in stile plug-in che contiene elementi di impostazione. Gli elementi delle impostazioni sono modellati come controller in stile plug-in. Pertanto, una pagina delle impostazioni è costruita da un singolo frammento host e più controller di impostazione.

DashboardFragment

DashboardFragment è l'host di controller delle preferenze in stile plug-in. Il frammento eredita da PreferenceFragment e dispone di hook per espandere e aggiornare sia gli elenchi di preferenze statiche che gli elenchi di preferenze dinamiche.

Preferenze statiche

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

Preferenze dinamiche

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

Le impostazioni dinamiche sono più pesanti rispetto alle impostazioni configurate staticamente, quindi normalmente gli sviluppatori dovrebbero 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 inserendo un'impostazione implementata dalle app OEM/Operatore).
  • L'impostazione dovrebbe essere visualizzata nella home page Impostazioni.
  • Hai già un'attività per l'impostazione e non desideri implementare la configurazione statica aggiuntiva.

Per configurare un'attività come impostazione dinamica, procedere come segue:

  • Contrassegna l'attività come impostazione dinamica aggiungendo un filtro di intenti all'attività.
  • Indica all'app Impostazioni a quale categoria appartiene. La categoria è una costante, definita in CategoryKey .
  • Facoltativo: aggiungi testo di 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 richiederà un elenco di Preferenze sia dalle impostazioni XML statiche che 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 ciascuna impostazione tramite PreferenceController (discusso di seguito). Quindi vengono visualizzati nell'interfaccia utente come un elenco misto.

PreferenceController

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

PreferenceController nella versione Android 9

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

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

Esistono diverse sottoclassi di BasePreferenceController , ciascuna mappata a uno stile di interfaccia utente specifico supportato dall'app Impostazioni per impostazione predefinita. Ad esempio, TogglePreferenceController dispone di un'API che si associa direttamente al modo in cui l'utente dovrebbe interagire con un'interfaccia utente delle preferenze basata su interruttore.

BasePreferenceController dispone di API come getAvailabilityStatus() , displayPreference() , handlePreferenceTreeClicked(), e così via. La documentazione dettagliata per ciascuna API si trova nella classe dell'interfaccia.

Una restrizione sull'implementazione BasePreferenceController (e delle sue sottoclassi come TogglePreferenceController ) è che la firma del costruttore deve corrispondere a uno dei seguenti:

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

Durante l'installazione di una preferenza sul 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 rilevanti vengano inviati al controller.

DashboardFragment mantiene un elenco di PreferenceController sullo schermo. Nel frammento onCreate() , tutti i controller vengono richiamati per il metodo getAvailabilityStatus() e, se restituisce true, displayPreference() viene richiamato per elaborare la logica di visualizzazione. getAvailabilityStatus() è importante anche per indicare al framework Impostazioni quali elementi sono disponibili durante la ricerca.

PreferenceController nelle versioni Android 8.x

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

In base alle interazioni delle preferenze, l'interfaccia di PreferenceController dispone delle API isAvailable() , displayPreference() , handlePreferenceTreeClicked() ecc. La documentazione dettagliata su ciascuna API può essere trovata nella classe dell'interfaccia.

Durante l'installazione di una preferenza sul 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 rilevanti vengano inviati al controller.

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

Utilizzo di 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 versione Android di seguito. Altrimenti segui la procedura di spostamento dinamico relativa alla tua versione Android.

Movimento 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 PreferenceController per questa preferenza dall'implementazione Java della pagina originale. Di solito è in createPreferenceControllers() . Il controller potrebbe essere dichiarato direttamente in XML.

    Nota : la preferenza potrebbe non avere un PreferenceController .

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

Movimento dinamico in Android 9

  1. Scopri quale categoria ospita la pagina originale e quella 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 Attività che rappresenta questa impostazione.
  3. Imposta il valore dei metadati dell'attività per com.android.settings.category sulla chiave di categoria della nuova pagina.

Spostamento statico nelle versioni 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 nell'XML della pagina originale.
  4. Aggiungi la preferenza all'XML della pagina di destinazione.
  5. Rimuovere PreferenceController per questa preferenza nell'implementazione Java della pagina originale. Di solito è in getPreferenceControllers() .
  6. Nota : è possibile che la preferenza non disponga di un PreferenceController .

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

Spostamento dinamico nelle versioni Android 8.x

  1. Scopri quale categoria ospita la pagina originale e quella 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 Attività che rappresenta questa impostazione.
  3. Modifica il valore dei metadati dell'attività per com.android.settings.category , imposta il valore sulla chiave di categoria della nuova pagina.

Creazione di una nuova preferenza in una pagina

Se la preferenza è elencata staticamente nel file XML delle preferenze della pagina originale, seguire la procedura statica riportata di seguito. Altrimenti seguire la procedura dinamica .

Creazione di 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 Preferenza nell'XML. Assicurati che abbia un android:key univoco.
  3. Definire un PreferenceController per questa preferenza nel metodo getPreferenceControllers() della pagina.
    • In Android 8.x e facoltativamente in Android 9, creare un'istanza di PreferenceController per questa preferenza nel metodo createPreferenceControllers() della pagina.

      Se questa preferenza esiste già in altri posti, è possibile che esista già un PreferenceController per essa. 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"/>
      

Creazione di una preferenza dinamica

  1. Scopri quale categoria ospita la pagina originale e quella 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, ereditando da DashboardFragment .
  2. Definire la sua categoria in DashboardFragmentRegistry .

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

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

Validazione

  • Esegui i test robotelettrici nelle Impostazioni. Tutti i test esistenti e nuovi dovrebbero essere superati.
  • Crea e installa Impostazioni, quindi apri manualmente la pagina da modificare. La pagina dovrebbe aggiornarsi immediatamente.