diff --git a/res/values/attrs.xml b/res/values/attrs.xml index b77c5442f7e..a4ce9f0af7e 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -69,6 +69,8 @@ + + diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml index dd661e08872..5a55ba5dab0 100644 --- a/res/xml/app_and_notification.xml +++ b/res/xml/app_and_notification.xml @@ -71,6 +71,7 @@ android:key="special_access" android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings" android:title="@string/special_access" - android:order="20" /> + android:order="20" + settings:searchable="false"/> diff --git a/res/xml/app_default_settings.xml b/res/xml/app_default_settings.xml index 3b7c80b1925..54676679875 100644 --- a/res/xml/app_default_settings.xml +++ b/res/xml/app_default_settings.xml @@ -25,7 +25,7 @@ android:key="assist_and_voice_input" android:title="@string/assist_and_voice_input_title" android:fragment="com.android.settings.applications.assist.ManageAssist" - settings:keywords="@string/keywords_assist_input"/> + settings:searchable="false"/> + android:fragment="com.android.settings.applications.defaultapps.DefaultBrowserPicker" + settings:searchable="false"> @@ -94,7 +95,7 @@ android:key="work_default_phone_app" android:title="@string/default_phone_title" android:fragment="com.android.settings.applications.defaultapps.DefaultPhonePicker" - settings:keywords="@string/keywords_default_phone_app"> + settings:searchable="false"> diff --git a/res/xml/default_autofill_picker_settings.xml b/res/xml/default_autofill_picker_settings.xml index 26dff7eca87..da72b43fec8 100644 --- a/res/xml/default_autofill_picker_settings.xml +++ b/res/xml/default_autofill_picker_settings.xml @@ -32,7 +32,7 @@ + android:fragment="com.android.settings.development.featureflags.FeatureFlagsDashboard" + settings:searchable="false" /> + android:title="@string/assist_and_voice_input_title" + settings:keywords="@string/keywords_assist_input"> getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - keys.add((new SpecialAppAccessPreferenceController(context)) - .getPreferenceKey()); - return keys; - } }; } diff --git a/src/com/android/settings/applications/DefaultAppSettings.java b/src/com/android/settings/applications/DefaultAppSettings.java index 3af5bc2882f..d8fd9ebb725 100644 --- a/src/com/android/settings/applications/DefaultAppSettings.java +++ b/src/com/android/settings/applications/DefaultAppSettings.java @@ -101,16 +101,6 @@ public class DefaultAppSettings extends DashboardFragment { return Arrays.asList(sir); } - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - keys.add(KEY_ASSIST_VOICE_INPUT); - // TODO (b/38230148) Remove these keys when we can differentiate work results - keys.add(DefaultWorkPhonePreferenceController.KEY); - keys.add(DefaultWorkBrowserPreferenceController.KEY); - return keys; - } - @Override public List createPreferenceControllers( Context context) { diff --git a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java index 4a99f5abed6..131a2340532 100644 --- a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java +++ b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java @@ -40,7 +40,7 @@ public class BackupSettingsActivityPreferenceController extends BasePreferenceCo @Override public int getAvailabilityStatus() { return mUm.isAdminUser() - ? AVAILABLE + ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java index 6cceaf3e518..14b8a811de8 100644 --- a/src/com/android/settings/core/BasePreferenceController.java +++ b/src/com/android/settings/core/BasePreferenceController.java @@ -274,6 +274,10 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl Log.w(TAG, "Skipping updateNonIndexableKeys due to empty key " + toString()); return; } + if (keys.contains(key)) { + Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list. " + toString()); + return; + } keys.add(key); } } diff --git a/src/com/android/settings/core/PreferenceControllerMixin.java b/src/com/android/settings/core/PreferenceControllerMixin.java index 3310df2fddf..da0b7e73d14 100644 --- a/src/com/android/settings/core/PreferenceControllerMixin.java +++ b/src/com/android/settings/core/PreferenceControllerMixin.java @@ -42,7 +42,12 @@ public interface PreferenceControllerMixin { final String key = ((AbstractPreferenceController) this).getPreferenceKey(); if (TextUtils.isEmpty(key)) { Log.w(TAG, - "Skipping updateNonIndexableKeys due to empty key " + this.toString()); + "Skipping updateNonIndexableKeys due to empty key " + toString()); + return; + } + if (keys.contains(key)) { + Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list. " + + toString()); return; } keys.add(key); diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java index ff196dcaaf6..8ef7f8dc460 100644 --- a/src/com/android/settings/core/PreferenceXmlParserUtils.java +++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java @@ -29,6 +29,9 @@ import android.util.Log; import android.util.TypedValue; import android.util.Xml; +import androidx.annotation.IntDef; +import androidx.annotation.VisibleForTesting; + import com.android.settings.R; import org.xmlpull.v1.XmlPullParser; @@ -41,9 +44,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import androidx.annotation.IntDef; -import androidx.annotation.VisibleForTesting; - /** * Utility class to parse elements of XML preferences */ @@ -53,7 +53,8 @@ public class PreferenceXmlParserUtils { @VisibleForTesting static final String PREF_SCREEN_TAG = "PreferenceScreen"; private static final List SUPPORTED_PREF_TYPES = Arrays.asList( - "Preference", "PreferenceCategory", "PreferenceScreen"); + "Preference", "PreferenceCategory", "PreferenceScreen", + "com.android.settings.widget.WorkOnlyCategory"); /** * Flag definition to indicate which metadata should be extracted when @@ -67,7 +68,8 @@ public class PreferenceXmlParserUtils { MetadataFlag.FLAG_NEED_PREF_CONTROLLER, MetadataFlag.FLAG_NEED_PREF_TITLE, MetadataFlag.FLAG_NEED_PREF_SUMMARY, - MetadataFlag.FLAG_NEED_PREF_ICON}) + MetadataFlag.FLAG_NEED_PREF_ICON, + MetadataFlag.FLAG_NEED_SEARCHABLE}) @Retention(RetentionPolicy.SOURCE) public @interface MetadataFlag { int FLAG_INCLUDE_PREF_SCREEN = 1; @@ -79,6 +81,7 @@ public class PreferenceXmlParserUtils { int FLAG_NEED_PREF_ICON = 1 << 6; int FLAG_NEED_PLATFORM_SLICE_FLAG = 1 << 7; int FLAG_NEED_KEYWORDS = 1 << 8; + int FLAG_NEED_SEARCHABLE = 1 << 9; } public static final String METADATA_PREF_TYPE = "type"; @@ -89,6 +92,7 @@ public class PreferenceXmlParserUtils { public static final String METADATA_ICON = "icon"; public static final String METADATA_PLATFORM_SLICE_FLAG = "platform_slice"; public static final String METADATA_KEYWORDS = "keywords"; + public static final String METADATA_SEARCHABLE = "searchable"; private static final String ENTRIES_SEPARATOR = "|"; @@ -154,18 +158,6 @@ public class PreferenceXmlParserUtils { R.styleable.Preference_controller); } - /** - * Call {@link #extractMetadata(Context, int, int)} with {@link #METADATA_ICON} instead. - */ - @Deprecated - public static int getDataIcon(Context context, AttributeSet attrs) { - final TypedArray ta = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.Preference); - final int dataIcon = ta.getResourceId(com.android.internal.R.styleable.Icon_icon, 0); - ta.recycle(); - return dataIcon; - } - /** * Extracts metadata from preference xml and put them into a {@link Bundle}. * @@ -232,6 +224,10 @@ public class PreferenceXmlParserUtils { if (hasFlag(flags, MetadataFlag.FLAG_NEED_KEYWORDS)) { preferenceMetadata.putString(METADATA_KEYWORDS, getKeywords(preferenceAttributes)); } + if (hasFlag(flags, MetadataFlag.FLAG_NEED_SEARCHABLE)) { + preferenceMetadata.putBoolean(METADATA_SEARCHABLE, + isSearchable(preferenceAttributes)); + } metadata.add(preferenceMetadata); preferenceAttributes.recycle(); @@ -312,6 +308,10 @@ public class PreferenceXmlParserUtils { return styledAttributes.getBoolean(R.styleable.Preference_platform_slice, false /* def */); } + private static boolean isSearchable(TypedArray styledAttributes) { + return styledAttributes.getBoolean(R.styleable.Preference_searchable, true /* default */); + } + private static String getKeywords(TypedArray styleAttributes) { return styleAttributes.getString(R.styleable.Preference_keywords); } diff --git a/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java b/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java index ae8e246b0b4..90266e03a65 100644 --- a/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java +++ b/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; @@ -30,7 +31,7 @@ final class AutofillDeveloperSettingsObserver extends ContentObserver { private final ContentResolver mResolver; public AutofillDeveloperSettingsObserver(Context context, Runnable changeCallback) { - super(new Handler()); + super(new Handler(Looper.getMainLooper())); mResolver = context.getContentResolver(); mChangeCallback = changeCallback; diff --git a/src/com/android/settings/gestures/SwipeUpPreferenceController.java b/src/com/android/settings/gestures/SwipeUpPreferenceController.java index f48d21b90d4..5e882c4e44f 100644 --- a/src/com/android/settings/gestures/SwipeUpPreferenceController.java +++ b/src/com/android/settings/gestures/SwipeUpPreferenceController.java @@ -47,6 +47,9 @@ public class SwipeUpPreferenceController extends GesturePreferenceController { final ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(R.string.config_recentsComponentName)); + if (recentsComponentName == null) { + return false; + } final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP) .setPackage(recentsComponentName.getPackageName()); if (context.getPackageManager().resolveService(quickStepIntent, diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java index 6c7c0d3861c..68b1b2446bb 100644 --- a/src/com/android/settings/language/LanguageAndInputSettings.java +++ b/src/com/android/settings/language/LanguageAndInputSettings.java @@ -108,7 +108,7 @@ public class LanguageAndInputSettings extends DashboardFragment { // Pointer and Tts final TtsPreferenceController ttsPreferenceController = - new TtsPreferenceController(context, new TtsEngines(context)); + new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH); controllers.add(ttsPreferenceController); final PointerSpeedController pointerController = new PointerSpeedController(context); controllers.add(pointerController); @@ -180,7 +180,6 @@ public class LanguageAndInputSettings extends DashboardFragment { public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); // Duplicates in summary and details pages. - keys.add(KEY_TEXT_TO_SPEECH); keys.add(KEY_PHYSICAL_KEYBOARD); return keys; } diff --git a/src/com/android/settings/language/TtsPreferenceController.java b/src/com/android/settings/language/TtsPreferenceController.java index c83492c4883..7e34175ce99 100644 --- a/src/com/android/settings/language/TtsPreferenceController.java +++ b/src/com/android/settings/language/TtsPreferenceController.java @@ -19,31 +19,26 @@ package com.android.settings.language; import android.content.Context; import android.speech.tts.TtsEngines; +import androidx.annotation.VisibleForTesting; + import com.android.settings.R; -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settings.core.BasePreferenceController; -public class TtsPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin { +public class TtsPreferenceController extends BasePreferenceController { - private static final String KEY_VOICE_CATEGORY = "voice_category"; - private static final String KEY_TTS_SETTINGS = "tts_settings_summary"; + @VisibleForTesting + TtsEngines mTtsEngines; - private final TtsEngines mTtsEngines; - - public TtsPreferenceController(Context context, TtsEngines ttsEngines) { - super(context); - mTtsEngines = ttsEngines; + public TtsPreferenceController(Context context, String key) { + super(context, key); + mTtsEngines = new TtsEngines(context); } @Override - public boolean isAvailable() { + public int getAvailabilityStatus() { return !mTtsEngines.getEngines().isEmpty() && - mContext.getResources().getBoolean(R.bool.config_show_tts_settings_summary); - } - - @Override - public String getPreferenceKey() { - return KEY_TTS_SETTINGS; + mContext.getResources().getBoolean(R.bool.config_show_tts_settings_summary) + ? AVAILABLE_UNSEARCHABLE + : CONDITIONALLY_UNAVAILABLE; } } diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java index fcfa8aadb6a..efbefde5b48 100644 --- a/src/com/android/settings/search/BaseSearchIndexProvider.java +++ b/src/com/android/settings/search/BaseSearchIndexProvider.java @@ -16,14 +16,21 @@ package com.android.settings.search; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag + .FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_SEARCHABLE; + import android.annotation.XmlRes; import android.content.Context; -import android.content.res.XmlResourceParser; +import android.os.Bundle; import android.provider.SearchIndexableResource; -import android.text.TextUtils; -import android.util.AttributeSet; import android.util.Log; -import android.util.Xml; + +import androidx.annotation.CallSuper; +import androidx.annotation.VisibleForTesting; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerListHelper; @@ -31,16 +38,12 @@ import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceXmlParserUtils; import com.android.settingslib.core.AbstractPreferenceController; -import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import androidx.annotation.CallSuper; -import androidx.annotation.VisibleForTesting; - /** * A basic SearchIndexProvider that returns no data to index. */ @@ -66,11 +69,12 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { 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); + return getNonIndexableKeysFromXml(context, true /* suppressAllPage */); } + final List nonIndexableKeys = new ArrayList<>(); + nonIndexableKeys.addAll(getNonIndexableKeysFromXml(context, false /* suppressAllPage */)); final List controllers = getPreferenceControllers(context); if (controllers != null && !controllers.isEmpty()) { - final List nonIndexableKeys = new ArrayList<>(); for (AbstractPreferenceController controller : controllers) { if (controller instanceof PreferenceControllerMixin) { ((PreferenceControllerMixin) controller) @@ -85,10 +89,8 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { nonIndexableKeys.add(controller.getPreferenceKey()); } } - return nonIndexableKeys; - } else { - return new ArrayList<>(); } + return nonIndexableKeys; } @Override @@ -131,7 +133,11 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { return true; } - private List getNonIndexableKeysFromXml(Context context) { + /** + * Get all non-indexable keys from xml. If {@param suppressAllPage} is set, all keys are + * considered non-indexable. Otherwise, only keys with searchable="false" are included. + */ + private List getNonIndexableKeysFromXml(Context context, boolean suppressAllPage) { final List resources = getXmlResourcesToIndex( context, true /* not used*/); if (resources == null || resources.isEmpty()) { @@ -139,27 +145,32 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { } final List nonIndexableKeys = new ArrayList<>(); for (SearchIndexableResource res : resources) { - nonIndexableKeys.addAll(getNonIndexableKeysFromXml(context, res.xmlResId)); + nonIndexableKeys.addAll( + getNonIndexableKeysFromXml(context, res.xmlResId, suppressAllPage)); } 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); + public List getNonIndexableKeysFromXml(Context context, @XmlRes int xmlResId, + boolean suppressAllPage) { + return getKeysFromXml(context, xmlResId, suppressAllPage); + } + + private List getKeysFromXml(Context context, @XmlRes int xmlResId, + boolean suppressAllPage) { + final List keys = new ArrayList<>(); try { - while (parser.next() != XmlPullParser.END_DOCUMENT) { - final String key = PreferenceXmlParserUtils.getDataKey(context, attrs); - if (!TextUtils.isEmpty(key)) { - nonIndexableKeys.add(key); + final List metadata = PreferenceXmlParserUtils.extractMetadata(context, + xmlResId, FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN | FLAG_NEED_SEARCHABLE); + for (Bundle bundle : metadata) { + if (suppressAllPage || !bundle.getBoolean(METADATA_SEARCHABLE, true)) { + keys.add(bundle.getString(METADATA_KEY)); } } } catch (IOException | XmlPullParserException e) { Log.w(TAG, "Error parsing non-indexable from xml " + xmlResId); } - return nonIndexableKeys; + return keys; } - } diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java index 52349ae6fa8..0c73e4d8913 100644 --- a/src/com/android/settings/system/SystemDashboardFragment.java +++ b/src/com/android/settings/system/SystemDashboardFragment.java @@ -101,8 +101,6 @@ public class SystemDashboardFragment extends DashboardFragment { @Override public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); - keys.add((new BackupSettingsActivityPreferenceController( - context).getPreferenceKey())); keys.add(KEY_RESET); return keys; } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 9aa56c234d3..89e9a67978c 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -49,6 +49,13 @@ import android.view.MenuItem; import android.view.View; import android.widget.SimpleAdapter; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; import com.android.internal.widget.LockPatternUtils; @@ -76,13 +83,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; -import androidx.annotation.VisibleForTesting; -import androidx.annotation.WorkerThread; -import androidx.appcompat.app.AlertDialog; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceScreen; - /** * Screen that manages the list of users on the device. * Guest user is an always visible entry, even if the guest is not currently @@ -635,8 +635,8 @@ public class UserSettings extends SettingsPreferenceFragment AlertDialog.Builder builder = new AlertDialog.Builder(context); SimpleAdapter adapter = new SimpleAdapter(builder.getContext(), data, R.layout.two_line_list_item, - new String[] {KEY_TITLE, KEY_SUMMARY}, - new int[] {R.id.title, R.id.summary}); + new String[]{KEY_TITLE, KEY_SUMMARY}, + new int[]{R.id.title, R.id.summary}); builder.setTitle(R.string.user_add_user_type_title); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @@ -1238,8 +1238,10 @@ public class UserSettings extends SettingsPreferenceFragment } @Override - public List getNonIndexableKeysFromXml(Context context, int xmlResId) { - final List niks = super.getNonIndexableKeysFromXml(context, xmlResId); + public List getNonIndexableKeysFromXml(Context context, int xmlResId, + boolean suppressAllPage) { + final List niks = super.getNonIndexableKeysFromXml(context, xmlResId, + suppressAllPage); new AddUserWhenLockedPreferenceController(context, KEY_ADD_USER_WHEN_LOCKED) .updateNonIndexableKeys(niks); new AutoSyncDataPreferenceController(context, null /* parent */) diff --git a/tests/robotests/res/xml-mcc999/display_settings.xml b/tests/robotests/res/xml-mcc999/display_settings.xml index 8c5d47ad4f5..fccad7fb454 100644 --- a/tests/robotests/res/xml-mcc999/display_settings.xml +++ b/tests/robotests/res/xml-mcc999/display_settings.xml @@ -59,5 +59,6 @@ android:title="pref_title_5" android:summaryOn="summary_on" android:summaryOff="summary_off" + settings:searchable="false" settings:keywords="keywords1, keywords2, keywords3" /> \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java index 97210b332b4..c332c064da3 100644 --- a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java @@ -17,6 +17,7 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -26,7 +27,6 @@ import android.os.UserManager; import com.android.settings.notification.EmergencyBroadcastPreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.XmlTestUtils; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,19 +42,16 @@ public class AppAndNotificationDashboardFragmentTest { @Test @Config(shadows = {ShadowEmergencyBroadcastPreferenceController.class}) - public void testNonIndexableKeys_existInXmlLayout() { + public void getNonIndexableKeys_shouldIncludeSpecialAppAccess() { final Context context = spy(RuntimeEnvironment.application); UserManager manager = mock(UserManager.class); when(manager.isAdminUser()).thenReturn(true); when(context.getSystemService(Context.USER_SERVICE)).thenReturn(manager); final List niks = AppAndNotificationDashboardFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(context); - AppAndNotificationDashboardFragment fragment = new AppAndNotificationDashboardFragment(); - final int xmlId = fragment.getPreferenceScreenResId(); - final List keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId); - - assertThat(keys).containsAllIn(niks); + assertThat(niks).contains( + new SpecialAppAccessPreferenceController(context).getPreferenceKey()); } @Implements(EmergencyBroadcastPreferenceController.class) diff --git a/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java b/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java index fef8eefee69..dda6b72e9f2 100644 --- a/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java +++ b/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java @@ -165,7 +165,7 @@ public class DefaultAppSettingsTest { final List niks = DefaultAppSettings.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(context); - final int xmlId = (new DefaultAppSettings()).getPreferenceScreenResId(); + final int xmlId = new DefaultAppSettings().getPreferenceScreenResId(); final List keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId); diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java index 70cfa21df20..b3dbdab01eb 100644 --- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java +++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java @@ -16,7 +16,10 @@ package com.android.settings.core; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; @@ -247,8 +250,7 @@ public class PreferenceXmlParserUtilsTest { @Test @Config(qualifiers = "mcc999") - public void extractMetadata_requestIncludesKeywords_shouldContainKeywords() - throws IOException, XmlPullParserException { + public void extractMetadata_requestIncludesKeywords_shouldContainKeywords() throws Exception { final String expectedKeywords = "a, b, c"; final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, R.xml.location_settings, @@ -260,6 +262,32 @@ public class PreferenceXmlParserUtilsTest { assertThat(keywords).isEqualTo(expectedKeywords); } + @Test + public void extractMetadata_requestSearchable_shouldDefaultToTrue() throws Exception { + final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, + R.xml.display_settings, MetadataFlag.FLAG_NEED_SEARCHABLE); + for (Bundle bundle : metadata) { + assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isTrue(); + } + } + + @Test + @Config(qualifiers = "mcc999") + public void extractMetadata_requestSearchable_shouldReturnAttributeValue() throws Exception { + final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, + R.xml.display_settings, + MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_SEARCHABLE); + boolean foundKey = false; + for (Bundle bundle : metadata) { + if (TextUtils.equals(bundle.getString(METADATA_KEY), "pref_key_5")) { + assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isFalse(); + foundKey = true; + break; + } + } + assertThat(foundKey).isTrue(); + } + /** * @param resId the ID for the XML preference * @return an XML resource parser that points to the start tag diff --git a/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java index cffe9213fb4..c483b8ccc9a 100644 --- a/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.language; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -25,6 +26,9 @@ import android.content.Context; import android.speech.tts.TextToSpeech; import android.speech.tts.TtsEngines; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -38,9 +42,6 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - @RunWith(SettingsRobolectricTestRunner.class) public class TtsPreferenceControllerTest { @@ -58,7 +59,8 @@ public class TtsPreferenceControllerTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mController = new TtsPreferenceController(mContext, mTtsEngines); + mController = new TtsPreferenceController(mContext, "test_key"); + mController.mTtsEngines = mTtsEngines; mPreference = new Preference(RuntimeEnvironment.application); mPreference.setKey(mController.getPreferenceKey()); when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); diff --git a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java index df60654c1f0..0c507d9605d 100644 --- a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java @@ -169,4 +169,24 @@ public class BaseSearchIndexProviderTest { assertThat(nonIndexableKeys).contains("status_header"); } + + @Test + @Config(qualifiers = "mcc999") + public void getNonIndexableKeys_hasSearchableAttributeInXml_shouldSuppressUnsearchable() { + final BaseSearchIndexProvider provider = new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.display_settings; + return Collections.singletonList(sir); + } + + }; + + final List nonIndexableKeys = + provider.getNonIndexableKeys(RuntimeEnvironment.application); + + assertThat(nonIndexableKeys).contains("pref_key_5"); + } } diff --git a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java index e76f43dd4b5..e3ef15e9174 100644 --- a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java @@ -1,6 +1,7 @@ package com.android.settings.search; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -21,6 +22,9 @@ import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import java.util.ArrayList; +import java.util.List; + @RunWith(SettingsRobolectricTestRunner.class) public class SettingsSearchIndexablesProviderTest { @@ -96,16 +100,19 @@ public class SettingsSearchIndexablesProviderTest { @Test @Config(qualifiers = "mcc999") public void testNonIndexablesColumnFetched() { - Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" + + final Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" + SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH); - final Cursor cursor = mProvider.query(rawUri, - SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null); + final List keys = new ArrayList<>(); - cursor.moveToFirst(); - assertThat(cursor.getCount()).isEqualTo(2); - assertThat(cursor.getString(0)).isEqualTo("pref_key_1"); - cursor.moveToNext(); - assertThat(cursor.getString(0)).isEqualTo("pref_key_3"); + try (Cursor cursor = mProvider.query(rawUri, + SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null)) { + while (cursor.moveToNext()) { + keys.add(cursor.getString(0)); + } + } + + assertThat(keys).hasSize(3); + assertThat(keys).containsAllOf("pref_key_1", "pref_key_3", "pref_key_5"); } } diff --git a/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java b/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java index 6e49f1e3949..9d26de2e6d3 100644 --- a/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java +++ b/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java @@ -73,7 +73,7 @@ public class EncryptionAndCredentialTest { final List expectedKeys = new ArrayList<>(); for (SearchIndexableResource res : index) { expectedKeys.addAll(((BaseSearchIndexProvider) SEARCH_INDEX_DATA_PROVIDER) - .getNonIndexableKeysFromXml(mContext, res.xmlResId)); + .getNonIndexableKeysFromXml(mContext, res.xmlResId, true /* suppressAll */)); } final List keys = SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); diff --git a/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java b/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java index 7e8493e0efe..6a96cf0cf59 100644 --- a/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java @@ -1,15 +1,16 @@ package com.android.settings.testutils; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag + .FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; + import android.content.Context; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; +import android.os.Bundle; import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Xml; import com.android.settings.core.PreferenceXmlParserUtils; -import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.util.ArrayList; @@ -25,30 +26,21 @@ public class XmlTestUtils { * on the screen. * * @param context of the preference screen. - * @param xmlId of the Preference Xml to be parsed. + * @param xmlId of the Preference Xml to be parsed. * @return List of all keys in the preference Xml */ public static List getKeysFromPreferenceXml(Context context, int xmlId) { - final XmlResourceParser parser = context.getResources().getXml(xmlId); - final AttributeSet attrs = Xml.asAttributeSet(parser); final List keys = new ArrayList<>(); - String key; try { - while (parser.next() != XmlPullParser.END_DOCUMENT) { - try { - key = PreferenceXmlParserUtils.getDataKey(context, attrs); - if (!TextUtils.isEmpty(key)) { - keys.add(key); - } - } catch (NullPointerException e) { - continue; - } catch (Resources.NotFoundException e) { - continue; + List metadata = PreferenceXmlParserUtils.extractMetadata(context, xmlId, + FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN); + for (Bundle bundle : metadata) { + final String key = bundle.getString(METADATA_KEY); + if (!TextUtils.isEmpty(key)) { + keys.add(key); } } - } catch (java.io.IOException e) { - return null; - } catch (XmlPullParserException e) { + } catch (java.io.IOException | XmlPullParserException e) { return null; }