O Android 8.0 introduziu uma nova arquitetura da informação para o app Configurações 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 funcionalidade de configurações e implementação facilitada.
Exemplos e origem
No momento, a maioria das páginas em "Configurações" é implementada usando o novo framework. Uma boa
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
- BackgroundPreferenceController:
frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
- BasePreferenceController (introduzido no Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Implementação
Recomendamos que os fabricantes de dispositivos adaptem as informações atuais das configurações
e inserir páginas de configuração adicionais conforme necessário para acomodar
recursos específicos do parceiro. Como mover preferências da página legada (implementado como
SettingsPreferencePage
) para uma nova página (implementada usando
DashboardFragment
) pode ser complicado. A preferência da
página legada provavelmente não está implementada com um PreferenceController
.
Portanto, ao mover uma preferência de uma página legada para uma nova, é necessário criar um
PreferenceController
e mover o código para o controlador antes de
instanciar no novo DashboardFragment
. As APIs que
As exigências de PreferenceController
estão descritas no nome e
documentadas no Javadoc.
É altamente recomendável adicionar um teste de unidade para cada PreferenceController
.
Se a alteração for enviada ao AOSP, será necessário um teste de unidade.
Para mais informações sobre como criar testes baseados no Robolectric, consulte a
arquivo readme packages/apps/Settings/tests/robotests/README.md
.
Arquitetura de informações no estilo de plug-in
Cada item de configurações é implementado como uma Preferência. Uma preferência pode ser movidos 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 estilo plug-in que contém itens de configuração. Os itens de configurações são modelados como controladores no estilo de plug-in. Portanto, uma página de configurações é construída por um fragmento de host único e vários controladores de configuração.
DashboardFragment
O DashboardFragment
é o host de controladores de preferência do 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áticas é definida em XML usando a tag <Preference>
. Um
A implementação de DashboardFragment
usa as
método getPreferenceScreenResId()
para definir qual arquivo XML contém
a lista estática de preferências a serem exibidas.
Preferências dinâmicas
Um item dinâmico representa um bloco com intent, que leva a uma atividade
externa ou interna. Normalmente, a intent leva a uma página de configuração diferente. Por exemplo:
a página de configuração na página inicial "Configurações" é um item dinâmico. Dinâmico
itens são definidos em AndroidManifest
(discutidos abaixo) e carregados
usando um FeatureProvider
(definido como
DashboardFeatureProvider
).
As configurações dinâmicas são mais pesadas do que as configurações configuradas estaticamente. Por isso, normalmente os desenvolvedores precisam implementar a configuração como estática. No entanto, a configuração dinâmica pode ser útil quando alguma das seguintes condições é verdadeira:
- A configuração não é implementada diretamente no app Configurações (como injetando uma configuração implementada por apps de OEM/operadora).
- A configuração vai aparecer na página inicial de configurações.
- Você já tem uma atividade para a configuração e não quer implementar a configuração extra estática.
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 filtro de intent à atividade.
- Informe ao app Configurações a categoria a que ele pertence. A categoria é uma constante,
definida em
CategoryKey
. - Opcional: adicione um texto de resumo quando a configuração for exibida.
Aqui está um exemplo retirado do app Configurações 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>
No momento da renderização, o fragmento solicita uma lista de preferências da API
Configurações dinâmicas e XML definidas em AndroidManifest
. Se as
PreferenceController
s forem definidas em código Java ou em XML,
DashboardFragment
vai gerenciar a lógica de tratamento de cada configuração
por 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
Uma PreferenceController
contém toda a lógica para interagir com o
preferência, incluindo exibição, atualização, indexação de pesquisas, 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
mapeada para um estilo de interface específico compatível com o app Configurações 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.
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
das subclasses, como TogglePreferenceController
) é que
A assinatura do construtor precisa corresponder a um dos seguintes itens:
public MyController(Context context, String key) {}
public MyController(Context context) {}
Ao instalar uma preferência para o 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 ao controlador.
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()
e, se ele retornar "verdadeiro",
displayPreference()
será invocado para processar a lógica de exibição.
O getAvailabilityStatus()
também é importante para informar ao framework
de configurações quais itens estão disponíveis durante a pesquisa.
PreferenceController nas 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.
A interface de
PreferenceController
tem as APIs isAvailable()
,
displayPreference()
, handlePreferenceTreeClicked()
etc., de acordo com as interações de preferência.
A documentação detalhada de cada API pode ser encontrada na classe de interface.
Ao instalar uma preferência para o 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 ao controlador.
DashboardFragment
mantém uma lista de PreferenceControllers
na tela. No onCreate()
do fragmento, todos
são invocados para o método isAvailable()
e, se
retorna verdadeiro, displayPreference()
é invocado para processar a exibição
lógica.
Usar o DashboardFragment
Mover uma preferência da página A para B
Se a preferência estiver listada de forma estática no arquivo XML de preferência 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 movimento Dinâmico para sua versão do Android.
Movimento estático no Android 9
- Encontrar os arquivos XML de preferência para a página original e o destino
página. Você pode encontrar essas informações na página
getPreferenceScreenResId()
. - 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 Java da página original. Normalmente, é emcreatePreferenceControllers()
: O controlador pode ser declarado em XML diretamente.Observação: a preferência pode não ter um
PreferenceController
. - Instância o
PreferenceController
nocreatePreferenceControllers()
da página de destino. Se oPreferenceController
for definido em XML na página antiga, defina-o em XML para a nova página também.
Movimento dinâmico no Android 9
- Encontre a categoria que hospeda a página original e a de destino. Você pode
encontrar essa informação em
DashboardFragmentRegistry
. - Abra o arquivo
AndroidManifest.xml
que contém a configuração que você precisa se mover e encontrar a entrada Activity 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 nas versões do Android 8.x
- Encontre os arquivos XML de preferências da página original e da página de destino. Você pode encontrar 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
para essa preferência na implementação Java da página original. Geralmente, ele fica emgetPreferenceControllers()
. - Instancie o
PreferenceController
no elementogetPreferenceControllers()
.
getPreferenceScreenResId()
da página.
Observação: é possível que a preferência não tenha
PreferenceController
Movimento dinâmico nas versões do Android 8.x
- Descubra qual categoria hospeda a página original e a de destino. Confira
essas informações em
DashboardFragmentRegistry
. - Abra o arquivo
AndroidManifest.xml
que contém a configuração que você precisa se mover e encontrar a entrada Activity que representa essa configuração. - Mude o valor de metadados da atividade para
com.android.settings.category
. 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 estaticamente listada no 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ência para a página. Você pode encontrar essas informações do 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,
instanciar 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á exista um
PreferenceController
para ela. É possível reutilizar oPreferenceController
sem criar um novo. -
A partir do Android 9, é possível declarar os
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,
instanciar um
Criar uma preferência dinâmica
- Descubra qual categoria hospeda a página original e a de destino. Você pode encontrar
essas informações em
DashboardFragmentRegistry
. - Criar uma nova 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 no
DashboardFragmentRegistry
.Observação: esta etapa é opcional. Se você não precisar 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 a essa página. Para mais mais informações, consulte a seção Implementação.
Validação
- Execute os testes do Robolectric nas Configurações. Todos os testes novos e existentes precisam passar.
- Crie e instale as Configurações e abra manualmente a página que está sendo modificada. A página será atualizada imediatamente.