blob: 0eff4d4adff5f3be6f2213ad699d333e5f90eea5 [file] [log] [blame]
Matthew Nga8f24262017-12-19 11:54:24 -08001/*
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
17package com.android.systemui.statusbar.phone;
18
Winson Chung661d5f92018-05-21 18:41:39 -070019import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
20import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
Matthew Ng86a436e2018-10-26 16:00:53 -070021import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
22
Winson Chung2dbcf092018-10-24 13:00:41 -070023import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
24import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
Matthew Ng86a436e2018-10-26 16:00:53 -070025import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
Matthew Ng472d3e42018-06-14 15:16:55 -070026import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
Matthew Ngc83b9892018-08-21 16:31:13 -070027import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
Matthew Ng86a436e2018-10-26 16:00:53 -070028import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
29import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
Winson Chung661d5f92018-05-21 18:41:39 -070030
Matthew Ng86a436e2018-10-26 16:00:53 -070031import android.annotation.Nullable;
Matthew Nga8f24262017-12-19 11:54:24 -080032import android.content.Context;
Winson Chung661d5f92018-05-21 18:41:39 -070033import android.content.res.Resources;
Matthew Nga8f24262017-12-19 11:54:24 -080034import android.graphics.Canvas;
Matthew Ng2ea93b72018-03-14 19:43:18 +000035import android.graphics.Matrix;
Matthew Nga8f24262017-12-19 11:54:24 -080036import android.os.RemoteException;
Matthew Ngb687c8a2018-10-02 11:31:38 -070037import android.provider.Settings;
Matthew Nga8f24262017-12-19 11:54:24 -080038import android.util.Log;
Matthew Nga8f24262017-12-19 11:54:24 -080039import android.view.MotionEvent;
40import android.view.View;
Matthew Ngc83b9892018-08-21 16:31:13 -070041import android.view.ViewPropertyAnimator;
Matthew Ng86a436e2018-10-26 16:00:53 -070042
Matthew Nga8f24262017-12-19 11:54:24 -080043import com.android.systemui.Dependency;
Matthew Ngc83b9892018-08-21 16:31:13 -070044import com.android.systemui.Interpolators;
Matthew Ng86a436e2018-10-26 16:00:53 -070045import com.android.systemui.R;
Matthew Ng86a436e2018-10-26 16:00:53 -070046import com.android.systemui.SysUiServiceProvider;
Gus Prevasab336792018-11-14 13:52:20 -050047import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
48import com.android.systemui.recents.OverviewProxyService;
Matthew Nga8f24262017-12-19 11:54:24 -080049import com.android.systemui.shared.recents.IOverviewProxy;
Matthew Ngf1f8a432018-11-08 18:03:29 -080050import com.android.systemui.shared.recents.utilities.Utilities;
Matthew Ngf29ad752018-04-26 11:24:05 -070051import com.android.systemui.shared.system.NavigationBarCompat;
Matthew Ng86a436e2018-10-26 16:00:53 -070052
Winson Chung0d3815d2018-09-25 18:11:54 -070053import java.io.PrintWriter;
Matthew Nga8f24262017-12-19 11:54:24 -080054
Matthew Nga8f24262017-12-19 11:54:24 -080055/**
Matthew Ngfba39692018-03-13 18:08:34 -070056 * Class to detect gestures on the navigation bar and implement quick scrub.
Matthew Ng86a436e2018-10-26 16:00:53 -070057 * Note that the variables in this class horizontal and vertical represents horizontal always
Matthew Ngf1f8a432018-11-08 18:03:29 -080058 * aligned with along the navigation bar.
Matthew Nga8f24262017-12-19 11:54:24 -080059 */
Matthew Ngfba39692018-03-13 18:08:34 -070060public class QuickStepController implements GestureHelper {
Matthew Nga8f24262017-12-19 11:54:24 -080061
Matthew Ng2ea93b72018-03-14 19:43:18 +000062 private static final String TAG = "QuickStepController";
Matthew Nga8f24262017-12-19 11:54:24 -080063
Matthew Ngc83b9892018-08-21 16:31:13 -070064 /** Experiment to swipe home button left to execute a back key press */
Matthew Ngb687c8a2018-10-02 11:31:38 -070065 private static final String HIDE_BACK_BUTTON_PROP = "quickstepcontroller_hideback";
Matthew Ngc83b9892018-08-21 16:31:13 -070066 private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
Matthew Ngc83b9892018-08-21 16:31:13 -070067
68 /** When the home-swipe-back gesture is disallowed, make it harder to pull */
Matthew Ngf1f8a432018-11-08 18:03:29 -080069 private static final float HORIZONTAL_GESTURE_DAMPING = 0.3f;
70 private static final float VERTICAL_GESTURE_DAMPING = 0.15f;
71 private static final float HORIZONTAL_DISABLED_GESTURE_DAMPING = 0.16f;
72 private static final float VERTICAL_DISABLED_GESTURE_DAMPING = 0.06f;
Matthew Ngc83b9892018-08-21 16:31:13 -070073
Matthew Ng86a436e2018-10-26 16:00:53 -070074 private static final int ACTION_SWIPE_UP_INDEX = 0;
75 private static final int ACTION_SWIPE_DOWN_INDEX = 1;
76 private static final int ACTION_SWIPE_LEFT_INDEX = 2;
77 private static final int ACTION_SWIPE_RIGHT_INDEX = 3;
78 private static final int MAX_GESTURES = 4;
79
Matthew Nga8f24262017-12-19 11:54:24 -080080 private NavigationBarView mNavigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -080081
Matthew Ng2ea93b72018-03-14 19:43:18 +000082 private boolean mAllowGestureDetection;
Matthew Ng90ef0632018-08-15 13:53:15 -070083 private boolean mNotificationsVisibleOnDown;
Matthew Nga8f24262017-12-19 11:54:24 -080084 private int mTouchDownX;
85 private int mTouchDownY;
Matthew Ng86a436e2018-10-26 16:00:53 -070086 private boolean mDragHPositive;
87 private boolean mDragVPositive;
Matthew Nga8f24262017-12-19 11:54:24 -080088 private boolean mIsRTL;
Matthew Ng86a436e2018-10-26 16:00:53 -070089 private int mNavBarPosition;
Matthew Ng7090a802018-01-19 13:36:22 -080090 private float mDarkIntensity;
Matthew Ng86a436e2018-10-26 16:00:53 -070091 private ViewPropertyAnimator mDragBtnAnimator;
Winson Chung661d5f92018-05-21 18:41:39 -070092 private ButtonDispatcher mHitTarget;
Matthew Ng20136e62018-05-30 12:20:31 -070093 private boolean mIsInScreenPinning;
Matthew Ng86a436e2018-10-26 16:00:53 -070094 private boolean mGestureHorizontalDragsButton;
95 private boolean mGestureVerticalDragsButton;
Matthew Ngf1f8a432018-11-08 18:03:29 -080096 private float mMaxDragLimit;
97 private float mMinDragLimit;
98 private float mDragDampeningFactor;
Matthew Nga8f24262017-12-19 11:54:24 -080099
Matthew Ng86a436e2018-10-26 16:00:53 -0700100 private NavigationGestureAction mCurrentAction;
101 private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
102
Matthew Nga8f24262017-12-19 11:54:24 -0800103 private final OverviewProxyService mOverviewEventSender;
Matthew Nga8f24262017-12-19 11:54:24 -0800104 private final Context mContext;
Winson Chung0d3815d2018-09-25 18:11:54 -0700105 private final StatusBar mStatusBar;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000106 private final Matrix mTransformGlobalMatrix = new Matrix();
107 private final Matrix mTransformLocalMatrix = new Matrix();
Matthew Ngc83b9892018-08-21 16:31:13 -0700108
Matthew Ng2ea93b72018-03-14 19:43:18 +0000109 public QuickStepController(Context context) {
Winson Chung661d5f92018-05-21 18:41:39 -0700110 final Resources res = context.getResources();
Matthew Nga8f24262017-12-19 11:54:24 -0800111 mContext = context;
Winson Chung0d3815d2018-09-25 18:11:54 -0700112 mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
Matthew Nga8f24262017-12-19 11:54:24 -0800113 mOverviewEventSender = Dependency.get(OverviewProxyService.class);
Matthew Nga8f24262017-12-19 11:54:24 -0800114 }
115
116 public void setComponents(NavigationBarView navigationBarView) {
117 mNavigationBarView = navigationBarView;
Matthew Ngc83b9892018-08-21 16:31:13 -0700118
Matthew Ngb687c8a2018-10-02 11:31:38 -0700119 mNavigationBarView.getBackButton().setVisibility(shouldhideBackButton(mContext)
Matthew Ngc83b9892018-08-21 16:31:13 -0700120 ? View.GONE
121 : View.VISIBLE);
Matthew Nga8f24262017-12-19 11:54:24 -0800122 }
123
Winson Chung4faf38a2018-02-06 08:53:37 -0800124 /**
Matthew Ng86a436e2018-10-26 16:00:53 -0700125 * Set each gesture an action. After set the gestures triggered will run the actions attached.
126 * @param swipeUpAction action after swiping up
127 * @param swipeDownAction action after swiping down
128 * @param swipeLeftAction action after swiping left
129 * @param swipeRightAction action after swiping right
130 */
131 public void setGestureActions(@Nullable NavigationGestureAction swipeUpAction,
132 @Nullable NavigationGestureAction swipeDownAction,
133 @Nullable NavigationGestureAction swipeLeftAction,
134 @Nullable NavigationGestureAction swipeRightAction) {
135 mGestureActions[ACTION_SWIPE_UP_INDEX] = swipeUpAction;
136 mGestureActions[ACTION_SWIPE_DOWN_INDEX] = swipeDownAction;
137 mGestureActions[ACTION_SWIPE_LEFT_INDEX] = swipeLeftAction;
138 mGestureActions[ACTION_SWIPE_RIGHT_INDEX] = swipeRightAction;
139
140 // Set the current state to all actions
141 for (NavigationGestureAction action: mGestureActions) {
142 if (action != null) {
143 action.setBarState(true, mNavBarPosition, mDragHPositive, mDragVPositive);
144 action.onDarkIntensityChange(mDarkIntensity);
145 }
146 }
147 }
148
149 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700150 * @return true if we want to intercept touch events for quick scrub and prevent proxying the
151 * event to the overview service.
Winson Chung4faf38a2018-02-06 08:53:37 -0800152 */
Matthew Nga8f24262017-12-19 11:54:24 -0800153 @Override
154 public boolean onInterceptTouchEvent(MotionEvent event) {
Winson Chung0d3815d2018-09-25 18:11:54 -0700155 if (mStatusBar.isKeyguardShowing()) {
156 // Disallow any handling when the keyguard is showing
157 return false;
158 }
Winson Chungde2a1242018-02-07 15:59:43 -0800159 return handleTouchEvent(event);
160 }
161
162 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700163 * @return true if we want to handle touch events for quick scrub or if down event (that will
164 * get consumed and ignored). No events will be proxied to the overview service.
Winson Chungde2a1242018-02-07 15:59:43 -0800165 */
166 @Override
167 public boolean onTouchEvent(MotionEvent event) {
Winson Chung0d3815d2018-09-25 18:11:54 -0700168 if (mStatusBar.isKeyguardShowing()) {
169 // Disallow any handling when the keyguard is showing
170 return false;
171 }
172
Matthew Ng2ea93b72018-03-14 19:43:18 +0000173 // The same down event was just sent on intercept and therefore can be ignored here
174 final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
175 && mOverviewEventSender.getProxy() != null;
176 return ignoreProxyDownEvent || handleTouchEvent(event);
Winson Chungde2a1242018-02-07 15:59:43 -0800177 }
178
179 private boolean handleTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700180 final boolean deadZoneConsumed =
181 mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
Matthew Ng86a436e2018-10-26 16:00:53 -0700182
183 // Requires proxy and an active gesture or able to perform any gesture to continue
184 if (mOverviewEventSender.getProxy() == null
185 || (mCurrentAction == null && !canPerformAnyAction())) {
Matthew Ng2cbe8cd2018-08-20 11:27:40 -0700186 return deadZoneConsumed;
Matthew Ng22cf5142018-03-14 12:26:14 -0700187 }
188 mNavigationBarView.requestUnbufferedDispatch(event);
189
Matthew Ng9a223632018-03-30 16:47:22 -0700190 int action = event.getActionMasked();
191 switch (action) {
Matthew Nga8f24262017-12-19 11:54:24 -0800192 case MotionEvent.ACTION_DOWN: {
193 int x = (int) event.getX();
194 int y = (int) event.getY();
Matthew Ng20136e62018-05-30 12:20:31 -0700195 mIsInScreenPinning = mNavigationBarView.inScreenPinning();
Winson Chung661d5f92018-05-21 18:41:39 -0700196
Matthew Ng86a436e2018-10-26 16:00:53 -0700197 for (NavigationGestureAction gestureAction: mGestureActions) {
198 if (gestureAction != null) {
199 gestureAction.reset();
200 }
Winson Chung0be8f082018-02-15 15:52:49 -0800201 }
Winson Chung661d5f92018-05-21 18:41:39 -0700202
Matthew Ng86a436e2018-10-26 16:00:53 -0700203 // Valid buttons to drag over
204 switch (mNavigationBarView.getDownHitTarget()) {
205 case HIT_TARGET_BACK:
206 mHitTarget = mNavigationBarView.getBackButton();
207 break;
208 case HIT_TARGET_HOME:
209 mHitTarget = mNavigationBarView.getHomeButton();
210 break;
211 case HIT_TARGET_OVERVIEW:
212 mHitTarget = mNavigationBarView.getRecentsButton();
213 break;
214 default:
215 mHitTarget = null;
216 break;
217 }
Winson Chung661d5f92018-05-21 18:41:39 -0700218 if (mHitTarget != null) {
219 // Pre-emptively delay the touch feedback for the button that we just touched
220 mHitTarget.setDelayTouchFeedback(true);
221 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000222 mTouchDownX = x;
223 mTouchDownY = y;
Matthew Ng86a436e2018-10-26 16:00:53 -0700224 mGestureHorizontalDragsButton = false;
225 mGestureVerticalDragsButton = false;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000226 mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
227 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
228 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
229 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
Matthew Ng2ea93b72018-03-14 19:43:18 +0000230 mAllowGestureDetection = true;
Matthew Ng90ef0632018-08-15 13:53:15 -0700231 mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
Matthew Nga8f24262017-12-19 11:54:24 -0800232 break;
233 }
234 case MotionEvent.ACTION_MOVE: {
Matthew Ng86a436e2018-10-26 16:00:53 -0700235 if (!mAllowGestureDetection) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000236 break;
237 }
238 int x = (int) event.getX();
239 int y = (int) event.getY();
240 int xDiff = Math.abs(x - mTouchDownX);
241 int yDiff = Math.abs(y - mTouchDownY);
Matthew Ng9a223632018-03-30 16:47:22 -0700242
Matthew Ng86a436e2018-10-26 16:00:53 -0700243 boolean exceededSwipeHorizontalTouchSlop, exceededSwipeVerticalTouchSlop;
244 int posH, touchDownH, posV, touchDownV;
Matthew Nge0903c92018-01-17 15:32:41 -0800245
Matthew Ng86a436e2018-10-26 16:00:53 -0700246 if (isNavBarVertical()) {
247 exceededSwipeHorizontalTouchSlop =
Matthew Ngf29ad752018-04-26 11:24:05 -0700248 yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
Matthew Ng86a436e2018-10-26 16:00:53 -0700249 exceededSwipeVerticalTouchSlop =
Matthew Ngf29ad752018-04-26 11:24:05 -0700250 xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
Matthew Ng86a436e2018-10-26 16:00:53 -0700251 posH = y;
252 touchDownH = mTouchDownY;
253 posV = x;
254 touchDownV = mTouchDownX;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000255 } else {
Matthew Ng86a436e2018-10-26 16:00:53 -0700256 exceededSwipeHorizontalTouchSlop =
Matthew Ngf29ad752018-04-26 11:24:05 -0700257 xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
Matthew Ng86a436e2018-10-26 16:00:53 -0700258 exceededSwipeVerticalTouchSlop =
Matthew Ngf29ad752018-04-26 11:24:05 -0700259 yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
Matthew Ng86a436e2018-10-26 16:00:53 -0700260 posH = x;
261 touchDownH = mTouchDownX;
262 posV = y;
263 touchDownV = mTouchDownY;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000264 }
Winson Chung0e490d922018-03-14 16:08:43 +0000265
Matthew Ng86a436e2018-10-26 16:00:53 -0700266 if (mCurrentAction != null) {
267 // Gesture started, provide positions to the current action
268 mCurrentAction.onGestureMove(x, y);
269 } else {
270 // Detect gesture and try to execute an action, only one can run at a time
271 if (exceededSwipeVerticalTouchSlop) {
272 if (mDragVPositive ? (posV < touchDownV) : (posV > touchDownV)) {
273 // Swiping up gesture
274 tryToStartGesture(mGestureActions[ACTION_SWIPE_UP_INDEX],
275 false /* alignedWithNavBar */, false /* positiveDirection */,
276 event);
277 } else {
278 // Swiping down gesture
279 tryToStartGesture(mGestureActions[ACTION_SWIPE_DOWN_INDEX],
280 false /* alignedWithNavBar */, true /* positiveDirection */,
281 event);
Winson Chung0e490d922018-03-14 16:08:43 +0000282 }
Matthew Ng86a436e2018-10-26 16:00:53 -0700283 } else if (exceededSwipeHorizontalTouchSlop) {
284 if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
285 // Swiping left (ltr) gesture
286 tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
287 true /* alignedWithNavBar */, false /* positiveDirection */,
288 event);
289 } else {
290 // Swiping right (ltr) gesture
291 tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
292 true /* alignedWithNavBar */, true /* positiveDirection */,
293 event);
Matthew Ngc83b9892018-08-21 16:31:13 -0700294 }
295 }
Matthew Nga8f24262017-12-19 11:54:24 -0800296 }
Matthew Ng86a436e2018-10-26 16:00:53 -0700297
298 handleDragHitTarget(mGestureHorizontalDragsButton ? posH : posV,
299 mGestureHorizontalDragsButton ? touchDownH : touchDownV);
Matthew Nga8f24262017-12-19 11:54:24 -0800300 break;
301 }
302 case MotionEvent.ACTION_CANCEL:
303 case MotionEvent.ACTION_UP:
Matthew Ng86a436e2018-10-26 16:00:53 -0700304 if (mCurrentAction != null) {
305 mCurrentAction.endGesture();
306 mCurrentAction = null;
307 }
308
309 // Return the hit target back to its original position
310 if (mHitTarget != null) {
311 final View button = mHitTarget.getCurrentView();
312 if (mGestureHorizontalDragsButton || mGestureVerticalDragsButton) {
313 mDragBtnAnimator = button.animate().setDuration(BACK_BUTTON_FADE_IN_ALPHA)
314 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
315 if (mGestureVerticalDragsButton ^ isNavBarVertical()) {
316 mDragBtnAnimator.translationY(0);
317 } else {
318 mDragBtnAnimator.translationX(0);
319 }
320 mDragBtnAnimator.start();
321 }
322 }
Matthew Nga8f24262017-12-19 11:54:24 -0800323 break;
324 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000325
Matthew Ng90ef0632018-08-15 13:53:15 -0700326 if (shouldProxyEvents(action)) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000327 proxyMotionEvents(event);
328 }
Matthew Ng86a436e2018-10-26 16:00:53 -0700329 return mCurrentAction != null || deadZoneConsumed;
330 }
331
332 private void handleDragHitTarget(int position, int touchDown) {
333 // Drag the hit target if gesture action requires it
334 if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
335 final View button = mHitTarget.getCurrentView();
336 if (mDragBtnAnimator != null) {
337 mDragBtnAnimator.cancel();
338 mDragBtnAnimator = null;
339 }
340
Matthew Ngf1f8a432018-11-08 18:03:29 -0800341 // Clamp drag to the bounding box of the navigation bar
342 float diff = (position - touchDown) * mDragDampeningFactor;
343 diff = Utilities.clamp(diff, mMinDragLimit, mMaxDragLimit);
Matthew Ng86a436e2018-10-26 16:00:53 -0700344 if (mGestureVerticalDragsButton ^ isNavBarVertical()) {
345 button.setTranslationY(diff);
346 } else {
347 button.setTranslationX(diff);
348 }
349 }
Matthew Nga8f24262017-12-19 11:54:24 -0800350 }
351
Matthew Ng90ef0632018-08-15 13:53:15 -0700352 private boolean shouldProxyEvents(int action) {
Matthew Ng86a436e2018-10-26 16:00:53 -0700353 final boolean actionValid = (mCurrentAction == null
354 || (mGestureActions[ACTION_SWIPE_UP_INDEX] != null
355 && mGestureActions[ACTION_SWIPE_UP_INDEX].isActive()));
356 if (actionValid && !mIsInScreenPinning) {
Matthew Ng90ef0632018-08-15 13:53:15 -0700357 // Allow down, cancel and up events, move and other events are passed if notifications
358 // are not showing and disabled gestures (such as long press) are not executed
359 switch (action) {
360 case MotionEvent.ACTION_DOWN:
361 case MotionEvent.ACTION_CANCEL:
362 case MotionEvent.ACTION_UP:
363 return true;
364 default:
365 return !mNotificationsVisibleOnDown && mAllowGestureDetection;
366 }
367 }
368 return false;
369 }
370
Matthew Nga8f24262017-12-19 11:54:24 -0800371 @Override
372 public void onDraw(Canvas canvas) {
Matthew Ng86a436e2018-10-26 16:00:53 -0700373 if (mCurrentAction != null) {
374 mCurrentAction.onDraw(canvas);
Matthew Ng2ea93b72018-03-14 19:43:18 +0000375 }
Matthew Nga8f24262017-12-19 11:54:24 -0800376 }
377
378 @Override
379 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
Matthew Ng86a436e2018-10-26 16:00:53 -0700380 for (NavigationGestureAction action: mGestureActions) {
381 if (action != null) {
382 action.onLayout(changed, left, top, right, bottom);
383 }
Matthew Nga8f24262017-12-19 11:54:24 -0800384 }
Matthew Nga8f24262017-12-19 11:54:24 -0800385 }
386
387 @Override
388 public void onDarkIntensityChange(float intensity) {
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700389 final float oldIntensity = mDarkIntensity;
Matthew Ng7090a802018-01-19 13:36:22 -0800390 mDarkIntensity = intensity;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700391
392 // When in quick scrub, invalidate gradient if changing intensity from black to white and
393 // vice-versa
Matthew Ng86a436e2018-10-26 16:00:53 -0700394 if (mCurrentAction != null && mNavigationBarView.isQuickScrubEnabled()
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700395 && Math.round(intensity) != Math.round(oldIntensity)) {
Matthew Ng86a436e2018-10-26 16:00:53 -0700396 mCurrentAction.onDarkIntensityChange(mDarkIntensity);
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700397 }
Matthew Ng7090a802018-01-19 13:36:22 -0800398 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800399 }
400
401 @Override
Matthew Ng86a436e2018-10-26 16:00:53 -0700402 public void setBarState(boolean isRTL, int navBarPosition) {
403 final boolean changed = (mIsRTL != isRTL) || (mNavBarPosition != navBarPosition);
Matthew Nga8f24262017-12-19 11:54:24 -0800404 mIsRTL = isRTL;
Matthew Ng86a436e2018-10-26 16:00:53 -0700405 mNavBarPosition = navBarPosition;
406
407 // Determine the drag directions depending on location of nav bar
408 switch (navBarPosition) {
409 case NAV_BAR_LEFT:
410 mDragHPositive = !isRTL;
411 mDragVPositive = false;
412 break;
413 case NAV_BAR_RIGHT:
414 mDragHPositive = isRTL;
415 mDragVPositive = true;
416 break;
417 case NAV_BAR_BOTTOM:
418 mDragHPositive = !isRTL;
419 mDragVPositive = true;
420 break;
421 }
422
423 for (NavigationGestureAction action: mGestureActions) {
424 if (action != null) {
425 action.setBarState(changed, mNavBarPosition, mDragHPositive, mDragVPositive);
Matthew Nga8f24262017-12-19 11:54:24 -0800426 }
Matthew Nga8f24262017-12-19 11:54:24 -0800427 }
428 }
429
Matthew Ng2ea93b72018-03-14 19:43:18 +0000430 @Override
431 public void onNavigationButtonLongPress(View v) {
432 mAllowGestureDetection = false;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000433 }
434
Winson Chung0d3815d2018-09-25 18:11:54 -0700435 @Override
436 public void dump(PrintWriter pw) {
437 pw.println("QuickStepController {");
Winson Chung0d3815d2018-09-25 18:11:54 -0700438 pw.print(" "); pw.println("mAllowGestureDetection=" + mAllowGestureDetection);
Winson Chung0d3815d2018-09-25 18:11:54 -0700439 pw.print(" "); pw.println("mNotificationsVisibleOnDown=" + mNotificationsVisibleOnDown);
Matthew Ng86a436e2018-10-26 16:00:53 -0700440 pw.print(" "); pw.println("mNavBarPosition=" + mNavBarPosition);
Winson Chung0d3815d2018-09-25 18:11:54 -0700441 pw.print(" "); pw.println("mIsRTL=" + mIsRTL);
442 pw.print(" "); pw.println("mIsInScreenPinning=" + mIsInScreenPinning);
443 pw.println("}");
444 }
445
Matthew Ng86a436e2018-10-26 16:00:53 -0700446 public NavigationGestureAction getCurrentAction() {
447 return mCurrentAction;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000448 }
449
Matthew Ng86a436e2018-10-26 16:00:53 -0700450 private void tryToStartGesture(NavigationGestureAction action, boolean alignedWithNavBar,
451 boolean positiveDirection, MotionEvent event) {
452 if (action == null) {
453 return;
454 }
Matthew Ng20136e62018-05-30 12:20:31 -0700455 if (mIsInScreenPinning) {
456 mNavigationBarView.showPinningEscapeToast();
457 mAllowGestureDetection = false;
458 return;
459 }
460
Matthew Ng86a436e2018-10-26 16:00:53 -0700461 // Start new action from gesture if is able to start and depending on notifications
462 // visibility and starting touch down target. If the action is enabled, then also check if
463 // can perform the action so that if action requires the button to be dragged, then the
464 // gesture will have a large dampening factor and prevent action from running.
465 final boolean validHitTarget = action.requiresTouchDownHitTarget() == HIT_TARGET_NONE
466 || action.requiresTouchDownHitTarget() == mNavigationBarView.getDownHitTarget();
467 if (mCurrentAction == null && validHitTarget && action.isEnabled()
468 && (!mNotificationsVisibleOnDown || action.canRunWhenNotificationsShowing())) {
469 if (action.canPerformAction()) {
470 mCurrentAction = action;
471 event.transform(mTransformGlobalMatrix);
472 action.startGesture(event);
473 event.transform(mTransformLocalMatrix);
Matthew Ngf1f8a432018-11-08 18:03:29 -0800474
475 // Calculate the bounding limits of drag to avoid dragging off nav bar's window
476 if (action.requiresDragWithHitTarget() && mHitTarget != null) {
477 final int[] buttonCenter = new int[2];
478 View button = mHitTarget.getCurrentView();
479 button.getLocationInWindow(buttonCenter);
480 buttonCenter[0] += button.getWidth() / 2;
481 buttonCenter[1] += button.getHeight() / 2;
482 final int x = isNavBarVertical() ? buttonCenter[1] : buttonCenter[0];
483 final int y = isNavBarVertical() ? buttonCenter[0] : buttonCenter[1];
484 final int iconHalfSize = mContext.getResources()
485 .getDimensionPixelSize(R.dimen.navigation_icon_size) / 2;
486
487 if (alignedWithNavBar) {
488 mMinDragLimit = iconHalfSize - x;
489 mMaxDragLimit = -x - iconHalfSize + (isNavBarVertical()
490 ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth());
491 } else {
492 mMinDragLimit = iconHalfSize - y;
493 mMaxDragLimit = -y - iconHalfSize + (isNavBarVertical()
494 ? mNavigationBarView.getWidth() : mNavigationBarView.getHeight());
495 }
496 }
Matthew Nga8f24262017-12-19 11:54:24 -0800497 }
Matthew Ng86a436e2018-10-26 16:00:53 -0700498
499 // Handle direction of the hit target drag from the axis that started the gesture
Matthew Ngf1f8a432018-11-08 18:03:29 -0800500 // Also calculate the dampening factor, weaker dampening if there is an active action
Matthew Ng86a436e2018-10-26 16:00:53 -0700501 if (action.requiresDragWithHitTarget()) {
502 if (alignedWithNavBar) {
503 mGestureHorizontalDragsButton = true;
504 mGestureVerticalDragsButton = false;
Matthew Ngf1f8a432018-11-08 18:03:29 -0800505 mDragDampeningFactor = action.isActive()
506 ? HORIZONTAL_GESTURE_DAMPING : HORIZONTAL_DISABLED_GESTURE_DAMPING;
Matthew Ng86a436e2018-10-26 16:00:53 -0700507 } else {
508 mGestureVerticalDragsButton = true;
509 mGestureHorizontalDragsButton = false;
Matthew Ngf1f8a432018-11-08 18:03:29 -0800510 mDragDampeningFactor = action.isActive()
511 ? VERTICAL_GESTURE_DAMPING : VERTICAL_DISABLED_GESTURE_DAMPING;
Matthew Ng86a436e2018-10-26 16:00:53 -0700512 }
513 }
Winson Chung661d5f92018-05-21 18:41:39 -0700514
515 if (mHitTarget != null) {
516 mHitTarget.abortCurrentGesture();
517 }
Matthew Nga8f24262017-12-19 11:54:24 -0800518 }
519 }
520
Matthew Ng86a436e2018-10-26 16:00:53 -0700521 private boolean canPerformAnyAction() {
522 for (NavigationGestureAction action: mGestureActions) {
523 if (action != null && action.isEnabled()) {
524 return true;
Matthew Nga8f24262017-12-19 11:54:24 -0800525 }
Matthew Nged166f92018-02-20 16:22:09 -0800526 }
Matthew Ng86a436e2018-10-26 16:00:53 -0700527 return false;
Matthew Ngc83b9892018-08-21 16:31:13 -0700528 }
529
Matthew Ng2ea93b72018-03-14 19:43:18 +0000530 private boolean proxyMotionEvents(MotionEvent event) {
531 final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
532 event.transform(mTransformGlobalMatrix);
533 try {
534 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
535 overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
536 }
537 overviewProxy.onMotionEvent(event);
538 if (DEBUG_OVERVIEW_PROXY) {
539 Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
540 }
541 return true;
542 } catch (RemoteException e) {
543 Log.e(TAG, "Callback failed", e);
544 } finally {
545 event.transform(mTransformLocalMatrix);
Matthew Ngdb2734c2018-02-16 16:02:20 -0800546 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000547 return false;
Matthew Ngdb2734c2018-02-16 16:02:20 -0800548 }
Matthew Ngb687c8a2018-10-02 11:31:38 -0700549
Matthew Ng86a436e2018-10-26 16:00:53 -0700550 protected boolean isNavBarVertical() {
551 return mNavBarPosition == NAV_BAR_LEFT || mNavBarPosition == NAV_BAR_RIGHT;
552 }
553
554 static boolean getBoolGlobalSetting(Context context, String key) {
Matthew Ngb687c8a2018-10-02 11:31:38 -0700555 return Settings.Global.getInt(context.getContentResolver(), key, 0) != 0;
556 }
557
Matthew Ngb687c8a2018-10-02 11:31:38 -0700558 public static boolean shouldhideBackButton(Context context) {
Matthew Ng86a436e2018-10-26 16:00:53 -0700559 return getBoolGlobalSetting(context, HIDE_BACK_BUTTON_PROP);
Matthew Ngb687c8a2018-10-02 11:31:38 -0700560 }
Matthew Nga8f24262017-12-19 11:54:24 -0800561}