From f74b9e522fbc0cff0a618913791ce929009bc2e1 Mon Sep 17 00:00:00 2001 From: Maurice Lam Date: Thu, 23 Mar 2017 14:58:47 -0700 Subject: [PATCH] Add exclusive attribute to suggestion category Add exlusive attribute to suggestion category XML, which when true, will prevent all other categories from being shown in suggestions. If there are multiple suggestions in a single exclusive category, all of them will be shown. If there are mutliple exclusive categories with enabled suggestions, only the first will be shown. Test: cd tests/robotests && mma Bug: 35668836 Change-Id: I8b95cdcd021a2d67d460259b4a44ca37290ffd48 --- .../android/settingslib/SuggestionParser.java | 40 +++++-- .../robotests/res/xml/suggestion_ordering.xml | 2 + .../settingslib/SuggestionParserTest.java | 109 ++++++++++++------ .../settingslib/drawer/TileUtilsTest.java | 36 +++--- 4 files changed, 124 insertions(+), 63 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java index 4b0ab59a931c6..b54d7e201c850 100644 --- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java +++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java @@ -106,11 +106,11 @@ public class SuggestionParser { public SuggestionParser( Context context, SharedPreferences sharedPrefs, int orderXml, String smartDismissControl) { - mContext = context; - mSuggestionList = (List) new SuggestionOrderInflater(mContext) - .parse(orderXml); - mSharedPrefs = sharedPrefs; - mSmartDismissControl = smartDismissControl; + this( + context, + sharedPrefs, + (List) new SuggestionOrderInflater(context).parse(orderXml), + smartDismissControl); } public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) { @@ -118,12 +118,15 @@ public class SuggestionParser { } @VisibleForTesting - public SuggestionParser(Context context, SharedPreferences sharedPrefs) { + public SuggestionParser( + Context context, + SharedPreferences sharedPrefs, + List suggestionList, + String smartDismissControl) { mContext = context; - mSuggestionList = new ArrayList(); + mSuggestionList = suggestionList; mSharedPrefs = sharedPrefs; - mSmartDismissControl = DEFAULT_SMART_DISMISS_CONTROL; - Log.wtf(TAG, "Only use this constructor for testing"); + mSmartDismissControl = smartDismissControl; } public List getSuggestions() { @@ -134,7 +137,19 @@ public class SuggestionParser { List suggestions = new ArrayList<>(); final int N = mSuggestionList.size(); for (int i = 0; i < N; i++) { - readSuggestions(mSuggestionList.get(i), suggestions, isSmartSuggestionEnabled); + final SuggestionCategory category = mSuggestionList.get(i); + if (category.exclusive) { + // If suggestions from an exclusive category are present, parsing is stopped + // and only suggestions from that category are displayed. Note that subsequent + // exclusive categories are also ignored. + List exclusiveSuggestions = new ArrayList<>(); + readSuggestions(category, exclusiveSuggestions, isSmartSuggestionEnabled); + if (!exclusiveSuggestions.isEmpty()) { + return exclusiveSuggestions; + } + } else { + readSuggestions(category, suggestions, isSmartSuggestionEnabled); + } } return suggestions; } @@ -368,6 +383,7 @@ public class SuggestionParser { public String category; public String pkg; public boolean multiple; + public boolean exclusive; } private static class SuggestionOrderInflater { @@ -377,6 +393,7 @@ public class SuggestionParser { private static final String ATTR_CATEGORY = "category"; private static final String ATTR_PACKAGE = "package"; private static final String ATTR_MULTIPLE = "multiple"; + private static final String ATTR_EXCLUSIVE = "exclusive"; private final Context mContext; @@ -451,6 +468,9 @@ public class SuggestionParser { category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE); String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE); category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple); + String exclusive = attrs.getAttributeValue(null, ATTR_EXCLUSIVE); + category.exclusive = + !TextUtils.isEmpty(exclusive) && Boolean.parseBoolean(exclusive); return category; } else { throw new IllegalArgumentException("Unknown item " + name); diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml index 1eeafba1bf8f5..0e2ce3be55eb7 100644 --- a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml +++ b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml @@ -15,6 +15,8 @@ --> + mSuggestionsBeforeDismiss; private List mSuggestionsAfterDismiss; private SharedPreferences mPrefs; private Tile mSuggestion; - private List mInfo; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - when(mContext.getPackageManager()).thenReturn(mPackageManager); + RuntimeEnvironment.setRobolectricPackageManager( + new TestPackageManager(RuntimeEnvironment.getAppResourceLoader())); + mContext = RuntimeEnvironment.application; mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); mSuggestion = new Tile(); mSuggestion.intent = new Intent("action"); mSuggestion.intent.setComponent(new ComponentName("pkg", "cls")); mSuggestion.metaData = new Bundle(); + mMultipleCategory = new SuggestionParser.SuggestionCategory(); + mMultipleCategory.category = "category1"; + mMultipleCategory.multiple = true; + mExclusiveCategory = new SuggestionParser.SuggestionCategory(); + mExclusiveCategory.category = "category2"; + mExclusiveCategory.exclusive = true; mSuggestionParser = new SuggestionParser( - mContext, mPrefs, R.xml.suggestion_ordering, "0,0"); - mSuggestioCategory = new SuggestionParser.SuggestionCategory(); - mSuggestioCategory.category = "category1"; - mSuggestioCategory.multiple = true; - mInfo = new ArrayList<>(); + mContext, mPrefs, Arrays.asList(mMultipleCategory, mExclusiveCategory), "0,0"); + ResolveInfo info1 = TileUtilsTest.newInfo(true, "category1"); info1.activityInfo.packageName = "pkg"; ResolveInfo info2 = TileUtilsTest.newInfo(true, "category1"); info2.activityInfo.packageName = "pkg2"; - mInfo.add(info1); - mInfo.add(info2); - when(mPackageManager.queryIntentActivitiesAsUser( - any(Intent.class), anyInt(), anyInt())).thenReturn(mInfo); + ResolveInfo info3 = TileUtilsTest.newInfo(true, "category2"); + info3.activityInfo.packageName = "pkg3"; + + Intent intent1 = new Intent(Intent.ACTION_MAIN).addCategory("category1"); + Intent intent2 = new Intent(Intent.ACTION_MAIN).addCategory("category2"); + RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info1); + RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info2); + RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent2, info3); } @Test @@ -99,30 +100,64 @@ public class SuggestionParserTest { @Test public void testGetSuggestions_withoutSmartSuggestions() { readAndDismissSuggestion(false); - mSuggestionParser.readSuggestions(mSuggestioCategory, mSuggestionsAfterDismiss, false); - assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2); - assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(1); + mSuggestionParser.readSuggestions(mMultipleCategory, mSuggestionsAfterDismiss, false); + assertThat(mSuggestionsBeforeDismiss).hasSize(2); + assertThat(mSuggestionsAfterDismiss).hasSize(1); assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0)); } @Test public void testGetSuggestions_withSmartSuggestions() { readAndDismissSuggestion(true); - assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2); - assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(2); + assertThat(mSuggestionsBeforeDismiss).hasSize(2); + assertThat(mSuggestionsAfterDismiss).hasSize(2); assertThat(mSuggestionsBeforeDismiss).isEqualTo(mSuggestionsAfterDismiss); } + @Test + public void testGetSuggestion_exclusiveNotAvailable() { + RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent( + new Intent(Intent.ACTION_MAIN).addCategory("category2"), + "pkg3"); + + // If exclusive item is not available, the other categories should be shown + final List suggestions = mSuggestionParser.getSuggestions(); + assertThat(suggestions).hasSize(2); + assertThat(suggestions.get(0).category).isEqualTo("category1"); + assertThat(suggestions.get(1).category).isEqualTo("category1"); + } + + @Test + public void testGetSuggestions_exclusive() { + final List suggestions = mSuggestionParser.getSuggestions(); + assertThat(suggestions).hasSize(1); + assertThat(suggestions.get(0).category).isEqualTo("category2"); + } + private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) { - mSuggestionsBeforeDismiss = new ArrayList(); - mSuggestionsAfterDismiss = new ArrayList(); + mSuggestionsBeforeDismiss = new ArrayList<>(); + mSuggestionsAfterDismiss = new ArrayList<>(); mSuggestionParser.readSuggestions( - mSuggestioCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled); - if (mSuggestionParser.dismissSuggestion( - mSuggestionsBeforeDismiss.get(0), isSmartSuggestionEnabled)) { - mInfo.remove(0); + mMultipleCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled); + final Tile suggestion = mSuggestionsBeforeDismiss.get(0); + if (mSuggestionParser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) { + RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent( + new Intent(Intent.ACTION_MAIN).addCategory(suggestion.category), + suggestion.intent.getComponent().getPackageName()); } mSuggestionParser.readSuggestions( - mSuggestioCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled); + mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled); + } + + private static class TestPackageManager extends DefaultPackageManager { + + TestPackageManager(ResourceLoader appResourceLoader) { + super(appResourceLoader); + } + + @Override + public List queryIntentActivitiesAsUser(Intent intent, int flags, int userId) { + return super.queryIntentActivities(intent, flags); + } } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 2d3c4a786f5c8..dfbe43bc39341 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -16,11 +16,22 @@ package com.android.settingslib.drawer; -import android.app.ActivityManager; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import android.content.IContentProvider; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; +import android.content.IContentProvider; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -40,34 +51,23 @@ import android.util.Pair; import com.android.settingslib.SuggestionParser; import com.android.settingslib.TestConfig; -import com.android.settingslib.drawer.TileUtilsTest; -import static org.mockito.Mockito.atLeastOnce; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.shadows.ShadowApplication; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; -import org.mockito.ArgumentCaptor; - @RunWith(RobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -179,7 +179,11 @@ public class TileUtilsTest { false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); - SuggestionParser parser = new SuggestionParser(mContext, null); + SuggestionParser parser = new SuggestionParser( + mContext, + null, + Collections.emptyList(), + "0,10"); parser.filterSuggestions(outTiles, 0, false); assertThat(outTiles.size()).isEqualTo(0); }