O Android 8.0 introduziu uma nova arquitetura de informações para o aplicativo Configurações para simplificar a forma como as configurações são organizadas e tornar mais fácil para os usuários encontrarem rapidamente configurações para personalizar seus dispositivos Android. O Android 9 introduziu algumas melhorias para fornecer mais funcionalidades de configurações e implementação mais fácil.
Exemplos e fonte
A maioria das páginas em Configurações estão atualmente implementadas usando a nova estrutura. 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 (introduzido no Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Implementação
Os fabricantes de dispositivos são incentivados a adaptar a arquitetura de informações de configurações existente e inserir páginas de configurações adicionais conforme necessário para acomodar recursos específicos do parceiro. Mover preferências de uma página herdada (implementada como SettingsPreferencePage
) para uma nova página (implementada usando DashboardFragment
) pode ser complicado. A preferência da página herdada provavelmente não é implementada com um PreferenceController
.
Portanto, ao mover preferências de uma página legada para uma nova página, você precisa criar um PreferenceController
e mover o código para o controlador antes de instanciá-lo no novo DashboardFragment
. As APIs exigidas PreferenceController
são descritas em seus nomes e documentadas em 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 obter mais informações sobre como escrever testes baseados em Robolectric, consulte o arquivo leia-me packages/apps/Settings/tests/robotests/README.md
.
Arquitetura de informação 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 de plug-in que contém itens de configuração. Os itens de configuração são modelados como controladores estilo plugin. Conseqüentemente, uma página de configurações é construída por um único fragmento de host e vários controladores de configuração.
Fragmento do painel
DashboardFragment
é o host de controladores de preferência estilo plugin. O fragmento herda de PreferenceFragment
e possui ganchos para expandir e atualizar listas de preferências estáticas e listas de preferências dinâmicas.
Preferências estáticas
Uma lista de preferências estáticas é definida em XML usando a tag <Preference>
. Uma implementação DashboardFragment
usa o 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 intenção, levando a uma Atividade externa ou interna. Normalmente, a intenção leva a uma página de configuração diferente. Por exemplo, o item de configuração "Google" na página inicial de Configurações é um item dinâmico. Itens dinâmicos são definidos em AndroidManifest
(discutido abaixo) e carregados por meio de um FeatureProvider
(definido como DashboardFeatureProvider
).
As configurações dinâmicas são mais pesadas do que as configurações configuradas estaticamente, portanto, normalmente os desenvolvedores devem implementar a configuração como estática. No entanto, a configuração dinâmica pode ser útil quando qualquer uma das seguintes situações for verdadeira:
- A configuração não é implementada diretamente no aplicativo Configurações (como injetar uma configuração implementada por aplicativos OEM/Carrier).
- A configuração deve aparecer na página inicial de Configurações.
- Você já tem uma atividade para a configuração e não deseja 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 filtro de intenção à atividade.
- Informe ao aplicativo 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.
Aqui está um exemplo retirado do aplicativo 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 solicitará uma lista de preferências do XML estático e das configurações dinâmicas definidas em AndroidManifest
. Quer os PreferenceController
s sejam definidos em código Java ou em XML, DashboardFragment
gerencia a lógica de manipulação de cada configuração por meio de PreferenceController
(discutido abaixo). Em seguida, eles são exibidos na UI como uma lista mista.
Controlador de preferência
Existem diferenças entre a implementação PreferenceController
no Android 9 e no Android 8.x, conforme descrito nesta seção.
PreferenceController na versão 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
Existem várias subclasses de BasePreferenceController
, cada uma mapeada para um estilo de UI específico que o aplicativo Configurações suporta por padrão. Por exemplo, TogglePreferenceController
possui uma API que mapeia diretamente como o usuário deve interagir com uma IU de preferência baseada em alternância.
BasePreferenceController
possui APIs como getAvailabilityStatus()
, displayPreference()
, handlePreferenceTreeClicked(),
etc. A documentação detalhada para cada API está na classe de interface.
Uma restrição na implementação BasePreferenceController
(e suas subclasses, como TogglePreferenceController
) é que a assinatura do construtor deve corresponder a um dos seguintes:
-
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 horário de exibição. No momento da instalação, o controlador é conectado ao fragmento para que todos os eventos futuros relevantes 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 retornar verdadeiro, displayPreference()
é invocado para processar a lógica de exibição. getAvailabilityStatus()
também é importante para informar à estrutura 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 e indexação de pesquisa. etc.
Correspondendo às interações de preferência, a interface de PreferenceController
possui APIs isAvailable()
, displayPreference()
, handlePreferenceTreeClicked()
etc. Documentação detalhada sobre 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 horário de exibição. No momento da instalação, o controlador é conectado ao fragmento para que todos os eventos futuros relevantes sejam enviados ao controlador.
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 retornar verdadeiro, displayPreference()
é invocado para processar a lógica de exibição.
Usando DashboardFragment
Movendo uma preferência da página A para B
Se a preferência estiver listada estaticamente no arquivo XML de preferências da página original, siga o procedimento de movimentação estática para sua versão do Android abaixo. Caso contrário, siga o procedimento de movimentação dinâmica para a versão do Android.
Movimento estático no Android 9
- Encontre os arquivos XML de preferência para a página original e a página de destino. Você pode encontrar 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 Java da página original. Geralmente está emcreatePreferenceControllers()
. O controlador pode ser declarado diretamente em XML.Nota : 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 também em XML para a nova página.
Movimento dinâmico no Android 9
- Descubra qual categoria a página original e de destino hospeda. 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 Activity que representa essa configuração. - Defina o valor dos metadados da atividade para
com.android.settings.category
como a chave de categoria da nova página.
Movimento estático nas versões do Android 8.x
- Encontre os arquivos XML de preferência para a página original e a 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
dessa preferência na implementação Java da página original. Geralmente está emgetPreferenceControllers()
. - Instancie o
PreferenceController
nogetPreferenceControllers()
da página de destino.
getPreferenceScreenResId()
da página. Nota : É possível que a preferência não possua um PreferenceController
.
Movimento dinâmico nas versões do Android 8.x
- Descubra qual categoria a página original e de destino hospeda. 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 Activity que representa essa configuração. - Altere o valor dos metadados da atividade para
com.android.settings.category
e defina o ponto de valor para a chave de categoria da nova página.
Criando uma nova preferência em uma página
Se a preferência estiver listada estaticamente no arquivo XML de preferências da página original, siga o procedimento estático abaixo. Caso contrário, siga o procedimento dinâmico .
Criando uma preferência estática
- Encontre os arquivos XML de preferência para a página. Você pode encontrar essas informações no método getPreferenceScreenResId() da página.
- Adicione um novo item de preferência no XML. Certifique-se de que ele tenha um
android:key
exclusivo. - Defina um
PreferenceController
para esta preferência no métodogetPreferenceControllers()
da página.- No Android 8.xe opcionalmente no Android 9, instancie um
PreferenceController
para essa preferência no métodocreatePreferenceControllers()
da página.Se esta preferência já existia em outros locais, é possível que já exista um
PreferenceController
para ela. Você pode reutilizar oPreferenceController
sem criar um novo. - A partir do Android 9, você pode optar por declarar o
PreferenceController
em XML ao lado da preferência. Por exemplo:<Preference android:key="reset_dashboard" android:title="@string/reset_dashboard_title" settings:controller="com.android.settings.system.ResetPreferenceController"/>
- No Android 8.xe opcionalmente no Android 9, instancie um
Criando uma preferência dinâmica
- Descubra qual categoria a página original e de destino hospeda. Você pode encontrar essas informações em
DashboardFragmentRegistry
. - Crie uma nova atividade no
AndroidManifest
- Adicione os metadados necessários à nova atividade para definir a configuração. Defina o valor dos metadados para
com.android.settings.category
com o mesmo valor definido na etapa 1.
Crie uma nova página
- Crie um novo fragmento, herdando de
DashboardFragment
. - Defina sua categoria em
DashboardFragmentRegistry
.Nota: Esta etapa é opcional. Se não precisar de nenhuma preferência dinâmica 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 obter mais informações, consulte a seção Implementação .
Validação
- Execute os testes robolétricos em Configurações. Todos os testes existentes e novos devem passar.
- Crie e instale as configurações e abra manualmente a página que está sendo modificada. A página deve ser atualizada imediatamente.