Merge changes from topic "credManSettings"
* changes: Calling isServiceEnabled with the context in credential manager settings Revert "Revert "Add Credential Manager settings""
This commit is contained in:
committed by
Android (Google) Code Review
commit
cf9fd9941d
@@ -126,6 +126,7 @@
|
||||
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
|
||||
<uses-permission android:name="android.permission.START_VIEW_APP_FEATURES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES" />
|
||||
<uses-permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS" />
|
||||
|
||||
<application
|
||||
android:name=".SettingsApplication"
|
||||
|
@@ -9805,8 +9805,12 @@
|
||||
<!-- AutoFill strings -->
|
||||
<!-- Preference label for choosing auto-fill service. [CHAR LIMIT=60] -->
|
||||
<string name="autofill_app">Autofill service</string>
|
||||
<!-- Preference label for choosing auto-fill service. [CHAR LIMIT=60] -->
|
||||
<string name="default_autofill_app">Default autofill service</string>
|
||||
<!-- Preference category for showing auto-fill services with saved passwords. [CHAR LIMIT=60] -->
|
||||
<string name="autofill_passwords">Passwords</string>
|
||||
<!-- Preference category for showing credman services with saved credentials. [CHAR LIMIT=60] -->
|
||||
<string name="credman_credentials">Password and identity services</string>
|
||||
<!-- Summary for passwords settings that shows how many passwords are saved for each autofill
|
||||
service. [CHAR LIMIT=NONE] -->
|
||||
<plurals name="autofill_passwords_count">
|
||||
@@ -9818,6 +9822,8 @@
|
||||
<string name="autofill_passwords_count_placeholder" translatable="false">\u2014</string>
|
||||
<!-- Keywords for the auto-fill feature. [CHAR LIMIT=NONE] -->
|
||||
<string name="autofill_keywords">auto, fill, autofill, password</string>
|
||||
<!-- Keywords for the credman feature. [CHAR LIMIT=NONE] -->
|
||||
<string name="credman_keywords">credentials, passkey, password</string>
|
||||
|
||||
<!-- Message of the warning dialog for setting the auto-fill app. [CHAR_LIMIT=NONE] -->
|
||||
<string name="autofill_confirmation_message">
|
||||
@@ -9830,6 +9836,21 @@
|
||||
]]>
|
||||
</string>
|
||||
|
||||
<!-- Title of the warning dialog for disabling the credential provider. [CHAR_LIMIT=NONE] -->
|
||||
<string name="credman_confirmation_message_title">Turn off %1$s\?</string>
|
||||
|
||||
<!-- Message of the warning dialog for disabling the credential provider. [CHAR_LIMIT=NONE] -->
|
||||
<string name="credman_confirmation_message">Saved info like addresses or payment methods won\'t be filled in when you sign in. To keep your saved info filled in, set a default autofill service.</string>
|
||||
|
||||
<!-- Title of the error dialog when too many credential providers are selected. [CHAR_LIMIT=NONE] -->
|
||||
<string name="credman_error_message_title">Password and identity services limit</string>
|
||||
|
||||
<!-- Message of the error dialog when too many credential providers are selected. [CHAR_LIMIT=NONE] -->
|
||||
<string name="credman_error_message">You can have up to 5 autofill and password services active at the same time. Turn off a service to add more.</string>
|
||||
|
||||
<!-- Positive button to turn off credential manager provider (confirmation). [CHAR LIMIT=60] -->
|
||||
<string name="credman_confirmation_message_positive_button">Turn off</string>
|
||||
|
||||
<!-- Preference category for autofill debugging development settings. [CHAR LIMIT=25] -->
|
||||
<string name="debug_autofill_category">Autofill</string>
|
||||
|
||||
|
79
res/xml/accounts_dashboard_settings_credman.xml
Normal file
79
res/xml/accounts_dashboard_settings_credman.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="user_and_account_settings_screen"
|
||||
android:title="@string/account_dashboard_title"
|
||||
settings:keywords="@string/keywords_accounts">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="default_service_category"
|
||||
android:order="10"
|
||||
android:title="@string/default_autofill_app">
|
||||
|
||||
<com.android.settings.widget.GearPreference
|
||||
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
|
||||
android:key="default_autofill_main"
|
||||
android:title="@string/default_autofill_app"
|
||||
settings:keywords="@string/autofill_keywords">
|
||||
<extra
|
||||
android:name="for_work"
|
||||
android:value="false" />
|
||||
</com.android.settings.widget.GearPreference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="credman_category"
|
||||
android:order="20"
|
||||
android:persistent="false"
|
||||
android:title="@string/credman_credentials"
|
||||
settings:controller="com.android.settings.applications.credentials.CredentialManagerPreferenceController"
|
||||
settings:keywords="@string/credman_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="passwords_category"
|
||||
android:order="30"
|
||||
android:persistent="false"
|
||||
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
|
||||
settings:keywords="@string/autofill_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="dashboard_tile_placeholder"
|
||||
android:order="130"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_account_data"
|
||||
android:title="@string/auto_sync_account_title"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="202"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_work_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_work"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
settings:forWork="true"
|
||||
android:order="203"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_personal_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_personal"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="204"/>
|
||||
|
||||
</PreferenceScreen>
|
73
res/xml/accounts_personal_dashboard_settings_credman.xml
Normal file
73
res/xml/accounts_personal_dashboard_settings_credman.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="user_and_account_settings_screen"
|
||||
android:title="@string/account_dashboard_title"
|
||||
settings:keywords="@string/keywords_accounts">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="default_service_category"
|
||||
android:order="10"
|
||||
android:title="@string/default_autofill_app">
|
||||
|
||||
<com.android.settings.widget.GearPreference
|
||||
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
|
||||
android:key="default_autofill_main"
|
||||
android:title="@string/default_autofill_app"
|
||||
settings:keywords="@string/autofill_keywords">
|
||||
<extra
|
||||
android:name="for_work"
|
||||
android:value="false" />
|
||||
</com.android.settings.widget.GearPreference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="credman_category"
|
||||
android:order="20"
|
||||
android:persistent="false"
|
||||
android:title="@string/credman_credentials"
|
||||
settings:controller="com.android.settings.applications.credentials.CredentialManagerPreferenceController"
|
||||
settings:keywords="@string/credman_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="passwords_category"
|
||||
android:order="30"
|
||||
android:persistent="false"
|
||||
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
|
||||
settings:keywords="@string/autofill_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="dashboard_tile_placeholder"
|
||||
android:order="130"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_account_data"
|
||||
android:title="@string/auto_sync_account_title"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="200"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_personal_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_personal"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="210"/>
|
||||
|
||||
</PreferenceScreen>
|
73
res/xml/accounts_work_dashboard_settings_credman.xml
Normal file
73
res/xml/accounts_work_dashboard_settings_credman.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="user_and_account_settings_screen"
|
||||
android:title="@string/account_dashboard_title"
|
||||
settings:keywords="@string/keywords_accounts">
|
||||
|
||||
<com.android.settings.widget.WorkOnlyCategory
|
||||
android:key="autofill_work_app_defaults"
|
||||
android:order="30"
|
||||
android:title="@string/default_autofill_app">
|
||||
|
||||
<com.android.settings.widget.GearPreference
|
||||
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
|
||||
android:key="default_autofill_work"
|
||||
android:title="@string/default_autofill_app"
|
||||
settings:searchable="false">
|
||||
<extra
|
||||
android:name="for_work"
|
||||
android:value="true" />
|
||||
</com.android.settings.widget.GearPreference>
|
||||
</com.android.settings.widget.WorkOnlyCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="credman_category"
|
||||
android:order="20"
|
||||
android:persistent="false"
|
||||
android:title="@string/credman_credentials"
|
||||
settings:controller="com.android.settings.applications.credentials.CredentialManagerPreferenceController"
|
||||
settings:keywords="@string/credman_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="passwords_category"
|
||||
android:order="30"
|
||||
android:persistent="false"
|
||||
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
|
||||
settings:keywords="@string/autofill_keywords" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="dashboard_tile_placeholder"
|
||||
android:order="130"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_account_data"
|
||||
android:title="@string/auto_sync_account_title"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="200"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_work_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_work"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="210"/>
|
||||
|
||||
</PreferenceScreen>
|
@@ -22,11 +22,14 @@ import android.accounts.AccountManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.credentials.CredentialManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.autofill.PasswordsPreferenceController;
|
||||
import com.android.settings.applications.credentials.CredentialManagerPreferenceController;
|
||||
import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
|
||||
import com.android.settings.applications.defaultapps.DefaultWorkAutofillPreferenceController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -44,10 +47,8 @@ import java.util.List;
|
||||
|
||||
@SearchIndexable
|
||||
public class AccountDashboardFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccountDashboardFrag";
|
||||
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCOUNT;
|
||||
@@ -60,7 +61,7 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accounts_dashboard_settings;
|
||||
return getPreferenceLayoutResId(this.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,6 +72,12 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (CredentialManager.isServiceEnabled(context)) {
|
||||
CredentialManagerPreferenceController cmpp =
|
||||
use(CredentialManagerPreferenceController.class);
|
||||
cmpp.setParentFragment(this);
|
||||
}
|
||||
|
||||
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
|
||||
}
|
||||
|
||||
@@ -95,11 +102,13 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
}
|
||||
|
||||
private static void buildAccountPreferenceControllers(
|
||||
Context context, DashboardFragment parent, String[] authorities,
|
||||
Context context,
|
||||
DashboardFragment parent,
|
||||
String[] authorities,
|
||||
List<AbstractPreferenceController> controllers) {
|
||||
final AccountPreferenceController accountPrefController =
|
||||
new AccountPreferenceController(context, parent, authorities,
|
||||
ProfileSelectFragment.ProfileType.ALL);
|
||||
new AccountPreferenceController(
|
||||
context, parent, authorities, ProfileSelectFragment.ProfileType.ALL);
|
||||
if (parent != null) {
|
||||
parent.getSettingsLifecycle().addObserver(accountPrefController);
|
||||
}
|
||||
@@ -109,8 +118,21 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
controllers.add(new AutoSyncWorkDataPreferenceController(context, parent));
|
||||
}
|
||||
|
||||
private static int getPreferenceLayoutResId(Context context) {
|
||||
return (context != null && CredentialManager.isServiceEnabled(context))
|
||||
? R.xml.accounts_dashboard_settings_credman
|
||||
: R.xml.accounts_dashboard_settings;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accounts_dashboard_settings) {
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = getPreferenceLayoutResId(context);
|
||||
return List.of(sir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractPreferenceController> createPreferenceControllers(
|
||||
@@ -124,11 +146,11 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
|
||||
@SuppressWarnings("MissingSuperCall") // TODO: Fix me
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
public List<SearchIndexableRaw> getDynamicRawDataToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final List<SearchIndexableRaw> indexRaws = new ArrayList<>();
|
||||
final UserManager userManager = (UserManager) context.getSystemService(
|
||||
Context.USER_SERVICE);
|
||||
final UserManager userManager =
|
||||
(UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
final List<UserInfo> profiles = userManager.getProfiles(UserHandle.myUserId());
|
||||
for (final UserInfo userInfo : profiles) {
|
||||
if (userInfo.isManagedProfile()) {
|
||||
|
@@ -22,9 +22,11 @@ import static com.android.settings.accounts.AccountDashboardFragment.buildAutofi
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.credentials.CredentialManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.autofill.PasswordsPreferenceController;
|
||||
import com.android.settings.applications.credentials.CredentialManagerPreferenceController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
|
||||
import com.android.settings.users.AutoSyncDataPreferenceController;
|
||||
@@ -34,11 +36,8 @@ import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Account Setting page for personal profile.
|
||||
*/
|
||||
/** Account Setting page for personal profile. */
|
||||
public class AccountPersonalDashboardFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccountPersonalFrag";
|
||||
|
||||
@Override
|
||||
@@ -53,6 +52,9 @@ public class AccountPersonalDashboardFragment extends DashboardFragment {
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
if (this.getContext() != null && CredentialManager.isServiceEnabled(this.getContext())) {
|
||||
return R.xml.accounts_personal_dashboard_settings_credman;
|
||||
}
|
||||
return R.xml.accounts_personal_dashboard_settings;
|
||||
}
|
||||
|
||||
@@ -64,6 +66,12 @@ public class AccountPersonalDashboardFragment extends DashboardFragment {
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (CredentialManager.isServiceEnabled(context)) {
|
||||
CredentialManagerPreferenceController cmpp =
|
||||
use(CredentialManagerPreferenceController.class);
|
||||
cmpp.setParentFragment(this);
|
||||
}
|
||||
|
||||
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
|
||||
}
|
||||
|
||||
@@ -77,11 +85,13 @@ public class AccountPersonalDashboardFragment extends DashboardFragment {
|
||||
}
|
||||
|
||||
private static void buildAccountPreferenceControllers(
|
||||
Context context, DashboardFragment parent, String[] authorities,
|
||||
Context context,
|
||||
DashboardFragment parent,
|
||||
String[] authorities,
|
||||
List<AbstractPreferenceController> controllers) {
|
||||
final AccountPreferenceController accountPrefController =
|
||||
new AccountPreferenceController(context, parent, authorities,
|
||||
ProfileSelectFragment.ProfileType.PERSONAL);
|
||||
new AccountPreferenceController(
|
||||
context, parent, authorities, ProfileSelectFragment.ProfileType.PERSONAL);
|
||||
if (parent != null) {
|
||||
parent.getSettingsLifecycle().addObserver(accountPrefController);
|
||||
}
|
||||
|
@@ -22,9 +22,11 @@ import static com.android.settings.accounts.AccountDashboardFragment.buildAutofi
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.credentials.CredentialManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.autofill.PasswordsPreferenceController;
|
||||
import com.android.settings.applications.credentials.CredentialManagerPreferenceController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
|
||||
import com.android.settings.users.AutoSyncDataPreferenceController;
|
||||
@@ -34,11 +36,8 @@ import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Account Setting page for work profile.
|
||||
*/
|
||||
/** Account Setting page for work profile. */
|
||||
public class AccountWorkProfileDashboardFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccountWorkProfileFrag";
|
||||
|
||||
@Override
|
||||
@@ -53,6 +52,9 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment {
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
if (this.getContext() != null && CredentialManager.isServiceEnabled(this.getContext())) {
|
||||
return R.xml.accounts_work_dashboard_settings_credman;
|
||||
}
|
||||
return R.xml.accounts_work_dashboard_settings;
|
||||
}
|
||||
|
||||
@@ -64,6 +66,12 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment {
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (CredentialManager.isServiceEnabled(context)) {
|
||||
CredentialManagerPreferenceController cmpp =
|
||||
use(CredentialManagerPreferenceController.class);
|
||||
cmpp.setParentFragment(this);
|
||||
}
|
||||
|
||||
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
|
||||
}
|
||||
|
||||
@@ -77,11 +85,13 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment {
|
||||
}
|
||||
|
||||
private static void buildAccountPreferenceControllers(
|
||||
Context context, DashboardFragment parent, String[] authorities,
|
||||
Context context,
|
||||
DashboardFragment parent,
|
||||
String[] authorities,
|
||||
List<AbstractPreferenceController> controllers) {
|
||||
final AccountPreferenceController accountPrefController =
|
||||
new AccountPreferenceController(context, parent, authorities,
|
||||
ProfileSelectFragment.ProfileType.WORK);
|
||||
new AccountPreferenceController(
|
||||
context, parent, authorities, ProfileSelectFragment.ProfileType.WORK);
|
||||
if (parent != null) {
|
||||
parent.getSettingsLifecycle().addObserver(accountPrefController);
|
||||
}
|
||||
|
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.credentials;
|
||||
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.credentials.CredentialManager;
|
||||
import android.credentials.ListEnabledProvidersException;
|
||||
import android.credentials.ListEnabledProvidersResponse;
|
||||
import android.credentials.SetEnabledProvidersException;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.UserHandle;
|
||||
import android.service.credentials.CredentialProviderInfo;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/** Queries available credential manager providers and adds preferences for them. */
|
||||
public class CredentialManagerPreferenceController extends BasePreferenceController
|
||||
implements LifecycleObserver {
|
||||
private static final String TAG = "CredentialManagerPreferenceController";
|
||||
private static final int MAX_SELECTABLE_PROVIDERS = 5;
|
||||
|
||||
private final PackageManager mPm;
|
||||
private final IconDrawableFactory mIconFactory;
|
||||
private final List<ServiceInfo> mServices;
|
||||
private final Set<String> mEnabledPackageNames;
|
||||
private final @Nullable CredentialManager mCredentialManager;
|
||||
private final CancellationSignal mCancellationSignal = new CancellationSignal();
|
||||
private final Executor mExecutor;
|
||||
|
||||
private @Nullable DashboardFragment mParentFragment = null;
|
||||
|
||||
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mPm = context.getPackageManager();
|
||||
mIconFactory = IconDrawableFactory.newInstance(mContext);
|
||||
mServices = new ArrayList<>();
|
||||
mEnabledPackageNames = new HashSet<>();
|
||||
mExecutor = ContextCompat.getMainExecutor(mContext);
|
||||
mCredentialManager =
|
||||
getCredentialManager(context, preferenceKey.equals("credentials_test"));
|
||||
}
|
||||
|
||||
private @Nullable CredentialManager getCredentialManager(Context context, boolean isTest) {
|
||||
if (isTest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object service = context.getSystemService(Context.CREDENTIAL_SERVICE);
|
||||
|
||||
if (service != null && CredentialManager.isServiceEnabled(context)) {
|
||||
return (CredentialManager) service;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isConnected() {
|
||||
return mCredentialManager != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent fragment and attaches this controller to the settings lifecycle.
|
||||
*
|
||||
* @param fragment the fragment to use as the parent
|
||||
*/
|
||||
public void setParentFragment(DashboardFragment fragment) {
|
||||
mParentFragment = fragment;
|
||||
fragment.getSettingsLifecycle().addObserver(this);
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_CREATE)
|
||||
void onCreate(LifecycleOwner lifecycleOwner) {
|
||||
if (mCredentialManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCredentialManager.listEnabledProviders(
|
||||
mCancellationSignal,
|
||||
mExecutor,
|
||||
new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() {
|
||||
@Override
|
||||
public void onResult(ListEnabledProvidersResponse result) {
|
||||
Set<String> enabledPackages = new HashSet<>();
|
||||
for (String flattenedComponentName : result.getProviderComponentNames()) {
|
||||
ComponentName cn =
|
||||
ComponentName.unflattenFromString(flattenedComponentName);
|
||||
if (cn != null) {
|
||||
enabledPackages.add(cn.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
List<ServiceInfo> services = new ArrayList<>();
|
||||
for (CredentialProviderInfo cpi :
|
||||
CredentialProviderInfo.getAvailableServices(mContext, getUser())) {
|
||||
services.add(cpi.getServiceInfo());
|
||||
}
|
||||
|
||||
init(lifecycleOwner, services, enabledPackages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ListEnabledProvidersException e) {
|
||||
Log.e(TAG, "listEnabledProviders error: " + e.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void init(
|
||||
LifecycleOwner lifecycleOwner,
|
||||
List<ServiceInfo> availableServices,
|
||||
Set<String> enabledPackages) {
|
||||
mServices.clear();
|
||||
mServices.addAll(availableServices);
|
||||
|
||||
mEnabledPackageNames.clear();
|
||||
mEnabledPackageNames.addAll(enabledPackages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mServices.isEmpty() ? CONDITIONALLY_UNAVAILABLE : AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
||||
Context context = screen.getContext();
|
||||
|
||||
for (ServiceInfo serviceInfo : mServices) {
|
||||
CharSequence title = "";
|
||||
if (serviceInfo.nonLocalizedLabel != null) {
|
||||
title = serviceInfo.loadLabel(mPm);
|
||||
}
|
||||
|
||||
group.addPreference(
|
||||
addProviderPreference(
|
||||
context,
|
||||
title,
|
||||
mIconFactory.getBadgedIcon(
|
||||
serviceInfo, serviceInfo.applicationInfo, getUser()),
|
||||
serviceInfo.packageName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the package name as an enabled credential manager provider.
|
||||
*
|
||||
* @param packageName the package name to enable
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public boolean togglePackageNameEnabled(String packageName) {
|
||||
if (mEnabledPackageNames.size() >= MAX_SELECTABLE_PROVIDERS) {
|
||||
return false;
|
||||
} else {
|
||||
mEnabledPackageNames.add(packageName);
|
||||
commitEnabledPackages();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the package name as a credential manager provider.
|
||||
*
|
||||
* @param packageName the package name to disable
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void togglePackageNameDisabled(String packageName) {
|
||||
mEnabledPackageNames.remove(packageName);
|
||||
commitEnabledPackages();
|
||||
}
|
||||
|
||||
/** Returns the enabled credential manager provider package names. */
|
||||
@VisibleForTesting
|
||||
public Set<String> getEnabledProviders() {
|
||||
return mEnabledPackageNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enabled credential manager provider flattened component names that can be stored
|
||||
* in the setting.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public List<String> getEnabledSettings() {
|
||||
// Get all the component names that match the enabled package names.
|
||||
List<String> enabledServices = new ArrayList<>();
|
||||
for (ServiceInfo service : mServices) {
|
||||
if (mEnabledPackageNames.contains(service.packageName)) {
|
||||
enabledServices.add(service.getComponentName().flattenToString());
|
||||
}
|
||||
}
|
||||
|
||||
return enabledServices;
|
||||
}
|
||||
|
||||
private SwitchPreference addProviderPreference(
|
||||
@NonNull Context prefContext,
|
||||
@NonNull CharSequence title,
|
||||
@Nullable Drawable icon,
|
||||
@NonNull String packageName) {
|
||||
final SwitchPreference pref = new SwitchPreference(prefContext);
|
||||
pref.setTitle(title);
|
||||
pref.setChecked(mEnabledPackageNames.contains(packageName));
|
||||
|
||||
if (icon != null) {
|
||||
pref.setIcon(Utils.getSafeIcon(icon));
|
||||
}
|
||||
|
||||
pref.setOnPreferenceClickListener(
|
||||
p -> {
|
||||
boolean isChecked = pref.isChecked();
|
||||
|
||||
if (isChecked) {
|
||||
// Show the error if too many enabled.
|
||||
if (!togglePackageNameEnabled(packageName)) {
|
||||
final DialogFragment fragment = newErrorDialogFragment();
|
||||
|
||||
if (fragment == null || mParentFragment == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fragment.show(
|
||||
mParentFragment.getActivity().getSupportFragmentManager(),
|
||||
ErrorDialogFragment.TAG);
|
||||
|
||||
// The user set the check to true so we need to set it back.
|
||||
pref.setChecked(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// Show the confirm disable dialog.
|
||||
final DialogFragment fragment =
|
||||
newConfirmationDialogFragment(packageName, title, pref);
|
||||
|
||||
if (fragment == null || mParentFragment == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fragment.show(
|
||||
mParentFragment.getActivity().getSupportFragmentManager(),
|
||||
ConfirmationDialogFragment.TAG);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void commitEnabledPackages() {
|
||||
// Commit using the CredMan API.
|
||||
if (mCredentialManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> enabledServices = getEnabledSettings();
|
||||
mCredentialManager.setEnabledProviders(
|
||||
enabledServices,
|
||||
getUser(),
|
||||
mExecutor,
|
||||
new OutcomeReceiver<Void, SetEnabledProvidersException>() {
|
||||
@Override
|
||||
public void onResult(Void result) {
|
||||
Log.i(TAG, "setEnabledProviders success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(SetEnabledProvidersException e) {
|
||||
Log.e(TAG, "setEnabledProviders error: " + e.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private @Nullable ConfirmationDialogFragment newConfirmationDialogFragment(
|
||||
@NonNull String packageName,
|
||||
@NonNull CharSequence appName,
|
||||
@NonNull SwitchPreference pref) {
|
||||
DialogHost host =
|
||||
new DialogHost() {
|
||||
@Override
|
||||
public DashboardFragment getParentFragment() {
|
||||
return mParentFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogClick(int whichButton) {
|
||||
if (whichButton == DialogInterface.BUTTON_POSITIVE) {
|
||||
// Since the package is now enabled then we
|
||||
// should remove it from the enabled list.
|
||||
togglePackageNameDisabled(packageName);
|
||||
} else if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
|
||||
// Set the checked back to true because we
|
||||
// backed out of turning this off.
|
||||
pref.setChecked(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (host.getParentFragment() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ConfirmationDialogFragment(host, packageName, appName);
|
||||
}
|
||||
|
||||
private @Nullable ErrorDialogFragment newErrorDialogFragment() {
|
||||
DialogHost host =
|
||||
new DialogHost() {
|
||||
@Override
|
||||
public DashboardFragment getParentFragment() {
|
||||
return mParentFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogClick(int whichButton) {}
|
||||
};
|
||||
|
||||
if (host.getParentFragment() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ErrorDialogFragment(host);
|
||||
}
|
||||
|
||||
private int getUser() {
|
||||
UserHandle workUser = getWorkProfileUser();
|
||||
return workUser != null ? workUser.getIdentifier() : UserHandle.myUserId();
|
||||
}
|
||||
|
||||
/** Called when the dialog button is clicked. */
|
||||
private interface DialogHost {
|
||||
void onDialogClick(int whichButton);
|
||||
|
||||
DashboardFragment getParentFragment();
|
||||
}
|
||||
|
||||
/** Dialog fragment parent class. */
|
||||
private abstract static class CredentialManagerDialogFragment extends InstrumentedDialogFragment
|
||||
implements DialogInterface.OnClickListener {
|
||||
|
||||
public static final String TAG = "CredentialManagerDialogFragment";
|
||||
public static final String PACKAGE_NAME_KEY = "package_name";
|
||||
public static final String APP_NAME_KEY = "app_name";
|
||||
|
||||
private DialogHost mDialogHost;
|
||||
|
||||
CredentialManagerDialogFragment(DialogHost dialogHost) {
|
||||
super();
|
||||
setTargetFragment(dialogHost.getParentFragment(), 0);
|
||||
mDialogHost = dialogHost;
|
||||
}
|
||||
|
||||
public DialogHost getDialogHost() {
|
||||
return mDialogHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
/** Dialog showing error when too many providers are selected. */
|
||||
private static class ErrorDialogFragment extends CredentialManagerDialogFragment {
|
||||
|
||||
ErrorDialogFragment(DialogHost dialogHost) {
|
||||
super(dialogHost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(getContext().getString(R.string.credman_error_message_title))
|
||||
.setMessage(getContext().getString(R.string.credman_error_message))
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirmation dialog fragment shows a dialog to the user to confirm that they are disabling a
|
||||
* provider.
|
||||
*/
|
||||
private static class ConfirmationDialogFragment extends CredentialManagerDialogFragment {
|
||||
|
||||
ConfirmationDialogFragment(
|
||||
DialogHost dialogHost, @NonNull String packageName, @NonNull CharSequence appName) {
|
||||
super(dialogHost);
|
||||
|
||||
final Bundle argument = new Bundle();
|
||||
argument.putString(PACKAGE_NAME_KEY, packageName);
|
||||
argument.putCharSequence(APP_NAME_KEY, appName);
|
||||
setArguments(argument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Bundle bundle = getArguments();
|
||||
final String title =
|
||||
getContext()
|
||||
.getString(
|
||||
R.string.credman_confirmation_message_title,
|
||||
bundle.getCharSequence(
|
||||
CredentialManagerDialogFragment.APP_NAME_KEY));
|
||||
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(title)
|
||||
.setMessage(getContext().getString(R.string.credman_confirmation_message))
|
||||
.setPositiveButton(R.string.credman_confirmation_message_positive_button, this)
|
||||
.setNegativeButton(android.R.string.cancel, this)
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
getDialogHost().onDialogClick(which);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.credentials;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class CredentialManagerPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private PreferenceScreen mScreen;
|
||||
private PreferenceCategory mCredentialsPreferenceCategory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
if (Looper.myLooper() == null) {
|
||||
Looper.prepare(); // needed to create the preference screen
|
||||
}
|
||||
mScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
|
||||
mCredentialsPreferenceCategory = new PreferenceCategory(mContext);
|
||||
mCredentialsPreferenceCategory.setKey("credentials_test");
|
||||
mScreen.addPreference(mCredentialsPreferenceCategory);
|
||||
}
|
||||
|
||||
@Test
|
||||
// Tests that getAvailabilityStatus() does not throw an exception if it's called before the
|
||||
// Controller is initialized (this can happen during indexing).
|
||||
public void getAvailabilityStatus_withoutInit_returnsUnavailable() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
new CredentialManagerPreferenceController(
|
||||
mContext, mCredentialsPreferenceCategory.getKey());
|
||||
assertThat(controller.isConnected()).isFalse();
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noServices_returnsUnavailable() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(Collections.emptyList());
|
||||
assertThat(controller.isConnected()).isFalse();
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_withServices_returnsAvailable() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(Lists.newArrayList(createServiceInfo()));
|
||||
assertThat(controller.isConnected()).isFalse();
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_noServices_noPreferencesAdded() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(Collections.emptyList());
|
||||
controller.displayPreference(mScreen);
|
||||
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_withServices_preferencesAdded() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(Lists.newArrayList(createServiceInfo()));
|
||||
controller.displayPreference(mScreen);
|
||||
assertThat(controller.isConnected()).isFalse();
|
||||
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_handlesToggleAndSave() {
|
||||
CredentialManagerPreferenceController controller =
|
||||
createControllerWithServices(
|
||||
Lists.newArrayList(
|
||||
createServiceInfo("com.android.provider1", "ClassA"),
|
||||
createServiceInfo("com.android.provider1", "ClassB"),
|
||||
createServiceInfo("com.android.provider2", "ClassA"),
|
||||
createServiceInfo("com.android.provider3", "ClassA"),
|
||||
createServiceInfo("com.android.provider4", "ClassA"),
|
||||
createServiceInfo("com.android.provider5", "ClassA"),
|
||||
createServiceInfo("com.android.provider6", "ClassA")));
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
assertThat(controller.isConnected()).isFalse();
|
||||
|
||||
// Ensure that we stay under 5 providers.
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider2")).isTrue();
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider3")).isTrue();
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider4")).isTrue();
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider5")).isTrue();
|
||||
assertThat(controller.togglePackageNameEnabled("com.android.provider6")).isFalse();
|
||||
|
||||
// Check that they are all actually registered.
|
||||
Set<String> enabledProviders = controller.getEnabledProviders();
|
||||
assertThat(enabledProviders.size()).isEqualTo(5);
|
||||
assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
|
||||
assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
|
||||
assertThat(enabledProviders.contains("com.android.provider3")).isTrue();
|
||||
assertThat(enabledProviders.contains("com.android.provider4")).isTrue();
|
||||
assertThat(enabledProviders.contains("com.android.provider5")).isTrue();
|
||||
assertThat(enabledProviders.contains("com.android.provider6")).isFalse();
|
||||
|
||||
// Check that the settings string has the right component names.
|
||||
List<String> enabledServices = controller.getEnabledSettings();
|
||||
assertThat(enabledServices.size()).isEqualTo(6);
|
||||
assertThat(enabledServices.contains("com.android.provider1/ClassA")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider1/ClassB")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider3/ClassA")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider4/ClassA")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider5/ClassA")).isTrue();
|
||||
assertThat(enabledServices.contains("com.android.provider6/ClassA")).isFalse();
|
||||
|
||||
// Toggle the provider disabled.
|
||||
controller.togglePackageNameDisabled("com.android.provider2");
|
||||
|
||||
// Check that the provider was removed from the list of providers.
|
||||
Set<String> currentlyEnabledProviders = controller.getEnabledProviders();
|
||||
assertThat(currentlyEnabledProviders.size()).isEqualTo(4);
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider1")).isTrue();
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider2")).isFalse();
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider3")).isTrue();
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider4")).isTrue();
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider5")).isTrue();
|
||||
assertThat(currentlyEnabledProviders.contains("com.android.provider6")).isFalse();
|
||||
|
||||
// Check that the provider was removed from the list of services stored in the setting.
|
||||
List<String> currentlyEnabledServices = controller.getEnabledSettings();
|
||||
assertThat(currentlyEnabledServices.size()).isEqualTo(5);
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider1/ClassA")).isTrue();
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider1/ClassB")).isTrue();
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider3/ClassA")).isTrue();
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider4/ClassA")).isTrue();
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider5/ClassA")).isTrue();
|
||||
assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse();
|
||||
}
|
||||
|
||||
private CredentialManagerPreferenceController createControllerWithServices(
|
||||
List<ServiceInfo> availableServices) {
|
||||
CredentialManagerPreferenceController controller =
|
||||
new CredentialManagerPreferenceController(
|
||||
mContext, mCredentialsPreferenceCategory.getKey());
|
||||
controller.init(() -> mock(Lifecycle.class), availableServices, new HashSet<>());
|
||||
return controller;
|
||||
}
|
||||
|
||||
private ServiceInfo createServiceInfo() {
|
||||
return createServiceInfo("com.android.provider", "CredManProvider");
|
||||
}
|
||||
|
||||
private ServiceInfo createServiceInfo(String packageName, String className) {
|
||||
ServiceInfo si = new ServiceInfo();
|
||||
si.packageName = packageName;
|
||||
si.name = className;
|
||||
si.nonLocalizedLabel = "test";
|
||||
|
||||
si.applicationInfo = new ApplicationInfo();
|
||||
si.applicationInfo.packageName = packageName;
|
||||
si.applicationInfo.nonLocalizedLabel = "test";
|
||||
|
||||
return si;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user