Loading src/com/android/settings/homepage/contextualcards/ContextualCardManager.java +55 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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() { Loading @@ -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>> { Loading src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java +71 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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(); } Loading Loading
src/com/android/settings/homepage/contextualcards/ContextualCardManager.java +55 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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() { Loading @@ -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>> { Loading
src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java +71 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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(); } Loading