Loading src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +26 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<String, LiveData<Slice>> mSliceLiveDataMap; @VisibleForTesting final Set<SliceViewHolder> mFlippedCardSet; private final Context mContext; private final LifecycleOwner mLifecycleOwner; Loading @@ -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 Loading Loading @@ -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); }); } Loading @@ -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); } } } tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +67 −19 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<Slice> mSliceLiveData; @Mock private ControllerRendererPool mControllerRendererPool; @Mock private SliceContextualCardController mController; private Activity mActivity; private SliceContextualCardRenderer mRenderer; Loading @@ -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 Loading @@ -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(sliceUri)); mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI)); 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); Loading @@ -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(); } Loading Loading
src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +26 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<String, LiveData<Slice>> mSliceLiveDataMap; @VisibleForTesting final Set<SliceViewHolder> mFlippedCardSet; private final Context mContext; private final LifecycleOwner mLifecycleOwner; Loading @@ -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 Loading Loading @@ -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); }); } Loading @@ -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); } } }
tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +67 −19 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<Slice> mSliceLiveData; @Mock private ControllerRendererPool mControllerRendererPool; @Mock private SliceContextualCardController mController; private Activity mActivity; private SliceContextualCardRenderer mRenderer; Loading @@ -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 Loading @@ -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(sliceUri)); mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI)); 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); Loading @@ -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(); } Loading