1 package com.android.settings.notification.history; 2 3 import static android.view.HapticFeedbackConstants.CLOCK_TICK; 4 5 import android.annotation.Nullable; 6 import android.content.Context; 7 import android.graphics.Canvas; 8 import android.util.AttributeSet; 9 import android.view.View; 10 11 import androidx.annotation.NonNull; 12 import androidx.recyclerview.widget.DividerItemDecoration; 13 import androidx.recyclerview.widget.ItemTouchHelper; 14 import androidx.recyclerview.widget.LinearLayoutManager; 15 import androidx.recyclerview.widget.RecyclerView; 16 17 public class NotificationHistoryRecyclerView extends RecyclerView { 18 19 private static final String TAG = "HistoryRecyclerView"; 20 21 private OnItemSwipeDeleteListener listener; 22 23 /** The amount of horizontal displacement caused by user's action, used to track the swiping. */ 24 private float dXLast; 25 NotificationHistoryRecyclerView(Context context)26 public NotificationHistoryRecyclerView(Context context) { 27 this(context, null); 28 } 29 NotificationHistoryRecyclerView(Context context, @Nullable AttributeSet attrs)30 public NotificationHistoryRecyclerView(Context context, @Nullable AttributeSet attrs) { 31 this(context, attrs, 0); 32 } 33 NotificationHistoryRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle)34 public NotificationHistoryRecyclerView(Context context, @Nullable AttributeSet attrs, 35 int defStyle) { 36 super(context, attrs, defStyle); 37 38 setLayoutManager(new LinearLayoutManager(getContext())); 39 addItemDecoration(new DividerItemDecoration(getContext(), LinearLayoutManager.VERTICAL)); 40 ItemTouchHelper touchHelper = new ItemTouchHelper( 41 new DismissTouchHelper(0, ItemTouchHelper.START | ItemTouchHelper.END)); 42 touchHelper.attachToRecyclerView(this); 43 } 44 setOnItemSwipeDeleteListener(OnItemSwipeDeleteListener listener)45 public void setOnItemSwipeDeleteListener(OnItemSwipeDeleteListener listener) { 46 this.listener = listener; 47 } 48 49 private class DismissTouchHelper extends ItemTouchHelper.SimpleCallback { 50 DismissTouchHelper(int dragDirs, int swipeDirs)51 public DismissTouchHelper(int dragDirs, int swipeDirs) { 52 super(dragDirs, swipeDirs); 53 } 54 55 @Override onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target)56 public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { 57 // Do nothing. 58 return false; 59 } 60 61 @Override onSwiped(ViewHolder viewHolder, int direction)62 public void onSwiped(ViewHolder viewHolder, int direction) { 63 if (listener != null) { 64 listener.onItemSwipeDeleted(viewHolder.getAdapterPosition()); 65 } 66 } 67 68 /** Performs haptic effect once the swiping goes past a certain location. */ 69 @Override onChildDraw(@onNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)70 public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, 71 @NonNull ViewHolder viewHolder, float dX, float dY, int actionState, 72 boolean isCurrentlyActive) { 73 super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 74 if (isCurrentlyActive) { 75 View view = viewHolder.itemView; 76 float swipeThreshold = getSwipeThreshold(viewHolder); 77 float snapOffset = swipeThreshold * view.getWidth(); 78 boolean snapIntoNewLocation = dX < -snapOffset || dX > snapOffset; 79 boolean snapIntoNewLocationLast = dXLast < -snapOffset || dXLast > snapOffset; 80 if (snapIntoNewLocation != snapIntoNewLocationLast) { 81 view.performHapticFeedback(CLOCK_TICK); 82 } 83 dXLast = dX; 84 } else { 85 dXLast = 0; 86 } 87 } 88 } 89 90 public interface OnItemSwipeDeleteListener { onItemSwipeDeleted(int position)91 void onItemSwipeDeleted(int position); 92 } 93 }