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:
@@ -19,6 +19,7 @@ message ContextualCard {
|
|||||||
POSSIBLE = 2;
|
POSSIBLE = 2;
|
||||||
IMPORTANT = 3;
|
IMPORTANT = 3;
|
||||||
DEFERRED_SETUP = 5;
|
DEFERRED_SETUP = 5;
|
||||||
|
STICKY = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Slice uri of the contextual card */
|
/** Slice uri of the contextual card */
|
||||||
|
@@ -258,7 +258,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
|||||||
preference.setSummary(summary);
|
preference.setSummary(summary);
|
||||||
} else if (tile.getMetaData() != null
|
} else if (tile.getMetaData() != null
|
||||||
&& tile.getMetaData().containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
|
&& tile.getMetaData().containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
|
||||||
// Set a placeholder summary before starting to fetch real summary, this is necessary
|
// Set a placeholder summary before starting to fetch real summary, this is necessary
|
||||||
// to avoid preference height change.
|
// to avoid preference height change.
|
||||||
preference.setSummary(R.string.summary_placeholder);
|
preference.setSummary(R.string.summary_placeholder);
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.homepage.contextualcards;
|
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.BLUETOOTH_DEVICES_SLICE_URI;
|
||||||
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_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;
|
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
|
||||||
@@ -129,18 +130,34 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
|
List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
|
||||||
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
|
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
|
||||||
|
final List<ContextualCard> stickyCards = new ArrayList<>();
|
||||||
final List<ContextualCard> visibleCards = new ArrayList<>();
|
final List<ContextualCard> visibleCards = new ArrayList<>();
|
||||||
final List<ContextualCard> hiddenCards = new ArrayList<>();
|
final List<ContextualCard> hiddenCards = new ArrayList<>();
|
||||||
|
|
||||||
final int size = eligibleCards.size();
|
final int maxCardCount = getCardCount();
|
||||||
final int cardCount = getCardCount();
|
eligibleCards.forEach(card -> {
|
||||||
for (int i = 0; i < size; i++) {
|
if (card.getCategory() != STICKY_VALUE) {
|
||||||
if (i < cardCount) {
|
return;
|
||||||
visibleCards.add(eligibleCards.get(i));
|
|
||||||
} else {
|
|
||||||
hiddenCards.add(eligibleCards.get(i));
|
|
||||||
}
|
}
|
||||||
}
|
if (stickyCards.size() < maxCardCount) {
|
||||||
|
stickyCards.add(card);
|
||||||
|
} else {
|
||||||
|
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)) {
|
if (!CardContentProvider.DELETE_CARD_URI.equals(mNotifyUri)) {
|
||||||
final MetricsFeatureProvider metricsFeatureProvider =
|
final MetricsFeatureProvider metricsFeatureProvider =
|
||||||
|
@@ -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.STICKY_VALUE;
|
||||||
import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_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.BLUETOOTH_DEVICES_SLICE_URI;
|
||||||
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/143055685):use category to determine whether they are sticky.
|
|
||||||
private List<ContextualCard> getCardsWithStickyViewType(List<ContextualCard> cards) {
|
private List<ContextualCard> getCardsWithStickyViewType(List<ContextualCard> cards) {
|
||||||
final List<ContextualCard> result = new ArrayList<>(cards);
|
final List<ContextualCard> result = new ArrayList<>(cards);
|
||||||
int replaceCount = 0;
|
int replaceCount = 0;
|
||||||
for (int index = 0; index < result.size(); index++) {
|
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) {
|
if (replaceCount > STICKY_CARDS.size() - 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ContextualCard card = cards.get(index);
|
|
||||||
if (card.getCardType() != ContextualCard.CardType.SLICE) {
|
if (card.getCardType() != ContextualCard.CardType.SLICE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.homepage.contextualcards;
|
package com.android.settings.homepage.contextualcards;
|
||||||
|
|
||||||
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.DEFAULT_CARD_COUNT;
|
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;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -82,15 +83,40 @@ public class ContextualCardLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDisplayableCards_fourEligibleCards_shouldShowDefaultCardCount() {
|
public void getDisplayableCards_fourEligibleCards_shouldShowDefaultCardCount() {
|
||||||
final List<ContextualCard> fourCards = getContextualCardList();
|
final List<ContextualCard> cards = getContextualCardList().stream().limit(4)
|
||||||
doReturn(fourCards).when(mContextualCardLoader).filterEligibleCards(anyList());
|
.collect(Collectors.toList());
|
||||||
|
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
|
||||||
|
|
||||||
final List<ContextualCard> result = mContextualCardLoader
|
final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
|
||||||
.getDisplayableCards(fourCards);
|
|
||||||
|
|
||||||
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
|
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
|
@Test
|
||||||
public void getDisplayableCards_refreshCardUri_shouldLogContextualCard() {
|
public void getDisplayableCards_refreshCardUri_shouldLogContextualCard() {
|
||||||
mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
|
mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
|
||||||
@@ -128,20 +154,20 @@ public class ContextualCardLoaderTest {
|
|||||||
private List<ContextualCard> getContextualCardList() {
|
private List<ContextualCard> getContextualCardList() {
|
||||||
final List<ContextualCard> cards = new ArrayList<>();
|
final List<ContextualCard> cards = new ArrayList<>();
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
.setName("test_wifi")
|
.setName("test_low_storage")
|
||||||
.setCardType(ContextualCard.CardType.SLICE)
|
.setCardType(ContextualCard.CardType.SLICE)
|
||||||
.setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
|
.setSliceUri(CustomSliceRegistry.LOW_STORAGE_SLICE_URI)
|
||||||
.build());
|
.build());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
.setName("test_flashlight")
|
.setName("test_flashlight")
|
||||||
.setCardType(ContextualCard.CardType.SLICE)
|
.setCardType(ContextualCard.CardType.SLICE)
|
||||||
.setSliceUri(
|
.setSliceUri(Uri.parse(
|
||||||
Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
|
"content://com.android.settings.test.slices/action/flashlight"))
|
||||||
.build());
|
.build());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
.setName("test_connected")
|
.setName("test_dark_theme")
|
||||||
.setCardType(ContextualCard.CardType.SLICE)
|
.setCardType(ContextualCard.CardType.SLICE)
|
||||||
.setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
|
.setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI)
|
||||||
.build());
|
.build());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
.setName("test_gesture")
|
.setName("test_gesture")
|
||||||
@@ -149,6 +175,24 @@ public class ContextualCardLoaderTest {
|
|||||||
.setSliceUri(Uri.parse(
|
.setSliceUri(Uri.parse(
|
||||||
"content://com.android.settings.test.slices/action/gesture_pick_up"))
|
"content://com.android.settings.test.slices/action/gesture_pick_up"))
|
||||||
.build());
|
.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;
|
return cards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
@Test
|
||||||
public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
|
public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
|
||||||
|
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
|
||||||
final List<ContextualCard> cards = new ArrayList<>();
|
final List<ContextualCard> cards = new ArrayList<>();
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
|
||||||
@@ -584,6 +604,7 @@ public class ContextualCardManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCardsWithViewType_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
|
public void getCardsWithViewType_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
|
||||||
|
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
|
||||||
final List<ContextualCard> cards = new ArrayList<>();
|
final List<ContextualCard> cards = new ArrayList<>();
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
|
||||||
@@ -602,6 +623,7 @@ public class ContextualCardManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCardsWithViewType_hasWifiAndBtDeviceSlice_shouldHaveTwoStickyCards() {
|
public void getCardsWithViewType_hasWifiAndBtDeviceSlice_shouldHaveTwoStickyCards() {
|
||||||
|
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
|
||||||
final List<ContextualCard> cards = new ArrayList<>();
|
final List<ContextualCard> cards = new ArrayList<>();
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
|
||||||
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
|
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
|
||||||
@@ -624,6 +646,7 @@ public class ContextualCardManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCardsWithViewType_noWifiOrBtDeviceSlice_shouldNotHaveStickyCard() {
|
public void getCardsWithViewType_noWifiOrBtDeviceSlice_shouldNotHaveStickyCard() {
|
||||||
|
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
|
||||||
final List<Integer> categories = Arrays.asList(
|
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,
|
||||||
@@ -683,8 +706,8 @@ public class ContextualCardManagerTest {
|
|||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
.setName("test_flashlight")
|
.setName("test_flashlight")
|
||||||
.setCardType(ContextualCard.CardType.SLICE)
|
.setCardType(ContextualCard.CardType.SLICE)
|
||||||
.setSliceUri(
|
.setSliceUri(Uri.parse(
|
||||||
Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
|
"content://com.android.settings.test.slices/action/flashlight"))
|
||||||
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
||||||
.build());
|
.build());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
|
Reference in New Issue
Block a user