From 9c52951ba6799e08ce9a9ede98467599f53e7d1a Mon Sep 17 00:00:00 2001 From: Emily Chuang Date: Thu, 15 Nov 2018 09:55:06 +0800 Subject: [PATCH] Make UI refresh when there is only one contextual card left. After having card dismissal mechanism implemented, it is possible that the card list loaded from the card loader will be empty (users may dismiss all cards). When there is only one card remaining on the screen and user dismiss it, the card should go away. Fixes: 119580732 Test: robotest Change-Id: I7ae3b03f16a0b8b009d8aa77811b5a6d39c359e7 --- .../ContextualCardManager.java | 25 ++++++++++++---- .../ContextualCardManagerTest.java | 30 +++++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java index 8bb8b4dd86a..30eae298752 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java @@ -62,10 +62,12 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo private static final int[] SETTINGS_CARDS = {ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION}; + @VisibleForTesting + final List mContextualCards; + private final Context mContext; private final ControllerRendererPool mControllerRendererPool; private final Lifecycle mLifecycle; - private final List mContextualCards; private final List mLifecycleObservers; private ContextualCardUpdateListener mListener; @@ -122,10 +124,23 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo public void onContextualCardUpdated(Map> updateList) { final Set cardTypes = updateList.keySet(); //Remove the existing data that matches the certain cardType before inserting new data. - final List cardsToKeep = mContextualCards - .stream() - .filter(card -> !cardTypes.contains(card.getCardType())) - .collect(Collectors.toList()); + List cardsToKeep; + + // We are not sure how many card types will be in the database, so when the list coming + // from the database is empty (e.g. no eligible cards/cards are dismissed), we cannot + // assign a specific card type for its map which is sending here. Thus, we assume that + // except Conditional cards, all other cards are from the database. So when the map sent + // here is empty, we only keep Conditional cards. + if (cardTypes.isEmpty()) { + cardsToKeep = mContextualCards.stream() + .filter(card -> card.getCardType() == ContextualCard.CardType.CONDITIONAL) + .collect(Collectors.toList()); + } else { + cardsToKeep = mContextualCards.stream() + .filter(card -> !cardTypes.contains(card.getCardType())) + .collect(Collectors.toList()); + } + final List allCards = new ArrayList<>(); allCards.addAll(cardsToKeep); allCards.addAll( diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java index 091a51b1d4c..82876722efa 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java @@ -18,8 +18,12 @@ package com.android.settings.homepage.contextualcards; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.Mockito.doNothing; + import android.content.Context; import android.net.Uri; +import android.util.ArrayMap; import com.android.settings.homepage.contextualcards.conditional.ConditionalContextualCard; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -27,6 +31,8 @@ import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; @@ -35,11 +41,17 @@ import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) public class ContextualCardManagerTest { + private static final String TEST_SLICE_URI = "context://test/test"; + + @Mock + ContextualCardUpdateListener mListener; + private Context mContext; private ContextualCardManager mManager; @Before public void setUp() { + MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; final ContextualCardsFragment fragment = new ContextualCardsFragment(); mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle()); @@ -47,10 +59,9 @@ public class ContextualCardManagerTest { @Test public void sortCards_hasConditionalAndSliceCards_conditionalShouldAlwaysBeTheLast() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; final List cards = new ArrayList<>(); cards.add(new ConditionalContextualCard.Builder().build()); - cards.add(buildContextualCard(sliceUri)); + cards.add(buildContextualCard(TEST_SLICE_URI)); final List sortedCards = mManager.sortCards(cards); @@ -58,6 +69,21 @@ public class ContextualCardManagerTest { .isEqualTo(ContextualCard.CardType.CONDITIONAL); } + @Test + public void onContextualCardUpdated_emtpyMapWithExistingCards_shouldOnlyKeepConditionalCard() { + mManager.mContextualCards.add(new ConditionalContextualCard.Builder().build()); + mManager.mContextualCards.add( + buildContextualCard(TEST_SLICE_URI)); + mManager.setListener(mListener); + + //Simulate database returns no contents. + mManager.onContextualCardUpdated(new ArrayMap<>()); + + assertThat(mManager.mContextualCards).hasSize(1); + assertThat(mManager.mContextualCards.get(0).getCardType()) + .isEqualTo(ContextualCard.CardType.CONDITIONAL); + } + private ContextualCard buildContextualCard(String sliceUri) { return new ContextualCard.Builder() .setName("test_name")