1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.homepage.contextualcards.slices; 18 19 import android.graphics.Canvas; 20 import android.view.View; 21 22 import androidx.annotation.NonNull; 23 import androidx.recyclerview.widget.ItemTouchHelper; 24 import androidx.recyclerview.widget.RecyclerView; 25 26 import com.android.settings.R; 27 import com.android.settings.homepage.contextualcards.ContextualCard; 28 29 public class SwipeDismissalDelegate extends ItemTouchHelper.Callback { 30 31 private static final String TAG = "SwipeDismissalDelegate"; 32 33 public interface Listener { onSwiped(int position)34 void onSwiped(int position); 35 } 36 37 private final SwipeDismissalDelegate.Listener mListener; 38 SwipeDismissalDelegate(SwipeDismissalDelegate.Listener listener)39 public SwipeDismissalDelegate(SwipeDismissalDelegate.Listener listener) { 40 mListener = listener; 41 } 42 43 /** 44 * Determine whether the ability to drag or swipe should be enabled or not. 45 * 46 * Only allow swipe on {@link ContextualCard} built with view type 47 * {@link SliceContextualCardRenderer#VIEW_TYPE_FULL_WIDTH} or 48 * {@link SliceContextualCardRenderer#VIEW_TYPE_HALF_WIDTH}. 49 * 50 * When the dismissal view is displayed, the swipe will also be disabled. 51 */ 52 @Override getMovementFlags(@onNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)53 public int getMovementFlags(@NonNull RecyclerView recyclerView, 54 @NonNull RecyclerView.ViewHolder viewHolder) { 55 if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH 56 || viewHolder.getItemViewType() 57 == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) {// Here we are making sure 58 // the current displayed view is the initial view of 59 // either slice full card or half card, and only allow swipe on these two types. 60 if (viewHolder.itemView.findViewById(R.id.dismissal_view).getVisibility() 61 == View.VISIBLE) { 62 // Disable swiping when we are in the dismissal view 63 return 0; 64 } 65 return makeMovementFlags(0 /*dragFlags*/, 66 ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT /*swipeFlags*/); 67 } 68 return 0; 69 } 70 71 @Override onMove(@onNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target)72 public boolean onMove(@NonNull RecyclerView recyclerView, 73 @NonNull RecyclerView.ViewHolder viewHolder, 74 @NonNull RecyclerView.ViewHolder target) { 75 return false; 76 } 77 78 @Override onSwiped(@onNull RecyclerView.ViewHolder viewHolder, int direction)79 public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { 80 mListener.onSwiped(viewHolder.getAdapterPosition()); 81 } 82 83 @Override clearView(@onNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)84 public void clearView(@NonNull RecyclerView recyclerView, 85 @NonNull RecyclerView.ViewHolder viewHolder) { 86 final View view = getSwipeableView(viewHolder); 87 getDefaultUIUtil().clearView(view); 88 } 89 90 @Override onChildDraw(@onNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)91 public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, 92 @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, 93 boolean isCurrentlyActive) { 94 final View view = getSwipeableView(viewHolder); 95 final View iconStart = viewHolder.itemView.findViewById(R.id.dismissal_icon_start); 96 final View iconEnd = viewHolder.itemView.findViewById(R.id.dismissal_icon_end); 97 98 if (dX > 0) { 99 iconStart.setVisibility(View.VISIBLE); 100 iconEnd.setVisibility(View.GONE); 101 } else if (dX < 0) { 102 iconStart.setVisibility(View.GONE); 103 iconEnd.setVisibility(View.VISIBLE); 104 } 105 getDefaultUIUtil().onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive); 106 } 107 108 /** 109 * Get the foreground view from the {@link android.widget.FrameLayout} as we only swipe 110 * the foreground out in {@link SwipeDismissalDelegate#onChildDraw} and gets the view 111 * beneath revealed. 112 * 113 * @return The foreground view. 114 */ getSwipeableView(RecyclerView.ViewHolder viewHolder)115 private View getSwipeableView(RecyclerView.ViewHolder viewHolder) { 116 if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) { 117 return ((SliceHalfCardRendererHelper.HalfCardViewHolder) viewHolder).content; 118 } 119 return ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView; 120 } 121 }