diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index b0928573c27..c7d38dd22f8 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -25,6 +25,7 @@ import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; +import android.content.IContentProvider; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -38,6 +39,7 @@ import android.provider.SearchIndexableResource; import android.provider.Settings; import android.security.KeyStore; import android.service.trust.TrustAgentService; +import android.support.annotation.VisibleForTesting; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceChangeListener; @@ -49,6 +51,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -56,6 +59,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.dashboard.DashboardFeatureProvider; +import com.android.settings.dashboard.SummaryLoader; import com.android.settings.fingerprint.FingerprintSettings; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; @@ -69,6 +73,7 @@ import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; +import com.android.settingslib.drawer.TileUtils; import java.util.ArrayList; import java.util.List; @@ -120,6 +125,11 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_TRUST_AGENT = "trust_agent"; private static final String KEY_SCREEN_PINNING = "screen_pinning_settings"; + // Package verifier Settings + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static final String KEY_PACKAGE_VERIFIER_STATE = "package_verifier_state"; + private static final int PACKAGE_VERIFIER_STATE_ENABLED = 1; + // These switch preferences need special handling since they're not all stored in Settings. private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_SHOW_PASSWORD, KEY_TOGGLE_INSTALL_APPLICATIONS, KEY_UNIFICATION, @@ -414,18 +424,20 @@ public class SecuritySettings extends SettingsPreferenceFragment Index.getInstance(getActivity()) .updateFromClassNameResource(SecuritySettings.class.getName(), true, true); - final List tilePrefs = mDashboardFeatureProvider.getPreferencesForCategory( - getActivity(), getPrefContext(), CategoryKey.CATEGORY_SECURITY); - if (tilePrefs != null && !tilePrefs.isEmpty()) { - for (Preference preference : tilePrefs) { - root.addPreference(preference); + if (mDashboardFeatureProvider.isEnabled()) { + final List tilePrefs = mDashboardFeatureProvider.getPreferencesForCategory( + getActivity(), getPrefContext(), CategoryKey.CATEGORY_SECURITY); + if (tilePrefs != null && !tilePrefs.isEmpty()) { + for (Preference preference : tilePrefs) { + root.addPreference(preference); + } } - } - // Update preference data with tile data. Security feature provider only updates the data - // if it actually needs to be changed. - mSecurityFeatureProvider.updatePreferences(getActivity(), root, - mDashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY)); + // Update preference data with tile data. Security feature provider only updates the + // data if it actually needs to be changed. + mSecurityFeatureProvider.updatePreferences(getActivity(), root, + mDashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY)); + } for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) { final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]); @@ -1306,4 +1318,63 @@ public class SecuritySettings extends SettingsPreferenceFragment } } + static class SummaryProvider implements SummaryLoader.SummaryProvider { + + private final Context mContext; + private final SummaryLoader mSummaryLoader; + + public SummaryProvider(Context context, SummaryLoader summaryLoader) { + mContext = context; + mSummaryLoader = summaryLoader; + } + + @Override + public void setListening(boolean listening) { + if (!listening) { + return; + } + int packageVerifierState = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.PACKAGE_VERIFIER_STATE, 0); + DashboardFeatureProvider dashboardFeatureProvider = + FeatureFactory.getFactory(mContext).getDashboardFeatureProvider(mContext); + if (dashboardFeatureProvider.isEnabled() + && (packageVerifierState == PACKAGE_VERIFIER_STATE_ENABLED)) { + DashboardCategory dashboardCategory = + dashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY); + mSummaryLoader.setSummary(this, getPackageVerifierSummary(dashboardCategory)); + } else { + mSummaryLoader.setSummary(this, null); + } + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + String getPackageVerifierSummary(DashboardCategory dashboardCategory) { + int tilesCount = (dashboardCategory != null) ? dashboardCategory.getTilesCount() : 0; + if (tilesCount == 0) { + return null; + } + for (int i = 0; i < tilesCount; i++) { + Tile tile = dashboardCategory.getTile(i); + if (!KEY_PACKAGE_VERIFIER_STATE.equals(tile.key)) { + continue; + } + String summaryUri = tile.metaData.getString( + TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null); + return TileUtils.getTextFromUri(mContext, summaryUri, + new ArrayMap(), + TileUtils.META_DATA_PREFERENCE_SUMMARY); + } + return null; + } + } + + public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY = + new SummaryLoader.SummaryProviderFactory() { + @Override + public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, + SummaryLoader summaryLoader) { + return new SummaryProvider(activity, summaryLoader); + } + }; + } diff --git a/tests/robotests/src/com/android/settings/SecuritySettingsTest.java b/tests/robotests/src/com/android/settings/SecuritySettingsTest.java new file mode 100644 index 00000000000..af853dca8e2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/SecuritySettingsTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2017 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; + +import android.content.Context; +import android.content.ContentResolver; +import android.content.IContentProvider; +import android.provider.Settings; +import android.os.Bundle; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.dashboard.SummaryLoader; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.Tile; +import com.android.settingslib.drawer.TileUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SecuritySettingsTest { + + private static final String MOCK_SUMMARY = "summary"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private DashboardCategory mDashboardCategory; + @Mock + private SummaryLoader mSummaryLoader; + + private SecuritySettings.SummaryProvider mSummaryProvider; + + @Implements(Settings.Secure.class) + public static class ShadowSecureSettings { + + private static final Map mValueMap = new HashMap<>(); + + @Implementation + public static boolean putInt(ContentResolver resolver, String name, int value) { + mValueMap.put(name, value); + return true; + } + + @Implementation + public static int getInt(ContentResolver resolver, String name, int defaultValue) { + Integer value = (Integer) mValueMap.get(name); + return value == null ? defaultValue : value; + } + } + + @Implements(com.android.settingslib.drawer.TileUtils.class) + public static class ShadowTileUtils { + @Implementation + public static String getTextFromUri(Context context, String uriString, + Map providerMap, String key) { + return MOCK_SUMMARY; + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + FakeFeatureFactory.setupForTest(mContext); + mSummaryProvider = new SecuritySettings.SummaryProvider(mContext, mSummaryLoader); + } + + @Test + public void testSummaryProvider_notListening() { + mSummaryProvider.setListening(false); + + verifyNoMoreInteractions(mSummaryLoader); + } + + @Test + @Config(shadows = { + ShadowSecureSettings.class, + }) + public void testSummaryProvider_packageVerifierDisabled() { + // Package verifier state is set to disabled. + ShadowSecureSettings.putInt(null, Settings.Secure.PACKAGE_VERIFIER_STATE, -1); + mSummaryProvider.setListening(true); + + verify(mSummaryLoader, times(1)).setSummary(any(), isNull(String.class)); + } + + @Test + public void testGetPackageVerifierSummary_nullInput() { + assertThat(mSummaryProvider.getPackageVerifierSummary(null)).isNull(); + + when(mDashboardCategory.getTilesCount()).thenReturn(0); + + assertThat(mSummaryProvider.getPackageVerifierSummary(mDashboardCategory)).isNull(); + } + + @Test + public void testGetPackageVerifierSummary_noMatchingTile() { + when(mDashboardCategory.getTilesCount()).thenReturn(1); + when(mDashboardCategory.getTile(0)).thenReturn(new Tile()); + + assertThat(mSummaryProvider.getPackageVerifierSummary(mDashboardCategory)).isNull(); + } + + @Test + @Config(shadows = { + ShadowTileUtils.class, + }) + public void testGetPackageVerifierSummary_matchingTile() { + when(mDashboardCategory.getTilesCount()).thenReturn(1); + Tile tile = new Tile(); + tile.key = SecuritySettings.KEY_PACKAGE_VERIFIER_STATE; + Bundle bundle = new Bundle(); + bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, "content://host/path"); + tile.metaData = bundle; + when(mDashboardCategory.getTile(0)).thenReturn(tile); + + assertThat(mSummaryProvider.getPackageVerifierSummary(mDashboardCategory)) + .isEqualTo(MOCK_SUMMARY); + } +}