Arquitectura informacional

Android 8.0 introdujo una nueva arquitectura de información para la aplicación Configuración para simplificar la forma en que se organizan las configuraciones y facilitar a los usuarios la búsqueda rápida de configuraciones para personalizar sus dispositivos Android. Android 9 introdujo algunas mejoras para proporcionar más funciones de configuración y una implementación más sencilla.

Ejemplos y fuente

La mayoría de las páginas de Configuración se implementan actualmente con el nuevo marco. Un buen ejemplo es DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

Las rutas de archivos para componentes importantes se enumeran a continuación:

  • Clave de categoría : 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 (introducido en Android 9): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implementación

Se alienta a los fabricantes de dispositivos a adaptar la arquitectura de información de configuración existente e insertar páginas de configuración adicionales según sea necesario para adaptarse a las características específicas de los socios. Mover preferencias de una página heredada (implementada como SettingsPreferencePage ) a una página nueva (implementada mediante DashboardFragment ) puede ser complicado. Es probable que la preferencia de la página heredada no esté implementada con un PreferenceController .

Entonces, al mover una preferencia de una página heredada a una página nueva, debe crear un PreferenceController y mover el código al controlador antes de instanciarlo en el nuevo DashboardFragment . Las API que requiere PreferenceController se describen en su nombre y se documentan en Javadoc.

Se recomienda encarecidamente agregar una prueba de unidad para cada PreferenceController . Si el cambio se envía a AOSP, se requiere una prueba unitaria. Para obtener más información sobre cómo escribir pruebas basadas en Robolectric, consulte el archivo Léame packages/apps/Settings/tests/robotests/README.md .

Arquitectura de información estilo complemento

Cada elemento de configuración se implementa como una preferencia. Una preferencia se puede mover fácilmente de una página a otra.

Para facilitar el movimiento de múltiples configuraciones, Android 8.0 introdujo un fragmento de host estilo complemento que contiene elementos de configuración. Los elementos de configuración se modelan como controladores de estilo complemento. Por lo tanto, una página de configuración se construye con un solo fragmento de host y varios controladores de configuración.

Fragmento del tablero

DashboardFragment es el host de controladores de preferencia de estilo complemento. El fragmento se hereda de PreferenceFragment y tiene ganchos para expandir y actualizar tanto listas de preferencias estáticas como listas de preferencias dinámicas.

Preferencias estáticas

Una lista de preferencias estática se define en XML usando la etiqueta <Preference> . Una implementación de DashboardFragment usa el método getPreferenceScreenResId() para definir qué archivo XML contiene la lista estática de preferencias para mostrar.

Preferencias dinámicas

Un elemento dinámico representa un mosaico con intención, que conduce a una actividad externa o interna. Por lo general, la intención conduce a una página de configuración diferente. Por ejemplo, el elemento de configuración "Google" en la página de inicio de Configuración es un elemento dinámico. Los elementos dinámicos se definen en AndroidManifest (discutido a continuación) y se cargan a través de un FeatureProvider (definido como DashboardFeatureProvider ).

La configuración dinámica es más pesada que la configuración estática, por lo que normalmente los desarrolladores deberían implementar la configuración como estática. Sin embargo, la configuración dinámica puede ser útil cuando se cumple alguna de las siguientes condiciones:

  • La configuración no se implementa directamente en la aplicación Configuración (como inyectar una configuración implementada por aplicaciones OEM/Carrier).
  • La configuración debería aparecer en la página de inicio de Configuración.
  • Ya tiene una actividad para la configuración y no desea implementar la configuración estática adicional.

Para configurar una actividad como una configuración dinámica, haga lo siguiente:

  • Marque la actividad como una configuración dinámica agregando un filtro de intención a la actividad.
  • Dígale a la aplicación Configuración a qué categoría pertenece. La categoría es una constante, definida en CategoryKey .
  • Opcional: agregue texto de resumen cuando se muestre la configuración.

Aquí hay un ejemplo tomado de la aplicación Configuración para 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>

En el momento de la representación, el fragmento solicitará una lista de Preferencias tanto del XML estático como de la configuración dinámica definida en AndroidManifest . Ya sea que los PreferenceController estén definidos en código Java o en XML, DashboardFragment administra la lógica de manejo de cada configuración a través de PreferenceController (que se explica a continuación). Luego se muestran en la interfaz de usuario como una lista mixta.

PreferenceController

Existen diferencias entre implementar PreferenceController en Android 9 y Android 8.x, como se describe en esta sección.

PreferenceController en la versión de Android 9

Un PreferenceController contiene toda la lógica para interactuar con la preferencia, incluida la visualización, actualización, indexación de búsqueda, etc.

La interfaz de PreferenceController se define como BasePreferenceController . Por ejemplo, vea el código en packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java

Hay varias subclases de BasePreferenceController , cada una de las cuales se asigna a un estilo de interfaz de usuario específico que la aplicación Configuración admite de forma predeterminada. Por ejemplo, TogglePreferenceController tiene una API que se asigna directamente a cómo el usuario debe interactuar con una interfaz de usuario de preferencia basada en alternar.

BasePreferenceController tiene API como getAvailabilityStatus() , displayPreference() , handlePreferenceTreeClicked(), etc. La documentación detallada de cada API se encuentra en la clase de interfaz.

Una restricción en la implementación de BasePreferenceController (y sus subclases como TogglePreferenceController ) es que la firma del constructor debe coincidir con cualquiera de los siguientes:

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

Al instalar una preferencia en el fragmento, el tablero proporciona un método para adjuntar un PreferenceController antes del tiempo de visualización. En el momento de la instalación, el controlador se conecta al fragmento para que todos los eventos relevantes futuros se envíen al controlador.

