diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java index 24266eea409..9c06beb7ebc 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java @@ -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 mContextualCards; @VisibleForTesting long mStartTime; + boolean mIsFirstLaunch; + @VisibleForTesting + List 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 cards) { final long loadTime = System.currentTimeMillis() - mStartTime; + final List 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 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 getCardsToKeep(List cards) { + if (mSavedCards != null) { + //screen rotate + final List 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> { diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java index 5f9bf0df6ac..e598e4c6946 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java @@ -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 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 2af84f96ca8..c405ffc4f1b 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java @@ -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 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 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 loadedCards = new ArrayList<>(); + loadedCards.add(buildContextualCard(TEST_SLICE_URI)); + loadedCards.add(newCard); + + mManager.onFinishCardLoading(loadedCards); + + final List actualCards = mManager.mContextualCards.stream() + .map(ContextualCard::getName) + .collect(Collectors.toList()); + final List 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 loadedCards = new ArrayList<>(); + loadedCards.add(buildContextualCard(TEST_SLICE_URI)); + loadedCards.add(newCard); + + mManager.onFinishCardLoading(loadedCards); + + final List actualCards = mManager.mContextualCards.stream() + .map(ContextualCard::getName) + .collect(Collectors.toList()); + final List 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(); }