Remove viewFlipper used in contextual card dismissal.

- Use view's visibility to control which view we should show.
- Slice view can be built with normal height after removing viewFlipper.

Bug: 129438972
Bug: 128689305
Test: robotests
Change-Id: If7e9bd30d5cb5bcd3b9ff9f09cc2eae36543b9e9
This commit is contained in:
Yi-Ling Chuang
2019-04-01 22:53:10 +08:00
parent dc2b2c7929
commit 734d826117
9 changed files with 86 additions and 117 deletions

View File

@@ -21,7 +21,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/homepage_card_dismissal_background" android:background="@color/homepage_card_dismissal_background"
android:orientation="vertical"> android:orientation="vertical"
android:visibility="gone">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -27,43 +27,37 @@
<include layout="@layout/dismissal_swipe_background"/> <include layout="@layout/dismissal_swipe_background"/>
<ViewFlipper <LinearLayout
android:id="@+id/view_flipper" android:id="@+id/content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:paddingEnd="@dimen/homepage_card_padding_end"
android:paddingTop="@dimen/homepage_half_card_padding_top"
android:paddingBottom="@dimen/homepage_half_card_padding_bottom"
android:background="@color/contextual_card_background"
android:orientation="vertical">
<LinearLayout <ImageView
android:id="@+id/content" android:id="@android:id/icon"
android:layout_width="@dimen/homepage_card_icon_size"
android:layout_height="@dimen/homepage_card_icon_size"
android:layout_marginStart="@dimen/homepage_card_icon_padding_start"/>
<TextView
android:id="@android:id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:paddingEnd="@dimen/homepage_card_padding_end" android:maxLines="2"
android:paddingTop="@dimen/homepage_half_card_padding_top" android:minLines="1"
android:paddingBottom="@dimen/homepage_half_card_padding_bottom" android:ellipsize="end"
android:background="@color/contextual_card_background" android:layout_marginStart="@dimen/homepage_card_text_padding_start"
android:orientation="vertical"> android:layout_marginTop="@dimen/homepage_half_card_title_margin_top"
android:textAppearance="@style/TextAppearance.ConditionCardTitle"/>
<ImageView </LinearLayout>
android:id="@android:id/icon"
android:layout_width="@dimen/homepage_card_icon_size"
android:layout_height="@dimen/homepage_card_icon_size"
android:layout_marginStart="@dimen/homepage_card_icon_padding_start"/>
<TextView <!--dismissal view-->
android:id="@android:id/title" <include layout="@layout/homepage_dismissal_view"/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:minLines="1"
android:ellipsize="end"
android:layout_marginStart="@dimen/homepage_card_text_padding_start"
android:layout_marginTop="@dimen/homepage_half_card_title_margin_top"
android:textAppearance="@style/TextAppearance.ConditionCardTitle"/>
</LinearLayout>
<!--dismissal view-->
<include layout="@layout/homepage_dismissal_view"/>
</ViewFlipper>
</FrameLayout> </FrameLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@@ -27,29 +27,16 @@
<include layout="@layout/dismissal_swipe_background"/> <include layout="@layout/dismissal_swipe_background"/>
<ViewFlipper <androidx.slice.widget.SliceView
android:id="@+id/view_flipper" android:id="@+id/slice_view"
style="@style/SliceViewStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"/>
<LinearLayout <!--dismissal view-->
android:id="@+id/slice_view_wrapper" <include layout="@layout/homepage_dismissal_view"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/contextual_card_background">
<androidx.slice.widget.SliceView
android:id="@+id/slice_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
style="@style/SliceViewStyle"/>
</LinearLayout>
<!--dismissal view-->
<include layout="@layout/homepage_dismissal_view"/>
</ViewFlipper>
</FrameLayout> </FrameLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@@ -77,8 +77,7 @@ public class ContextualCardsFragment extends InstrumentedFragment implements
mCardsContainer.setAdapter(mContextualCardsAdapter); mCardsContainer.setAdapter(mContextualCardsAdapter);
mContextualCardManager.setListener(mContextualCardsAdapter); mContextualCardManager.setListener(mContextualCardsAdapter);
mCardsContainer.setListener(this); mCardsContainer.setListener(this);
mItemTouchHelper = new ItemTouchHelper( mItemTouchHelper = new ItemTouchHelper(new SwipeDismissalDelegate(mContextualCardsAdapter));
new SwipeDismissalDelegate(context, mContextualCardsAdapter));
mItemTouchHelper.attachToRecyclerView(mCardsContainer); mItemTouchHelper.attachToRecyclerView(mCardsContainer);
return rootView; return rootView;

View File