DashboardFragment mantiene una lista de PreferenceController s en la pantalla. En onCreate() del fragmento, se invocan todos los controladores para el método getAvailabilityStatus() y, si devuelve verdadero, se invoca displayPreference() para procesar la lógica de visualización. getAvailabilityStatus() también es importante para decirle al marco de configuración qué elementos están disponibles durante la búsqueda.

PreferenceController en versiones de Android 8.x

Un PreferenceController contiene toda la lógica para interactuar con la preferencia, incluida la visualización, la actualización y la indexación de búsqueda. etc

En correspondencia con las interacciones de preferencias, la interfaz de PreferenceController tiene las API isAvailable() , displayPreference() , handlePreferenceTreeClicked() etc. La documentación detallada de cada API se puede encontrar en la clase de interfaz.

Al instalar una preferencia en el fragmento, el tablero proporciona un método para adjuntar un PreferenceController antes del tiempo de visualización. En el momento de la instalación, el controlador se conecta al fragmento para que todos los eventos relevantes futuros se envíen al controlador.

DashboardFragment mantiene una lista de PreferenceControllers en la pantalla. En onCreate() del fragmento, se invocan todos los controladores para el método isAvailable() y, si devuelve verdadero, se invoca displayPreference() para procesar la lógica de visualización.

Usando DashboardFragment

Mover una preferencia de la página A a la B

Si la preferencia aparece de forma estática en el archivo XML de preferencias de la página original, siga el procedimiento de movimiento estático para su versión de Android a continuación. De lo contrario, siga el procedimiento de movimiento dinámico para su versión de Android.

Movimiento estático en Android 9

  1. Encuentre los archivos XML de preferencia para la página original y la página de destino. Puede encontrar esta información en el método getPreferenceScreenResId() de la página.
  2. Elimina la preferencia del XML de la página original.
  3. Agregue la preferencia al XML de la página de destino.
  4. Elimine PreferenceController para esta preferencia de la implementación de Java de la página original. Por lo general, está en createPreferenceControllers() . El controlador podría declararse directamente en XML.

    Nota : Es posible que la preferencia no tenga un PreferenceController .

  5. Crea una instancia del PreferenceController en el createPreferenceControllers() de la página de destino. Si PreferenceController está definido en XML en la página anterior, defínalo también en XML para la página nueva.

Movimiento dinámico en Android 9

  1. Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en DashboardFragmentRegistry .
  2. Abra el archivo AndroidManifest.xml que contiene la configuración que necesita mover y busque la entrada Actividad que representa esta configuración.
  3. Establezca el valor de los metadatos de la actividad para com.android.settings.category en la clave de categoría de la nueva página.

Movimiento estático en las versiones de Android 8.x

  1. Encuentre los archivos XML de preferencia para la página original y la página de destino.
  2. Puede encontrar esta información en el método getPreferenceScreenResId() de la página.
  3. Elimina la preferencia en el XML de la página original.
  4. Agregue la preferencia al XML de la página de destino.
  5. Elimine PreferenceController para esta preferencia en la implementación de Java de la página original. Por lo general, está en getPreferenceControllers() .
  6. Nota : es posible que la preferencia no tenga un PreferenceController .

  7. Cree una instancia de PreferenceController en getPreferenceControllers() de la página de destino.

Movimiento dinámico en versiones de Android 8.x

  1. Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en DashboardFragmentRegistry .
  2. Abra el archivo AndroidManifest.xml que contiene la configuración que necesita mover y busque la entrada Actividad que representa esta configuración.
  3. Cambie el valor de los metadatos de la actividad para com.android.settings.category , establezca el punto de valor en la clave de categoría de la nueva página.

Crear una nueva preferencia en una página

Si la preferencia aparece de forma estática en el archivo XML de preferencias de la página original, siga el procedimiento estático que se indica a continuación. De lo contrario, siga el procedimiento dinámico .

Creación de una preferencia estática

  1. Busque los archivos XML de preferencia para la página. Puede encontrar esta información en el método getPreferenceScreenResId() de la página.
  2. Agregue un nuevo elemento de preferencia en el XML. Asegúrate de que tenga un android:key único.
  3. Defina un PreferenceController para esta preferencia en el método getPreferenceControllers() de la página.
    • En Android 8.x y opcionalmente en Android 9, cree una instancia de PreferenceController para esta preferencia en el método createPreferenceControllers() de la página.

      Si esta preferencia ya existía en otros lugares, es posible que ya exista un PreferenceController para ella. Puede reutilizar el PreferenceController sin crear uno nuevo.

    • A partir de Android 9, puede optar por declarar PreferenceController en XML junto a la preferencia. Por ejemplo:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>
      

Creación de una preferencia dinámica

  1. Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en DashboardFragmentRegistry .
  2. Crear una nueva actividad en AndroidManifest
  3. Agregue los metadatos necesarios a la nueva actividad para definir la configuración. Establezca el valor de los metadatos para com.android.settings.category en el mismo valor definido en el paso 1.

Crear una nueva página

  1. Cree un nuevo fragmento heredado de DashboardFragment .
  2. Defina su categoría en DashboardFragmentRegistry .

    Nota: Este paso es opcional. Si no necesita ninguna preferencia dinámica en esta página, no necesita proporcionar una clave de categoría.

  3. Siga los pasos para agregar la configuración necesaria para esta página. Para obtener más información, consulte la sección Implementación .

Validación

  • Ejecute las pruebas roboeléctricas en Configuración. Todas las pruebas existentes y nuevas deben pasar.
  • Cree e instale la Configuración, luego abra manualmente la página que se está modificando. La página debería actualizarse inmediatamente.