From 52ba133285d7bbdb762cc7a5bd678f6fe390b819 Mon Sep 17 00:00:00 2001 From: Prabal Singh Date: Tue, 6 Dec 2022 14:28:10 +0000 Subject: [PATCH] Create MoreSecurtiyPrivacyFragment Created a new MoreSecurityPrivacyFragment, a new more_security_privacy_settings xml. This more_security_privacy_settings xml is a created by merging privacy_advanced_settings.xml and security_advanced_settings.xml and the MoreSecurityPrivacyFragment is created by merging PrivacyDashboardFragment and SecurityAdvancedSettings fragments. Test: adb shell am start -a com.android.settings.security.MORE_SECURITY_PRIVACY_SETTINGS Bug: b/261557620 Change-Id: I8729f4eaf25a31f91354383e7b6cb5e0fc7df976 --- AndroidManifest.xml | 14 ++ res/values/strings.xml | 9 + res/xml/more_security_privacy_settings.xml | 227 ++++++++++++++++++ res/xml/security_advanced_settings.xml | 2 +- src/com/android/settings/Settings.java | 2 + .../core/gateway/SettingsGateway.java | 2 + .../privacy/PrivacyDashboardFragment.java | 53 ++-- .../MoreSecurityPrivacyFragment.java | 155 ++++++++++++ .../safetycenter/SafetyCenterUtils.java | 191 +++++++++++++++ .../security/SecurityAdvancedSettings.java | 72 ++---- .../src/com/android/settings/TestUtils.java | 41 ++++ .../privacy/PrivacyDashboardFragmentTest.java | 77 ++++++ ...reSecurityPrivacyFragmentSettingsTest.java | 102 ++++++++ .../SecurityAdvancedSettingsTest.java | 17 ++ .../security/SecuritySettingsTest.java | 46 +--- 15 files changed, 889 insertions(+), 121 deletions(-) create mode 100644 res/xml/more_security_privacy_settings.xml create mode 100644 src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java create mode 100644 src/com/android/settings/safetycenter/SafetyCenterUtils.java create mode 100644 tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java create mode 100644 tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b5818c2b541..d357e8c40fe 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1875,6 +1875,20 @@ android:value="@string/menu_key_security"/> + + + + + + + + + More privacy settings + + More settings + + Security + + Privacy + + Work profile + You can add up to %d fingerprints diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml new file mode 100644 index 00000000000..ae4153434e8 --- /dev/null +++ b/res/xml/more_security_privacy_settings.xml @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/security_advanced_settings.xml b/res/xml/security_advanced_settings.xml index f57ab9a1255..c8ce420b4f1 100644 --- a/res/xml/security_advanced_settings.xml +++ b/res/xml/security_advanced_settings.xml @@ -110,7 +110,7 @@ diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 0c58fff09e0..f9671b0e4af 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -209,6 +209,8 @@ public class Settings extends SettingsActivity { } /** Activity for the Advanced security settings. */ public static class SecurityAdvancedSettings extends SettingsActivity { /* empty */ } + /** Activity for the More settings page. */ + public static class MoreSecurityPrivacySettingsActivity extends SettingsActivity { /* empty */ } public static class UsageAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class AppUsageAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class LocationSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 5d80193a208..708f317994e 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -165,6 +165,7 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.privacy.PrivacyControlsFragment; import com.android.settings.privacy.PrivacyDashboardFragment; import com.android.settings.regionalpreferences.RegionalPreferencesEntriesFragment; +import com.android.settings.safetycenter.MoreSecurityPrivacyFragment; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.MemtagPage; import com.android.settings.security.SecurityAdvancedSettings; @@ -240,6 +241,7 @@ public class SettingsGateway { LocationServices.class.getName(), SecuritySettings.class.getName(), SecurityAdvancedSettings.class.getName(), + MoreSecurityPrivacyFragment.class.getName(), UsageAccessDetails.class.getName(), PrivacySettings.class.getName(), DeviceAdminSettings.class.getName(), diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java index 46a05b06109..045405b0d24 100644 --- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java +++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java @@ -16,12 +16,6 @@ package com.android.settings.privacy; -import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY; - import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; @@ -32,23 +26,20 @@ import android.provider.SearchIndexableResource; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.notification.LockScreenNotificationPreferenceController; import com.android.settings.safetycenter.SafetyCenterManagerWrapper; +import com.android.settings.safetycenter.SafetyCenterUtils; +import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @SearchIndexable public class PrivacyDashboardFragment extends DashboardFragment { private static final String TAG = "PrivacyDashboardFrag"; - private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "privacy_lock_screen_notifications"; - private static final String KEY_WORK_PROFILE_CATEGORY = - "privacy_work_profile_notifications_category"; private static final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS = "privacy_lock_screen_work_profile_notifications"; @@ -65,18 +56,13 @@ public class PrivacyDashboardFragment extends DashboardFragment { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - replaceEnterpriseStringTitle("privacy_lock_screen_work_profile_notifications", - WORK_PROFILE_LOCKED_NOTIFICATION_TITLE, - R.string.locked_work_profile_notification_title); - replaceEnterpriseStringTitle("interact_across_profiles_privacy", - CONNECTED_WORK_AND_PERSONAL_APPS_TITLE, R.string.interact_across_profiles_title); - replaceEnterpriseStringTitle("privacy_work_profile_notifications_category", - WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, R.string.profile_section_header); - replaceEnterpriseStringTitle("work_policy_info", - WORK_PROFILE_PRIVACY_POLICY_INFO, R.string.work_policy_privacy_settings); - replaceEnterpriseStringSummary("work_policy_info", - WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY, - R.string.work_policy_privacy_settings_summary); + List privacyOverrideStrings = + SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries(); + for (int i = 0; i < privacyOverrideStrings.size(); i++) { + EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i); + replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), + overrideString.getOverrideKey(), overrideString.getResource()); + } } @Override @@ -104,26 +90,21 @@ public class PrivacyDashboardFragment extends DashboardFragment { private static List buildPreferenceControllers( Context context, Lifecycle lifecycle) { - final List controllers = new ArrayList<>(); - final LockScreenNotificationPreferenceController notificationController = - new LockScreenNotificationPreferenceController(context, - KEY_LOCK_SCREEN_NOTIFICATIONS, - KEY_WORK_PROFILE_CATEGORY, - KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS); - if (lifecycle != null) { - lifecycle.addObserver(notificationController); - } - controllers.add(notificationController); - - return controllers; - + return SafetyCenterUtils.getControllersForAdvancedPrivacy(context, lifecycle); } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { + /** + * If SafetyCenter is enabled, all of these entries will be in the More Settings + * page, and we don't want to index these entries. + */ @Override public List getXmlResourcesToIndex( Context context, boolean enabled) { + if (SafetyCenterManagerWrapper.get().isEnabled(context)) { + return null; + } final SearchIndexableResource sir = new SearchIndexableResource(context); sir.xmlResId = getPreferenceScreenResId(context); return Arrays.asList(sir); diff --git a/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java new file mode 100644 index 00000000000..95732f433ea --- /dev/null +++ b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2023 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.safetycenter; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.SearchIndexableResource; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.security.LockUnificationPreferenceController; +import com.android.settings.security.trustagent.TrustAgentListPreferenceController; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +/** + * An overflow menu for {@code SecuritySettings} containing advanced security and privacy settings. + * + *

This also includes all work-profile related settings. + */ +@SearchIndexable +public class MoreSecurityPrivacyFragment extends DashboardFragment { + private static final String TAG = "MoreSecurityPrivacyFragment"; + private static final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS = + "privacy_lock_screen_work_profile_notifications"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.MORE_SECURITY_PRIVACY_SETTINGS; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.more_security_privacy_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + List privacyOverrideStrings = + SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries(); + for (int i = 0; i < privacyOverrideStrings.size(); i++) { + EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i); + replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), + overrideString.getOverrideKey(), overrideString.getResource()); + } + List securityOverrideStrings = + SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries(); + for (int i = 0; i < securityOverrideStrings.size(); i++) { + EnterpriseOverrideString overrideString = securityOverrideStrings.get(i); + replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), + overrideString.getOverrideKey(), overrideString.getResource()); + } + } + + /** + * see confirmPatternThenDisableAndClear + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (use(TrustAgentListPreferenceController.class) + .handleActivityResult(requestCode, resultCode)) { + return; + } + if (use(LockUnificationPreferenceController.class) + .handleActivityResult(requestCode, resultCode, data)) { + return; + } + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/); + } + + private static List buildPreferenceControllers( + Context context, Lifecycle lifecycle, DashboardFragment host) { + final List controllers = new ArrayList<>(); + controllers.addAll(SafetyCenterUtils.getControllersForAdvancedPrivacy(context, lifecycle)); + controllers.addAll( + SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host)); + return controllers; + + } + + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.more_security_privacy_settings) { + /** + * If SafetyCenter is disabled, all of these entries will be in the More Security + * Settings and the Privacy page, and we don't want to index these entries. + */ + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { + return null; + } + return super.getXmlResourcesToIndex(context, enabled); + } + + @Override + public List createPreferenceControllers( + Context context) { + return buildPreferenceControllers(context, null, null); + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + final int profileUserId = + Utils.getManagedProfileId( + UserManager.get(context), UserHandle.myUserId()); + // If work profile is supported, we should keep the search result. + if (profileUserId != UserHandle.USER_NULL) { + return keys; + } + + // Otherwise, we should hide the search result. + keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS); + return keys; + } + }; +} diff --git a/src/com/android/settings/safetycenter/SafetyCenterUtils.java b/src/com/android/settings/safetycenter/SafetyCenterUtils.java new file mode 100644 index 00000000000..6c7967d6a3d --- /dev/null +++ b/src/com/android/settings/safetycenter/SafetyCenterUtils.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 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.safetycenter; + +import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE; +import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK; +import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO; +import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY; + +import android.annotation.StringRes; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController; +import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController; +import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.notification.LockScreenNotificationPreferenceController; +import com.android.settings.privacy.PrivacyDashboardFragment; +import com.android.settings.security.ChangeProfileScreenLockPreferenceController; +import com.android.settings.security.LockUnificationPreferenceController; +import com.android.settings.security.VisiblePatternProfilePreferenceController; +import com.android.settings.security.trustagent.TrustAgentListPreferenceController; +import com.android.settings.widget.PreferenceCategoryController; +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.ArrayList; +import java.util.List; + +/** + * A class with helper method used in logic involving safety center. + */ +public final class SafetyCenterUtils { + + /** + * Returns preference controllers related to advanced security entries. + * This is used in {@link MoreSecurityPrivacyFragment} and + * {@link com.android.settings.security.SecurityAdvancedSettings}. + */ + public static List getControllersForAdvancedSecurity( + Context context, + com.android.settingslib.core.lifecycle.Lifecycle lifecycle, DashboardFragment host) { + final String WORK_PROFILE_SECURITY_CATEGORY = "work_profile_category"; + final List controllers = new ArrayList<>(); + controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle)); + + final List profileSecurityControllers = new ArrayList<>(); + profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController( + context, host)); + profileSecurityControllers.add(new LockUnificationPreferenceController(context, host)); + profileSecurityControllers.add(new VisiblePatternProfilePreferenceController( + context, lifecycle)); + profileSecurityControllers.add(new FaceProfileStatusPreferenceController( + context, lifecycle)); + profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController( + context, lifecycle)); + profileSecurityControllers + .add(new CombinedBiometricProfileStatusPreferenceController(context, lifecycle)); + controllers.add(new PreferenceCategoryController(context, WORK_PROFILE_SECURITY_CATEGORY) + .setChildren(profileSecurityControllers)); + controllers.addAll(profileSecurityControllers); + return controllers; + } + + /** + * Returns preference controllers for advanced privacy entries. + * This is used in {@link MoreSecurityPrivacyFragment} and {@link PrivacyDashboardFragment}. + */ + public static List getControllersForAdvancedPrivacy( + Context context, com.android.settingslib.core.lifecycle.Lifecycle lifecycle) { + final String KEY_LOCK_SCREEN_NOTIFICATIONS = "privacy_lock_screen_notifications"; + final String KEY_WORK_PROFILE_CATEGORY = + "privacy_work_profile_notifications_category"; + final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS = + "privacy_lock_screen_work_profile_notifications"; + final List controllers = new ArrayList<>(); + final LockScreenNotificationPreferenceController notificationController = + new LockScreenNotificationPreferenceController(context, + KEY_LOCK_SCREEN_NOTIFICATIONS, + KEY_WORK_PROFILE_CATEGORY, + KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS); + if (lifecycle != null) { + lifecycle.addObserver(notificationController); + } + controllers.add(notificationController); + return controllers; + } + + /** + * A class that stores the resource that will be overridden using preferenceKey and overrideKey. + */ + public static final class EnterpriseOverrideString { + private final String mPreferenceKey; + private final String mOverrideKey; + @StringRes private final int mResource; + + public EnterpriseOverrideString( + String preferenceKey, + String overrideKey, + @StringRes int resource) { + this.mPreferenceKey = preferenceKey; + this.mOverrideKey = overrideKey; + this.mResource = resource; + } + + @StringRes + public int getResource() { + return mResource; + } + + public String getPreferenceKey() { + return mPreferenceKey; + } + + public String getOverrideKey() { + return mOverrideKey; + } + } + + /** + * Returns a list of @{EnterpriseOverrideString} for the privacy entries. + */ + public static List getEnterpriseOverrideStringForPrivacyEntries() { + List enterpriseOverrideStrings = new ArrayList<>(); + enterpriseOverrideStrings.add( + new EnterpriseOverrideString("privacy_lock_screen_work_profile_notifications", + WORK_PROFILE_LOCKED_NOTIFICATION_TITLE, + R.string.locked_work_profile_notification_title)); + enterpriseOverrideStrings.add( + new EnterpriseOverrideString("interact_across_profiles_privacy", + CONNECTED_WORK_AND_PERSONAL_APPS_TITLE, + R.string.interact_across_profiles_title)); + enterpriseOverrideStrings.add( + new EnterpriseOverrideString("privacy_work_profile_notifications_category", + WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, + R.string.profile_section_header)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("work_policy_info", + WORK_PROFILE_PRIVACY_POLICY_INFO, R.string.work_policy_privacy_settings)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("work_policy_info", + WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY, + R.string.work_policy_privacy_settings_summary)); + return enterpriseOverrideStrings; + } + + /** + * Returns a list of @{EnterpriseOverrideString} for the security entries. + */ + public static List getEnterpriseOverrideStringForSecurityEntries() { + List enterpriseOverrideStrings = new ArrayList<>(); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("unlock_set_or_change_profile", + WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE, + R.string.unlock_set_unlock_launch_picker_title_profile)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("unification", + WORK_PROFILE_UNIFY_LOCKS_SUMMARY, + R.string.lock_settings_profile_unification_summary)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("fingerprint_settings_profile", + FINGERPRINT_FOR_WORK, + R.string.security_settings_work_fingerprint_preference_title)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("manage_device_admin", + MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin)); + enterpriseOverrideStrings.add(new EnterpriseOverrideString("security_category_profile", + WORK_PROFILE_SECURITY_TITLE, R.string.lock_settings_profile_title)); + enterpriseOverrideStrings.add( + new EnterpriseOverrideString("enterprise_privacy", MANAGED_DEVICE_INFO, + R.string.enterprise_privacy_settings)); + return enterpriseOverrideStrings; + } + + private SafetyCenterUtils() {} +} diff --git a/src/com/android/settings/security/SecurityAdvancedSettings.java b/src/com/android/settings/security/SecurityAdvancedSettings.java index f716064a6ae..b2b2782f3d0 100644 --- a/src/com/android/settings/security/SecurityAdvancedSettings.java +++ b/src/com/android/settings/security/SecurityAdvancedSettings.java @@ -16,34 +16,25 @@ package com.android.settings.security; -import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK; -import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO; -import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE; -import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY; - import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.provider.SearchIndexableResource; import com.android.settings.R; -import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController; -import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController; -import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.safetycenter.SafetyCenterManagerWrapper; +import com.android.settings.safetycenter.SafetyCenterUtils; +import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.security.trustagent.TrustAgentListPreferenceController; -import com.android.settings.widget.PreferenceCategoryController; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.search.SearchIndexable; -import java.util.ArrayList; import java.util.List; /** @@ -55,7 +46,6 @@ import java.util.List; public class SecurityAdvancedSettings extends DashboardFragment { private static final String TAG = "SecurityAdvancedSettings"; - private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile"; /** Used in case of old Security settings when SafetyCenter is disabled */ private static final String CATEGORY_SECURITY_LEGACY_ADVANCED_SETTINGS = @@ -64,22 +54,13 @@ public class SecurityAdvancedSettings extends DashboardFragment { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - replaceEnterpriseStringTitle("unlock_set_or_change_profile", - WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE, - R.string.unlock_set_unlock_launch_picker_title_profile); - replaceEnterpriseStringSummary("unification", - WORK_PROFILE_UNIFY_LOCKS_SUMMARY, - R.string.lock_settings_profile_unification_summary); - replaceEnterpriseStringTitle("fingerprint_settings_profile", - FINGERPRINT_FOR_WORK, - R.string.security_settings_work_fingerprint_preference_title); - replaceEnterpriseStringTitle("manage_device_admin", - MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin); - replaceEnterpriseStringTitle("security_category_profile", - WORK_PROFILE_SECURITY_TITLE, R.string.lock_settings_profile_title); - replaceEnterpriseStringTitle("enterprise_privacy", MANAGED_DEVICE_INFO, - R.string.enterprise_privacy_settings); - + List securityOverrideStrings = + SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries(); + for (int i = 0; i < securityOverrideStrings.size(); i++) { + EnterpriseOverrideString overrideString = securityOverrideStrings.get(i); + replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), + overrideString.getOverrideKey(), overrideString.getResource()); + } } @Override @@ -140,26 +121,7 @@ public class SecurityAdvancedSettings extends DashboardFragment { private static List buildPreferenceControllers(Context context, Lifecycle lifecycle, DashboardFragment host) { - final List controllers = new ArrayList<>(); - controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle)); - - final List profileSecurityControllers = new ArrayList<>(); - profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController( - context, host)); - profileSecurityControllers.add(new LockUnificationPreferenceController(context, host)); - profileSecurityControllers.add(new VisiblePatternProfilePreferenceController( - context, lifecycle)); - profileSecurityControllers.add(new FaceProfileStatusPreferenceController( - context, lifecycle)); - profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController( - context, lifecycle)); - profileSecurityControllers - .add(new CombinedBiometricProfileStatusPreferenceController(context, lifecycle)); - controllers.add(new PreferenceCategoryController(context, WORK_PROFILE_SECURITY_CATEGORY) - .setChildren(profileSecurityControllers)); - controllers.addAll(profileSecurityControllers); - - return controllers; + return SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host); } /** @@ -167,6 +129,18 @@ public class SecurityAdvancedSettings extends DashboardFragment { */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.security_advanced_settings) { + /** + * If SafetyCenter is enabled, all of these entries will be in the More Settings + * page, and we don't want to index these entries. + */ + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + if (SafetyCenterManagerWrapper.get().isEnabled(context)) { + return null; + } + return super.getXmlResourcesToIndex(context, enabled); + } @Override public List createPreferenceControllers(Context diff --git a/tests/unit/src/com/android/settings/TestUtils.java b/tests/unit/src/com/android/settings/TestUtils.java index d7b1ea4a8b1..151b7c1e578 100644 --- a/tests/unit/src/com/android/settings/TestUtils.java +++ b/tests/unit/src/com/android/settings/TestUtils.java @@ -15,6 +15,21 @@ */ package com.android.settings; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; + +import android.annotation.XmlRes; +import android.content.Context; +import android.os.Bundle; +import android.provider.SearchIndexableResource; + +import com.android.settings.core.PreferenceXmlParserUtils; +import com.android.settings.search.BaseSearchIndexProvider; + +import java.util.ArrayList; +import java.util.List; + /** * Convenience methods and constants for testing. */ @@ -22,4 +37,30 @@ public class TestUtils { public static final long KILOBYTE = 1024L; // TODO: Change to 1000 in O Robolectric. public static final long MEGABYTE = KILOBYTE * KILOBYTE; public static final long GIGABYTE = KILOBYTE * MEGABYTE; + + public static List getAllXmlKeys( + Context context, BaseSearchIndexProvider indexProvider) + throws Exception { + final List resources = indexProvider.getXmlResourcesToIndex( + context, true /* not used*/); + if (resources == null || resources.isEmpty()) { + return new ArrayList<>(); + } + final List keys = new ArrayList<>(); + for (SearchIndexableResource res : resources) { + keys.addAll(getKeysFromXml(res.xmlResId, context)); + } + return keys; + } + + private static List getKeysFromXml(@XmlRes int xmlResId, Context context) + throws Exception { + final List keys = new ArrayList<>(); + final List metadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId, + FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN); + for (Bundle bundle : metadata) { + keys.add(bundle.getString(METADATA_KEY)); + } + return keys; + } } diff --git a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java new file mode 100644 index 00000000000..c49bb258e1d --- /dev/null +++ b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 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.privacy; + + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.TestUtils; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; +import com.android.settings.search.BaseSearchIndexProvider; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +public class PrivacyDashboardFragmentTest { + + private Context mContext; + private PrivacyDashboardFragment mPrivacyDashboardFragment; + + @Mock + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; + + @Before + @UiThreadTest + public void setUp() { + MockitoAnnotations.initMocks(this); + MockitoAnnotations.initMocks(this); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mContext = ApplicationProvider.getApplicationContext(); + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; + mPrivacyDashboardFragment = spy(new PrivacyDashboardFragment()); + when(mPrivacyDashboardFragment.getContext()).thenReturn(mContext); + } + + @Test + public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception { + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true); + BaseSearchIndexProvider indexProvider = PrivacyDashboardFragment.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isEmpty(); + } +} diff --git a/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java b/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java new file mode 100644 index 00000000000..7ed0a021a85 --- /dev/null +++ b/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2023 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.safetycenter; + + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.TestUtils; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.testutils.ResourcesUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class MoreSecurityPrivacyFragmentSettingsTest { + private static final String SCREEN_XML_RESOURCE_NAME = "more_security_privacy_settings"; + private MoreSecurityPrivacyFragment mMoreSecurityPrivacyFragment; + private Context mContext; + @Mock + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; + @Before + @UiThreadTest + public void setUp() { + MockitoAnnotations.initMocks(this); + MockitoAnnotations.initMocks(this); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mContext = ApplicationProvider.getApplicationContext(); + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; + mMoreSecurityPrivacyFragment = spy(new MoreSecurityPrivacyFragment()); + when(mMoreSecurityPrivacyFragment.getContext()).thenReturn(mContext); + } + + @Test + public void getPreferenceXml_returnsMoreSecurityPrivacy() { + assertThat(mMoreSecurityPrivacyFragment.getPreferenceScreenResId()) + .isEqualTo(getXmlResId(SCREEN_XML_RESOURCE_NAME)); + } + + @Test + public void whenSafetyCenterIsEnabled_pageIndexIncluded() throws Exception { + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true); + BaseSearchIndexProvider indexProvider = + MoreSecurityPrivacyFragment.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isNotEmpty(); + } + + @Test + public void whenSafetyCenterIsDisabled_pageIndexExcluded() throws Exception { + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false); + BaseSearchIndexProvider indexProvider = + MoreSecurityPrivacyFragment.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isEmpty(); + } + + private int getXmlResId(String resName) { + return ResourcesUtils.getResourcesId(mContext, "xml", resName); + } +} diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java index 2efb357b869..9851a1a70df 100644 --- a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java +++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java @@ -16,6 +16,7 @@ package com.android.settings.security; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -29,7 +30,9 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.TestUtils; import com.android.settings.safetycenter.SafetyCenterManagerWrapper; +import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.ResourcesUtils; import com.android.settingslib.drawer.CategoryKey; @@ -40,6 +43,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class SecurityAdvancedSettingsTest { private static final String SCREEN_XML_RESOURCE_NAME = "security_advanced_settings"; @@ -100,6 +105,18 @@ public class SecurityAdvancedSettingsTest { .isEqualTo(LEGACY_CATEGORY_KEY); } + @Test + public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception { + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false); + BaseSearchIndexProvider indexProvider = SecurityAdvancedSettings.SEARCH_INDEX_DATA_PROVIDER; + + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); + List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); + allXmlKeys.removeAll(nonIndexableKeys); + + assertThat(allXmlKeys).isEmpty(); + } + private int getXmlResId(String resName) { return ResourcesUtils.getResourcesId(mContext, "xml", resName); } diff --git a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java index c51788472c1..dee90b45f36 100644 --- a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java +++ b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java @@ -21,24 +21,18 @@ import static android.content.Context.FINGERPRINT_SERVICE; import static android.content.pm.PackageManager.FEATURE_FACE; import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; -import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; -import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN; -import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; - import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import android.annotation.XmlRes; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; -import android.os.Bundle; import android.os.Looper; -import android.provider.SearchIndexableResource; import androidx.lifecycle.Lifecycle; import androidx.preference.Preference; @@ -48,10 +42,11 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.TestUtils; import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController; import com.android.settings.biometrics.face.FaceStatusPreferenceController; import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController; -import com.android.settings.core.PreferenceXmlParserUtils; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.security.trustagent.TrustAgentManager; import com.android.settings.testutils.FakeFeatureFactory; @@ -64,7 +59,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; import java.util.List; @RunWith(AndroidJUnit4.class) @@ -85,6 +79,8 @@ public class SecuritySettingsTest { private FingerprintManager mFingerprintManager; @Mock private PackageManager mPackageManager; + @Mock + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; private PreferenceScreen mScreen; @@ -96,6 +92,7 @@ public class SecuritySettingsTest { } MockitoAnnotations.initMocks(this); + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mContext = spy(ApplicationProvider.getApplicationContext()); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.hasSystemFeature(FEATURE_FACE)).thenReturn(true); @@ -132,12 +129,14 @@ public class SecuritySettingsTest { } @Test - public void noAlternativeFragmentAvailable_pageIndexIncluded() throws Exception { + public void noAlternativeFragmentAvailableAndSafetyCenterIsDisabled_pageIndexIncluded() + throws Exception { when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()).thenReturn( false); + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false); BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER; - List allXmlKeys = getAllXmlKeys(indexProvider); + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); allXmlKeys.removeAll(nonIndexableKeys); @@ -150,7 +149,7 @@ public class SecuritySettingsTest { true); BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER; - List allXmlKeys = getAllXmlKeys(indexProvider); + List allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider); List nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext); allXmlKeys.removeAll(nonIndexableKeys); @@ -340,29 +339,6 @@ public class SecuritySettingsTest { assertThat(mPreferenceCombined.isVisible()).isFalse(); } - private List getAllXmlKeys(BaseSearchIndexProvider indexProvider) throws Exception { - final List resources = indexProvider.getXmlResourcesToIndex( - mContext, true /* not used*/); - if (resources == null || resources.isEmpty()) { - return new ArrayList<>(); - } - final List keys = new ArrayList<>(); - for (SearchIndexableResource res : resources) { - keys.addAll(getKeysFromXml(res.xmlResId)); - } - return keys; - } - - private List getKeysFromXml(@XmlRes int xmlResId) throws Exception { - final List keys = new ArrayList<>(); - final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, xmlResId, - FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN); - for (Bundle bundle : metadata) { - keys.add(bundle.getString(METADATA_KEY)); - } - return keys; - } - boolean isFacePrefAvailable(List controllers) { return controllers.stream().filter( controller -> controller instanceof FaceStatusPreferenceController