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
- 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. - Elimina la preferencia del XML de la página original.
- Agregue la preferencia al XML de la página de destino.
- Elimine
PreferenceController
para esta preferencia de la implementación de Java de la página original. Por lo general, está encreatePreferenceControllers()
. El controlador podría declararse directamente en XML.Nota : Es posible que la preferencia no tenga un
PreferenceController
. - Crea una instancia del
PreferenceController
en elcreatePreferenceControllers()
de la página de destino. SiPreferenceController
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
- Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en
DashboardFragmentRegistry
. - Abra el archivo
AndroidManifest.xml
que contiene la configuración que necesita mover y busque la entrada Actividad que representa esta configuración. - 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
- 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
- Elimina la preferencia en el XML de la página original.
- Agregue la preferencia al XML de la página de destino.
- Elimine
PreferenceController
para esta preferencia en la implementación de Java de la página original. Por lo general, está engetPreferenceControllers()
. - Cree una instancia de
PreferenceController
engetPreferenceControllers()
de la página de destino.
getPreferenceScreenResId()
de la página. Nota : es posible que la preferencia no tenga un PreferenceController
.
Movimiento dinámico en versiones de Android 8.x
- Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en
DashboardFragmentRegistry
. - Abra el archivo
AndroidManifest.xml
que contiene la configuración que necesita mover y busque la entrada Actividad que representa esta configuración. - 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
- Busque los archivos XML de preferencia para la página. Puede encontrar esta información en el método getPreferenceScreenResId() de la página.
- Agregue un nuevo elemento de preferencia en el XML. Asegúrate de que tenga un
android:key
único. - Defina un
PreferenceController
para esta preferencia en el métodogetPreferenceControllers()
de la página.- En Android 8.x y opcionalmente en Android 9, cree una instancia de
PreferenceController
para esta preferencia en el métodocreatePreferenceControllers()
de la página.Si esta preferencia ya existía en otros lugares, es posible que ya exista un
PreferenceController
para ella. Puede reutilizar elPreferenceController
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"/>
- En Android 8.x y opcionalmente en Android 9, cree una instancia de
Creación de una preferencia dinámica
- Encuentre qué categoría aloja la página original y la de destino. Puede encontrar esta información en
DashboardFragmentRegistry
. - Crear una nueva actividad en
AndroidManifest
- 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
- Cree un nuevo fragmento heredado de
DashboardFragment
. - 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.
- 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.