Build a way to decide card width
Slice cards in contextual homepage are shown as half card or full card.
We will use Category field of ContextualCard to decide card width.
In this CL, also fixed the problem of not showing full card after a
consecutive suggestion card dismissal.
Bug: 119655434
Bug: 121315057
Test: visual, robotest
Change-Id: I3243b9db21b8f288cab88238b20d7d50a2a20d46
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 88478e3..49e2a76 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -107,12 +107,12 @@
}
}
}
- return getFinalDisplayableCards(result);
+ return getDisplayableCards(result);
}
// Get final displayed cards and log what cards will be displayed/hidden
@VisibleForTesting
- List<ContextualCard> getFinalDisplayableCards(List<ContextualCard> candidates) {
+ List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
final List<ContextualCard> visibleCards = new ArrayList<>();
final List<ContextualCard> hiddenCards = new ArrayList<>();
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 067de7c..12088f8 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE;
import static java.util.stream.Collectors.groupingBy;
@@ -172,7 +173,8 @@
//replace with the new data
mContextualCards.clear();
- mContextualCards.addAll(sortCards(allCards));
+ final List<ContextualCard> sortedCards = sortCards(allCards);
+ mContextualCards.addAll(assignCardWidth(sortedCards));
loadCardControllers();
@@ -224,6 +226,24 @@
mListener = listener;
}
+ @VisibleForTesting
+ List<ContextualCard> assignCardWidth(List<ContextualCard> cards) {
+ final List<ContextualCard> result = new ArrayList<>(cards);
+ // Shows as half cards if 2 suggestion type of cards are next to each other.
+ // Shows as full card if 1 suggestion type of card lives alone.
+ for (int index = 1; index < result.size(); index++) {
+ final ContextualCard previous = result.get(index - 1);
+ final ContextualCard current = result.get(index);
+ if (current.getCategory() == SUGGESTION_VALUE
+ && previous.getCategory() == SUGGESTION_VALUE) {
+ result.set(index - 1, previous.mutate().setIsHalfWidth(true).build());
+ result.set(index, current.mutate().setIsHalfWidth(true).build());
+ index++;
+ }
+ }
+ return result;
+ }
+
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
if (mSavedCards != null) {
//screen rotate
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index c62a6bb..c47fa38 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -29,16 +29,16 @@
import com.android.settings.slices.CustomSliceRegistry;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
@RunWith(RobolectricTestRunner.class)
public class ContextualCardLoaderTest {
@@ -82,29 +82,29 @@
}
@Test
- public void getFinalDisplayableCards_twoEligibleCards_shouldShowAll() {
+ public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
.collect(Collectors.toList());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(cards);
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(cards.size());
}
@Test
- public void getFinalDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
+ public void getDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
fiveCards);
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
}
@Test
- public void getFinalDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
+ public void getDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
.collect(Collectors.toList());
cards.add(new ContextualCard.Builder()
@@ -115,18 +115,18 @@
.build());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(cards);
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(3);
}
@Test
- public void getFinalDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
+ public void getDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
.collect(Collectors.toList());
doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
threeCards);
assertThat(result).hasSize(2);
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 c405ffc..3fc8e06 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -32,6 +32,8 @@
import com.android.settings.homepage.contextualcards.conditional.ConditionFooterContextualCard;
import com.android.settings.homepage.contextualcards.conditional.ConditionHeaderContextualCard;
import com.android.settings.homepage.contextualcards.conditional.ConditionalContextualCard;
+import com.android.settings.intelligence.ContextualCardProto;
+import com.android.settings.slices.CustomSliceRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -203,6 +205,134 @@
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
}
+
+ @Test
+ public void assignCardWidth_noSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> noSuggestionCards = buildCategoriedCards(getContextualCardList(),
+ categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(noSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_oneSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> oneSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(oneSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_twoConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> twoConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, false, true, true, false);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ twoConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
+ @Test
+ public void assignCardWidth_twoNonConsecutiveSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> twoNonConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ twoNonConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_threeConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> threeConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, true, true, false, false);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ threeConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
+ @Test
+ public void assignCardWidth_fourConsecutiveSuggestionCards_shouldHaveFourHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> fourConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, true, true, true, true);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ fourConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
.setName(TEST_SLICE_NAME)
@@ -210,4 +340,45 @@
.setSliceUri(Uri.parse(sliceUri))
.build();
}
+
+ private List<ContextualCard> buildCategoriedCards(List<ContextualCard> cards,
+ List<Integer> categories) {
+ final List<ContextualCard> result = new ArrayList<>();
+ for (int i = 0; i < cards.size(); i++) {
+ result.add(cards.get(i).mutate().setCategory(categories.get(i)).build());
+ }
+ return result;
+ }
+
+ private List<ContextualCard> getContextualCardList() {
+ final List<ContextualCard> cards = new ArrayList<>();
+ cards.add(new ContextualCard.Builder()
+ .setName("test_wifi")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_flashlight")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(
+ Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_connected")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_gesture")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(Uri.parse(
+ "content://com.android.settings.test.slices/action/gesture_pick_up"))
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_battery")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.BATTERY_INFO_SLICE_URI)
+ .build());
+ return cards;
+ }
}