blob: b34a07d329438d37128925d69fb49d283d799f3f [file] [log] [blame]
Winson Chungfa7053782016-11-08 15:45:10 -08001/*
2 * Copyright (C) 2016 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 com.android.systemui.pip.phone;
18
Winson Chungfa7053782016-11-08 15:45:10 -080019import android.graphics.PointF;
Winson Chungfa7053782016-11-08 15:45:10 -080020import android.view.MotionEvent;
21import android.view.VelocityTracker;
22import android.view.ViewConfiguration;
23
Winson Chung29a78652017-02-09 18:35:26 -080024import java.io.PrintWriter;
25
Winson Chungfa7053782016-11-08 15:45:10 -080026/**
27 * This keeps track of the touch state throughout the current touch gesture.
28 */
29public class PipTouchState {
Winson Chung29a78652017-02-09 18:35:26 -080030 private static final String TAG = "PipTouchHandler";
Winson Chungfa7053782016-11-08 15:45:10 -080031
32 private ViewConfiguration mViewConfig;
33
34 private VelocityTracker mVelocityTracker;
35 private final PointF mDownTouch = new PointF();
36 private final PointF mDownDelta = new PointF();
37 private final PointF mLastTouch = new PointF();
38 private final PointF mLastDelta = new PointF();
39 private final PointF mVelocity = new PointF();
Winson Chung85d39982017-02-24 15:21:25 -080040 private boolean mAllowTouches = true;
Winson Chung2a82fe52017-02-02 14:43:34 -080041 private boolean mIsUserInteracting = false;
Winson Chungfa7053782016-11-08 15:45:10 -080042 private boolean mIsDragging = false;
43 private boolean mStartedDragging = false;
Winson Chungd5a01592016-11-11 16:25:04 -080044 private boolean mAllowDraggingOffscreen = false;
Winson Chungfa7053782016-11-08 15:45:10 -080045 private int mActivePointerId;
46
47 public PipTouchState(ViewConfiguration viewConfig) {
48 mViewConfig = viewConfig;
49 }
50
51 /**
Winson Chung85d39982017-02-24 15:21:25 -080052 * Resets this state.
53 */
54 public void reset() {
55 mAllowDraggingOffscreen = false;
56 mIsDragging = false;
57 mStartedDragging = false;
58 mIsUserInteracting = false;
59 }
60
61 /**
Winson Chungfa7053782016-11-08 15:45:10 -080062 * Processess a given touch event and updates the state.
63 */
64 public void onTouchEvent(MotionEvent ev) {
65 switch (ev.getAction()) {
66 case MotionEvent.ACTION_DOWN: {
Winson Chung85d39982017-02-24 15:21:25 -080067 if (!mAllowTouches) {
68 return;
69 }
70
Winson Chungfa7053782016-11-08 15:45:10 -080071 // Initialize the velocity tracker
72 initOrResetVelocityTracker();
Winson Chung85d39982017-02-24 15:21:25 -080073
Winson Chungfa7053782016-11-08 15:45:10 -080074 mActivePointerId = ev.getPointerId(0);
75 mLastTouch.set(ev.getX(), ev.getY());
76 mDownTouch.set(mLastTouch);
Winson Chungd5a01592016-11-11 16:25:04 -080077 mAllowDraggingOffscreen = true;
Winson Chung2a82fe52017-02-02 14:43:34 -080078 mIsUserInteracting = true;
Winson Chungfa7053782016-11-08 15:45:10 -080079 break;
80 }
81 case MotionEvent.ACTION_MOVE: {
Winson Chung85d39982017-02-24 15:21:25 -080082 // Skip event if we did not start processing this touch gesture
83 if (!mIsUserInteracting) {
84 break;
85 }
86
Winson Chungfa7053782016-11-08 15:45:10 -080087 // Update the velocity tracker
88 mVelocityTracker.addMovement(ev);
89 int pointerIndex = ev.findPointerIndex(mActivePointerId);
90 float x = ev.getX(pointerIndex);
91 float y = ev.getY(pointerIndex);
92 mLastDelta.set(x - mLastTouch.x, y - mLastTouch.y);
93 mDownDelta.set(x - mDownTouch.x, y - mDownTouch.y);
94
95 boolean hasMovedBeyondTap = mDownDelta.length() > mViewConfig.getScaledTouchSlop();
96 if (!mIsDragging) {
97 if (hasMovedBeyondTap) {
98 mIsDragging = true;
99 mStartedDragging = true;
100 }
101 } else {
102 mStartedDragging = false;
103 }
104 mLastTouch.set(x, y);
105 break;
106 }
107 case MotionEvent.ACTION_POINTER_UP: {
Winson Chung85d39982017-02-24 15:21:25 -0800108 // Skip event if we did not start processing this touch gesture
109 if (!mIsUserInteracting) {
110 break;
111 }
112
Winson Chungfa7053782016-11-08 15:45:10 -0800113 // Update the velocity tracker
114 mVelocityTracker.addMovement(ev);
115
116 int pointerIndex = ev.getActionIndex();
117 int pointerId = ev.getPointerId(pointerIndex);
118 if (pointerId == mActivePointerId) {
119 // Select a new active pointer id and reset the movement state
120 final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
121 mActivePointerId = ev.getPointerId(newPointerIndex);
122 mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex));
123 }
124 break;
125 }
126 case MotionEvent.ACTION_UP: {
Winson Chung85d39982017-02-24 15:21:25 -0800127 // Skip event if we did not start processing this touch gesture
128 if (!mIsUserInteracting) {
129 break;
130 }
131
Winson Chungfa7053782016-11-08 15:45:10 -0800132 // Update the velocity tracker
133 mVelocityTracker.addMovement(ev);
134 mVelocityTracker.computeCurrentVelocity(1000,
135 mViewConfig.getScaledMaximumFlingVelocity());
136 mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
137
138 int pointerIndex = ev.findPointerIndex(mActivePointerId);
139 mLastTouch.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
140
141 // Fall through to clean up
142 }
143 case MotionEvent.ACTION_CANCEL: {
144 recycleVelocityTracker();
145 break;
146 }
147 }
148 }
149
150 /**
151 * @return the velocity of the active touch pointer at the point it is lifted off the screen.
152 */
153 public PointF getVelocity() {
154 return mVelocity;
155 }
156
157 /**
158 * @return the last touch position of the active pointer.
159 */
160 public PointF getLastTouchPosition() {
161 return mLastTouch;
162 }
163
164 /**
165 * @return the movement delta between the last handled touch event and the previous touch
166 * position.
167 */
168 public PointF getLastTouchDelta() {
169 return mLastDelta;
170 }
171
172 /**
Mady Mellor57d22552017-03-09 15:37:13 -0800173 * @return the down touch position.
174 */
175 public PointF getDownTouchPosition() {
176 return mDownTouch;
177 }
178
179 /**
Winson Chungfa7053782016-11-08 15:45:10 -0800180 * @return the movement delta between the last handled touch event and the down touch
181 * position.
182 */
183 public PointF getDownTouchDelta() {
184 return mDownDelta;
185 }
186
187 /**
188 * @return whether the user has started dragging.
189 */
190 public boolean isDragging() {
191 return mIsDragging;
192 }
193
194 /**
Winson Chung2a82fe52017-02-02 14:43:34 -0800195 * @return whether the user is currently interacting with the PiP.
196 */
197 public boolean isUserInteracting() {
198 return mIsUserInteracting;
199 }
200
201 /**
Winson Chungfa7053782016-11-08 15:45:10 -0800202 * @return whether the user has started dragging just in the last handled touch event.
203 */
204 public boolean startedDragging() {
205 return mStartedDragging;
206 }
207
Winson Chungd5a01592016-11-11 16:25:04 -0800208 /**
Winson Chung85d39982017-02-24 15:21:25 -0800209 * Sets whether touching is currently allowed.
210 */
211 public void setAllowTouches(boolean allowTouches) {
212 mAllowTouches = allowTouches;
213
214 // If the user happens to touch down before this is sent from the system during a transition
215 // then block any additional handling by resetting the state now
216 if (mIsUserInteracting) {
217 reset();
218 }
219 }
220
221 /**
Winson Chungd5a01592016-11-11 16:25:04 -0800222 * Disallows dragging offscreen for the duration of the current gesture.
223 */
224 public void setDisallowDraggingOffscreen() {
225 mAllowDraggingOffscreen = false;
226 }
227
228 /**
229 * @return whether dragging offscreen is allowed during this gesture.
230 */
231 public boolean allowDraggingOffscreen() {
232 return mAllowDraggingOffscreen;
233 }
234
Winson Chungfa7053782016-11-08 15:45:10 -0800235 private void initOrResetVelocityTracker() {
236 if (mVelocityTracker == null) {
237 mVelocityTracker = VelocityTracker.obtain();
238 } else {
239 mVelocityTracker.clear();
240 }
241 }
242
243 private void recycleVelocityTracker() {
244 if (mVelocityTracker != null) {
245 mVelocityTracker.recycle();
246 mVelocityTracker = null;
247 }
248 }
Winson Chung29a78652017-02-09 18:35:26 -0800249
250 public void dump(PrintWriter pw, String prefix) {
251 final String innerPrefix = prefix + " ";
252 pw.println(prefix + TAG);
Winson Chung85d39982017-02-24 15:21:25 -0800253 pw.println(innerPrefix + "mAllowTouches=" + mAllowTouches);
Winson Chung29a78652017-02-09 18:35:26 -0800254 pw.println(innerPrefix + "mDownTouch=" + mDownTouch);
255 pw.println(innerPrefix + "mDownDelta=" + mDownDelta);
256 pw.println(innerPrefix + "mLastTouch=" + mLastTouch);
257 pw.println(innerPrefix + "mLastDelta=" + mLastDelta);
258 pw.println(innerPrefix + "mVelocity=" + mVelocity);
259 pw.println(innerPrefix + "mIsUserInteracting=" + mIsUserInteracting);
260 pw.println(innerPrefix + "mIsDragging=" + mIsDragging);
261 pw.println(innerPrefix + "mStartedDragging=" + mStartedDragging);
262 pw.println(innerPrefix + "mAllowDraggingOffscreen=" + mAllowDraggingOffscreen);
263 }
Winson Chungfa7053782016-11-08 15:45:10 -0800264}