From 9f90680456c4608b51fc0ef92da7f443ddaef6b8 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Thu, 3 Aug 2017 15:12:36 -0700 Subject: [PATCH] Fix crash when dismissing suggestions. When the suggestions are in default mode and the number of suggestions are more than the default count, we set the sublist of the suggestions list as the suggestion adapter data. In this case, operation on the list should be done in the sublist instead of the original list to maintain the list consistency check. Hence, when dismissing the suggestion, change to remove the suggestion from the suggestion adapter instead of from the dashboard adapter, so that any following interaction with the suggestions will not trigger the concurrent modification exception. Bug: 64279080 Test: make RunSettingsRoboTests Change-Id: I970b6af8a1c72bc0c3ee89fef890ae6a669c71d2 --- .../settings/dashboard/DashboardAdapter.java | 3 +-- .../suggestions/SuggestionAdapter.java | 4 ++++ .../dashboard/DashboardAdapterTest.java | 24 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index 59fef3c66fd..2bf1c01f144 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -211,8 +211,7 @@ public class DashboardAdapter extends RecyclerView.Adapter return null; } + public void removeSuggestion(Tile suggestion) { + mSuggestions.remove(suggestion); + notifyDataSetChanged(); + } } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java index a86c3c95305..8a8a13d02be 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java @@ -351,6 +351,30 @@ public class DashboardAdapterTest { verify(adapter, never()).notifyDashboardDataChanged(any()); } + @Test + public void testSuggestionDismissed_moreThanTwoSuggestions_defaultMode_shouldNotCrash() { + final RecyclerView data = new RecyclerView(RuntimeEnvironment.application); + final View itemView = mock(View.class); + when(itemView.findViewById(R.id.data)).thenReturn(data); + final DashboardAdapter.SuggestionAndConditionContainerHolder holder = + new DashboardAdapter.SuggestionAndConditionContainerHolder(itemView); + final List suggestions = + makeSuggestions("pkg1", "pkg2", "pkg3", "pkg4"); + final DashboardAdapter adapter = spy(new DashboardAdapter(mContext, null /*savedInstance */, + null /* conditions */, null /* suggestionParser */, null /* callback */)); + adapter.setCategoriesAndSuggestions(null /* category */, suggestions); + adapter.onBindConditionAndSuggestion( + holder, DashboardAdapter.SUGGESTION_CONDITION_HEADER_POSITION); + // default mode, only displaying 2 suggestions + + adapter.onSuggestionDismissed(suggestions.get(1)); + + // verify operations that access the lists will not cause ConcurrentModificationException + assertThat(holder.data.getAdapter().getItemCount()).isEqualTo(1); + adapter.setCategoriesAndSuggestions(null /* category */, suggestions); + // should not crash + } + @Test public void testSuggestionDismissed_onlySuggestion_updateDashboardData() { DashboardAdapter adapter =