From 058d2d10e2d503f141c8fbe2ce8f2adaaeeba2cc Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Thu, 3 Aug 2017 10:54:48 -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 suggestions 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 sugestion adapter instead of from the dashboard adapter, so that any following interaction with the suggestions will not trigger the concurrent modification exception. Change-Id: I4caba74cfcc7bd0d53ad8c7dffcb127b3ebd845d Merged-In: I970b6af8a1c72bc0c3ee89fef890ae6a669c71d2 Fix: 64279080 Test: make RunSettingsRoboTests --- .../settings/dashboard/DashboardAdapter.java | 3 +-- .../suggestions/SuggestionAdapter.java | 4 +++ .../dashboard/DashboardAdapterTest.java | 26 +++++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index 8f4b27d2ef5..70fd659c8d0 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -232,8 +232,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 df16b4b56d9..4d81320a9f7 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java @@ -34,14 +34,12 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Icon; import android.os.Bundle; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; -import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -355,6 +353,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(new ArrayList<>(), 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(new ArrayList<>(), suggestions); + // should not crash + } + @Test public void testSuggestioDismissed_onlySuggestion_updateDashboardData() { DashboardAdapter adapter =