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 PreferenceController
s 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
PreferenceController
s 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
PreferenceController
dessa 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
PreferenceController
nocreatePreferenceControllers()
da página de destino. Se oPreferenceController
estiver 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.xml
que 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.category
como 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
PreferenceController
dessa preferência na implementação em Java da página original. Normalmente, ele fica emgetPreferenceControllers()
. - Instancie o
PreferenceController
nogetPreferenceControllers()
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.xml
que 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.category
e 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:key
exclusivo. -
Defina um
PreferenceController
para essa preferência no métodogetPreferenceControllers()
da página.- No Android 8.x e, opcionalmente, no Android 9,
instancie um
PreferenceController
para essa preferência no métodocreatePreferenceControllers()
da página.Se essa preferência já existia em outros lugares, é possível que já haja um
PreferenceController
para ela. É possível reutilizar oPreferenceController
sem criar um novo. -
No Android 9 e versões mais recentes, é possível declarar o
PreferenceController
em 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.category
como 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.