Limit the suggestions to be shown to 5.

- when creating the dashboard data, pass the sublist of suggestions to
cap the total number of suggestions to be shown to 5.
- if user swipe away the suggestion, it will only remove the suggestion
from the suggestion adapater, and will not trigger rebuilding the whole
UI.

Change-Id: I3bbc08bb67c411ff5671a837efa40da0ac885983
Merged-In: I1efabeb2a805c670007c631d3ccb0fdfbde7b55a
Fix: 64072051
Test: make RunSettingsRoboTests
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index da9e8a7..8f4b27d 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -67,6 +67,8 @@
     static final String STATE_SUGGESTION_CONDITION_MODE = "suggestion_condition_mode";
     @VisibleForTesting
     static final int SUGGESTION_CONDITION_HEADER_POSITION = 0;
+    @VisibleForTesting
+    static final int MAX_SUGGESTION_TO_SHOW = 5;
 
     private final IconCache mCache;
     private final Context mContext;
@@ -174,7 +176,8 @@
 
         final DashboardData prevData = mDashboardData;
         mDashboardData = new DashboardData.Builder(prevData)
-                .setSuggestions(suggestions)
+                .setSuggestions(suggestions.subList(0,
+                        Math.min(suggestions.size(), MAX_SUGGESTION_TO_SHOW)))
                 .setCategories(categories)
                 .build();
         notifyDashboardDataChanged(prevData);
@@ -215,9 +218,12 @@
         notifyDashboardDataChanged(prevData);
     }
 
-    public void onSuggestionDismissed() {
+    public void onSuggestionDismissed(Tile suggestion) {
         final List<Tile> suggestions = mDashboardData.getSuggestions();
-        if (suggestions != null && suggestions.size() == 1) {
+        if (suggestions == null || suggestions.isEmpty()) {
+            return;
+        }
+        if (suggestions.size() == 1) {
             // The only suggestion is dismissed, and the the empty suggestion container will
             // remain as the dashboard item. Need to refresh the dashboard list.
             final DashboardData prevData = mDashboardData;
@@ -225,6 +231,9 @@
                     .setSuggestions(null)
                     .build();
             notifyDashboardDataChanged(prevData);
+        } else {
+            suggestions.remove(suggestion);
+            mSuggestionAdapter.notifyDataSetChanged();
         }
     }
 
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 4d2bd66..4a53a7c 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -245,10 +245,7 @@
 
     @Override
     public void onSuggestionDismissed(Tile suggestion) {
-        mAdapter.onSuggestionDismissed();
-        // Refresh the UI to pick up suggestions that can now be shown because, say, a higher
-        // priority suggestion has been dismissed, or an exclusive suggestion category is emptied.
-        rebuildUI();
+        mAdapter.onSuggestionDismissed(suggestion);
     }
 
     private class SuggestionLoader extends AsyncTask<Void, Void, List<Tile>> {
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
index 8cf8736..df16b4b 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
@@ -325,17 +325,33 @@
     }
 
     @Test
-    public void testSuggestioDismissed_notOnlySuggestion_doNothing() {
+    public void testSuggestioDismissed_notOnlySuggestion_updateSuggestionOnly() {
         final DashboardAdapter adapter =
                 spy(new DashboardAdapter(mContext, null, null, null, null));
-        adapter.setCategoriesAndSuggestions(
-                new ArrayList<>(), makeSuggestions("pkg1", "pkg2", "pkg3"));
+        final List<Tile> suggestions = makeSuggestions("pkg1", "pkg2", "pkg3");
+        adapter.setCategoriesAndSuggestions(new ArrayList<>(), suggestions);
+
+        final RecyclerView data = mock(RecyclerView.class);
+        when(data.getResources()).thenReturn(mResources);
+        when(data.getContext()).thenReturn(mContext);
+        when(mResources.getDisplayMetrics()).thenReturn(mock(DisplayMetrics.class));
+        final View itemView = mock(View.class);
+        when(itemView.findViewById(R.id.data)).thenReturn(data);
+        final DashboardAdapter.SuggestionAndConditionContainerHolder holder =
+                new DashboardAdapter.SuggestionAndConditionContainerHolder(itemView);
+
+        adapter.onBindConditionAndSuggestion(
+                holder, DashboardAdapter.SUGGESTION_CONDITION_HEADER_POSITION);
+
         final DashboardData dashboardData = adapter.mDashboardData;
         reset(adapter); // clear interactions tracking
 
-        adapter.onSuggestionDismissed();
+        final Tile suggestionToRemove = suggestions.get(1);
+        adapter.onSuggestionDismissed(suggestionToRemove);
 
         assertThat(adapter.mDashboardData).isEqualTo(dashboardData);
+        assertThat(suggestions.size()).isEqualTo(2);
+        assertThat(suggestions.contains(suggestionToRemove)).isFalse();
         verify(adapter, never()).notifyDashboardDataChanged(any());
     }
 
@@ -343,11 +359,12 @@
     public void testSuggestioDismissed_onlySuggestion_updateDashboardData() {
         DashboardAdapter adapter =
                 spy(new DashboardAdapter(mContext, null, null, null, null));
-        adapter.setCategoriesAndSuggestions(new ArrayList<>(), makeSuggestions("pkg1"));
+        final List<Tile> suggestions = makeSuggestions("pkg1");
+        adapter.setCategoriesAndSuggestions(new ArrayList<>(), suggestions);
         final DashboardData dashboardData = adapter.mDashboardData;
         reset(adapter); // clear interactions tracking
 
-        adapter.onSuggestionDismissed();
+        adapter.onSuggestionDismissed(suggestions.get(0));
 
         assertThat(adapter.mDashboardData).isNotEqualTo(dashboardData);
         verify(adapter).notifyDashboardDataChanged(any());
@@ -370,6 +387,16 @@
     }
 
     @Test
+    public void testSetCategoriesAndSuggestions_limitSuggestionSize() {
+        List<Tile> packages =
+                makeSuggestions("pkg1", "pkg2", "pkg3", "pkg4", "pkg5", "pkg6", "pkg7");
+        mDashboardAdapter.setCategoriesAndSuggestions(Collections.emptyList(), packages);
+
+        assertThat(mDashboardAdapter.mDashboardData.getSuggestions().size())
+                .isEqualTo(DashboardAdapter.MAX_SUGGESTION_TO_SHOW);
+    }
+
+    @Test
     public void testBindConditionAndSuggestion_shouldSetSuggestionAdapterAndNoCrash() {
         mDashboardAdapter = new DashboardAdapter(mContext, null, null, null, null);
         final List<Tile> suggestions = makeSuggestions("pkg1");
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
index c6446f1..32657b8 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
@@ -111,9 +111,8 @@
     }
 
     @Test
-    public void onSuggestionDismissed_categoryShouldBeRefreshed() {
-        doNothing().when(mSummary).rebuildUI();
+    public void onSuggestionDismissed_shouldNotRebuildUI() {
         mSummary.onSuggestionDismissed(mock(Tile.class));
-        verify(mSummary).rebuildUI();
+        verify(mSummary, never()).rebuildUI();
     }
 }
\ No newline at end of file