Adds SecuritySetting feature for providing an alternative SecuritySettings fragment
Bug: 181764224
Test: New tests added to SettingsUnitTests.
Test: Tested manually with and without feature-provided fragment.
Test: No new failures in SettingsUnitTests, or robolectric. No failures in security directory of robolectric tests.
Change-Id: I21038baf3098c18e1713a332085a5efc376f73da
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 0e47556..e7b23b9 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -41,6 +41,7 @@
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
@@ -162,6 +163,11 @@
*/
public abstract ExtraAppInfoFeatureProvider getExtraAppInfoFeatureProvider();
+ /**
+ * Retrieve implementation for SecuritySettings feature.
+ */
+ public abstract SecuritySettingsFeatureProvider getSecuritySettingsFeatureProvider();
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index dc08547..9105c10 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -63,6 +63,8 @@
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecurityFeatureProviderImpl;
+import com.android.settings.security.SecuritySettingsFeatureProvider;
+import com.android.settings.security.SecuritySettingsFeatureProviderImpl;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.slices.SlicesFeatureProviderImpl;
import com.android.settings.users.UserFeatureProvider;
@@ -100,6 +102,7 @@
private FaceFeatureProvider mFaceFeatureProvider;
private WifiTrackerLibProvider mWifiTrackerLibProvider;
private ExtraAppInfoFeatureProvider mExtraAppInfoFeatureProvider;
+ private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -313,4 +316,12 @@
}
return mExtraAppInfoFeatureProvider;
}
+
+ @Override
+ public SecuritySettingsFeatureProvider getSecuritySettingsFeatureProvider() {
+ if (mSecuritySettingsFeatureProvider == null) {
+ mSecuritySettingsFeatureProvider = new SecuritySettingsFeatureProviderImpl();
+ }
+ return mSecuritySettingsFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/security/SecuritySettingsFeatureProvider.java b/src/com/android/settings/security/SecuritySettingsFeatureProvider.java
new file mode 100644
index 0000000..78e4bc7
--- /dev/null
+++ b/src/com/android/settings/security/SecuritySettingsFeatureProvider.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/** FeatureProvider for security settings. */
+public interface SecuritySettingsFeatureProvider {
+
+ /** Returns whether an alternative SecuritySettings fragment is available. */
+ boolean hasAlternativeSecuritySettingsFragment();
+
+ /** Returns the alternative SecuritySettings fragment name if available. */
+ String getAlternativeSecuritySettingsFragmentClassname();
+}
diff --git a/src/com/android/settings/security/SecuritySettingsFeatureProviderImpl.java b/src/com/android/settings/security/SecuritySettingsFeatureProviderImpl.java
new file mode 100644
index 0000000..8aba523
--- /dev/null
+++ b/src/com/android/settings/security/SecuritySettingsFeatureProviderImpl.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/** Implementation for {@code SecuritySettingsFeatureProvider}. */
+public class SecuritySettingsFeatureProviderImpl implements SecuritySettingsFeatureProvider {
+
+ @Override
+ public boolean hasAlternativeSecuritySettingsFragment() {
+ return false;
+ }
+
+ @Override
+ public String getAlternativeSecuritySettingsFragmentClassname() {
+ return null;
+ }
+}
diff --git a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java
index 4efc620..349a91d 100644
--- a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java
+++ b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java
@@ -19,12 +19,17 @@
import android.content.Context;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.text.TextUtils;
import android.util.FeatureFlagUtils;
+import androidx.preference.Preference;
+
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.FeatureFlags;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.overlay.FeatureFactory;
public class TopLevelSecurityEntryPreferenceController extends BasePreferenceController {
@@ -56,4 +61,28 @@
return mContext.getText(R.string.security_dashboard_summary_no_fingerprint);
}
}
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return super.handlePreferenceTreeClick(preference);
+ }
+
+ SecuritySettingsFeatureProvider securitySettingsFeatureProvider =
+ FeatureFactory.getFactory(mContext).getSecuritySettingsFeatureProvider();
+ if (securitySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) {
+ String alternativeFragmentClassname =
+ securitySettingsFeatureProvider
+ .getAlternativeSecuritySettingsFragmentClassname();
+ if (alternativeFragmentClassname != null) {
+ new SubSettingLauncher(mContext)
+ .setDestination(alternativeFragmentClassname)
+ .setSourceMetricsCategory(getMetricsCategory())
+ .launch();
+ return true;
+ }
+ }
+
+ return super.handlePreferenceTreeClick(preference);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 7bd7813..b7e6ffd 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -43,6 +43,7 @@
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
@@ -83,6 +84,7 @@
public WifiTrackerLibProvider wifiTrackerLibProvider;
public ExtraAppInfoFeatureProvider extraAppInfoFeatureProvider;
+ public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -130,6 +132,7 @@
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
wifiTrackerLibProvider = mock(WifiTrackerLibProvider.class);
extraAppInfoFeatureProvider = mock(ExtraAppInfoFeatureProvider.class);
+ securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
}
@Override
@@ -256,4 +259,9 @@
public ExtraAppInfoFeatureProvider getExtraAppInfoFeatureProvider() {
return extraAppInfoFeatureProvider;
}
+
+ @Override
+ public SecuritySettingsFeatureProvider getSecuritySettingsFeatureProvider() {
+ return securitySettingsFeatureProvider;
+ }
}
diff --git a/tests/unit/src/com/android/settings/security/SecuritySettingsFeatureProviderImplTest.java b/tests/unit/src/com/android/settings/security/SecuritySettingsFeatureProviderImplTest.java
new file mode 100644
index 0000000..5b0c7b5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/security/SecuritySettingsFeatureProviderImplTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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 androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SecuritySettingsFeatureProviderImplTest {
+
+ private SecuritySettingsFeatureProviderImpl mSecuritySettingsFeatureProvider;
+
+ @Before
+ public void setUp() {
+ mSecuritySettingsFeatureProvider = new SecuritySettingsFeatureProviderImpl();
+ }
+
+ @Test
+ public void hasAlternativeSecuritySettingsFragment_returnsFalse() {
+ assertThat(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
+ .isFalse();
+ }
+
+ @Test
+ public void getAlternativeSecuritySettingsFragmentClassname_returnsNull() {
+ String alternativeFragmentClassname =
+ mSecuritySettingsFeatureProvider.getAlternativeSecuritySettingsFragmentClassname();
+ assertThat(alternativeFragmentClassname).isNull();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java b/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java
new file mode 100644
index 0000000..a9acd2a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class TopLevelSecurityEntryPreferenceControllerTest {
+
+ private static final String PREFERENCE_KEY = "top_level_security";
+ private static final String ALTERNATIVE_FRAGMENT_CLASSNAME = "AlternativeFragmentClassname";
+
+ private TopLevelSecurityEntryPreferenceController mTopLevelSecurityEntryPreferenceController;
+ private Preference mPreference;
+ private FakeFeatureFactory mFeatureFactory;
+ private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider;
+
+ @Mock
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider();
+
+ mPreference = new Preference(ApplicationProvider.getApplicationContext());
+ mPreference.setKey(PREFERENCE_KEY);
+
+ doNothing().when(mContext).startActivity(any(Intent.class));
+ mTopLevelSecurityEntryPreferenceController =
+ new TopLevelSecurityEntryPreferenceController(mContext, PREFERENCE_KEY);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_forDifferentPreferenceKey_isNotHandled() {
+ Preference preference = new Preference(ApplicationProvider.getApplicationContext());
+ preference.setKey("some_other_preference");
+
+ boolean preferenceHandled =
+ mTopLevelSecurityEntryPreferenceController.handlePreferenceTreeClick(preference);
+
+ assertThat(preferenceHandled).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_withAlternativeFragment_launchesAlternativeFragment() {
+ when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
+ .thenReturn(true);
+ when(mSecuritySettingsFeatureProvider.getAlternativeSecuritySettingsFragmentClassname())
+ .thenReturn(ALTERNATIVE_FRAGMENT_CLASSNAME);
+ final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ boolean preferenceHandled =
+ mTopLevelSecurityEntryPreferenceController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(preferenceHandled).isTrue();
+ verify(mContext).startActivity(intentCaptor.capture());
+ assertThat(intentCaptor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ .isEqualTo(ALTERNATIVE_FRAGMENT_CLASSNAME);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_withDisabledAlternative_isNotHandled() {
+ when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
+ .thenReturn(false);
+ when(mSecuritySettingsFeatureProvider.getAlternativeSecuritySettingsFragmentClassname())
+ .thenReturn(ALTERNATIVE_FRAGMENT_CLASSNAME);
+
+ boolean preferenceHandled =
+ mTopLevelSecurityEntryPreferenceController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(preferenceHandled).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_withoutAlternativeFragmentName_isNotHandled() {
+ when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment())
+ .thenReturn(true);
+ when(mSecuritySettingsFeatureProvider.getAlternativeSecuritySettingsFragmentClassname())
+ .thenReturn(null);
+
+ boolean preferenceHandled =
+ mTopLevelSecurityEntryPreferenceController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(preferenceHandled).isFalse();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
index a90c9bf..b6f330b 100644
--- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -41,6 +41,7 @@
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
@@ -78,6 +79,7 @@
public WifiTrackerLibProvider wifiTrackerLibProvider;
public ExtraAppInfoFeatureProvider extraAppInfoFeatureProvider;
+ public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -116,6 +118,7 @@
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
wifiTrackerLibProvider = mock(WifiTrackerLibProvider.class);
extraAppInfoFeatureProvider = mock(ExtraAppInfoFeatureProvider.class);
+ securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
}
@Override
@@ -242,4 +245,9 @@
public ExtraAppInfoFeatureProvider getExtraAppInfoFeatureProvider() {
return extraAppInfoFeatureProvider;
}
+
+ @Override
+ public SecuritySettingsFeatureProvider getSecuritySettingsFeatureProvider() {
+ return securitySettingsFeatureProvider;
+ }
}