1/*
2 * Copyright 2017 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
17package androidx.recyclerview.selection;
18
19import android.graphics.Point;
20import android.view.KeyEvent;
21import android.view.MotionEvent;
22
23import androidx.annotation.NonNull;
24
25/**
26 * Utility methods for working with {@link MotionEvent} instances.
27 */
28final class MotionEvents {
29
30    private MotionEvents() {}
31
32    static boolean isMouseEvent(@NonNull MotionEvent e) {
33        return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
34    }
35
36    static boolean isTouchEvent(@NonNull MotionEvent e) {
37        return e.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER;
38    }
39
40    static boolean isActionMove(@NonNull MotionEvent e) {
41        return e.getActionMasked() == MotionEvent.ACTION_MOVE;
42    }
43
44    static boolean isActionDown(@NonNull MotionEvent e) {
45        return e.getActionMasked() == MotionEvent.ACTION_DOWN;
46    }
47
48    static boolean isActionUp(@NonNull MotionEvent e) {
49        return e.getActionMasked() == MotionEvent.ACTION_UP;
50    }
51
52    static boolean isActionPointerUp(@NonNull MotionEvent e) {
53        return e.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
54    }
55
56    @SuppressWarnings("unused")
57    static boolean isActionPointerDown(@NonNull MotionEvent e) {
58        return e.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
59    }
60
61    static boolean isActionCancel(@NonNull MotionEvent e) {
62        return e.getActionMasked() == MotionEvent.ACTION_CANCEL;
63    }
64
65    static Point getOrigin(@NonNull MotionEvent e) {
66        return new Point((int) e.getX(), (int) e.getY());
67    }
68
69    static boolean isPrimaryMouseButtonPressed(@NonNull MotionEvent e) {
70        return isButtonPressed(e, MotionEvent.BUTTON_PRIMARY);
71    }
72
73    static boolean isSecondaryMouseButtonPressed(@NonNull MotionEvent e) {
74        return isButtonPressed(e, MotionEvent.BUTTON_SECONDARY);
75    }
76
77    static boolean isTertiaryMouseButtonPressed(@NonNull MotionEvent e) {
78        return isButtonPressed(e, MotionEvent.BUTTON_TERTIARY);
79    }
80
81    // NOTE: Can replace this with MotionEvent.isButtonPressed once targeting 21 or higher.
82    private static boolean isButtonPressed(MotionEvent e, int button) {
83        if (button == 0) {
84            return false;
85        }
86        return (e.getButtonState() & button) == button;
87    }
88
89    static boolean isShiftKeyPressed(@NonNull MotionEvent e) {
90        return hasBit(e.getMetaState(), KeyEvent.META_SHIFT_ON);
91    }
92
93    static boolean isCtrlKeyPressed(@NonNull MotionEvent e) {
94        return hasBit(e.getMetaState(), KeyEvent.META_CTRL_ON);
95    }
96
97    static boolean isAltKeyPressed(@NonNull MotionEvent e) {
98        return hasBit(e.getMetaState(), KeyEvent.META_ALT_ON);
99    }
100
101    static boolean isTouchpadScroll(@NonNull MotionEvent e) {
102        // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
103        // returned.
104        return isMouseEvent(e) && isActionMove(e) && e.getButtonState() == 0;
105    }
106
107    /**
108     * Returns true if the event is a drag event (which is presumbaly, but not
109     * explicitly required to be a mouse event).
110     * @param e
111     */
112    static boolean isPointerDragEvent(MotionEvent e) {
113        return isPrimaryMouseButtonPressed(e)
114                && isActionMove(e);
115    }
116
117    private static boolean hasBit(int metaState, int bit) {
118        return (metaState & bit) != 0;
119    }
120}
121