diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java index 4378be3f0d7..8720a3ce488 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java +++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java @@ -69,9 +69,9 @@ public class SliceContextualCardController implements ContextualCardController { dbHelper.markContextualCardAsDismissed(mContext, card.getName()); }); showFeedbackDialog(card); - final ContextualCardFeatureProvider contexualCardFeatureProvider = + final ContextualCardFeatureProvider contextualCardFeatureProvider = FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(); - contexualCardFeatureProvider.logContextualCardDismiss(mContext, card); + contextualCardFeatureProvider.logContextualCardDismiss(mContext, card); } @Override diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java index a2d6e2b119c..4df2a04cd9e 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java @@ -28,8 +28,11 @@ import android.widget.ViewFlipper; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; +import androidx.lifecycle.OnLifecycleEvent; import androidx.recyclerview.widget.RecyclerView; import androidx.slice.Slice; import androidx.slice.SliceItem; @@ -51,13 +54,15 @@ import java.util.Set; * Card renderer for {@link ContextualCard} built as slices. */ public class SliceContextualCardRenderer implements ContextualCardRenderer, - SliceView.OnSliceActionListener { + SliceView.OnSliceActionListener, LifecycleObserver { public static final int VIEW_TYPE = R.layout.homepage_slice_tile; private static final String TAG = "SliceCardRenderer"; @VisibleForTesting final Map> mSliceLiveDataMap; + @VisibleForTesting + final Set mFlippedCardSet; private final Context mContext; private final LifecycleOwner mLifecycleOwner; @@ -71,6 +76,8 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, mSliceLiveDataMap = new ArrayMap<>(); mControllerRendererPool = controllerRendererPool; mCardSet = new ArraySet<>(); + mFlippedCardSet = new ArraySet<>(); + mLifecycleOwner.getLifecycle().addObserver(this); } @Override @@ -122,20 +129,23 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, } private void initDismissalActions(SliceViewHolder cardHolder, ContextualCard card) { - final ViewFlipper viewFlipper = cardHolder.itemView.findViewById(R.id.viewFlipper); cardHolder.sliceView.setOnLongClickListener(v -> { - viewFlipper.showNext(); + cardHolder.viewFlipper.showNext(); + mFlippedCardSet.add(cardHolder); return true; }); final Button btnKeep = cardHolder.itemView.findViewById(R.id.keep); btnKeep.setOnClickListener(v -> { - viewFlipper.showPrevious(); + cardHolder.resetCard(); + mFlippedCardSet.remove(cardHolder); }); final Button btnRemove = cardHolder.itemView.findViewById(R.id.remove); btnRemove.setOnClickListener(v -> { mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card); + cardHolder.resetCard(); + mFlippedCardSet.remove(cardHolder); }); } @@ -158,12 +168,24 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, } } + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + mFlippedCardSet.stream().forEach(holder -> holder.resetCard()); + mFlippedCardSet.clear(); + } + public static class SliceViewHolder extends RecyclerView.ViewHolder { public final SliceView sliceView; + public final ViewFlipper viewFlipper; public SliceViewHolder(View view) { super(view); sliceView = view.findViewById(R.id.slice_view); + viewFlipper = view.findViewById(R.id.viewFlipper); + } + + public void resetCard() { + viewFlipper.setDisplayedChild(0); } } } diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java index 13a2bc5ba87..11d0106565c 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java @@ -18,6 +18,7 @@ package com.android.settings.homepage.contextualcards.slices; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import android.app.Activity; @@ -51,10 +52,14 @@ import org.robolectric.android.controller.ActivityController; @RunWith(SettingsRobolectricTestRunner.class) public class SliceContextualCardRendererTest { + private static final String TEST_SLICE_URI = "content://test/test"; + @Mock private LiveData mSliceLiveData; @Mock private ControllerRendererPool mControllerRendererPool; + @Mock + private SliceContextualCardController mController; private Activity mActivity; private SliceContextualCardRenderer mRenderer; @@ -75,10 +80,9 @@ public class SliceContextualCardRendererTest { @Test public void bindView_shouldSetScrollableToFalse() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); - mRenderer.bindView(viewHolder, buildContextualCard(sliceUri)); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); assertThat( ((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.isScrollable @@ -99,64 +103,107 @@ public class SliceContextualCardRendererTest { @Test public void bindView_newSliceLiveData_shouldAddDataToMap() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; - - mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri)); + mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI)); assertThat(mRenderer.mSliceLiveDataMap.size()).isEqualTo(1); } @Test public void bindView_sliceLiveDataShouldObserveSliceView() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; + mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI)); - mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri)); - - assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue(); + assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isTrue(); } @Test public void bindView_sliceLiveDataShouldRemoveObservers() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; - mRenderer.mSliceLiveDataMap.put(sliceUri, mSliceLiveData); + mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData); - mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri)); + mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI)); verify(mSliceLiveData).removeObservers(mLifecycleOwner); } @Test public void longClick_shouldFlipCard() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final View card = viewHolder.itemView.findViewById(R.id.slice_view); final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper); final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view); - mRenderer.bindView(viewHolder, buildContextualCard(sliceUri)); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); - assertThat(card).isNotNull(); card.performLongClick(); assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView); } + @Test + public void longClick_shouldAddViewHolderToSet() { + final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); + final View card = viewHolder.itemView.findViewById(R.id.slice_view); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); + + card.performLongClick(); + + assertThat(mRenderer.mFlippedCardSet).contains(viewHolder); + } + @Test public void viewClick_keepCard_shouldFlipBackToSlice() { - final String sliceUri = "content://com.android.settings.slices/action/flashlight"; final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final View card = viewHolder.itemView.findViewById(R.id.slice_view); final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep); final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper); - mRenderer.bindView(viewHolder, buildContextualCard(sliceUri)); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); - assertThat(card).isNotNull(); card.performLongClick(); - assertThat(btnKeep).isNotNull(); btnKeep.performClick(); assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class); } + @Test + public void viewClick_keepCard_shouldRemoveViewHolderFromSet() { + final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); + final View card = viewHolder.itemView.findViewById(R.id.slice_view); + final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); + + card.performLongClick(); + btnKeep.performClick(); + + assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder); + } + + @Test + public void viewClick_removeCard_shouldRemoveViewHolderFromSet() { + final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); + final View card = viewHolder.itemView.findViewById(R.id.slice_view); + final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove); + final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI); + mRenderer.bindView(viewHolder, contextualCard); + doReturn(mController).when(mControllerRendererPool).getController(mActivity, + ContextualCard.CardType.SLICE); + + card.performLongClick(); + btnRemove.performClick(); + + assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder); + } + + @Test + public void onStop_cardIsFlipped_shouldFlipBack() { + final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); + final View card = viewHolder.itemView.findViewById(R.id.slice_view); + final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper); + mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); + + card.performLongClick(); + mRenderer.onStop(); + + assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class); + } + private RecyclerView.ViewHolder getSliceViewHolder() { final int viewType = mRenderer.getViewType(false /* isHalfWidth */); final RecyclerView recyclerView = new RecyclerView(mActivity); @@ -169,6 +216,7 @@ public class SliceContextualCardRendererTest { private ContextualCard buildContextualCard(String sliceUri) { return new ContextualCard.Builder() .setName("test_name") + .setCardType(ContextualCard.CardType.SLICE) .setSliceUri(Uri.parse(sliceUri)) .build(); }