O Android 8.0 introduziu uma nova arquitetura de informações para o app Config. para simplificar a maneira como as configurações são organizadas e facilitar para os usuários encontrar rapidamente as configurações para personalizar os dispositivos Android. O Android 9 introduziu algumas melhorias para oferecer mais funcionalidades de configurações e facilitar a implementação.
Exemplos e origem
A maioria das páginas em "Configurações" está implementada usando o novo framework. Um bom exemplo é DisplaySettings:
packages/apps/Settings/src/com/android/settings/DisplaySettings.java
Os caminhos de arquivos para componentes importantes estão listados abaixo:
- 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 (lançado no Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Implementação
Recomendamos que os fabricantes de dispositivos adaptem a arquitetura de informações das configurações atuais e insiram páginas de configurações adicionais conforme necessário para acomodar recursos específicos do parceiro. Mover preferências de uma página legada (implementada como
SettingsPreferencePage) para uma nova página (implementada usando
DashboardFragment) pode ser complicado. É provável que a preferência da página legada não seja implementada com um PreferenceController.
Portanto, ao mover preferências de uma página legada para uma nova, é necessário criar um
PreferenceController e mover o código para o controlador antes de
instanciá-lo no novo DashboardFragment. As APIs que
PreferenceController exige são descritas no nome e
documentadas no Javadoc.
É altamente recomendável adicionar um teste de unidade para cada PreferenceController.
Se a mudança for enviada ao AOSP, um teste de unidade será necessário.
Para mais informações sobre como escrever testes baseados no Robolectric, consulte o arquivo readme packages/apps/Settings/tests/robotests/README.md.
Arquitetura de informações no estilo plug-in
Cada item de configuração é implementado como uma preferência. Uma preferência pode ser facilmente movida de uma página para outra.
Para facilitar a movimentação de várias configurações, o Android 8.0 introduziu um fragmento de host no estilo plug-in que contém itens de configurações. Os itens de configurações são modelados como controladores no estilo plug-in. Portanto, uma página de configurações é construída por um único fragmento de host e vários controladores de configurações.
DashboardFragment
DashboardFragment é o host dos controladores de preferências no estilo de plug-in.
O fragmento herda de PreferenceFragment e tem hooks para
expandir e atualizar listas de preferências estáticas e dinâmicas.
Preferências estáticas
Uma lista de preferências estática é definida em XML usando a tag <Preference>. Uma implementação de
DashboardFragment usa o método
getPreferenceScreenResId() para definir qual arquivo XML contém
a lista estática de preferências a ser exibida.
Preferências dinâmicas
Um item dinâmico representa um bloco com intent, levando a uma atividade externa ou interna. Normalmente, a intent leva a uma página de configurações diferente. Por exemplo, o item de configuração "Google" na página inicial das configurações é dinâmico. Os itens dinâmicos são definidos em AndroidManifest (discutido abaixo) e carregados por um FeatureProvider (definido como
DashboardFeatureProvider).
As configurações dinâmicas são mais pesadas do que as configuradas de forma estática. Por isso, normalmente os desenvolvedores implementam a configuração como estática. No entanto, a configuração dinâmica pode ser útil quando uma das seguintes condições é verdadeira:
- A configuração não é implementada diretamente no app Configurações, como inserir uma configuração implementada por apps de OEM/operadora.
- A configuração vai aparecer na página inicial das configurações.
- Você já tem uma atividade para a configuração e não quer implementar a configuração estática extra.
Para configurar uma atividade como uma configuração dinâmica, faça o seguinte:
- Marque a atividade como uma configuração dinâmica adicionando um intent-filter a ela.
- Informe ao app Configurações a qual categoria ele pertence. A categoria é uma constante definida em
CategoryKey. - Opcional: adicione um texto de resumo quando a configuração for exibida.
Confira um exemplo do app Configurações 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>
No momento da renderização, o fragmento vai pedir uma lista de preferências do XML estático
e das configurações dinâmicas definidas em AndroidManifest. Se os PreferenceControllers forem definidos em código Java ou em XML, o DashboardFragment vai gerenciar a lógica de processamento de cada configuração usando PreferenceController (discutido abaixo). Em seguida, eles são exibidos na interface como uma lista mista.
PreferenceController
Há diferenças entre a implementação de PreferenceController
no Android 9 e no Android 8.x, conforme descrito nesta
seção.
PreferenceController na versão do Android 9
Um PreferenceController contém toda a lógica para interagir com a
preferência, incluindo exibição, atualização, indexação de pesquisa etc.
A interface de PreferenceController é definida como BasePreferenceController. Por exemplo, consulte o código em
packages/apps/Settings/src/com/android/settings/core/
BasePreferenceController.java
Há várias subclasses de BasePreferenceController, cada uma
mapeando para um estilo de interface específico que o app Configurações oferece suporte por padrão. Por exemplo, TogglePreferenceController tem uma API que mapeia diretamente como o usuário deve interagir com uma interface de preferência baseada em alternância.
O BasePreferenceController tem APIs como
getAvailabilityStatus(), displayPreference(),
handlePreferenceTreeClicked(), etc. A documentação detalhada de cada
API está na classe de interface.
Uma restrição na implementação de BasePreferenceController (e
suas subclasses, como TogglePreferenceController) é que a
assinatura do construtor precisa corresponder a uma destas opções:
public MyController(Context context, String key) {}public MyController(Context context) {}
Ao instalar uma preferência no fragmento, o painel fornece um método para
anexar um PreferenceController antes do tempo de exibição. No momento da instalação, o controlador é conectado ao fragmento para que todos os eventos relevantes futuros sejam enviados a ele.
DashboardFragment mantém uma lista de
PreferenceControllers na tela. No onCreate() do fragmento, todos os controladores são invocados para o método getAvailabilityStatus(). Se ele retornar "true", o displayPreference() será invocado para processar a lógica de exibição.
getAvailabilityStatus() também é importante para informar ao framework
de configurações quais itens estão disponíveis durante a pesquisa.
PreferenceController em versões do Android 8.x
Um PreferenceController contém toda a lógica para interagir com a
preferência, incluindo exibição, atualização, indexação de pesquisa etc.
Correspondendo às interações de preferência, a interface de
PreferenceController tem APIs isAvailable(),
displayPreference(), handlePreferenceTreeClicked() etc.
A documentação detalhada de cada API pode ser encontrada na classe de interface.
Ao instalar uma preferência no fragmento, o painel fornece um método para
anexar um PreferenceController antes do tempo de exibição. No momento da instalação, o controlador é conectado ao fragmento para que todos os eventos relevantes futuros sejam enviados a ele.
DashboardFragment mantém uma lista de PreferenceControllers
na tela. No onCreate() do fragmento, todos os
controladores são invocados para o método isAvailable(), e se ele
retornar "true", displayPreference() será invocado para processar a lógica de
exibição.
Usar DashboardFragment
Mover uma preferência da página A para a página B
Se a preferência estiver listada de forma estática no arquivo XML de preferências da página original, siga o procedimento de movimentação Estático para sua versão do Android abaixo. Caso contrário, siga o procedimento de movimentação dinâmica para sua versão do Android.
Movimento estático no Android 9
- Encontre os arquivos XML de preferência da página original e da página de destino. Você encontra essas informações no método
getPreferenceScreenResId()da página. - Remova a preferência do XML da página original.
- Adicione a preferência ao XML da página de destino.
- Remova o
PreferenceControllerdessa preferência da implementação em Java da página original. Normalmente, ele fica emcreatePreferenceControllers(). O controlador pode ser declarado diretamente em XML.Observação: a preferência pode não ter um
PreferenceController. - Instancie o
PreferenceControllernocreatePreferenceControllers()da página de destino. Se oPreferenceControllerestiver definido em XML na página antiga, defina-o em XML também para a nova página.
Movimentação dinâmica no Android 9
- Descubra em qual categoria as páginas de origem e de destino estão hospedadas. Você pode
encontrar essas informações em
DashboardFragmentRegistry. - Abra o arquivo
AndroidManifest.xmlque contém a configuração que você precisa mover e encontre a entrada de atividade que representa essa configuração. - Defina o valor de metadados da atividade para
com.android.settings.categorycomo a chave de categoria da nova página.
Movimentação estática em versões do Android 8.x
- Encontre os arquivos XML de preferência da página original e da página de destino. Você encontra essas informações no método
- Remova a preferência no XML da página original.
- Adicione a preferência ao XML da página de destino.
- Remova o
PreferenceControllerdessa preferência na implementação em Java da página original. Normalmente, ele fica emgetPreferenceControllers(). - Instancie o
PreferenceControllernogetPreferenceControllers()da página de destino.
getPreferenceScreenResId()
da página.
Observação:é possível que a preferência não tenha um
PreferenceController.
Movimentação dinâmica em versões do Android 8.x
- Descubra em qual categoria as páginas de origem e de destino estão hospedadas. Você pode encontrar
essas informações em
DashboardFragmentRegistry. - Abra o arquivo
AndroidManifest.xmlque contém a configuração que você precisa mover e encontre a entrada de atividade que representa essa configuração. - Mude o valor de metadados da atividade para
com.android.settings.categorye defina o ponto de valor como a chave de categoria da nova página.
Criar uma nova preferência em uma página
Se a preferência estiver listada de forma estática no arquivo XML de preferências da página original, siga o procedimento estático abaixo. Caso contrário, siga o procedimento dinâmico.
Criar uma preferência estática
- Encontre os arquivos XML de preferências da página. Você pode encontrar essas informações no método getPreferenceScreenResId() da página.
- Adicione um novo item de preferência no XML. Verifique se ele tem um
android:keyexclusivo. -
Defina um
PreferenceControllerpara essa preferência no métodogetPreferenceControllers()da página.- No Android 8.x e, opcionalmente, no Android 9,
instancie um
PreferenceControllerpara essa preferência no métodocreatePreferenceControllers()da página.Se essa preferência já existia em outros lugares, é possível que já haja um
PreferenceControllerpara ela. É possível reutilizar oPreferenceControllersem criar um novo. -
No Android 9 e versões mais recentes, é possível declarar o
PreferenceControllerem XML ao lado da preferência. Exemplo:<Preference android:key="reset_dashboard" android:title="@string/reset_dashboard_title" settings:controller="com.android.settings.system.ResetPreferenceController"/>
- No Android 8.x e, opcionalmente, no Android 9,
instancie um
Criar uma preferência dinâmica
- Descubra em qual categoria as páginas de origem e de destino estão hospedadas. Você pode encontrar
essas informações em
DashboardFragmentRegistry. - Criar uma atividade em
AndroidManifest - Adicione os metadados necessários à nova atividade para definir a configuração. Defina o valor de metadados para
com.android.settings.categorycomo o mesmo valor definido na etapa 1.
Criar nova página
- Crie um novo fragmento, herdando de
DashboardFragment. - Defina a categoria em
DashboardFragmentRegistry.Observação:esta etapa é opcional. Se você não precisar de preferências dinâmicas nesta página, não será necessário fornecer uma chave de categoria.
- Siga as etapas para adicionar as configurações necessárias para esta página. Para mais informações, consulte a seção Implementação.
Validação
- Execute os testes do Robolectric em "Configurações". Todos os testes atuais e novos precisam ser aprovados.
- Crie e instale as configurações e abra manualmente a página que está sendo modificada. A página será atualizada imediatamente.