Merge "Make Wifi and Bluetooth Slices not dismissable."

This commit is contained in:
TreeHugger Robot
2020-01-21 10:56:58 +00:00
committed by Android (Google) Code Review
5 changed files with 168 additions and 14 deletions

View 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>

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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()