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
This commit is contained in:
@@ -107,12 +107,12 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
}
|
||||
}
|
||||
}
|
||||
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<>();
|
||||
|
@@ -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 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
|
||||
//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 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
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
|
||||
|
@@ -29,16 +29,16 @@ import android.net.Uri;
|
||||
|
||||
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 @@ public class ContextualCardLoaderTest {
|
||||
}
|
||||
|
||||
@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 @@ public class ContextualCardLoaderTest {
|
||||
.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);
|
||||
|
@@ -32,6 +32,8 @@ import android.util.ArrayMap;
|
||||
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 @@ public class ContextualCardManagerTest {
|
||||
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 @@ public class ContextualCardManagerTest {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user