Merge "Make Wifi and Bluetooth Slices not dismissable."
This commit is contained in:
committed by
Android (Google) Code Review
commit
814e65adcb
32
res/layout/contextual_slice_sticky_tile.xml
Normal file
32
res/layout/contextual_slice_sticky_tile.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/ContextualCardStyle">
|
||||||
|
|
||||||
|
<androidx.slice.widget.SliceView
|
||||||
|
android:id="@+id/slice_view"
|
||||||
|
style="@style/ContextualCardSliceViewStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:importantForAccessibility="no"/>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
@@ -87,6 +87,10 @@ public class ContextualCardLookupTable {
|
|||||||
SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH,
|
SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH,
|
||||||
SliceContextualCardController.class,
|
SliceContextualCardController.class,
|
||||||
SliceContextualCardRenderer.class));
|
SliceContextualCardRenderer.class));
|
||||||
|
add(new ControllerRendererMapping(CardType.SLICE,
|
||||||
|
SliceContextualCardRenderer.VIEW_TYPE_STICKY,
|
||||||
|
SliceContextualCardController.class,
|
||||||
|
SliceContextualCardRenderer.class));
|
||||||
add(new ControllerRendererMapping(CardType.CONDITIONAL_FOOTER,
|
add(new ControllerRendererMapping(CardType.CONDITIONAL_FOOTER,
|
||||||
ConditionFooterContextualCardRenderer.VIEW_TYPE,
|
ConditionFooterContextualCardRenderer.VIEW_TYPE,
|
||||||
ConditionContextualCardController.class,
|
ConditionContextualCardController.class,
|
||||||
|
@@ -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.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
|
||||||
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.CONTEXTUAL_WIFI_SLICE_URI;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.groupingBy;
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.format.DateUtils;
|
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 com.android.settingslib.core.lifecycle.events.OnStop;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -80,6 +84,8 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
|||||||
static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
|
static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
|
||||||
|
|
||||||
private static final String TAG = "ContextualCardManager";
|
private static final String TAG = "ContextualCardManager";
|
||||||
|
private static final List<Uri> STICKY_CARDS =
|
||||||
|
Arrays.asList(CONTEXTUAL_WIFI_SLICE_URI, BLUETOOTH_DEVICES_SLICE_URI);
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final Lifecycle mLifecycle;
|
private final Lifecycle mLifecycle;
|
||||||
@@ -308,7 +314,9 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
|||||||
if (cards.isEmpty()) {
|
if (cards.isEmpty()) {
|
||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
return getCardsWithSuggestionViewType(cards);
|
|
||||||
|
final List<ContextualCard> result = getCardsWithStickyViewType(cards);
|
||||||
|
return getCardsWithSuggestionViewType(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -338,6 +346,29 @@ 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) {
|
||||||
|
final List<ContextualCard> 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
|
@VisibleForTesting
|
||||||
List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
|
List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
|
||||||
if (mSavedCards != null) {
|
if (mSavedCards != null) {
|
||||||
|
@@ -54,6 +54,7 @@ import java.util.Set;
|
|||||||
public class SliceContextualCardRenderer implements ContextualCardRenderer, LifecycleObserver {
|
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_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_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";
|
private static final String TAG = "SliceCardRenderer";
|
||||||
|
|
||||||
@@ -137,7 +138,9 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (holder.getItemViewType() != VIEW_TYPE_STICKY) {
|
||||||
initDismissalActions(holder, card);
|
initDismissalActions(holder, card);
|
||||||
|
}
|
||||||
|
|
||||||
if (card.isPendingDismiss()) {
|
if (card.isPendingDismiss()) {
|
||||||
showDismissalView(holder);
|
showDismissalView(holder);
|
||||||
|
@@ -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.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_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_HALF_WIDTH;
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_STICKY;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -109,8 +110,8 @@ public class ContextualCardManagerTest {
|
|||||||
mManager = new ContextualCardManager(mContext, mLifecycle, outState);
|
mManager = new ContextualCardManager(mContext, mLifecycle, outState);
|
||||||
|
|
||||||
final List<String> actualCards = mManager.mSavedCards.stream().collect(Collectors.toList());
|
final List<String> actualCards = mManager.mSavedCards.stream().collect(Collectors.toList());
|
||||||
final List<String> expectedCards = Arrays.asList("test_wifi", "test_flashlight",
|
final List<String> expectedCards = Arrays.asList("test_low_storage", "test_flashlight",
|
||||||
"test_connected", "test_gesture", "test_battery");
|
"test_dark_theme", "test_gesture", "test_battery");
|
||||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +349,8 @@ public class ContextualCardManagerTest {
|
|||||||
pool.getController(mContext,
|
pool.getController(mContext,
|
||||||
ContextualCard.CardType.CONDITIONAL);
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
final OnStart controller = spy((OnStart) conditionController);
|
final OnStart controller = spy((OnStart) conditionController);
|
||||||
doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
|
doReturn(controller).when(pool).getController(mContext,
|
||||||
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
|
|
||||||
manager.onWindowFocusChanged(true /* hasWindowFocus */);
|
manager.onWindowFocusChanged(true /* hasWindowFocus */);
|
||||||
|
|
||||||
@@ -366,7 +368,8 @@ public class ContextualCardManagerTest {
|
|||||||
pool.getController(mContext,
|
pool.getController(mContext,
|
||||||
ContextualCard.CardType.CONDITIONAL);
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
final OnStart controller = spy((OnStart) conditionController);
|
final OnStart controller = spy((OnStart) conditionController);
|
||||||
doReturn(controller).when(pool).getController(mContext, ContextualCard.CardType.CONDITIONAL);
|
doReturn(controller).when(pool).getController(mContext,
|
||||||
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
|
|
||||||
manager.onWindowFocusChanged(true /* hasWindowFocus */);
|
manager.onWindowFocusChanged(true /* hasWindowFocus */);
|
||||||
|
|
||||||
@@ -384,7 +387,8 @@ public class ContextualCardManagerTest {
|
|||||||
pool.getController(mContext,
|
pool.getController(mContext,
|
||||||
ContextualCard.CardType.CONDITIONAL);
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
final OnStop controller = spy((OnStop) conditionController);
|
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 */);
|
manager.onWindowFocusChanged(false /* hasWindowFocus */);
|
||||||
|
|
||||||
@@ -400,7 +404,8 @@ public class ContextualCardManagerTest {
|
|||||||
pool.getController(mContext,
|
pool.getController(mContext,
|
||||||
ContextualCard.CardType.CONDITIONAL);
|
ContextualCard.CardType.CONDITIONAL);
|
||||||
final OnStop controller = spy((OnStop) conditionController);
|
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 */);
|
manager.onWindowFocusChanged(false /* hasWindowFocus */);
|
||||||
|
|
||||||
@@ -540,6 +545,85 @@ public class ContextualCardManagerTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
|
||||||
|
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.IMPORTANT_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_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
|
||||||
|
final List<ContextualCard> cards = new ArrayList<>();
|
||||||
|
cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
|
||||||
|
cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
|
||||||
|
final List<Integer> categories = Arrays.asList(
|
||||||
|
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
|
||||||
|
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
|
||||||
|
);
|
||||||
|
final List<ContextualCard> cardListWithBT = buildCategoriedCards(cards, categories);
|
||||||
|
|
||||||
|
final List<ContextualCard> 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<ContextualCard> 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<Integer> categories = Arrays.asList(
|
||||||
|
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
|
||||||
|
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
|
||||||
|
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
|
||||||
|
);
|
||||||
|
final List<ContextualCard> cardListWithWifiBT = buildCategoriedCards(cards, categories);
|
||||||
|
|
||||||
|
final List<ContextualCard> 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<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.SUGGESTION_VALUE
|
||||||
|
);
|
||||||
|
final List<ContextualCard> cardListWithoutWifiBT =
|
||||||
|
buildCategoriedCards(getContextualCardList(), categories);
|
||||||
|
|
||||||
|
final List<ContextualCard> result = mManager.getCardsWithViewType(cardListWithoutWifiBT);
|
||||||
|
|
||||||
|
assertThat(result).hasSize(cardListWithoutWifiBT.size());
|
||||||
|
assertThat(result.stream()
|
||||||
|
.filter(card -> card.getViewType() == VIEW_TYPE_STICKY)
|
||||||
|
.count())
|
||||||
|
.isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCardsToKeep_hasSavedCard_shouldResetSavedCards() {
|
public void getCardsToKeep_hasSavedCard_shouldResetSavedCards() {
|
||||||
final List<String> savedCardNames = new ArrayList<>();
|
final List<String> savedCardNames = new ArrayList<>();
|
||||||
@@ -572,9 +656,9 @@ public class ContextualCardManagerTest {
|
|||||||
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)
|
||||||
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
||||||
.build());
|
.build());
|
||||||
cards.add(new ContextualCard.Builder()
|
cards.add(new ContextualCard.Builder()
|
||||||
@@ -585,9 +669,9 @@ public class ContextualCardManagerTest {
|
|||||||
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
||||||
.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)
|
||||||
.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