Merge "Build a way to decide card width"
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
|
// Get final displayed cards and log what cards will be displayed/hidden
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<ContextualCard> getFinalDisplayableCards(List<ContextualCard> candidates) {
|
List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
|
||||||
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
|
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
|
||||||
final List<ContextualCard> visibleCards = new ArrayList<>();
|
final List<ContextualCard> visibleCards = new ArrayList<>();
|
||||||
final List<ContextualCard> hiddenCards = new ArrayList<>();
|
final List<ContextualCard> hiddenCards = new ArrayList<>();
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.homepage.contextualcards;
|
package com.android.settings.homepage.contextualcards;
|
||||||
|
|
||||||
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
|
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;
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
@@ -172,7 +173,8 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
|||||||
|
|
||||||
//replace with the new data
|
//replace with the new data
|
||||||
mContextualCards.clear();
|
mContextualCards.clear();
|
||||||
mContextualCards.addAll(sortCards(allCards));
|
final List<ContextualCard> sortedCards = sortCards(allCards);
|
||||||
|
mContextualCards.addAll(assignCardWidth(sortedCards));
|
||||||
|
|
||||||
loadCardControllers();
|
loadCardControllers();
|
||||||
|
|
||||||
@@ -224,6 +226,24 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
|||||||
mListener = listener;
|
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) {
|
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
|
||||||
if (mSavedCards != null) {
|
if (mSavedCards != null) {
|
||||||
//screen rotate
|
//screen rotate
|
||||||
|
@@ -29,16 +29,16 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import com.android.settings.slices.CustomSliceRegistry;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ContextualCardLoaderTest {
|
public class ContextualCardLoaderTest {
|
||||||
|
|
||||||
@@ -82,29 +82,29 @@ public class ContextualCardLoaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFinalDisplayableCards_twoEligibleCards_shouldShowAll() {
|
public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
|
||||||
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
|
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
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());
|
assertThat(result).hasSize(cards.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFinalDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
|
public void getDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
|
||||||
final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
|
final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
|
||||||
doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
||||||
|
|
||||||
final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
|
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
|
||||||
fiveCards);
|
fiveCards);
|
||||||
|
|
||||||
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
|
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFinalDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
|
public void getDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
|
||||||
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
|
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
@@ -115,18 +115,18 @@ public class ContextualCardLoaderTest {
|
|||||||
.build());
|
.build());
|
||||||
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
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);
|
assertThat(result).hasSize(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFinalDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
|
public void getDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
|
||||||
final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
|
final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
|
||||||
|
|
||||||
final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
|
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
|
||||||
threeCards);
|
threeCards);
|
||||||
|
|
||||||
assertThat(result).hasSize(2);
|
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.ConditionFooterContextualCard;
|
||||||
import com.android.settings.homepage.contextualcards.conditional.ConditionHeaderContextualCard;
|
import com.android.settings.homepage.contextualcards.conditional.ConditionHeaderContextualCard;
|
||||||
import com.android.settings.homepage.contextualcards.conditional.ConditionalContextualCard;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -203,6 +205,134 @@ public class ContextualCardManagerTest {
|
|||||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
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) {
|
private ContextualCard buildContextualCard(String sliceUri) {
|
||||||
return new ContextualCard.Builder()
|
return new ContextualCard.Builder()
|
||||||
.setName(TEST_SLICE_NAME)
|
.setName(TEST_SLICE_NAME)
|
||||||
@@ -210,4 +340,45 @@ public class ContextualCardManagerTest {
|
|||||||
.setSliceUri(Uri.parse(sliceUri))
|
.setSliceUri(Uri.parse(sliceUri))
|
||||||
.build();
|
.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