@@ -24,7 +24,6 @@ import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ViewFlipper;
import androidx.annotation.LayoutRes; import androidx.annotation.LayoutRes;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -142,7 +141,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
} }
if (card.isPendingDismiss()) { if (card.isPendingDismiss()) {
flipCardToDismissalView(holder); showDismissalView(holder);
mFlippedCardSet.add(holder); mFlippedCardSet.add(holder);
} }
} }
@@ -170,12 +169,19 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
} }
private void resetCardView(RecyclerView.ViewHolder holder) { private void resetCardView(RecyclerView.ViewHolder holder) {
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper); holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.GONE);
viewFlipper.setDisplayedChild(0 /* whichChild */); getInitialView(holder).setVisibility(View.VISIBLE);
} }
private void flipCardToDismissalView(RecyclerView.ViewHolder holder) { private void showDismissalView(RecyclerView.ViewHolder holder) {
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper); holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.VISIBLE);
viewFlipper.showNext(); getInitialView(holder).setVisibility(View.INVISIBLE);
}
private View getInitialView(RecyclerView.ViewHolder viewHolder) {
if (viewHolder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
return ((SliceHalfCardRendererHelper.HalfCardViewHolder) viewHolder).content;
}
return ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView;
} }
} }

View File

@@ -71,12 +71,10 @@ class SliceFullCardRendererHelper {
static class SliceViewHolder extends RecyclerView.ViewHolder { static class SliceViewHolder extends RecyclerView.ViewHolder {
public final SliceView sliceView; public final SliceView sliceView;
public final LinearLayout sliceViewWrapper;
public SliceViewHolder(View view) { public SliceViewHolder(View view) {
super(view); super(view);
sliceView = view.findViewById(R.id.slice_view); sliceView = view.findViewById(R.id.slice_view);
sliceViewWrapper = view.findViewById(R.id.slice_view_wrapper);
} }
} }
} }

View File

