blob: ff923e56a33f7b46635c367108349b22d2ebfd18 [file] [log] [blame]
Jorim Jaggidd98d412015-11-18 15:57:38 -08001/*
2 * Copyright (C) 2014 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.statusbar.phone;
18
Jorim Jaggi213cbe62015-12-02 18:17:07 -080019import android.app.ActivityManager;
Jorim Jaggidd98d412015-11-18 15:57:38 -080020import android.content.Context;
Jorim Jaggidd98d412015-11-18 15:57:38 -080021import android.content.res.Resources;
Matthew Nga8f24262017-12-19 11:54:24 -080022import android.graphics.Canvas;
Matthew Ng8c039fd2017-11-15 11:09:44 -080023import android.graphics.Matrix;
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -080024import android.graphics.Rect;
Matthew Ng13dbf872017-10-27 11:02:14 -070025import android.os.RemoteException;
26import android.util.Log;
Jorim Jaggidd98d412015-11-18 15:57:38 -080027import android.view.MotionEvent;
28import android.view.VelocityTracker;
Jorim Jaggi298c0812016-01-14 19:40:24 -080029import android.view.View;
Jorim Jaggidd98d412015-11-18 15:57:38 -080030
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010031import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Winsonc0d70582016-01-29 10:24:39 -080032import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
Jason Monkde850bb2017-02-01 19:26:30 -050033import com.android.systemui.Dependency;
Matthew Ng13dbf872017-10-27 11:02:14 -070034import com.android.systemui.OverviewProxyService;
Jorim Jaggidd98d412015-11-18 15:57:38 -080035import com.android.systemui.R;
36import com.android.systemui.RecentsComponent;
Jason Monk67e6c802016-08-30 14:09:21 -040037import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
Winson Chung38d31c22017-11-08 14:32:32 -080038import com.android.systemui.shared.recents.IOverviewProxy;
Matthew Nga8f24262017-12-19 11:54:24 -080039import com.android.systemui.shared.recents.utilities.Utilities;
Jorim Jaggidd98d412015-11-18 15:57:38 -080040import com.android.systemui.stackdivider.Divider;
Winsone759cd52015-12-03 16:55:06 -080041import com.android.systemui.tuner.TunerService;
Jorim Jaggidd98d412015-11-18 15:57:38 -080042
Winsonc0d70582016-01-29 10:24:39 -080043import static android.view.WindowManager.DOCKED_INVALID;
44import static android.view.WindowManager.DOCKED_LEFT;
45import static android.view.WindowManager.DOCKED_TOP;
Matthew Ngbd824572018-01-17 16:25:56 -080046import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
47import static com.android.systemui.OverviewProxyService.TAG_OPS;
Jorim Jaggidd98d412015-11-18 15:57:38 -080048
49/**
50 * Class to detect gestures on the navigation bar.
51 */
Matthew Ng00000d82018-01-09 10:33:17 -080052public class NavigationBarGestureHelper implements TunerService.Tunable, GestureHelper {
Jorim Jaggidd98d412015-11-18 15:57:38 -080053
Matthew Ng13dbf872017-10-27 11:02:14 -070054 private static final String TAG = "NavBarGestureHelper";
Winsone759cd52015-12-03 16:55:06 -080055 private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080056 /**
57 * When dragging from the navigation bar, we drag in recents.
58 */
59 public static final int DRAG_MODE_NONE = -1;
Jorim Jaggidd98d412015-11-18 15:57:38 -080060
61 /**
62 * When dragging from the navigation bar, we drag in recents.
63 */
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080064 public static final int DRAG_MODE_RECENTS = 0;
Jorim Jaggidd98d412015-11-18 15:57:38 -080065
66 /**
67 * When dragging from the navigation bar, we drag the divider.
68 */
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080069 public static final int DRAG_MODE_DIVIDER = 1;
Jorim Jaggidd98d412015-11-18 15:57:38 -080070
71 private RecentsComponent mRecentsComponent;
72 private Divider mDivider;
Jorim Jaggi213cbe62015-12-02 18:17:07 -080073 private Context mContext;
Jorim Jaggi298c0812016-01-14 19:40:24 -080074 private NavigationBarView mNavigationBarView;
Jorim Jaggidd98d412015-11-18 15:57:38 -080075 private boolean mIsVertical;
Jorim Jaggidd98d412015-11-18 15:57:38 -080076
Matthew Nga8f24262017-12-19 11:54:24 -080077 private final QuickScrubController mQuickScrubController;
Jorim Jaggidd98d412015-11-18 15:57:38 -080078 private final int mScrollTouchSlop;
Matthew Ng8c039fd2017-11-15 11:09:44 -080079 private final Matrix mTransformGlobalMatrix = new Matrix();
80 private final Matrix mTransformLocalMatrix = new Matrix();
Jorim Jaggidd98d412015-11-18 15:57:38 -080081 private int mTouchDownX;
82 private int mTouchDownY;
Jorim Jaggi298c0812016-01-14 19:40:24 -080083 private boolean mDownOnRecents;
Jorim Jaggidd98d412015-11-18 15:57:38 -080084 private VelocityTracker mVelocityTracker;
Matthew Ng13dbf872017-10-27 11:02:14 -070085 private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
Jorim Jaggidd98d412015-11-18 15:57:38 -080086
87 private boolean mDockWindowEnabled;
88 private boolean mDockWindowTouchSlopExceeded;
89 private int mDragMode;
90
91 public NavigationBarGestureHelper(Context context) {
Jorim Jaggi213cbe62015-12-02 18:17:07 -080092 mContext = context;
Jorim Jaggidd98d412015-11-18 15:57:38 -080093 Resources r = context.getResources();
94 mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
Matthew Nga8f24262017-12-19 11:54:24 -080095 mQuickScrubController = new QuickScrubController(context);
Jason Monkde850bb2017-02-01 19:26:30 -050096 Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
97 }
98
99 public void destroy() {
100 Dependency.get(TunerService.class).removeTunable(this);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800101 }
102
Jorim Jaggi298c0812016-01-14 19:40:24 -0800103 public void setComponents(RecentsComponent recentsComponent, Divider divider,
104 NavigationBarView navigationBarView) {
Jorim Jaggidd98d412015-11-18 15:57:38 -0800105 mRecentsComponent = recentsComponent;
106 mDivider = divider;
Jorim Jaggi298c0812016-01-14 19:40:24 -0800107 mNavigationBarView = navigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -0800108 mQuickScrubController.setComponents(mNavigationBarView);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800109 }
110
111 public void setBarState(boolean isVertical, boolean isRTL) {
112 mIsVertical = isVertical;
Matthew Nga8f24262017-12-19 11:54:24 -0800113 mQuickScrubController.setBarState(isVertical, isRTL);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800114 }
115
Matthew Ng7d05e772017-11-09 14:41:07 -0800116 private boolean proxyMotionEvents(MotionEvent event) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700117 final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
118 if (overviewProxy != null) {
119 mNavigationBarView.requestUnbufferedDispatch(event);
Matthew Ng8c039fd2017-11-15 11:09:44 -0800120 event.transform(mTransformGlobalMatrix);
Matthew Ng13dbf872017-10-27 11:02:14 -0700121 try {
122 overviewProxy.onMotionEvent(event);
Matthew Ngbd824572018-01-17 16:25:56 -0800123 if (DEBUG_OVERVIEW_PROXY) {
124 Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
125 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800126 return true;
Matthew Ng13dbf872017-10-27 11:02:14 -0700127 } catch (RemoteException e) {
128 Log.e(TAG, "Callback failed", e);
Matthew Ng8c039fd2017-11-15 11:09:44 -0800129 } finally {
130 event.transform(mTransformLocalMatrix);
Matthew Ng13dbf872017-10-27 11:02:14 -0700131 }
132 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800133 return false;
134 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700135
Matthew Ng7d05e772017-11-09 14:41:07 -0800136 public boolean onInterceptTouchEvent(MotionEvent event) {
Jorim Jaggidd98d412015-11-18 15:57:38 -0800137 int action = event.getAction();
138 switch (action & MotionEvent.ACTION_MASK) {
139 case MotionEvent.ACTION_DOWN: {
140 mTouchDownX = (int) event.getX();
141 mTouchDownY = (int) event.getY();
Matthew Ng8c039fd2017-11-15 11:09:44 -0800142 mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
143 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
144 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
145 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800146 break;
147 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800148 }
Matthew Nga8f24262017-12-19 11:54:24 -0800149 if (!mQuickScrubController.onInterceptTouchEvent(event)) {
150 proxyMotionEvents(event);
151 return false;
152 }
153 return (mDockWindowEnabled && interceptDockWindowEvent(event));
154 }
155
156 public void onDraw(Canvas canvas) {
157 if (mOverviewEventSender.getProxy() != null) {
158 mQuickScrubController.onDraw(canvas);
159 }
160 }
161
162 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
163 mQuickScrubController.onLayout(changed, left, top, right, bottom);
164 }
165
166 public void onDarkIntensityChange(float intensity) {
167 mQuickScrubController.onDarkIntensityChange(intensity);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800168 }
169
170 private boolean interceptDockWindowEvent(MotionEvent event) {
171 switch (event.getActionMasked()) {
172 case MotionEvent.ACTION_DOWN:
173 handleDragActionDownEvent(event);
174 break;
175 case MotionEvent.ACTION_MOVE:
176 return handleDragActionMoveEvent(event);
177 case MotionEvent.ACTION_UP:
178 case MotionEvent.ACTION_CANCEL:
179 handleDragActionUpEvent(event);
180 break;
181 }
182 return false;
183 }
184
185 private boolean handleDockWindowEvent(MotionEvent event) {
186 switch (event.getActionMasked()) {
187 case MotionEvent.ACTION_DOWN:
188 handleDragActionDownEvent(event);
189 break;
190 case MotionEvent.ACTION_MOVE:
191 handleDragActionMoveEvent(event);
192 break;
193 case MotionEvent.ACTION_UP:
194 case MotionEvent.ACTION_CANCEL:
195 handleDragActionUpEvent(event);
196 break;
197 }
198 return true;
199 }
200
201 private void handleDragActionDownEvent(MotionEvent event) {
202 mVelocityTracker = VelocityTracker.obtain();
203 mVelocityTracker.addMovement(event);
204 mDockWindowTouchSlopExceeded = false;
205 mTouchDownX = (int) event.getX();
206 mTouchDownY = (int) event.getY();
Anthony Chenada13042016-01-19 16:57:20 -0800207
208 if (mNavigationBarView != null) {
Jason Monka2081822016-01-18 14:41:03 -0500209 View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView();
Anthony Chenada13042016-01-19 16:57:20 -0800210 if (recentsButton != null) {
211 mDownOnRecents = mTouchDownX >= recentsButton.getLeft()
212 && mTouchDownX <= recentsButton.getRight()
213 && mTouchDownY >= recentsButton.getTop()
214 && mTouchDownY <= recentsButton.getBottom();
Jason Monka2081822016-01-18 14:41:03 -0500215 } else {
216 mDownOnRecents = false;
Anthony Chenada13042016-01-19 16:57:20 -0800217 }
218 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800219 }
220
221 private boolean handleDragActionMoveEvent(MotionEvent event) {
222 mVelocityTracker.addMovement(event);
223 int x = (int) event.getX();
224 int y = (int) event.getY();
225 int xDiff = Math.abs(x - mTouchDownX);
226 int yDiff = Math.abs(y - mTouchDownY);
Victor Chan9b8018c2016-01-08 10:48:35 -0800227 if (mDivider == null || mRecentsComponent == null) {
228 return false;
229 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800230 if (!mDockWindowTouchSlopExceeded) {
231 boolean touchSlopExceeded = !mIsVertical
Jorim Jaggi47cf6382015-12-10 16:32:46 -0800232 ? yDiff > mScrollTouchSlop && yDiff > xDiff
233 : xDiff > mScrollTouchSlop && xDiff > yDiff;
Jorim Jaggi298c0812016-01-14 19:40:24 -0800234 if (mDownOnRecents && touchSlopExceeded
235 && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800236 Rect initialBounds = null;
Winsone6309aa2016-01-08 11:19:21 -0800237 int dragMode = calculateDragMode();
Matthew Ngbf155872017-10-27 15:24:39 -0700238 int createMode = ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Winsone6309aa2016-01-08 11:19:21 -0800239 if (dragMode == DRAG_MODE_DIVIDER) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800240 initialBounds = new Rect();
241 mDivider.getView().calculateBoundsForPosition(mIsVertical
242 ? (int) event.getRawX()
243 : (int) event.getRawY(),
244 mDivider.getView().isHorizontalDivision()
245 ? DOCKED_TOP
246 : DOCKED_LEFT,
247 initialBounds);
Winsone6309aa2016-01-08 11:19:21 -0800248 } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX
Jorim Jaggi213cbe62015-12-02 18:17:07 -0800249 < mContext.getResources().getDisplayMetrics().widthPixels / 2) {
Matthew Ngbf155872017-10-27 15:24:39 -0700250 createMode = ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800251 }
Matthew Ngbf155872017-10-27 15:24:39 -0700252 boolean docked = mRecentsComponent.splitPrimaryTask(dragMode, createMode,
253 initialBounds, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
Winsone6309aa2016-01-08 11:19:21 -0800254 if (docked) {
255 mDragMode = dragMode;
256 if (mDragMode == DRAG_MODE_DIVIDER) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800257 mDivider.getView().startDragging(false /* animate */, true /* touching*/);
Winsone6309aa2016-01-08 11:19:21 -0800258 }
259 mDockWindowTouchSlopExceeded = true;
Winsone6309aa2016-01-08 11:19:21 -0800260 return true;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800261 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800262 }
263 } else {
264 if (mDragMode == DRAG_MODE_DIVIDER) {
Jorim Jaggidc249c42015-12-15 14:57:31 -0800265 int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
Jorim Jaggie435e982015-12-30 13:54:32 +0100266 SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
Jorim Jaggidf012d52016-01-15 22:40:13 -0800267 .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */);
Jorim Jaggie435e982015-12-30 13:54:32 +0100268 mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800269 } else if (mDragMode == DRAG_MODE_RECENTS) {
270 mRecentsComponent.onDraggingInRecents(event.getRawY());
271 }
272 }
273 return false;
274 }
275
276 private void handleDragActionUpEvent(MotionEvent event) {
277 mVelocityTracker.addMovement(event);
278 mVelocityTracker.computeCurrentVelocity(1000);
Victor Chan9b8018c2016-01-08 10:48:35 -0800279 if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) {
Jorim Jaggidd98d412015-11-18 15:57:38 -0800280 if (mDragMode == DRAG_MODE_DIVIDER) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800281 mDivider.getView().stopDragging(mIsVertical
282 ? (int) event.getRawX()
283 : (int) event.getRawY(),
284 mIsVertical
285 ? mVelocityTracker.getXVelocity()
Jorim Jaggidf012d52016-01-15 22:40:13 -0800286 : mVelocityTracker.getYVelocity(),
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700287 true /* avoidDismissStart */, false /* logMetrics */);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800288 } else if (mDragMode == DRAG_MODE_RECENTS) {
289 mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
290 }
291 }
292 mVelocityTracker.recycle();
293 mVelocityTracker = null;
294 }
295
296 private int calculateDragMode() {
297 if (mIsVertical && !mDivider.getView().isHorizontalDivision()) {
298 return DRAG_MODE_DIVIDER;
299 }
300 if (!mIsVertical && mDivider.getView().isHorizontalDivision()) {
301 return DRAG_MODE_DIVIDER;
302 }
303 return DRAG_MODE_RECENTS;
304 }
305
306 public boolean onTouchEvent(MotionEvent event) {
Matthew Nga8f24262017-12-19 11:54:24 -0800307 boolean result = mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800308 if (mDockWindowEnabled) {
309 result |= handleDockWindowEvent(event);
310 }
311 return result;
312 }
313
314 @Override
Winsone759cd52015-12-03 16:55:06 -0800315 public void onTuningChanged(String key, String newValue) {
316 switch (key) {
317 case KEY_DOCK_WINDOW_GESTURE:
Jorim Jaggi8f2a44f2016-02-03 22:18:45 -0800318 mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0);
Winsone759cd52015-12-03 16:55:06 -0800319 break;
320 }
321 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800322}