Card showing mechanism change in homepage

- update contextual card proto interface to fit the new SettingsIntelligence
- show sticky cards at the tail of the card area

Bug: 149274976
Test: robotest
Change-Id: Icca167825c1c037ec12d8836d82c5fdff4331a8e
This commit is contained in:
Jason Chiu
2020-02-11 17:46:34 +08:00
parent fe83913c03
commit ca9ece1a0c
6 changed files with 116 additions and 23 deletions

View File

@@ -19,6 +19,7 @@ message ContextualCard {
POSSIBLE = 2;
IMPORTANT = 3;
DEFERRED_SETUP = 5;
STICKY = 6;
}
/** Slice uri of the contextual card */

View File

@@ -16,6 +16,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE;
import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI;
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
@@ -129,18 +130,34 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
@VisibleForTesting
List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
final List<ContextualCard> stickyCards = new ArrayList<>();
final List<ContextualCard> visibleCards = new ArrayList<>();
final List<ContextualCard> hiddenCards = new ArrayList<>();
final int size = eligibleCards.size();
final int cardCount = getCardCount();
for (int i = 0; i < size; i++) {
if (i < cardCount) {
visibleCards.add(eligibleCards.get(i));
final int maxCardCount = getCardCount();
eligibleCards.forEach(card -> {
if (card.getCategory() != STICKY_VALUE) {
return;
}
if (stickyCards.size() < maxCardCount) {
stickyCards.add(card);
} else {
hiddenCards.add(eligibleCards.get(i));
hiddenCards.add(card);
}
});
final int nonStickyCardCount = maxCardCount - stickyCards.size();
eligibleCards.forEach(card -> {
if (card.getCategory() == STICKY_VALUE) {
return;
}
if (visibleCards.size() < nonStickyCardCount) {
visibleCards.add(card);
} else {
hiddenCards.add(card);
}
});
visibleCards.addAll(stickyCards);
if (!CardContentProvider.DELETE_CARD_URI.equals(mNotifyUri)) {
final MetricsFeatureProvider metricsFeatureProvider =

View File

@@ -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.STICKY_VALUE;
import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE;
import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
@@ -346,16 +347,23 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
return result;
}
// TODO(b/143055685):use category to determine whether they are sticky.
private List<ContextualCard> getCardsWithStickyViewType(List<ContextualCard> cards) {
final List<ContextualCard> result = new ArrayList<>(cards);
int replaceCount = 0;
for (int index = 0; index < result.size(); index++) {
final ContextualCard card = cards.get(index);
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2)) {
if (card.getCategory() == STICKY_VALUE) {
result.set(index, card.mutate().setViewType(
SliceContextualCardRenderer.VIEW_TYPE_STICKY).build());
}
continue;
}
if (replaceCount > STICKY_CARDS.size() - 1) {
break;
}
final ContextualCard card = cards.get(index);
if (card.getCardType() != ContextualCard.CardType.SLICE) {
continue;
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.DEFAULT_CARD_COUNT;
import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE;
import static com.google.common.truth.Truth.assertThat;
@@ -82,15 +83,40 @@ public class ContextualCardLoaderTest {
@Test
public void getDisplayableCards_fourEligibleCards_shouldShowDefaultCardCount() {
final List<ContextualCard> fourCards = getContextualCardList();
doReturn(fourCards).when(mContextualCardLoader).filterEligibleCards(anyList());
final List<ContextualCard> cards = getContextualCardList().stream().limit(4)
.collect(Collectors.toList());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
final List<ContextualCard> result = mContextualCardLoader
.getDisplayableCards(fourCards);
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
}
@Test
public void getDisplayableCards_oneStickyCard_shouldShowOneStickyCardAtTheTail() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(5)
.collect(Collectors.toList());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
assertThat(result.get(DEFAULT_CARD_COUNT - 1).getCategory()).isEqualTo(STICKY_VALUE);
}
@Test
public void getDisplayableCards_threeStickyCards_shouldShowThreeStickyCardAtTheTail() {
final List<ContextualCard> cards = getContextualCardList();
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
for (int i = 1; i <= Math.min(3, DEFAULT_CARD_COUNT); i++) {
assertThat(result.get(DEFAULT_CARD_COUNT - i).getCategory()).isEqualTo(STICKY_VALUE);
}
}
@Test
public void getDisplayableCards_refreshCardUri_shouldLogContextualCard() {
mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
@@ -128,20 +154,20 @@ public class ContextualCardLoaderTest {
private List<ContextualCard> getContextualCardList() {
final List<ContextualCard> cards = new ArrayList<>();
cards.add(new ContextualCard.Builder()
.setName("test_wifi")
.setName("test_low_storage")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
.setSliceUri(CustomSliceRegistry.LOW_STORAGE_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"))
.setSliceUri(Uri.parse(
"content://com.android.settings.test.slices/action/flashlight"))
.build());
cards.add(new ContextualCard.Builder()
.setName("test_connected")
.setName("test_dark_theme")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
.setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI)
.build());
cards.add(new ContextualCard.Builder()
.setName("test_gesture")
@@ -149,6 +175,24 @@ public class ContextualCardLoaderTest {
.setSliceUri(Uri.parse(
"content://com.android.settings.test.slices/action/gesture_pick_up"))
.build());
cards.add(new ContextualCard.Builder()
.setName("test_wifi")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
.setCategory(STICKY_VALUE)
.build());
cards.add(new ContextualCard.Builder()
.setName("test_connected")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
.setCategory(STICKY_VALUE)
.build());
cards.add(new ContextualCard.Builder()
.setName("test_sticky")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(Uri.parse("content://com.android.settings.test.slices/action/sticky"))
.setCategory(STICKY_VALUE)
.build());
return cards;
}
}

View File

@@ -564,8 +564,28 @@ public class ContextualCardManagerTest {
}
}
@Test
public void getCardsWithViewType_hasOneStickySlice_shouldHaveOneStickyCard() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, true);
final List<ContextualCard> cards = new ArrayList<>();
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.STICKY_VALUE,
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
);
final List<ContextualCard> cardListWithWifi = buildCategoriedCards(cards, categories);
final List<ContextualCard> result = mManager.getCardsWithViewType(cardListWithWifi);
assertThat(result).hasSize(cards.size());
assertThat(result.get(0).getViewType()).isEqualTo(VIEW_TYPE_STICKY);
assertThat(result.get(1).getViewType()).isEqualTo(VIEW_TYPE_FULL_WIDTH);
}
@Test
public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
final List<ContextualCard> cards = new ArrayList<>();
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
@@ -584,6 +604,7 @@ public class ContextualCardManagerTest {
@Test
public void getCardsWithViewType_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
final List<ContextualCard> cards = new ArrayList<>();
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
@@ -602,6 +623,7 @@ public class ContextualCardManagerTest {
@Test
public void getCardsWithViewType_hasWifiAndBtDeviceSlice_shouldHaveTwoStickyCards() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
final List<ContextualCard> cards = new ArrayList<>();
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
@@ -624,6 +646,7 @@ public class ContextualCardManagerTest {
@Test
public void getCardsWithViewType_noWifiOrBtDeviceSlice_shouldNotHaveStickyCard() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -683,8 +706,8 @@ public class ContextualCardManagerTest {
cards.add(new ContextualCard.Builder()
.setName("test_flashlight")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(
Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
.setSliceUri(Uri.parse(
"content://com.android.settings.test.slices/action/flashlight"))
.setViewType(VIEW_TYPE_FULL_WIDTH)
.build());
cards.add(new ContextualCard.Builder()