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
This commit is contained in:
Doris Ling
2017-08-03 15:12:36 -07:00
parent be2246bee7
commit 9f90680456
3 changed files with 29 additions and 2 deletions

View File

@@ -211,8 +211,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
.build(); .build();
notifyDashboardDataChanged(prevData); notifyDashboardDataChanged(prevData);
} else { } else {
suggestions.remove(suggestion); mSuggestionAdapter.removeSuggestion(suggestion);
mSuggestionAdapter.notifyDataSetChanged();
} }
} }

View File

@@ -134,4 +134,8 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
return null; return null;
} }
public void removeSuggestion(Tile suggestion) {
mSuggestions.remove(suggestion);
notifyDataSetChanged();
}
} }

View File

@@ -351,6 +351,30 @@ public class DashboardAdapterTest {
verify(adapter, never()).notifyDashboardDataChanged(any()); 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<Tile> 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 @Test
public void testSuggestionDismissed_onlySuggestion_updateDashboardData() { public void testSuggestionDismissed_onlySuggestion_updateDashboardData() {
DashboardAdapter adapter = DashboardAdapter adapter =