Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bccad4ab authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Reset dismissal UI to the baseline when exiting the page."

parents c4be214f 2efa9346
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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
+26 −4
Original line number Diff line number Diff line
@@ -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<String, LiveData<Slice>> mSliceLiveDataMap;
    @VisibleForTesting
    final Set<SliceViewHolder> 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);
        }
    }
}
+67 −19
Original line number Diff line number Diff line
@@ -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<Slice> 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(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);
@@ -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();
    }