From cabc509e4f2d43a65910e1c8aa642aa59d781cae Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 14 Mar 2017 12:38:43 -0700 Subject: [PATCH] Allow page to suppress all of its content from search. To suppress things from search, we usually use preferencecontroller to control individual items. But a page can sometimes to disabled entirely. Now it can set isPageSearchEnabled to false to achieve that. Change-Id: I39424b7fdc6460e27fd7c83cf09b5ace12d1cc37 Fix: 36201167 Test: make RunSettingsRoboTests --- .../android/settings/SettingsActivity.java | 4 +- .../enterprise/EnterprisePrivacySettings.java | 30 ++++++++---- .../search/BaseSearchIndexProvider.java | 48 +++++++++++++++++++ .../EnterprisePrivacySettingsTest.java | 36 +++++++++++++- .../search/BaseSearchIndexProviderTest.java | 34 +++++++++++++ 5 files changed, 139 insertions(+), 13 deletions(-) diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 7a4d5f86390..00a2c7d72d1 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -64,6 +64,7 @@ import com.android.settings.core.instrumentation.SharedPreferencesLogger; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardSummary; import com.android.settings.dashboard.SearchResultsSummary; +import com.android.settings.enterprise.EnterprisePrivacySettings; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.DynamicIndexableContentMonitor; import com.android.settings.search2.SearchFeatureProvider; @@ -945,8 +946,7 @@ public class SettingsActivity extends SettingsDrawerActivity setTileEnabled(new ComponentName(packageName, Settings.EnterprisePrivacySettingsActivity.class.getName()), - FeatureFactory.getFactory(this).getEnterprisePrivacyFeatureProvider(this) - .hasDeviceOwner(), isAdmin); + EnterprisePrivacySettings.isPageEnabled(this), isAdmin); setTileEnabled(new ComponentName(packageName, Settings.WifiDisplaySettingsActivity.class.getName()), diff --git a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java index 140a05c611e..3f66f02ff1a 100644 --- a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java +++ b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java @@ -23,6 +23,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.PreferenceController; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import java.util.ArrayList; @@ -71,14 +72,25 @@ public class EnterprisePrivacySettings extends DashboardFragment { return controllers; } + public static boolean isPageEnabled(Context context) { + return FeatureFactory.getFactory(context) + .getEnterprisePrivacyFeatureProvider(context) + .hasDeviceOwner(); + } + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.enterprise_privacy_settings; - return Arrays.asList(sir); - } - }; + new BaseSearchIndexProvider() { + @Override + protected boolean isPageSearchEnabled(Context context) { + return isPageEnabled(context); + } + + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.enterprise_privacy_settings; + return Arrays.asList(sir); + } + }; } diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java index 38c8d40116a..54f66ead941 100644 --- a/src/com/android/settings/search/BaseSearchIndexProvider.java +++ b/src/com/android/settings/search/BaseSearchIndexProvider.java @@ -17,10 +17,20 @@ package com.android.settings.search; import android.content.Context; +import android.content.res.XmlResourceParser; import android.provider.SearchIndexableResource; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; import com.android.settings.core.PreferenceController; +import com.android.settings.search2.XmlParserUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -30,6 +40,7 @@ import java.util.List; */ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { + private static final String TAG = "BaseSearchIndex"; private static final List EMPTY_LIST = Collections.emptyList(); public BaseSearchIndexProvider() { @@ -47,6 +58,10 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { @Override public List getNonIndexableKeys(Context context) { + if (!isPageSearchEnabled(context)) { + // Entire page should be suppressed, mark all keys from this page as non-indexable. + return getNonIndexableKeysFromXml(context); + } final List controllers = getPreferenceControllers(context); if (controllers != null && !controllers.isEmpty()) { final List nonIndexableKeys = new ArrayList<>(); @@ -63,4 +78,37 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { public List getPreferenceControllers(Context context) { return null; } + + /** + * Returns true if the page should be considered in search query. If return false, entire page + * will be suppressed during search query. + */ + protected boolean isPageSearchEnabled(Context context) { + return true; + } + + private List getNonIndexableKeysFromXml(Context context) { + final List resources = getXmlResourcesToIndex( + context, true /* not used*/); + if (resources == null || resources.isEmpty()) { + return EMPTY_LIST; + } + 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); + } + } + } catch (IOException | XmlPullParserException e) { + Log.w(TAG, "Error parsing non-indexable from xml " + res.xmlResId); + } + } + return nonIndexableKeys; + } + } diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java index 26901989344..29ca4cd52b3 100644 --- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java +++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java @@ -16,22 +16,29 @@ package com.android.settings.enterprise; +import android.content.Context; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.PreferenceController; +import com.android.settings.testutils.FakeFeatureFactory; 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.shadows.ShadowApplication; -import static com.google.common.truth.Truth.assertThat; - import java.util.List; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + /** * Tests for {@link EnterprisePrivacySettings}. */ @@ -39,10 +46,17 @@ import java.util.List; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public final class EnterprisePrivacySettingsTest { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + private FakeFeatureFactory mFeatureFactory; private EnterprisePrivacySettings mSettings; @Before public void setUp() { + MockitoAnnotations.initMocks(this); + FakeFeatureFactory.setupForTest(mContext); + mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); + mSettings = new EnterprisePrivacySettings(); } @@ -68,6 +82,24 @@ public final class EnterprisePrivacySettingsTest { .isEqualTo(R.xml.enterprise_privacy_settings); } + @Test + public void isPageEnabled_hasDeviceOwner_shouldReturnTrue() { + when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner()) + .thenReturn(true); + + assertThat(EnterprisePrivacySettings.isPageEnabled(mContext)) + .isTrue(); + } + + @Test + public void isPageEnabled_noDeviceOwner_shouldReturnFalse() { + when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner()) + .thenReturn(false); + + assertThat(EnterprisePrivacySettings.isPageEnabled(mContext)) + .isFalse(); + } + @Test public void getPreferenceControllers() { final List controllers = mSettings.getPreferenceControllers( diff --git a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java index 818f8a25655..6a3447291bd 100644 --- a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java @@ -18,7 +18,9 @@ package com.android.settings.search; import android.content.Context; +import android.provider.SearchIndexableResource; +import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.PreferenceController; @@ -28,9 +30,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -96,4 +100,34 @@ public class BaseSearchIndexProviderTest { assertThat(mIndexProvider.getNonIndexableKeys(mContext)).contains(TEST_PREF_KEY); } + + @Test + public void getNonIndexableKeys_pageSearchIsDisabled_shouldSuppressEverything() { + final BaseSearchIndexProvider provider = new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.language_and_input; + return Arrays.asList(sir); + } + + @Override + protected boolean isPageSearchEnabled(Context context) { + return false; + } + }; + + final List nonIndexableKeys = provider + .getNonIndexableKeys(RuntimeEnvironment.application); + + assertThat(nonIndexableKeys).containsAllOf("phone_language", "spellcheckers_settings", + "key_user_dictionary_settings", "gesture_settings_category", "gesture_assist", + "gesture_swipe_down_fingerprint", "gesture_double_tap_power", + "gesture_double_twist", "gesture_double_tap_screen", "gesture_pick_up", + "pointer_settings_category", "pointer_speed", "voice_category", "tts_settings", + "game_controller_settings_category", "vibrate_input_devices"); + } + + }