diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 91476051960..4b1a7d1b115 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1675,6 +1675,19 @@ android:value="true" /> + + + + + + + + Lift finger, then touch sensor again Can\u2019t use fingerprint sensor. Visit a repair provider + + Advanced settings + + Work profile lock, Smart Lock + + Smart Lock and more + + Advanced settings + You can add up to %d fingerprints diff --git a/res/xml/security_advanced_settings.xml b/res/xml/security_advanced_settings.xml new file mode 100644 index 00000000000..84ebd4a03c7 --- /dev/null +++ b/res/xml/security_advanced_settings.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 5b687afc488..0550441d3f2 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -62,112 +62,13 @@ settings:keywords="@string/keywords_biometric_settings" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:key="security_advanced_settings" + android:title="@string/security_advanced_settings" + android:summary="@string/summary_placeholder" + android:fragment="com.android.settings.security.SecurityAdvancedSettings" + settings:controller="com.android.settings.security.SecurityAdvancedSettingsController" + settings:keywords="@string/security_advanced_settings_keywords" /> \ No newline at end of file diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 96f362c1779..899c5d138d6 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -190,6 +190,8 @@ public class Settings extends SettingsActivity { return alternativeFragmentClassname; } } + /** Activity for the Advanced security settings. */ + public static class SecurityAdvancedSettings 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 c88fe463781..583766e8797 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -150,6 +150,7 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.privacy.PrivacyDashboardFragment; import com.android.settings.security.CryptKeeperSettings; import com.android.settings.security.LockscreenDashboardFragment; +import com.android.settings.security.SecurityAdvancedSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.shortcut.CreateShortcut; import com.android.settings.sound.MediaControlsSettings; @@ -215,6 +216,7 @@ public class SettingsGateway { PrivacyDashboardFragment.class.getName(), LocationServices.class.getName(), SecuritySettings.class.getName(), + SecurityAdvancedSettings.class.getName(), UsageAccessDetails.class.getName(), PrivacySettings.class.getName(), DeviceAdminSettings.class.getName(), diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index 89b21c9ac8e..eb04f3c3ddb 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -43,6 +43,7 @@ import com.android.settings.notification.SoundSettings; import com.android.settings.notification.zen.ZenModeSettings; import com.android.settings.privacy.PrivacyDashboardFragment; import com.android.settings.security.LockscreenDashboardFragment; +import com.android.settings.security.SecurityAdvancedSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.system.SystemDashboardFragment; import com.android.settingslib.drawer.CategoryKey; @@ -90,6 +91,8 @@ public class DashboardFragmentRegistry { CategoryKey.CATEGORY_STORAGE); PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettings.class.getName(), CategoryKey.CATEGORY_SECURITY); + PARENT_TO_CATEGORY_KEY_MAP.put(SecurityAdvancedSettings.class.getName(), + CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS); PARENT_TO_CATEGORY_KEY_MAP.put(AccountDetailDashboardFragment.class.getName(), CategoryKey.CATEGORY_ACCOUNT_DETAIL); PARENT_TO_CATEGORY_KEY_MAP.put(AccountDashboardFragment.class.getName(), diff --git a/src/com/android/settings/security/SecurityAdvancedSettings.java b/src/com/android/settings/security/SecurityAdvancedSettings.java new file mode 100644 index 00000000000..5231b50cd9e --- /dev/null +++ b/src/com/android/settings/security/SecurityAdvancedSettings.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2021 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.security; + +import static com.android.settings.security.EncryptionStatusPreferenceController.PREF_KEY_ENCRYPTION_SECURITY_PAGE; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; + +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.enterprise.EnterprisePrivacyPreferenceController; +import com.android.settings.enterprise.FinancedPrivacyPreferenceController; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController; +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; + +/** + * An overflow menu for {@code SecuritySettings} containing advanced security settings. + * + *

This includes all work-profile related settings. + */ +@SearchIndexable +public class SecurityAdvancedSettings extends DashboardFragment { + + private static final String TAG = "SecurityAdvancedSettings"; + private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.SECURITY_ADVANCED; + } + + @Override + public String getCategoryKey() { + return CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.security_advanced_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/); + } + + /** + * 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); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle, DashboardFragment host) { + final List controllers = new ArrayList<>(); + controllers.add(new EnterprisePrivacyPreferenceController(context)); + controllers.add(new FinancedPrivacyPreferenceController(context)); + controllers.add(new ManageTrustAgentsPreferenceController(context)); + controllers.add(new ScreenPinningPreferenceController(context)); + controllers.add(new SimLockPreferenceController(context)); + controllers.add(new EncryptionStatusPreferenceController(context, + PREF_KEY_ENCRYPTION_SECURITY_PAGE)); + 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; + } + + /** + * For Search. Please keep it in sync when updating "createPreferenceHierarchy()" + */ + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.security_advanced_settings) { + + @Override + public List createPreferenceControllers(Context + context) { + return buildPreferenceControllers(context, null /* lifecycle */, + null /* host*/); + } + }; +} diff --git a/src/com/android/settings/security/SecurityAdvancedSettingsController.java b/src/com/android/settings/security/SecurityAdvancedSettingsController.java new file mode 100644 index 00000000000..904141d5485 --- /dev/null +++ b/src/com/android/settings/security/SecurityAdvancedSettingsController.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 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.security; + +import android.content.Context; +import android.content.pm.CrossProfileApps; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; + +/** + * Controller to decide the summary of "Advanced settings" option in the + * Security settings screen. + */ +public class SecurityAdvancedSettingsController extends BasePreferenceController { + + private final CrossProfileApps mCrossProfileApps; + + public SecurityAdvancedSettingsController(Context context, String preferenceKey) { + super(context, preferenceKey); + + mCrossProfileApps = context.getSystemService(CrossProfileApps.class); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public CharSequence getSummary() { + return isWorkProfilePresent() + ? mContext.getResources().getString( + R.string.security_advanced_settings_work_profile_settings_summary) + : mContext.getResources().getString( + R.string.security_advanced_settings_no_work_profile_settings_summary); + } + + private boolean isWorkProfilePresent() { + return !mCrossProfileApps.getTargetUserProfiles().isEmpty(); + } +} diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index be123f23397..0d31ca2c6f6 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -15,25 +15,18 @@ */ package com.android.settings.security; -import static com.android.settings.security.EncryptionStatusPreferenceController.PREF_KEY_ENCRYPTION_SECURITY_PAGE; - import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import com.android.settings.R; -import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController; import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController; -import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController; import com.android.settings.biometrics.face.FaceStatusPreferenceController; -import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController; import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.enterprise.EnterprisePrivacyPreferenceController; -import com.android.settings.enterprise.FinancedPrivacyPreferenceController; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.safetycenter.SafetyCenterStatus; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController; import com.android.settings.security.trustagent.TrustAgentListPreferenceController; import com.android.settings.widget.PreferenceCategoryController; import com.android.settingslib.core.AbstractPreferenceController; @@ -48,7 +41,6 @@ public class SecuritySettings extends DashboardFragment { private static final String TAG = "SecuritySettings"; private static final String SECURITY_CATEGORY = "security_category"; - private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile"; public static final int CHANGE_TRUST_AGENT_SETTINGS = 126; public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; @@ -106,15 +98,6 @@ public class SecuritySettings extends DashboardFragment { private static List buildPreferenceControllers(Context context, Lifecycle lifecycle, SecuritySettings host) { final List controllers = new ArrayList<>(); - controllers.add(new EnterprisePrivacyPreferenceController(context)); - controllers.add(new FinancedPrivacyPreferenceController(context)); - controllers.add(new ManageTrustAgentsPreferenceController(context)); - controllers.add(new ScreenPinningPreferenceController(context)); - controllers.add(new SimLockPreferenceController(context)); - controllers.add(new EncryptionStatusPreferenceController(context, - PREF_KEY_ENCRYPTION_SECURITY_PAGE)); - controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle)); - final List securityPreferenceControllers = new ArrayList<>(); securityPreferenceControllers.add(new FaceStatusPreferenceController(context, lifecycle)); securityPreferenceControllers.add(new FingerprintStatusPreferenceController( @@ -126,22 +109,6 @@ public class SecuritySettings extends DashboardFragment { .setChildren(securityPreferenceControllers)); controllers.addAll(securityPreferenceControllers); - 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; } @@ -161,7 +128,8 @@ public class SecuritySettings extends DashboardFragment { @Override protected boolean isPageSearchEnabled(Context context) { return !FeatureFactory.getFactory(context).getSecuritySettingsFeatureProvider() - .hasAlternativeSecuritySettingsFragment(); + .hasAlternativeSecuritySettingsFragment() + && !SafetyCenterStatus.isEnabled(); } }; } diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsControllerTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsControllerTest.java new file mode 100644 index 00000000000..2863ed51619 --- /dev/null +++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsControllerTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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.security; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.CrossProfileApps; +import android.os.UserHandle; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +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.Collections; + +@RunWith(AndroidJUnit4.class) +public class SecurityAdvancedSettingsControllerTest { + + private static final String PREFERENCE_KEY = "security_advanced_settings"; + private static final String NO_WORK_PROFILE_SUMMARY_RESOURCE_NAME = + "security_advanced_settings_no_work_profile_settings_summary"; + private static final String WORK_PROFILE_SUMMARY_RESOURCE_NAME = + "security_advanced_settings_work_profile_settings_summary"; + + @Mock + private CrossProfileApps mCrossProfileApps; + private Context mContext; + + private SecurityAdvancedSettingsController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getSystemService(CrossProfileApps.class)).thenReturn(mCrossProfileApps); + + mController = new SecurityAdvancedSettingsController(mContext, PREFERENCE_KEY); + } + + @Test + public void getSummary_withoutWorkProfile() { + when(mCrossProfileApps.getTargetUserProfiles()).thenReturn(Collections.emptyList()); + + assertThat(mController.getSummary()) + .isEqualTo(getResourcesString(NO_WORK_PROFILE_SUMMARY_RESOURCE_NAME)); + } + + @Test + public void getSummary_withWorkProfile() { + when(mCrossProfileApps.getTargetUserProfiles()).thenReturn( + Collections.singletonList(new UserHandle(0)) + ); + + assertThat(mController.getSummary()) + .isEqualTo(getResourcesString(WORK_PROFILE_SUMMARY_RESOURCE_NAME)); + } + + private String getResourcesString(String resName) { + return ResourcesUtils.getResourcesString(mContext, resName); + } +} diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java new file mode 100644 index 00000000000..6e30bbb020a --- /dev/null +++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 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.security; + +import static com.google.common.truth.Truth.assertThat; + +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.ResourcesUtils; +import com.android.settingslib.drawer.CategoryKey; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SecurityAdvancedSettingsTest { + private static final String SCREEN_XML_RESOURCE_NAME = "security_advanced_settings"; + + private Context mContext; + private SecurityAdvancedSettings mSecurityAdvancedSettings; + + @Before + @UiThreadTest + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mContext = ApplicationProvider.getApplicationContext(); + + mSecurityAdvancedSettings = new SecurityAdvancedSettings(); + } + + @Test + public void getPreferenceXml_returnsAdvancedSettings() { + assertThat(mSecurityAdvancedSettings.getPreferenceScreenResId()) + .isEqualTo(getXmlResId(SCREEN_XML_RESOURCE_NAME)); + } + + @Test + public void getCategoryKey_whenCalled_returnsSecurity() { + assertThat(mSecurityAdvancedSettings.getCategoryKey()) + .isEqualTo(CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS); + } + + private int getXmlResId(String resName) { + return ResourcesUtils.getResourcesId(mContext, "xml", resName); + } +}