Android 8.0 introdujo una nueva arquitectura de la información para la app de Configuración con el objetivo de simplificar la forma en que se organizan estas opciones y facilitar a los usuarios la búsqueda rápida de parámetros de configuración para personalizar sus dispositivos Android. Android 9 introdujo algunas mejoras para proporcionar más funcionalidad de configuración y facilitar la implementación.
Ejemplos y fuente
Actualmente, la mayoría de las páginas de Configuración se implementan con el nuevo framework. Un buen ejemplo es DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java
.
A continuación, se indican las rutas de acceso a los archivos para los componentes importantes:
- 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 (presentado en Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Implementación
Se recomienda a los fabricantes de dispositivos que adapten la arquitectura de información de configuración existente y que inserten páginas de configuración adicionales según sea necesario para adaptarse a las funciones específicas de los socios. Mover las preferencias de una página heredada (implementada como SettingsPreferencePage
) a una página nueva (implementada con DashboardFragment
) puede ser complicado. Es probable que la preferencia de la página heredada no se implemente con un PreferenceController
.
Por lo tanto, cuando muevas una preferencia de una página heredada a una nueva, deberás crear un PreferenceController
y mover el código al controlador antes de crear una instancia de él en el nuevo DashboardFragment
. Las APIs que requiere PreferenceController
se describen en su nombre y se documentan en Javadoc.
Te recomendamos que agregues una prueba de unidades para cada PreferenceController
.
Si el cambio se envía al AOSP, se requiere una prueba de unidades.
Si quieres obtener más información para escribir pruebas basadas en Robolectric, consulta el archivo readme packages/apps/Settings/tests/robotests/README.md
.
Arquitectura de la información tipo 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 desplazamiento de varias configuraciones, Android 8.0 introdujo un fragmento de host de estilo complemento que contiene elementos de configuración. Los elementos de configuración se modelan como controladores estilo complemento. Por lo tanto, un solo fragmento de host y varios controladores de configuración construyen una página de configuración.
Fragmento de panel
DashboardFragment
es un host de controladores de preferencias de estilo de complemento.
El fragmento se hereda de PreferenceFragment
y tiene hooks para expandir y actualizar las listas de preferencias estáticas y las dinámicas.
Preferencias estáticas
Se define una lista de preferencias estáticas en XML con la etiqueta <Preference>
. Una implementación de DashboardFragment
usa el método getPreferenceScreenResId()
para definir qué archivo en formato XML contiene la lista estática de preferencias que se mostrará.
Preferencias dinámicas
Un elemento dinámico representa una tarjeta con un intent, que lleva a una actividad externa o interna. Por lo general, el intent conduce a una página de configuración diferente. Por ejemplo, el elemento de configuración "Google" de la página principal de Configuración es un elemento dinámico. Los elementos dinámicos se definen en AndroidManifest
(que se analizan 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, por lo general, los desarrolladores deberían implementar una configuración como estática. Sin embargo, la configuración dinámica puede ser útil cuando se cumple alguna de las siguientes condiciones:
- El parámetro de configuración no se implementa directamente en la app de Configuración (por ejemplo, si se inserta un parámetro de configuración implementado por las apps del OEM o el operador).
- La configuración debería aparecer en la página principal de Configuración.
- Ya tienes una actividad para la configuración y no deseas implementar la configuración estática adicional.
Para configurar una actividad como un parámetro de configuración dinámico, haz lo siguiente:
- Para marcar la actividad como una configuración dinámica, agrega un filtro de intents a la actividad.
- Dile a la app de Configuración a qué categoría pertenece. La categoría es una constante que se define en
CategoryKey
. - Opcional: Agrega texto de resumen cuando se muestre el parámetro de configuración.
Este es un ejemplo tomado de la app de Configuración de 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>
Durante el tiempo de renderización, el fragmento solicitará una lista de Preferencias de la configuración XML estática y la configuración dinámica definida en AndroidManifest
. Ya sea que los objetos PreferenceController
se definan en código Java o XML, DashboardFragment
administra la lógica de control de cada configuración a través de PreferenceController
(se explica a continuación). Luego, se muestran en la IU como una lista mixta.
Controlador de preferencia
Existen diferencias entre la implementación de 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, incluidas la visualización, la actualización, la indexación de búsquedas, etcétera.
La interfaz de PreferenceController
se define como BasePreferenceController
. Por ejemplo, consulta el código en packages/apps/Settings/src/com/android/settings/core/
BasePreferenceController.java
.
Hay varias subclases de BasePreferenceController
, y cada una se asigna a un estilo de IU específico que la app de Configuración admite de forma predeterminada. Por ejemplo, TogglePreferenceController
tiene una API que mapea directamente la forma en que el usuario debe interactuar con una IU de preferencias basada en el botón de activación.
BasePreferenceController
tiene APIs como getAvailabilityStatus()
, displayPreference()
, handlePreferenceTreeClicked(),
, etc. La documentación detallada de cada API se encuentra en la clase de interfaz.
Una restricción para implementar BasePreferenceController
(y sus subclases, como TogglePreferenceController
) establece que la firma del constructor debe coincidir con cualquiera de las siguientes opciones:
public MyController(Context context, String key) {}
public MyController(Context context) {}
Mientras se instala una preferencia para el fragmento, el panel 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 objetos PreferenceController
en la pantalla. En el onCreate()
del fragmento, se invocan todos los controladores para el método getAvailabilityStatus()
y, si el resultado es verdadero, se invoca a displayPreference()
para procesar la lógica de visualización.
getAvailabilityStatus()
también es importante para indicarle al framework de Settings 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, incluidas la visualización, la actualización, la indexación de búsquedas, etcétera.
Según las interacciones de preferencias, la interfaz de
PreferenceController
tiene las APIs isAvailable()
,
displayPreference()
, handlePreferenceTreeClicked()
, etc. Puedes encontrar documentación detallada sobre cada API en la clase de interfaz.
Mientras se instala una preferencia para el fragmento, el panel 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 el onCreate()
del fragmento, se invocan todos los controladores para el método isAvailable()
y, si el resultado es verdadero, se invoca a displayPreference()
para procesar la lógica de la pantalla.
Usa DashboardFragment
Cómo mover una preferencia de la página A a la B
Si la preferencia se indica estáticamente en el archivo XML de preferencias de la página original, sigue el procedimiento de movimiento estático para tu versión de Android que se muestra a continuación. De lo contrario, sigue el procedimiento de traslado dinámico correspondiente a la versión de Android.
Movimiento estático en Android 9
- Busca los archivos en formato XML de preferencia para la página original y la de destino. Puedes encontrar esta información en el método
getPreferenceScreenResId()
de la página. - Quita la preferencia del archivo XML de la página original.
- Agrega la preferencia al XML de la página de destino.
- Quita el
PreferenceController
para esta preferencia de la implementación de Java de la página original. Por lo general, está encreatePreferenceControllers()
. El controlador se puede declarar directamente en XML.Nota: Es posible que la preferencia no tenga un
PreferenceController
. - Crea una instancia de
PreferenceController
en elcreatePreferenceControllers()
de la página de destino. Si el objetoPreferenceController
está definido en XML en la página anterior, defínelo también en ese formato para la página nueva.
Movimiento dinámico en Android 9
- Descubre qué categoría aloja la página original y la de destino. Puedes encontrar esta información en
DashboardFragmentRegistry
. - Abre el archivo
AndroidManifest.xml
que contiene la configuración que necesitas mover y busca la entrada de actividad que representa esta configuración. - Establece el valor de metadatos de la actividad en
com.android.settings.category
según la clave de categoría de la página nueva.
Movimiento estático en las versiones de Android 8.x
- Busca los archivos en formato XML de preferencia para la página original y la de destino. Puedes encontrar esta información en el método
- Quita la preferencia en el archivo XML de la página original.
- Agrega la preferencia al XML de la página de destino.
- Quita el
PreferenceController
para esta preferencia en la implementación de Java de la página original. Por lo general, está engetPreferenceControllers()
. - Crea una instancia de
PreferenceController
en elgetPreferenceControllers()
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
- Descubre qué categoría aloja la página original y la de destino. Puedes encontrar esta información en
DashboardFragmentRegistry
. - Abre el archivo
AndroidManifest.xml
que contiene la configuración que necesitas mover y busca la entrada de actividad que representa esta configuración. - Cambiar el valor de metadatos de la actividad para
com.android.settings.category
y establecer el punto de valor en la clave de categoría de la nueva página
Cómo crear una nueva preferencia en una página
Si la preferencia se indica estáticamente en el archivo XML de preferencias de la página original, sigue el procedimiento estático que se muestra a continuación. De lo contrario, sigue el procedimiento dinámico.
Crea una preferencia estática
- Busca los archivos en formato XML de preferencia para la página. Puedes encontrar esta información en el método getPreferenceScreenResId() de la página.
- Agrega un nuevo elemento de Preferencia en el archivo XML. Asegúrate de que tenga un
android:key
único. -
Define un elemento
PreferenceController
para esta preferencia en el métodogetPreferenceControllers()
de la página.- En Android 8.x y, opcionalmente, en Android 9, crea 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 haya un
PreferenceController
para ella. Puedes reutilizar el objetoPreferenceController
sin crear uno nuevo. -
A partir de Android 9, puedes declarar el
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, crea una instancia de
Cómo crear una preferencia dinámica
- Descubre qué categoría aloja la página original y la de destino. Puedes encontrar esta información en
DashboardFragmentRegistry
. - Crea una actividad nueva en
AndroidManifest
- Agrega los metadatos necesarios a la actividad nueva para definir la configuración. Configura el valor de metadatos de
com.android.settings.category
con el mismo valor definido en el paso 1.
Crear página nueva
- Crea un nuevo fragmento y lo hereda de
DashboardFragment
. - Define su categoría en
DashboardFragmentRegistry
.Nota: Este paso es opcional. Si no necesitas ninguna preferencia dinámica en esta página, no es necesario que proporciones una clave de categoría.
- Sigue los pasos para agregar la configuración necesaria para esta página. Para obtener más información, consulta la sección Implementación.
Validación
- Ejecuta las pruebas robóticas en Configuración. Deberían aprobarse todas las pruebas existentes y nuevas.
- Compila e instala la configuración y, luego, abre manualmente la página que deseas modificar. La página debería actualizarse de inmediato.