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 package com.android.launcher3.touch;
17 
18 import android.content.Context;
19 import android.graphics.PointF;
20 import android.view.MotionEvent;
21 import android.view.ViewConfiguration;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.launcher3.Utilities;
26 
27 /**
28  * Two dimensional scroll/drag/swipe gesture detector that reports x and y displacement/velocity.
29  */
30 public class BothAxesSwipeDetector extends BaseSwipeDetector {
31 
32     public static final int DIRECTION_UP = 1 << 0;
33     // Note that this will track left instead of right in RTL.
34     public static final int DIRECTION_RIGHT = 1 << 1;
35     public static final int DIRECTION_DOWN = 1 << 2;
36     // Note that this will track right instead of left in RTL.
37     public static final int DIRECTION_LEFT = 1 << 3;
38 
39     /* Client of this gesture detector can register a callback. */
40     private final Listener mListener;
41 
42     private int mScrollDirections;
43 
BothAxesSwipeDetector(@onNull Context context, @NonNull Listener l)44     public BothAxesSwipeDetector(@NonNull Context context, @NonNull Listener l) {
45         super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
46         mListener = l;
47     }
48 
setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop)49     public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
50         mScrollDirections = scrollDirectionFlags;
51         mIgnoreSlopWhenSettling = ignoreSlop;
52     }
53 
54     @Override
shouldScrollStart(PointF displacement)55     protected boolean shouldScrollStart(PointF displacement) {
56         // Check if the client is interested in scroll in current direction.
57         boolean canScrollUp = (mScrollDirections & DIRECTION_UP) > 0
58                 && displacement.y <= -mTouchSlop;
59         boolean canScrollRight = (mScrollDirections & DIRECTION_RIGHT) > 0
60                 && displacement.x >= mTouchSlop;
61         boolean canScrollDown = (mScrollDirections & DIRECTION_DOWN) > 0
62                 && displacement.y >= mTouchSlop;
63         boolean canScrollLeft = (mScrollDirections & DIRECTION_LEFT) > 0
64                 && displacement.x <= -mTouchSlop;
65         return canScrollUp || canScrollRight || canScrollDown || canScrollLeft;
66     }
67 
68     @Override
reportDragStartInternal(boolean recatch)69     protected void reportDragStartInternal(boolean recatch) {
70         mListener.onDragStart(!recatch);
71     }
72 
73     @Override
reportDraggingInternal(PointF displacement, MotionEvent event)74     protected void reportDraggingInternal(PointF displacement, MotionEvent event) {
75         mListener.onDrag(displacement, event);
76     }
77 
78     @Override
reportDragEndInternal(PointF velocity)79     protected void reportDragEndInternal(PointF velocity) {
80         mListener.onDragEnd(velocity);
81     }
82 
83     /** Listener to receive updates on the swipe. */
84     public interface Listener {
85         /** @param start whether this was the original drag start, as opposed to a recatch. */
onDragStart(boolean start)86         void onDragStart(boolean start);
87 
onDrag(PointF displacement, MotionEvent motionEvent)88         boolean onDrag(PointF displacement, MotionEvent motionEvent);
89 
onDragEnd(PointF velocity)90         void onDragEnd(PointF velocity);
91     }
92 }
93