1 /* 2 * Copyright (C) 2018 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.dialer.speeddial.draghelper; 18 19 import android.support.v7.widget.RecyclerView.ViewHolder; 20 import android.support.v7.widget.helper.ItemTouchHelper; 21 import android.view.HapticFeedbackConstants; 22 import android.view.MotionEvent; 23 import android.view.View; 24 import android.view.View.OnTouchListener; 25 import android.view.ViewConfiguration; 26 import com.android.dialer.common.Assert; 27 28 /** OnTouchListener for the {@link com.android.dialer.speeddial.FavoritesViewHolder}. */ 29 public class SpeedDialFavoritesViewHolderOnTouchListener implements OnTouchListener { 30 31 private final ViewConfiguration configuration; 32 private final ItemTouchHelper itemTouchHelper; 33 private final ViewHolder viewHolder; 34 private final OnTouchFinishCallback onTouchFinishCallback; 35 36 private boolean hasPerformedLongClick; 37 private float startX; 38 private float startY; 39 SpeedDialFavoritesViewHolderOnTouchListener( ViewConfiguration configuration, ItemTouchHelper itemTouchHelper, ViewHolder viewHolder, OnTouchFinishCallback onTouchFinishCallback)40 public SpeedDialFavoritesViewHolderOnTouchListener( 41 ViewConfiguration configuration, 42 ItemTouchHelper itemTouchHelper, 43 ViewHolder viewHolder, 44 OnTouchFinishCallback onTouchFinishCallback) { 45 this.configuration = configuration; 46 this.itemTouchHelper = itemTouchHelper; 47 this.viewHolder = viewHolder; 48 this.onTouchFinishCallback = onTouchFinishCallback; 49 } 50 51 @Override onTouch(View v, MotionEvent event)52 public boolean onTouch(View v, MotionEvent event) { 53 switch (event.getAction()) { 54 case MotionEvent.ACTION_DOWN: 55 startX = event.getX(); 56 startY = event.getY(); 57 return true; 58 case MotionEvent.ACTION_MOVE: 59 // If the user has long clicked the view 60 if (event.getEventTime() - event.getDownTime() > ViewConfiguration.getLongPressTimeout()) { 61 // Perform long click if we haven't already 62 if (!hasPerformedLongClick) { 63 v.performLongClick(); 64 v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 65 hasPerformedLongClick = true; 66 } else if (moveEventExceedsTouchSlop(event)) { 67 itemTouchHelper.startDrag(viewHolder); 68 onTouchFinishCallback.onTouchFinished(true); 69 } 70 } 71 return true; 72 case MotionEvent.ACTION_UP: 73 if (event.getEventTime() - event.getDownTime() < ViewConfiguration.getLongPressTimeout()) { 74 v.performClick(); 75 } 76 // fallthrough 77 case MotionEvent.ACTION_CANCEL: 78 hasPerformedLongClick = false; 79 onTouchFinishCallback.onTouchFinished(false); 80 return true; 81 default: 82 return false; 83 } 84 } 85 moveEventExceedsTouchSlop(MotionEvent event)86 private boolean moveEventExceedsTouchSlop(MotionEvent event) { 87 Assert.checkArgument(event.getAction() == MotionEvent.ACTION_MOVE); 88 if (event.getHistorySize() <= 0) { 89 return false; 90 } 91 92 return Math.abs(startX - event.getX()) > configuration.getScaledTouchSlop() 93 || Math.abs(startY - event.getY()) > configuration.getScaledTouchSlop(); 94 } 95 96 /** Callback to listen for on touch events ending. */ 97 public interface OnTouchFinishCallback { 98 99 /** 100 * Called when the user stops touching the view. 101 * 102 * @see MotionEvent#ACTION_UP 103 * @see MotionEvent#ACTION_CANCEL 104 */ onTouchFinished(boolean closeContextMenu)105 void onTouchFinished(boolean closeContextMenu); 106 } 107 } 108