Don't have cards auto-filled in the foreground when a card gets dismissed.
Currently if users dismiss a card or navigate back to the homepage, new suggestions will be auto filled in. We should only add new cards upon next visit. Also fix suggestion cards undismissable problem. Fixes: 121175037 Bug: 120628661 Test: robotests Change-Id: I01d74aaaa21c8408e5cecafef04a7d52c97bccc5
This commit is contained in:
@@ -35,6 +35,7 @@ import androidx.loader.content.Loader;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -56,7 +57,9 @@ import java.util.stream.Collectors;
|
||||
* get the page refreshed.
|
||||
*/
|
||||
public class ContextualCardManager implements ContextualCardLoader.CardContentLoaderListener,
|
||||
ContextualCardUpdateListener {
|
||||
ContextualCardUpdateListener, LifecycleObserver, OnSaveInstanceState {
|
||||
|
||||
private static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
|
||||
|
||||
private static final String TAG = "ContextualCardManager";
|
||||
|
||||
@@ -68,6 +71,9 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
final List<ContextualCard> mContextualCards;
|
||||
@VisibleForTesting
|
||||
long mStartTime;
|
||||
boolean mIsFirstLaunch;
|
||||
@VisibleForTesting
|
||||
List<String> mSavedCards;
|
||||
|
||||
private final Context mContext;
|
||||
private final ControllerRendererPool mControllerRendererPool;
|
||||
@@ -76,12 +82,20 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
|
||||
private ContextualCardUpdateListener mListener;
|
||||
|
||||
public ContextualCardManager(Context context, Lifecycle lifecycle) {
|
||||
public ContextualCardManager(Context context, Lifecycle lifecycle, Bundle savedInstanceState) {
|
||||
mContext = context;
|
||||
mLifecycle = lifecycle;
|
||||
mContextualCards = new ArrayList<>();
|
||||
mLifecycleObservers = new ArrayList<>();
|
||||
mControllerRendererPool = new ControllerRendererPool();
|
||||
mLifecycle.addObserver(this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
mIsFirstLaunch = true;
|
||||
mSavedCards = null;
|
||||
} else {
|
||||
mSavedCards = savedInstanceState.getStringArrayList(KEY_CONTEXTUAL_CARDS);
|
||||
}
|
||||
//for data provided by Settings
|
||||
for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
|
||||
setupController(cardType);
|
||||
@@ -172,13 +186,34 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
@Override
|
||||
public void onFinishCardLoading(List<ContextualCard> cards) {
|
||||
final long loadTime = System.currentTimeMillis() - mStartTime;
|
||||
final List<ContextualCard> cardsToKeep = getCardsToKeep(cards);
|
||||
|
||||
//navigate back to the homepage or after card dismissal
|
||||
if (!mIsFirstLaunch) {
|
||||
onContextualCardUpdated(cardsToKeep.stream()
|
||||
.collect(groupingBy(ContextualCard::getCardType)));
|
||||
return;
|
||||
}
|
||||
|
||||
//only log homepage display upon a fresh launch
|
||||
if (loadTime <= ContextualCardLoader.CARD_CONTENT_LOADER_TIMEOUT_MS) {
|
||||
onContextualCardUpdated(
|
||||
cards.stream().collect(groupingBy(ContextualCard::getCardType)));
|
||||
onContextualCardUpdated(cards.stream()
|
||||
.collect(groupingBy(ContextualCard::getCardType)));
|
||||
}
|
||||
final long totalTime = System.currentTimeMillis() - mStartTime;
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider()
|
||||
.logHomepageDisplay(mContext, totalTime);
|
||||
|
||||
mIsFirstLaunch = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
final ArrayList<String> cards = mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
outState.putStringArrayList(KEY_CONTEXTUAL_CARDS, cards);
|
||||
}
|
||||
|
||||
public ControllerRendererPool getControllerRendererPool() {
|
||||
@@ -189,6 +224,22 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
|
||||
if (mSavedCards != null) {
|
||||
//screen rotate
|
||||
final List<ContextualCard> cardsToKeep = cards.stream()
|
||||
.filter(card -> mSavedCards.contains(card.getName()))
|
||||
.collect(Collectors.toList());
|
||||
mSavedCards = null;
|
||||
return cardsToKeep;
|
||||
} else {
|
||||
//navigate back to the homepage or after dismissing a card
|
||||
return cards.stream()
|
||||
.filter(card -> mContextualCards.contains(card))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
static class CardContentLoaderCallbacks implements
|
||||
LoaderManager.LoaderCallbacks<List<ContextualCard>> {
|
||||
|
||||
|
@@ -42,7 +42,8 @@ public class ContextualCardsFragment extends InstrumentedFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle());
|
||||
mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle(),
|
||||
savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -42,13 +42,16 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ContextualCardManagerTest {
|
||||
|
||||
private static final String TEST_SLICE_URI = "context://test/test";
|
||||
private static final String TEST_SLICE_NAME = "test_name";
|
||||
|
||||
@Mock
|
||||
ContextualCardUpdateListener mListener;
|
||||
@@ -61,7 +64,8 @@ public class ContextualCardManagerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
final ContextualCardsFragment fragment = new ContextualCardsFragment();
|
||||
mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle());
|
||||
mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle(),
|
||||
null /* bundle */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,9 +139,74 @@ public class ContextualCardManagerTest {
|
||||
verify(manager, never()).onContextualCardUpdated(anyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_newLaunch_twoLoadedCards_shouldShowTwoCards() {
|
||||
mManager.mStartTime = System.currentTimeMillis();
|
||||
mManager.setListener(mListener);
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
cards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
cards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
|
||||
mManager.onFinishCardLoading(cards);
|
||||
|
||||
assertThat(mManager.mContextualCards).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_hasSavedCard_shouldOnlyShowSavedCard() {
|
||||
mManager.setListener(mListener);
|
||||
final List<String> savedCardNames = new ArrayList<>();
|
||||
savedCardNames.add(TEST_SLICE_NAME);
|
||||
mManager.mIsFirstLaunch = false;
|
||||
mManager.mSavedCards = savedCardNames;
|
||||
final ContextualCard newCard =
|
||||
new ContextualCard.Builder()
|
||||
.setName("test_name2")
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse("content://test/test2"))
|
||||
.build();
|
||||
final List<ContextualCard> loadedCards = new ArrayList<>();
|
||||
loadedCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
loadedCards.add(newCard);
|
||||
|
||||
mManager.onFinishCardLoading(loadedCards);
|
||||
|
||||
final List<String> actualCards = mManager.mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toList());
|
||||
final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
|
||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_reloadData_shouldOnlyShowOldCard() {
|
||||
mManager.setListener(mListener);
|
||||
mManager.mIsFirstLaunch = false;
|
||||
//old card
|
||||
mManager.mContextualCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
final ContextualCard newCard =
|
||||
new ContextualCard.Builder()
|
||||
.setName("test_name2")
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse("content://test/test2"))
|
||||
.build();
|
||||
final List<ContextualCard> loadedCards = new ArrayList<>();
|
||||
loadedCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
loadedCards.add(newCard);
|
||||
|
||||
mManager.onFinishCardLoading(loadedCards);
|
||||
|
||||
final List<String> actualCards = mManager.mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toList());
|
||||
final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
|
||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
||||
}
|
||||
|
||||
private ContextualCard buildContextualCard(String sliceUri) {
|
||||
return new ContextualCard.Builder()
|
||||
.setName("test_name")
|
||||
.setName(TEST_SLICE_NAME)
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse(sliceUri))
|
||||
.build();
|
||||
}
|
||||
|
Reference in New Issue
Block a user