diff --git a/res/layout/contextual_slice_sticky_tile.xml b/res/layout/contextual_slice_sticky_tile.xml
new file mode 100644
index 00000000000..8e82f5339a0
--- /dev/null
+++ b/res/layout/contextual_slice_sticky_tile.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
index 1f2e89ba60b..4a02d91b5ef 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
@@ -87,6 +87,10 @@ public class ContextualCardLookupTable {
SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH,
SliceContextualCardController.class,
SliceContextualCardRenderer.class));
+ add(new ControllerRendererMapping(CardType.SLICE,
+ SliceContextualCardRenderer.VIEW_TYPE_STICKY,
+ SliceContextualCardController.class,
+ SliceContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.CONDITIONAL_FOOTER,
ConditionFooterContextualCardRenderer.VIEW_TYPE,
ConditionContextualCardController.class,
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 662448cc070..9e9069fc5f7 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -18,11 +18,14 @@ 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 com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
+import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
import static java.util.stream.Collectors.groupingBy;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.format.DateUtils;
@@ -51,6 +54,7 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -80,6 +84,8 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
private static final String TAG = "ContextualCardManager";
+ private static final List STICKY_CARDS =
+ Arrays.asList(CONTEXTUAL_WIFI_SLICE_URI, BLUETOOTH_DEVICES_SLICE_URI);
private final Context mContext;
private final Lifecycle mLifecycle;
@@ -308,7 +314,9 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
if (cards.isEmpty()) {
return cards;
}
- return getCardsWithSuggestionViewType(cards);
+
+ final List result = getCardsWithStickyViewType(cards);
+ return getCardsWithSuggestionViewType(result);
}
@VisibleForTesting
@@ -338,6 +346,29 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
return result;
}
+ // TODO(b/143055685):use category to determine whether they are sticky.
+ private List getCardsWithStickyViewType(List cards) {
+ final List result = new ArrayList<>(cards);
+ int replaceCount = 0;
+ for (int index = 0; index < result.size(); index++) {
+ if (replaceCount > STICKY_CARDS.size() - 1) {
+ break;
+ }
+
+ final ContextualCard card = cards.get(index);
+ if (card.getCardType() != ContextualCard.CardType.SLICE) {
+ continue;
+ }
+
+ if (STICKY_CARDS.contains(card.getSliceUri())) {
+ result.set(index, card.mutate().setViewType(
+ SliceContextualCardRenderer.VIEW_TYPE_STICKY).build());
+ replaceCount++;
+ }
+ }
+ return result;
+ }
+
@VisibleForTesting
List getCardsToKeep(List cards) {
if (mSavedCards != null) {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 23008745d17..6f07d4712e1 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -54,6 +54,7 @@ import java.util.Set;
public class SliceContextualCardRenderer implements ContextualCardRenderer, LifecycleObserver {
public static final int VIEW_TYPE_FULL_WIDTH = R.layout.contextual_slice_full_tile;
public static final int VIEW_TYPE_HALF_WIDTH = R.layout.contextual_slice_half_tile;
+ public static final int VIEW_TYPE_STICKY = R.layout.contextual_slice_sticky_tile;
private static final String TAG = "SliceCardRenderer";
@@ -137,7 +138,9 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
}
});
- initDismissalActions(holder, card);
+ if (holder.getItemViewType() != VIEW_TYPE_STICKY) {
+ initDismissalActions(holder, card);
+ }
if (card.isPendingDismiss()) {
showDismissalView(holder);
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 63294446581..be3c6855a26 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -19,6 +19,7 @@ package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardManager.KEY_CONTEXTUAL_CARDS;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH;
+import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_STICKY;
import static com.google.common.truth.Truth.assertThat;
@@ -109,8 +110,8 @@ public class ContextualCardManagerTest {
mManager = new ContextualCardManager(mContext, mLifecycle, outState);
final List actualCards = mManager.mSavedCards.stream().collect(Collectors.toList());
- final List expectedCards = Arrays.asList("test_wifi", "test_flashlight",
- "test_connected", "test_gesture", "test_battery");
+ final List expectedCards = Arrays.asList("test_low_storage", "test_flashlight",
+ "test_dark_theme", "test_gesture", "test_battery");
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
}
@@ -347,8 +348,9 @@ public class ContextualCardManagerTest {
final ConditionContextualCardController conditionController =
pool.getController(mContext,
ContextualCard.CardType.CONDITIONAL);
- final OnStart controller = spy((OnStart)conditionController);
- doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
+ final OnStart controller = spy((OnStart) conditionController);
+ doReturn(controller).when(pool).getController(mContext,
+ ContextualCard.CardType.CONDITIONAL);
manager.onWindowFocusChanged(true /* hasWindowFocus */);
@@ -365,8 +367,9 @@ public class ContextualCardManagerTest {
final ConditionContextualCardController conditionController =
pool.getController(mContext,
ContextualCard.CardType.CONDITIONAL);
- final OnStart controller = spy((OnStart)conditionController);
- doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
+ final OnStart controller = spy((OnStart) conditionController);
+ doReturn(controller).when(pool).getController(mContext,
+ ContextualCard.CardType.CONDITIONAL);
manager.onWindowFocusChanged(true /* hasWindowFocus */);
@@ -384,7 +387,8 @@ public class ContextualCardManagerTest {
pool.getController(mContext,
ContextualCard.CardType.CONDITIONAL);
final OnStop controller = spy((OnStop) conditionController);
- doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
+ doReturn(controller).when(pool).getController(mContext,
+ ContextualCard.CardType.CONDITIONAL);
manager.onWindowFocusChanged(false /* hasWindowFocus */);
@@ -400,7 +404,8 @@ public class ContextualCardManagerTest {
pool.getController(mContext,
ContextualCard.CardType.CONDITIONAL);
final OnStop controller = spy((OnStop) conditionController);
- doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
+ doReturn(controller).when(pool).getController(mContext,
+ ContextualCard.CardType.CONDITIONAL);
manager.onWindowFocusChanged(false /* hasWindowFocus */);
@@ -540,6 +545,85 @@ public class ContextualCardManagerTest {
}
}
+ @Test
+ public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
+ final List cards = new ArrayList<>();
+ cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
+ cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
+ final List categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List cardListWithWifi = buildCategoriedCards(cards, categories);
+
+ final List 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_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
+ final List cards = new ArrayList<>();
+ cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
+ cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
+ final List categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List cardListWithBT = buildCategoriedCards(cards, categories);
+
+ final List result = mManager.getCardsWithViewType(cardListWithBT);
+
+ 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_hasWifiAndBtDeviceSlice_shouldHaveTwoStickyCards() {
+ final List cards = new ArrayList<>();
+ cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
+ cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
+ cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
+ final List categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List cardListWithWifiBT = buildCategoriedCards(cards, categories);
+
+ final List result = mManager.getCardsWithViewType(cardListWithWifiBT);
+
+ assertThat(result).hasSize(cards.size());
+ assertThat(result.stream()
+ .filter(card -> card.getViewType() == VIEW_TYPE_STICKY)
+ .count())
+ .isEqualTo(2);
+ }
+
+ @Test
+ public void getCardsWithViewType_noWifiOrBtDeviceSlice_shouldNotHaveStickyCard() {
+ final List 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.SUGGESTION_VALUE
+ );
+ final List cardListWithoutWifiBT =
+ buildCategoriedCards(getContextualCardList(), categories);
+
+ final List result = mManager.getCardsWithViewType(cardListWithoutWifiBT);
+
+ assertThat(result).hasSize(cardListWithoutWifiBT.size());
+ assertThat(result.stream()
+ .filter(card -> card.getViewType() == VIEW_TYPE_STICKY)
+ .count())
+ .isEqualTo(0);
+ }
+
@Test
public void getCardsToKeep_hasSavedCard_shouldResetSavedCards() {
final List savedCardNames = new ArrayList<>();
@@ -572,9 +656,9 @@ public class ContextualCardManagerTest {
private List getContextualCardList() {
final List 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)
.setViewType(VIEW_TYPE_FULL_WIDTH)
.build());
cards.add(new ContextualCard.Builder()
@@ -585,9 +669,9 @@ public class ContextualCardManagerTest {
.setViewType(VIEW_TYPE_FULL_WIDTH)
.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)
.setViewType(VIEW_TYPE_FULL_WIDTH)
.build());
cards.add(new ContextualCard.Builder()