blob: 1341301ac47ed1df1389f394880c5e4b51990418 [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;
21import static com.android.systemui.Interpolators.ALPHA_IN;
22import static com.android.systemui.Interpolators.ALPHA_OUT;
23import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
24import static com.android.systemui.OverviewProxyService.TAG_OPS;
Matthew Ng472d3e42018-06-14 15:16:55 -070025import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
Winson Chung661d5f92018-05-21 18:41:39 -070026
Matthew Nga8f24262017-12-19 11:54:24 -080027import android.animation.Animator;
28import android.animation.AnimatorListenerAdapter;
29import android.animation.AnimatorSet;
30import android.animation.ObjectAnimator;
Winson Chung661d5f92018-05-21 18:41:39 -070031import android.animation.PropertyValuesHolder;
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 Ng4fa3a9d2018-06-12 16:42:11 -070036import android.graphics.Paint;
37import android.graphics.RadialGradient;
Matthew Nga8f24262017-12-19 11:54:24 -080038import android.graphics.Rect;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -070039import android.graphics.Shader;
Matthew Nga8f24262017-12-19 11:54:24 -080040import android.os.Handler;
41import android.os.RemoteException;
Winson Chung661d5f92018-05-21 18:41:39 -070042import android.util.FloatProperty;
Matthew Nga8f24262017-12-19 11:54:24 -080043import android.util.Log;
44import android.util.Slog;
Matthew Nga8f24262017-12-19 11:54:24 -080045import android.view.MotionEvent;
46import android.view.View;
Matthew Nga8f24262017-12-19 11:54:24 -080047import android.view.WindowManagerGlobal;
Matthew Nga8f24262017-12-19 11:54:24 -080048import com.android.systemui.Dependency;
49import com.android.systemui.OverviewProxyService;
50import com.android.systemui.R;
51import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
52import com.android.systemui.shared.recents.IOverviewProxy;
53import com.android.systemui.shared.recents.utilities.Utilities;
Matthew Ngf29ad752018-04-26 11:24:05 -070054import com.android.systemui.shared.system.NavigationBarCompat;
Matthew Nga8f24262017-12-19 11:54:24 -080055
Matthew Nga8f24262017-12-19 11:54:24 -080056/**
Matthew Ngfba39692018-03-13 18:08:34 -070057 * Class to detect gestures on the navigation bar and implement quick scrub.
Matthew Nga8f24262017-12-19 11:54:24 -080058 */
Matthew Ngfba39692018-03-13 18:08:34 -070059public class QuickStepController implements GestureHelper {
Matthew Nga8f24262017-12-19 11:54:24 -080060
Matthew Ng2ea93b72018-03-14 19:43:18 +000061 private static final String TAG = "QuickStepController";
Winson Chung661d5f92018-05-21 18:41:39 -070062 private static final int ANIM_IN_DURATION_MS = 150;
Winson Chung4baf1242018-05-24 14:21:57 -070063 private static final int ANIM_OUT_DURATION_MS = 134;
64 private static final float TRACK_SCALE = 0.95f;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -070065 private static final float GRADIENT_WIDTH = .75f;
Matthew Nga8f24262017-12-19 11:54:24 -080066
67 private NavigationBarView mNavigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -080068
Matthew Nga8f24262017-12-19 11:54:24 -080069 private boolean mQuickScrubActive;
Matthew Ng2ea93b72018-03-14 19:43:18 +000070 private boolean mAllowGestureDetection;
71 private boolean mQuickStepStarted;
Matthew Ng90ef0632018-08-15 13:53:15 -070072 private boolean mNotificationsVisibleOnDown;
Matthew Nga8f24262017-12-19 11:54:24 -080073 private int mTouchDownX;
74 private int mTouchDownY;
75 private boolean mDragPositive;
76 private boolean mIsVertical;
77 private boolean mIsRTL;
Matthew Ng7090a802018-01-19 13:36:22 -080078 private float mTrackAlpha;
Winson Chung4baf1242018-05-24 14:21:57 -070079 private float mTrackScale = TRACK_SCALE;
Matthew Ng7090a802018-01-19 13:36:22 -080080 private float mDarkIntensity;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -070081 private RadialGradient mHighlight;
82 private float mHighlightCenter;
Winson Chung661d5f92018-05-21 18:41:39 -070083 private AnimatorSet mTrackAnimator;
84 private ButtonDispatcher mHitTarget;
85 private View mCurrentNavigationBarView;
Matthew Ng20136e62018-05-30 12:20:31 -070086 private boolean mIsInScreenPinning;
Matthew Nga8f24262017-12-19 11:54:24 -080087
88 private final Handler mHandler = new Handler();
Matthew Nga8f24262017-12-19 11:54:24 -080089 private final Rect mTrackRect = new Rect();
Matthew Nga8f24262017-12-19 11:54:24 -080090 private final OverviewProxyService mOverviewEventSender;
Matthew Nga8f24262017-12-19 11:54:24 -080091 private final int mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -070092 private final int mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -080093 private final Context mContext;
Matthew Ng2ea93b72018-03-14 19:43:18 +000094 private final Matrix mTransformGlobalMatrix = new Matrix();
95 private final Matrix mTransformLocalMatrix = new Matrix();
Matthew Ng4fa3a9d2018-06-12 16:42:11 -070096 private final Paint mTrackPaint = new Paint();
Matthew Nga8f24262017-12-19 11:54:24 -080097
Winson Chung661d5f92018-05-21 18:41:39 -070098 private final FloatProperty<QuickStepController> mTrackAlphaProperty =
99 new FloatProperty<QuickStepController>("TrackAlpha") {
100 @Override
101 public void setValue(QuickStepController controller, float alpha) {
102 mTrackAlpha = alpha;
103 mNavigationBarView.invalidate();
104 }
105
106 @Override
107 public Float get(QuickStepController controller) {
108 return mTrackAlpha;
109 }
Matthew Nga8f24262017-12-19 11:54:24 -0800110 };
111
Winson Chung4baf1242018-05-24 14:21:57 -0700112 private final FloatProperty<QuickStepController> mTrackScaleProperty =
113 new FloatProperty<QuickStepController>("TrackScale") {
114 @Override
115 public void setValue(QuickStepController controller, float scale) {
116 mTrackScale = scale;
117 mNavigationBarView.invalidate();
118 }
119
120 @Override
121 public Float get(QuickStepController controller) {
122 return mTrackScale;
123 }
124 };
125
Winson Chung661d5f92018-05-21 18:41:39 -0700126 private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
127 new FloatProperty<QuickStepController>("NavBarAlpha") {
128 @Override
129 public void setValue(QuickStepController controller, float alpha) {
130 if (mCurrentNavigationBarView != null) {
131 mCurrentNavigationBarView.setAlpha(alpha);
132 }
Matthew Nga8f24262017-12-19 11:54:24 -0800133 }
Winson Chung661d5f92018-05-21 18:41:39 -0700134
135 @Override
136 public Float get(QuickStepController controller) {
137 if (mCurrentNavigationBarView != null) {
138 return mCurrentNavigationBarView.getAlpha();
139 }
140 return 1f;
Matthew Nga8f24262017-12-19 11:54:24 -0800141 }
142 };
143
144 private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
145 @Override
146 public void onAnimationEnd(Animator animation) {
Winson Chung661d5f92018-05-21 18:41:39 -0700147 resetQuickScrub();
Matthew Nga8f24262017-12-19 11:54:24 -0800148 }
149 };
150
Matthew Ng2ea93b72018-03-14 19:43:18 +0000151 public QuickStepController(Context context) {
Winson Chung661d5f92018-05-21 18:41:39 -0700152 final Resources res = context.getResources();
Matthew Nga8f24262017-12-19 11:54:24 -0800153 mContext = context;
Matthew Nga8f24262017-12-19 11:54:24 -0800154 mOverviewEventSender = Dependency.get(OverviewProxyService.class);
Winson Chung661d5f92018-05-21 18:41:39 -0700155 mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
156 mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700157 mTrackPaint.setAntiAlias(true);
158 mTrackPaint.setDither(true);
Matthew Nga8f24262017-12-19 11:54:24 -0800159 }
160
161 public void setComponents(NavigationBarView navigationBarView) {
162 mNavigationBarView = navigationBarView;
163 }
164
Winson Chung4faf38a2018-02-06 08:53:37 -0800165 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700166 * @return true if we want to intercept touch events for quick scrub and prevent proxying the
167 * event to the overview service.
Winson Chung4faf38a2018-02-06 08:53:37 -0800168 */
Matthew Nga8f24262017-12-19 11:54:24 -0800169 @Override
170 public boolean onInterceptTouchEvent(MotionEvent event) {
Winson Chungde2a1242018-02-07 15:59:43 -0800171 return handleTouchEvent(event);
172 }
173
174 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700175 * @return true if we want to handle touch events for quick scrub or if down event (that will
176 * get consumed and ignored). No events will be proxied to the overview service.
Winson Chungde2a1242018-02-07 15:59:43 -0800177 */
178 @Override
179 public boolean onTouchEvent(MotionEvent event) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000180 // The same down event was just sent on intercept and therefore can be ignored here
181 final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
182 && mOverviewEventSender.getProxy() != null;
183 return ignoreProxyDownEvent || handleTouchEvent(event);
Winson Chungde2a1242018-02-07 15:59:43 -0800184 }
185
186 private boolean handleTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700187 final boolean deadZoneConsumed =
188 mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
Winson Chungd95a2252018-04-04 17:02:29 +0000189 if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
190 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
Matthew Ng22cf5142018-03-14 12:26:14 -0700191 return false;
192 }
193 mNavigationBarView.requestUnbufferedDispatch(event);
194
Matthew Ng9a223632018-03-30 16:47:22 -0700195 int action = event.getActionMasked();
196 switch (action) {
Matthew Nga8f24262017-12-19 11:54:24 -0800197 case MotionEvent.ACTION_DOWN: {
198 int x = (int) event.getX();
199 int y = (int) event.getY();
Matthew Ng20136e62018-05-30 12:20:31 -0700200 mIsInScreenPinning = mNavigationBarView.inScreenPinning();
Winson Chung661d5f92018-05-21 18:41:39 -0700201
Winson Chung0be8f082018-02-15 15:52:49 -0800202 // End any existing quickscrub animations before starting the new transition
Winson Chung661d5f92018-05-21 18:41:39 -0700203 if (mTrackAnimator != null) {
204 mTrackAnimator.end();
205 mTrackAnimator = null;
Winson Chung0be8f082018-02-15 15:52:49 -0800206 }
Winson Chung661d5f92018-05-21 18:41:39 -0700207
208 mCurrentNavigationBarView = mNavigationBarView.getCurrentView();
209 mHitTarget = mNavigationBarView.getButtonAtPosition(x, y);
210 if (mHitTarget != null) {
211 // Pre-emptively delay the touch feedback for the button that we just touched
212 mHitTarget.setDelayTouchFeedback(true);
213 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000214 mTouchDownX = x;
215 mTouchDownY = y;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000216 mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
217 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
218 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
219 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
220 mQuickStepStarted = false;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000221 mAllowGestureDetection = true;
Matthew Ng90ef0632018-08-15 13:53:15 -0700222 mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
Matthew Nga8f24262017-12-19 11:54:24 -0800223 break;
224 }
225 case MotionEvent.ACTION_MOVE: {
Winson Chung661d5f92018-05-21 18:41:39 -0700226 if (mQuickStepStarted || !mAllowGestureDetection){
Matthew Ng2ea93b72018-03-14 19:43:18 +0000227 break;
228 }
229 int x = (int) event.getX();
230 int y = (int) event.getY();
231 int xDiff = Math.abs(x - mTouchDownX);
232 int yDiff = Math.abs(y - mTouchDownY);
Matthew Ng9a223632018-03-30 16:47:22 -0700233
Winson Chung661d5f92018-05-21 18:41:39 -0700234 boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000235 int pos, touchDown, offset, trackSize;
Matthew Nge0903c92018-01-17 15:32:41 -0800236
Matthew Ng2ea93b72018-03-14 19:43:18 +0000237 if (mIsVertical) {
Matthew Ngf29ad752018-04-26 11:24:05 -0700238 exceededScrubTouchSlop =
239 yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
240 exceededSwipeUpTouchSlop =
241 xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000242 pos = y;
243 touchDown = mTouchDownY;
244 offset = pos - mTrackRect.top;
245 trackSize = mTrackRect.height();
246 } else {
Matthew Ngf29ad752018-04-26 11:24:05 -0700247 exceededScrubTouchSlop =
248 xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
249 exceededSwipeUpTouchSlop =
250 yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000251 pos = x;
252 touchDown = mTouchDownX;
253 offset = pos - mTrackRect.left;
254 trackSize = mTrackRect.width();
255 }
256 // Decide to start quickstep if dragging away from the navigation bar, otherwise in
257 // the parallel direction, decide to start quickscrub. Only one may run.
Matthew Ng9a223632018-03-30 16:47:22 -0700258 if (!mQuickScrubActive && exceededSwipeUpTouchSlop) {
Matthew Ng90ef0632018-08-15 13:53:15 -0700259 if (mNavigationBarView.isQuickStepSwipeUpEnabled()
260 && !mNotificationsVisibleOnDown) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000261 startQuickStep(event);
Winson Chung0e490d922018-03-14 16:08:43 +0000262 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000263 break;
264 }
Winson Chung0e490d922018-03-14 16:08:43 +0000265
Winson Chung661d5f92018-05-21 18:41:39 -0700266 // Do not handle quick scrub if disabled
267 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000268 break;
269 }
270
271 if (!mDragPositive) {
272 offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
273 }
274
Matthew Ng9a223632018-03-30 16:47:22 -0700275 final boolean allowDrag = !mDragPositive
276 ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
Winson Chung661d5f92018-05-21 18:41:39 -0700277 float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
Matthew Ng9a223632018-03-30 16:47:22 -0700278 if (allowDrag) {
Matthew Ng9a223632018-03-30 16:47:22 -0700279 // Passing the drag slop then touch slop will start quick step
280 if (!mQuickScrubActive && exceededScrubTouchSlop) {
Matthew Ngfba39692018-03-13 18:08:34 -0700281 startQuickScrub();
Winson Chung0e490d922018-03-14 16:08:43 +0000282 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000283 }
Matthew Ng9a223632018-03-30 16:47:22 -0700284
Winson Chung661d5f92018-05-21 18:41:39 -0700285 if (mQuickScrubActive && (mDragPositive && offset >= 0
Matthew Ng2ea93b72018-03-14 19:43:18 +0000286 || !mDragPositive && offset <= 0)) {
Winson Chung661d5f92018-05-21 18:41:39 -0700287 try {
288 mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
289 if (DEBUG_OVERVIEW_PROXY) {
290 Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
Winson Chung0e490d922018-03-14 16:08:43 +0000291 }
Winson Chung661d5f92018-05-21 18:41:39 -0700292 } catch (RemoteException e) {
293 Log.e(TAG, "Failed to send progress of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800294 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700295 mHighlightCenter = x;
296 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800297 }
298 break;
299 }
300 case MotionEvent.ACTION_CANCEL:
301 case MotionEvent.ACTION_UP:
Winson Chungd10ca302018-02-14 10:13:41 -0800302 endQuickScrub(true /* animate */);
Matthew Nga8f24262017-12-19 11:54:24 -0800303 break;
304 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000305
Matthew Ng90ef0632018-08-15 13:53:15 -0700306 if (shouldProxyEvents(action)) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000307 proxyMotionEvents(event);
308 }
Matthew Ng472d3e42018-06-14 15:16:55 -0700309 return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed;
Matthew Nga8f24262017-12-19 11:54:24 -0800310 }
311
Matthew Ng90ef0632018-08-15 13:53:15 -0700312 private boolean shouldProxyEvents(int action) {
313 if (!mQuickScrubActive && !mIsInScreenPinning) {
314 // Allow down, cancel and up events, move and other events are passed if notifications
315 // are not showing and disabled gestures (such as long press) are not executed
316 switch (action) {
317 case MotionEvent.ACTION_DOWN:
318 case MotionEvent.ACTION_CANCEL:
319 case MotionEvent.ACTION_UP:
320 return true;
321 default:
322 return !mNotificationsVisibleOnDown && mAllowGestureDetection;
323 }
324 }
325 return false;
326 }
327
Matthew Nga8f24262017-12-19 11:54:24 -0800328 @Override
329 public void onDraw(Canvas canvas) {
Matthew Ngf781bbd2018-03-21 14:58:55 -0700330 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000331 return;
332 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700333 mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
Winson Chung4baf1242018-05-24 14:21:57 -0700334
335 // Scale the track, but apply the inverse scale from the nav bar
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700336 final float radius = mTrackRect.height() / 2;
Winson Chung4baf1242018-05-24 14:21:57 -0700337 canvas.save();
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700338 float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
339 canvas.translate(translate, 0);
Winson Chung4baf1242018-05-24 14:21:57 -0700340 canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
341 1f / mNavigationBarView.getScaleY(),
342 mTrackRect.centerX(), mTrackRect.centerY());
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700343 canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
344 mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
Winson Chung4baf1242018-05-24 14:21:57 -0700345 canvas.restore();
Matthew Nga8f24262017-12-19 11:54:24 -0800346 }
347
348 @Override
349 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson Chung661d5f92018-05-21 18:41:39 -0700350 final int paddingLeft = mNavigationBarView.getPaddingLeft();
351 final int paddingTop = mNavigationBarView.getPaddingTop();
352 final int paddingRight = mNavigationBarView.getPaddingRight();
353 final int paddingBottom = mNavigationBarView.getPaddingBottom();
354 final int width = (right - left) - paddingRight - paddingLeft;
355 final int height = (bottom - top) - paddingBottom - paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800356 final int x1, x2, y1, y2;
357 if (mIsVertical) {
Winson Chung661d5f92018-05-21 18:41:39 -0700358 x1 = (width - mTrackThickness) / 2 + paddingLeft;
Matthew Nga8f24262017-12-19 11:54:24 -0800359 x2 = x1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700360 y1 = paddingTop + mTrackEndPadding;
361 y2 = y1 + height - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800362 } else {
Winson Chung661d5f92018-05-21 18:41:39 -0700363 y1 = (height - mTrackThickness) / 2 + paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800364 y2 = y1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700365 x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
366 x2 = x1 + width - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800367 }
368 mTrackRect.set(x1, y1, x2, y2);
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700369 updateHighlight();
Matthew Nga8f24262017-12-19 11:54:24 -0800370 }
371
372 @Override
373 public void onDarkIntensityChange(float intensity) {
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700374 final float oldIntensity = mDarkIntensity;
Matthew Ng7090a802018-01-19 13:36:22 -0800375 mDarkIntensity = intensity;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700376
377 // When in quick scrub, invalidate gradient if changing intensity from black to white and
378 // vice-versa
379 if (mNavigationBarView.isQuickScrubEnabled()
380 && Math.round(intensity) != Math.round(oldIntensity)) {
381 updateHighlight();
382 }
Matthew Ng7090a802018-01-19 13:36:22 -0800383 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800384 }
385
386 @Override
Matthew Nga8f24262017-12-19 11:54:24 -0800387 public void setBarState(boolean isVertical, boolean isRTL) {
Winson Chungd10ca302018-02-14 10:13:41 -0800388 final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
389 if (changed) {
390 // End quickscrub if the state changes mid-transition
391 endQuickScrub(false /* animate */);
392 }
Matthew Nga8f24262017-12-19 11:54:24 -0800393 mIsVertical = isVertical;
394 mIsRTL = isRTL;
395 try {
396 int navbarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
397 mDragPositive = navbarPos == NAV_BAR_LEFT || navbarPos == NAV_BAR_BOTTOM;
398 if (isRTL) {
399 mDragPositive = !mDragPositive;
400 }
401 } catch (RemoteException e) {
402 Slog.e(TAG, "Failed to get nav bar position.", e);
403 }
404 }
405
Matthew Ng2ea93b72018-03-14 19:43:18 +0000406 @Override
407 public void onNavigationButtonLongPress(View v) {
408 mAllowGestureDetection = false;
409 mHandler.removeCallbacksAndMessages(null);
410 }
411
412 private void startQuickStep(MotionEvent event) {
Matthew Ng20136e62018-05-30 12:20:31 -0700413 if (mIsInScreenPinning) {
414 mNavigationBarView.showPinningEscapeToast();
415 mAllowGestureDetection = false;
416 return;
417 }
418
Matthew Ng2ea93b72018-03-14 19:43:18 +0000419 mQuickStepStarted = true;
420 event.transform(mTransformGlobalMatrix);
421 try {
422 mOverviewEventSender.getProxy().onQuickStep(event);
423 if (DEBUG_OVERVIEW_PROXY) {
424 Log.d(TAG_OPS, "Quick Step Start");
425 }
426 } catch (RemoteException e) {
427 Log.e(TAG, "Failed to send quick step started.", e);
428 } finally {
429 event.transform(mTransformLocalMatrix);
430 }
431 mOverviewEventSender.notifyQuickStepStarted();
Matthew Ng2ea93b72018-03-14 19:43:18 +0000432 mHandler.removeCallbacksAndMessages(null);
Matthew Ng9a223632018-03-30 16:47:22 -0700433
Winson Chung661d5f92018-05-21 18:41:39 -0700434 if (mHitTarget != null) {
435 mHitTarget.abortCurrentGesture();
436 }
437
438 if (mQuickScrubActive) {
Matthew Ng9a223632018-03-30 16:47:22 -0700439 animateEnd();
440 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000441 }
442
Matthew Nga8f24262017-12-19 11:54:24 -0800443 private void startQuickScrub() {
Matthew Ng20136e62018-05-30 12:20:31 -0700444 if (mIsInScreenPinning) {
445 mNavigationBarView.showPinningEscapeToast();
446 mAllowGestureDetection = false;
447 return;
448 }
449
Winson Chung661d5f92018-05-21 18:41:39 -0700450 if (!mQuickScrubActive) {
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700451 updateHighlight();
Matthew Nga8f24262017-12-19 11:54:24 -0800452 mQuickScrubActive = true;
Winson Chung4baf1242018-05-24 14:21:57 -0700453 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
454 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
455 PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
Winson Chung661d5f92018-05-21 18:41:39 -0700456 trackAnimator.setInterpolator(ALPHA_IN);
457 trackAnimator.setDuration(ANIM_IN_DURATION_MS);
458 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
459 navBarAnimator.setInterpolator(ALPHA_OUT);
460 navBarAnimator.setDuration(ANIM_OUT_DURATION_MS);
461 mTrackAnimator = new AnimatorSet();
462 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
463 mTrackAnimator.start();
Matthew Ng6607c3d2018-04-26 15:23:27 -0700464
Matthew Ng472d3e42018-06-14 15:16:55 -0700465 // Disable slippery for quick scrub to not cancel outside the nav bar
466 mNavigationBarView.updateSlippery();
467
Matthew Nga8f24262017-12-19 11:54:24 -0800468 try {
469 mOverviewEventSender.getProxy().onQuickScrubStart();
Matthew Ngbd824572018-01-17 16:25:56 -0800470 if (DEBUG_OVERVIEW_PROXY) {
471 Log.d(TAG_OPS, "Quick Scrub Start");
472 }
Matthew Nga8f24262017-12-19 11:54:24 -0800473 } catch (RemoteException e) {
474 Log.e(TAG, "Failed to send start of quick scrub.", e);
475 }
Tracy Zhou27599052018-04-16 15:47:29 -0700476 mOverviewEventSender.notifyQuickScrubStarted();
Winson Chung661d5f92018-05-21 18:41:39 -0700477
478 if (mHitTarget != null) {
479 mHitTarget.abortCurrentGesture();
480 }
Matthew Nga8f24262017-12-19 11:54:24 -0800481 }
482 }
483
Winson Chungd10ca302018-02-14 10:13:41 -0800484 private void endQuickScrub(boolean animate) {
Winson Chung661d5f92018-05-21 18:41:39 -0700485 if (mQuickScrubActive) {
Matthew Nged166f92018-02-20 16:22:09 -0800486 animateEnd();
Winson Chung661d5f92018-05-21 18:41:39 -0700487 try {
488 mOverviewEventSender.getProxy().onQuickScrubEnd();
489 if (DEBUG_OVERVIEW_PROXY) {
490 Log.d(TAG_OPS, "Quick Scrub End");
Matthew Ngbd824572018-01-17 16:25:56 -0800491 }
Winson Chung661d5f92018-05-21 18:41:39 -0700492 } catch (RemoteException e) {
493 Log.e(TAG, "Failed to send end of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800494 }
Matthew Nged166f92018-02-20 16:22:09 -0800495 }
Winson Chung661d5f92018-05-21 18:41:39 -0700496 if (!animate) {
497 if (mTrackAnimator != null) {
498 mTrackAnimator.end();
499 mTrackAnimator = null;
500 }
Matthew Nga8f24262017-12-19 11:54:24 -0800501 }
Matthew Nga8f24262017-12-19 11:54:24 -0800502 }
503
Winson Chung661d5f92018-05-21 18:41:39 -0700504 private void animateEnd() {
505 if (mTrackAnimator != null) {
506 mTrackAnimator.cancel();
507 }
508
Winson Chung4baf1242018-05-24 14:21:57 -0700509 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
510 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
511 PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
Winson Chung661d5f92018-05-21 18:41:39 -0700512 trackAnimator.setInterpolator(ALPHA_OUT);
513 trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
514 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
515 navBarAnimator.setInterpolator(ALPHA_IN);
516 navBarAnimator.setDuration(ANIM_IN_DURATION_MS);
517 mTrackAnimator = new AnimatorSet();
518 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
519 mTrackAnimator.addListener(mQuickScrubEndListener);
520 mTrackAnimator.start();
521 }
522
523 private void resetQuickScrub() {
524 mQuickScrubActive = false;
525 mAllowGestureDetection = false;
Matthew Ng819daaa2018-07-23 15:12:57 -0700526 if (mCurrentNavigationBarView != null) {
527 mCurrentNavigationBarView.setAlpha(1f);
528 }
Winson Chung661d5f92018-05-21 18:41:39 -0700529 mCurrentNavigationBarView = null;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700530 updateHighlight();
531 }
532
533 private void updateHighlight() {
Matthew Ng908111d2018-06-26 15:22:56 -0700534 if (mTrackRect.isEmpty()) {
535 return;
536 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700537 int colorBase, colorGrad;
538 if (mDarkIntensity > 0.5f) {
539 colorBase = mContext.getColor(R.color.quick_step_track_background_background_dark);
540 colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_dark);
541 } else {
542 colorBase = mContext.getColor(R.color.quick_step_track_background_background_light);
543 colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_light);
544 }
545 mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
546 mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
547 Shader.TileMode.CLAMP);
548 mTrackPaint.setShader(mHighlight);
Winson Chung661d5f92018-05-21 18:41:39 -0700549 }
550
Matthew Ng2ea93b72018-03-14 19:43:18 +0000551 private boolean proxyMotionEvents(MotionEvent event) {
552 final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
553 event.transform(mTransformGlobalMatrix);
554 try {
555 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
556 overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
557 }
558 overviewProxy.onMotionEvent(event);
559 if (DEBUG_OVERVIEW_PROXY) {
560 Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
561 }
562 return true;
563 } catch (RemoteException e) {
564 Log.e(TAG, "Callback failed", e);
565 } finally {
566 event.transform(mTransformLocalMatrix);
Matthew Ngdb2734c2018-02-16 16:02:20 -0800567 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000568 return false;
Matthew Ngdb2734c2018-02-16 16:02:20 -0800569 }
Matthew Nga8f24262017-12-19 11:54:24 -0800570}