diff --git a/res/xml/encryption_and_credential.xml b/res/xml/encryption_and_credential.xml index be643b16ff4..715ea141158 100644 --- a/res/xml/encryption_and_credential.xml +++ b/res/xml/encryption_and_credential.xml @@ -24,25 +24,21 @@ android:order="100"> + android:title="@string/credential_storage_type" /> + android:summary="@string/credentials_install_summary"> + android:summary="@string/credentials_reset_summary"> diff --git a/res/xml/security_settings_unencrypted.xml b/res/xml/security_settings_unencrypted.xml index 7c51d259aae..27dbe968038 100644 --- a/res/xml/security_settings_unencrypted.xml +++ b/res/xml/security_settings_unencrypted.xml @@ -18,14 +18,14 @@ android:title="@string/crypt_keeper_settings_title"> - + diff --git a/src/com/android/settings/EncryptionAndCredential.java b/src/com/android/settings/EncryptionAndCredential.java index 3cb2740ad73..4892f7ef389 100644 --- a/src/com/android/settings/EncryptionAndCredential.java +++ b/src/com/android/settings/EncryptionAndCredential.java @@ -20,7 +20,6 @@ import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -34,7 +33,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; @@ -106,7 +104,6 @@ public class EncryptionAndCredential extends SettingsPreferenceFragment implemen } } - // Credential storage mKeyStore = KeyStore.getInstance(); // needs to be initialized for onResume() @@ -182,83 +179,57 @@ public class EncryptionAndCredential extends SettingsPreferenceFragment implemen @Override public List getXmlResourcesToIndex( Context context, boolean enabled) { - final List index = new ArrayList(); + final List index = new ArrayList<>(); - final DevicePolicyManager dpm = (DevicePolicyManager) - context.getSystemService(Context.DEVICE_POLICY_SERVICE); - final UserManager um = UserManager.get(context); - - if (um.isAdminUser()) { - switch (dpm.getStorageEncryptionStatus()) { - case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE: - // The device is currently encrypted. - index.add(getSearchResource(context, R.xml.security_settings_encrypted)); - break; - case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE: - // This device supports encryption but isn't encrypted. - index.add(getSearchResource(context, R.xml.security_settings_unencrypted)); - break; - } - } + // Add everything. We will suppress some of them in getNonIndexableKeys() + index.add(getSearchResource(context, R.xml.encryption_and_credential)); + index.add(getSearchResource(context, R.xml.security_settings_encrypted)); + index.add(getSearchResource(context, R.xml.security_settings_unencrypted)); return index; } + @Override + protected boolean isPageSearchEnabled(Context context) { + final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); + return um.isAdminUser(); + } + private SearchIndexableResource getSearchResource(Context context, int xmlResId) { final SearchIndexableResource sir = new SearchIndexableResource(context); sir.xmlResId = xmlResId; return sir; } - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final List result = new ArrayList(); - final Resources res = context.getResources(); - - final String screenTitle = res.getString( - R.string.encryption_and_credential_settings_title); - - SearchIndexableRaw data = new SearchIndexableRaw(context); - data.title = screenTitle; - data.screenTitle = screenTitle; - result.add(data); - - final UserManager um = UserManager.get(context); - if (!um.isAdminUser()) { - int resId = um.isLinkedUser() ? - R.string.profile_info_settings_title : R.string.user_info_settings_title; - - data = new SearchIndexableRaw(context); - data.title = res.getString(resId); - data.screenTitle = screenTitle; - result.add(data); - } - - // Credential storage - if (!um.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { - KeyStore keyStore = KeyStore.getInstance(); - - final int storageSummaryRes = keyStore.isHardwareBacked() ? - R.string.credential_storage_type_hardware : - R.string.credential_storage_type_software; - - data = new SearchIndexableRaw(context); - data.title = res.getString(storageSummaryRes); - data.screenTitle = screenTitle; - result.add(data); - } - - return result; - } - @Override public List getNonIndexableKeys(Context context) { final List keys = super.getNonIndexableKeys(context); - - final UserManager um = UserManager.get(context); + if (!isPageSearchEnabled(context)) { + return keys; + } + final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { keys.add(KEY_CREDENTIALS_MANAGER); + keys.add(KEY_RESET_CREDENTIALS); + keys.add(KEY_CREDENTIALS_INSTALL); + keys.add(KEY_CREDENTIAL_STORAGE_TYPE); + keys.add(KEY_USER_CREDENTIALS); + } + + final DevicePolicyManager dpm = (DevicePolicyManager) + context.getSystemService(Context.DEVICE_POLICY_SERVICE); + switch (dpm.getStorageEncryptionStatus()) { + case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE: + // The device is currently encrypted. Disable security_settings_unencrypted + keys.addAll(getNonIndexableKeysFromXml( + context, R.xml.security_settings_unencrypted)); + break; + default: + // This device supports encryption but isn't encrypted. + keys.addAll(getNonIndexableKeysFromXml( + context, R.xml.security_settings_encrypted)); + break; } return keys; diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java index 11b4db12154..239de15ff4c 100644 --- a/src/com/android/settings/search/BaseSearchIndexProvider.java +++ b/src/com/android/settings/search/BaseSearchIndexProvider.java @@ -16,10 +16,12 @@ package com.android.settings.search; +import android.annotation.XmlRes; import android.content.Context; import android.content.res.XmlResourceParser; import android.provider.SearchIndexableResource; import android.support.annotation.CallSuper; +import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -94,18 +96,25 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { } final List nonIndexableKeys = new ArrayList<>(); for (SearchIndexableResource res : resources) { - final XmlResourceParser parser = context.getResources().getXml(res.xmlResId); - final AttributeSet attrs = Xml.asAttributeSet(parser); - try { - while (parser.next() != XmlPullParser.END_DOCUMENT) { - final String key = XmlParserUtils.getDataKey(context, attrs); - if (!TextUtils.isEmpty(key)) { - nonIndexableKeys.add(key); - } + nonIndexableKeys.addAll(getNonIndexableKeysFromXml(context, res.xmlResId)); + } + return nonIndexableKeys; + } + + @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) + public List getNonIndexableKeysFromXml(Context context, @XmlRes int xmlResId) { + final List nonIndexableKeys = new ArrayList<>(); + final XmlResourceParser parser = context.getResources().getXml(xmlResId); + final AttributeSet attrs = Xml.asAttributeSet(parser); + try { + while (parser.next() != XmlPullParser.END_DOCUMENT) { + final String key = XmlParserUtils.getDataKey(context, attrs); + if (!TextUtils.isEmpty(key)) { + nonIndexableKeys.add(key); } - } catch (IOException | XmlPullParserException e) { - Log.w(TAG, "Error parsing non-indexable from xml " + res.xmlResId); } + } catch (IOException | XmlPullParserException e) { + Log.w(TAG, "Error parsing non-indexable from xml " + xmlResId); } return nonIndexableKeys; } diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 9b84bf1087e..31d39b5e367 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -171,8 +171,7 @@ public final class SearchIndexableResources { addIndex(LocationSettings.class, R.xml.location_settings, R.drawable.ic_settings_location); addIndex(ScanningSettings.class, R.xml.location_scanning, R.drawable.ic_settings_location); addIndex(SecuritySettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_security); - addIndex(EncryptionAndCredential.class, R.xml.encryption_and_credential, - R.drawable.ic_settings_security); + addIndex(EncryptionAndCredential.class, NO_DATA_RES_ID, R.drawable.ic_settings_security); addIndex(ScreenPinningSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_security); addIndex(UserAndAccountDashboardFragment.class, NO_DATA_RES_ID, R.drawable.ic_settings_accounts); diff --git a/tests/robotests/src/com/android/settings/EncryptionAndCredentialTest.java b/tests/robotests/src/com/android/settings/EncryptionAndCredentialTest.java index bc88b1aaa46..7a3875e8128 100644 --- a/tests/robotests/src/com/android/settings/EncryptionAndCredentialTest.java +++ b/tests/robotests/src/com/android/settings/EncryptionAndCredentialTest.java @@ -16,23 +16,110 @@ package com.android.settings; +import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE; +import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE; +import static com.android.settings.EncryptionAndCredential.SEARCH_INDEX_DATA_PROVIDER; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserManager; +import android.provider.SearchIndexableResource; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import static com.google.common.truth.Truth.assertThat; - +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; + +import java.util.ArrayList; +import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class EncryptionAndCredentialTest { + @Mock + private UserManager mUserManager; + @Mock + private DevicePolicyManager mDevicePolicyManager; + + private ShadowApplication mApplication; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mApplication = ShadowApplication.getInstance(); + mApplication.setSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager); + mApplication.setSystemService(Context.USER_SERVICE, mUserManager); + mContext = mApplication.getApplicationContext(); + } + @Test public void getMetricsCategory_shouldReturnEncryptionAndCredential() { EncryptionAndCredential fragment = new EncryptionAndCredential(); assertThat(fragment.getMetricsCategory()).isEqualTo(MetricsEvent.ENCRYPTION_AND_CREDENTIAL); } + // Search provider tests + @Test + public void getXmlResourcesToIndex_shouldReturnAllXmls() { + final List index = + SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( + mContext, true /* enabled */); + + assertThat(index).hasSize(3); + } + + @Test + public void getNonIndexableKeys_pageIsDisabled_shouldReturnAllKeysAsNonIndexable() { + when(mUserManager.isAdminUser()).thenReturn(false); + + final List index = + SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(mContext, true /* enabled */); + final List expectedKeys = new ArrayList<>(); + for (SearchIndexableResource res : index) { + expectedKeys.addAll(((BaseSearchIndexProvider) SEARCH_INDEX_DATA_PROVIDER) + .getNonIndexableKeysFromXml(mContext, res.xmlResId)); + } + final List keys = SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(keys).containsExactlyElementsIn(expectedKeys); + } + + @Test + public void getNonIndexableKeys_deviceEncrypted_shouldReturnUnencryptedKeys() { + when(mUserManager.isAdminUser()).thenReturn(true); + when(mDevicePolicyManager.getStorageEncryptionStatus()).thenReturn( + ENCRYPTION_STATUS_ACTIVE); + + final List expectedKeys = new ArrayList<>(); + expectedKeys.addAll(((BaseSearchIndexProvider) SEARCH_INDEX_DATA_PROVIDER) + .getNonIndexableKeysFromXml(mContext, R.xml.security_settings_unencrypted)); + final List keys = SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(keys).containsExactlyElementsIn(expectedKeys); + } + + @Test + public void getNonIndexableKeys_deviceNotEncrypted_shouldReturnEncryptedKeys() { + when(mUserManager.isAdminUser()).thenReturn(true); + when(mDevicePolicyManager.getStorageEncryptionStatus()) + .thenReturn(ENCRYPTION_STATUS_INACTIVE); + + final List expectedKeys = new ArrayList<>(); + expectedKeys.addAll(((BaseSearchIndexProvider) SEARCH_INDEX_DATA_PROVIDER) + .getNonIndexableKeysFromXml(mContext, R.xml.security_settings_encrypted)); + final List keys = SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(keys).containsExactlyElementsIn(expectedKeys); + } }