@@ -16,10 +16,8 @@
package com.android.settings.homepage.contextualcards.slices; package com.android.settings.homepage.contextualcards.slices;
import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.view.View; import android.view.View;
import android.widget.ViewFlipper;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
@@ -36,11 +34,9 @@ public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
void onSwiped(int position); void onSwiped(int position);
} }
private final Context mContext;
private final SwipeDismissalDelegate.Listener mListener; private final SwipeDismissalDelegate.Listener mListener;
public SwipeDismissalDelegate(Context context, SwipeDismissalDelegate.Listener listener) { public SwipeDismissalDelegate(SwipeDismissalDelegate.Listener listener) {
mContext = context;
mListener = listener; mListener = listener;
} }
@@ -59,14 +55,10 @@ public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
switch (viewHolder.getItemViewType()) { switch (viewHolder.getItemViewType()) {
case SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH: case SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH:
case SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH: case SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH:
//TODO(b/129438972): Convert this to a regular view. // Here we are making sure the current displayed view is the initial view of
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper); // either slice full card or half card, and only allow swipe on these two types.
if (viewHolder.itemView.findViewById(R.id.dismissal_view).getVisibility()
// As we are using ViewFlipper to switch between the initial view and == View.VISIBLE) {
// dismissal view, here we are making sure the current displayed view is the
// initial view of either slice full card or half card, and only allow swipe on
// these two types.
if (viewFlipper.getCurrentView().getId() != getInitialViewId(viewHolder)) {
// Disable swiping when we are in the dismissal view // Disable swiping when we are in the dismissal view
return 0; return 0;
} }
@@ -114,13 +106,6 @@ public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
getDefaultUIUtil().onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive); getDefaultUIUtil().onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive);
} }
private int getInitialViewId(RecyclerView.ViewHolder viewHolder) {
if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) {
return R.id.content;
}
return R.id.slice_view_wrapper;
}
/** /**
* Get the foreground view from the {@link android.widget.FrameLayout} as we only swipe * Get the foreground view from the {@link android.widget.FrameLayout} as we only swipe
* the foreground out in {@link SwipeDismissalDelegate#onChildDraw} and gets the view * the foreground out in {@link SwipeDismissalDelegate#onChildDraw} and gets the view
@@ -132,6 +117,6 @@ public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) { if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) {
return ((SliceHalfCardRendererHelper.HalfCardViewHolder) viewHolder).content; return ((SliceHalfCardRendererHelper.HalfCardViewHolder) viewHolder).content;
} }
return ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceViewWrapper; return ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView;
} }
} }

View File

@@ -28,14 +28,12 @@ import android.net.Uri;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ViewFlipper;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice; import androidx.slice.Slice;
import androidx.slice.widget.SliceView;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard; import com.android.settings.homepage.contextualcards.ContextualCard;
@@ -116,16 +114,15 @@ public class SliceContextualCardRendererTest {
} }
@Test @Test
public void bindView_isPendingDismiss_shouldFlipToDismissalView() { public void bindView_isPendingDismiss_shouldShowDismissalView() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper);
final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view); final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
final ContextualCard card = buildContextualCard( final ContextualCard card = buildContextualCard(
TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build(); TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
mRenderer.bindView(viewHolder, card); mRenderer.bindView(viewHolder, card);
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView); assertThat(dismissalView.getVisibility()).isEqualTo(View.VISIBLE);
} }
@Test @Test
@@ -140,24 +137,29 @@ public class SliceContextualCardRendererTest {
} }
@Test @Test
public void viewClick_keepCard_shouldFlipBackToSlice() { public void viewClick_keepCard_shouldShowSlice() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View sliceView = viewHolder.itemView.findViewById(R.id.slice_view);
final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep); final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper); final ContextualCard card = buildContextualCard(
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
viewFlipper.setDisplayedChild(1); mRenderer.bindView(viewHolder, card);
btnKeep.performClick(); btnKeep.performClick();
assertThat(viewFlipper.getCurrentView().getId()).isEqualTo(R.id.slice_view_wrapper); assertThat(dismissalView.getVisibility()).isEqualTo(View.GONE);
assertThat(sliceView.getVisibility()).isEqualTo(View.VISIBLE);
} }
@Test @Test
public void viewClick_keepCard_shouldRemoveViewHolderFromSet() { public void viewClick_keepCard_shouldRemoveViewHolderFromSet() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep); final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); final ContextualCard card = buildContextualCard(
mRenderer.mFlippedCardSet.add(viewHolder); TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
mRenderer.bindView(viewHolder, card);
assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
btnKeep.performClick(); btnKeep.performClick();
@@ -168,11 +170,12 @@ public class SliceContextualCardRendererTest {
public void viewClick_removeCard_shouldRemoveViewHolderFromSet() { public void viewClick_removeCard_shouldRemoveViewHolderFromSet() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove); final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI); final ContextualCard card = buildContextualCard(
mRenderer.bindView(viewHolder, contextualCard); TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
mRenderer.bindView(viewHolder, card);
assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
doReturn(mController).when(mControllerRendererPool).getController(mActivity, doReturn(mController).when(mControllerRendererPool).getController(mActivity,
ContextualCard.CardType.SLICE); ContextualCard.CardType.SLICE);
mRenderer.mFlippedCardSet.add(viewHolder);
btnRemove.performClick(); btnRemove.performClick();
@@ -195,16 +198,19 @@ public class SliceContextualCardRendererTest {
} }
@Test @Test
public void onStop_cardIsFlipped_shouldFlipBack() { public void onStop_cardIsInDismissalView_shouldResetToSliceView() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper); final View sliceView = viewHolder.itemView.findViewById(R.id.slice_view);
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI)); final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
viewFlipper.setDisplayedChild(1); final ContextualCard card = buildContextualCard(
mRenderer.mFlippedCardSet.add(viewHolder); TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
mRenderer.bindView(viewHolder, card);
assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
mRenderer.onStop(); mRenderer.onStop();
assertThat(viewFlipper.getCurrentView().getId()).isEqualTo(R.id.slice_view_wrapper); assertThat(sliceView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(dismissalView.getVisibility()).isEqualTo(View.GONE);
} }
private RecyclerView.ViewHolder getSliceViewHolder() { private RecyclerView.ViewHolder getSliceViewHolder() {

View File

@@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify;
import android.app.Activity; import android.app.Activity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ViewFlipper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -68,7 +67,7 @@ public class SwipeDismissalDelegateTest {
activityController.create(); activityController.create();
mRecyclerView = new RecyclerView(mActivity); mRecyclerView = new RecyclerView(mActivity);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity)); mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
mDismissalDelegate = new SwipeDismissalDelegate(mActivity, mDismissalDelegateListener); mDismissalDelegate = new SwipeDismissalDelegate(mDismissalDelegateListener);
} }
@Test @Test
@@ -86,22 +85,16 @@ public class SwipeDismissalDelegateTest {
@Test @Test
public void getMovementFlags_dismissalView_shouldDisableSwipe() { public void getMovementFlags_dismissalView_shouldDisableSwipe() {
final RecyclerView.ViewHolder holder = getSliceViewHolder(); final RecyclerView.ViewHolder holder = getSliceViewHolder();
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper); holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.VISIBLE);
viewFlipper.showNext();
final View dismissalView = holder.itemView.findViewById(R.id.dismissal_view);
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, holder)).isEqualTo(0); assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, holder)).isEqualTo(0);
} }
@Test @Test
public void getMovementFlags_SliceViewHolder_shouldEnableSwipe() { public void getMovementFlags_SliceViewHolder_shouldEnableSwipe() {
final RecyclerView.ViewHolder holder = getSliceViewHolder(); final RecyclerView.ViewHolder holder = getSliceViewHolder();
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper); holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.GONE);
viewFlipper.setDisplayedChild(0);
final View sliceViewWrapper = holder.itemView.findViewById(R.id.slice_view_wrapper);
assertThat(viewFlipper.getCurrentView()).isEqualTo(sliceViewWrapper);
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, getSliceViewHolder())) assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, getSliceViewHolder()))
.isNotEqualTo(0); .isNotEqualTo(0);
} }