blob: 860b77e1b251bbd271e1866bdf5d2bec0f24b7c4 [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;
25
Matthew Nga8f24262017-12-19 11:54:24 -080026import android.animation.Animator;
27import android.animation.AnimatorListenerAdapter;
28import android.animation.AnimatorSet;
Matthew Ng7090a802018-01-19 13:36:22 -080029import android.animation.ArgbEvaluator;
Matthew Nga8f24262017-12-19 11:54:24 -080030import 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;
Winson Chung4baf1242018-05-24 14:21:57 -070035import android.graphics.Color;
Matthew Ng2ea93b72018-03-14 19:43:18 +000036import android.graphics.Matrix;
Matthew Nga8f24262017-12-19 11:54:24 -080037import android.graphics.Rect;
Winson Chung4baf1242018-05-24 14:21:57 -070038import android.graphics.drawable.Drawable;
Matthew Nga8f24262017-12-19 11:54:24 -080039import android.os.Handler;
40import android.os.RemoteException;
Winson Chung661d5f92018-05-21 18:41:39 -070041import android.util.FloatProperty;
Matthew Nga8f24262017-12-19 11:54:24 -080042import android.util.Log;
43import android.util.Slog;
Matthew Nga8f24262017-12-19 11:54:24 -080044import android.view.MotionEvent;
45import android.view.View;
Matthew Nga8f24262017-12-19 11:54:24 -080046import android.view.WindowManagerGlobal;
47import android.view.animation.DecelerateInterpolator;
48import android.view.animation.Interpolator;
49import android.support.annotation.DimenRes;
50import com.android.systemui.Dependency;
51import com.android.systemui.OverviewProxyService;
52import com.android.systemui.R;
53import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
54import com.android.systemui.shared.recents.IOverviewProxy;
55import com.android.systemui.shared.recents.utilities.Utilities;
Matthew Ngf29ad752018-04-26 11:24:05 -070056import com.android.systemui.shared.system.NavigationBarCompat;
Winson Chung4baf1242018-05-24 14:21:57 -070057import com.android.internal.graphics.ColorUtils;
Matthew Nga8f24262017-12-19 11:54:24 -080058
Matthew Nga8f24262017-12-19 11:54:24 -080059/**
Matthew Ngfba39692018-03-13 18:08:34 -070060 * Class to detect gestures on the navigation bar and implement quick scrub.
Matthew Nga8f24262017-12-19 11:54:24 -080061 */
Matthew Ngfba39692018-03-13 18:08:34 -070062public class QuickStepController implements GestureHelper {
Matthew Nga8f24262017-12-19 11:54:24 -080063
Matthew Ng2ea93b72018-03-14 19:43:18 +000064 private static final String TAG = "QuickStepController";
Winson Chung661d5f92018-05-21 18:41:39 -070065 private static final int ANIM_IN_DURATION_MS = 150;
Winson Chung4baf1242018-05-24 14:21:57 -070066 private static final int ANIM_OUT_DURATION_MS = 134;
67 private static final float TRACK_SCALE = 0.95f;
Matthew Nga8f24262017-12-19 11:54:24 -080068
69 private NavigationBarView mNavigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -080070
Matthew Nga8f24262017-12-19 11:54:24 -080071 private boolean mQuickScrubActive;
Matthew Ng2ea93b72018-03-14 19:43:18 +000072 private boolean mAllowGestureDetection;
73 private boolean mQuickStepStarted;
Matthew Nga8f24262017-12-19 11:54:24 -080074 private int mTouchDownX;
75 private int mTouchDownY;
76 private boolean mDragPositive;
77 private boolean mIsVertical;
78 private boolean mIsRTL;
Matthew Ng7090a802018-01-19 13:36:22 -080079 private float mTrackAlpha;
Winson Chung4baf1242018-05-24 14:21:57 -070080 private float mTrackScale = TRACK_SCALE;
Matthew Ng7090a802018-01-19 13:36:22 -080081 private int mLightTrackColor;
82 private int mDarkTrackColor;
83 private float mDarkIntensity;
Winson Chung661d5f92018-05-21 18:41:39 -070084 private AnimatorSet mTrackAnimator;
85 private ButtonDispatcher mHitTarget;
86 private View mCurrentNavigationBarView;
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();
Winson Chung4baf1242018-05-24 14:21:57 -070090 private final Drawable mTrackDrawable;
Matthew Nga8f24262017-12-19 11:54:24 -080091 private final OverviewProxyService mOverviewEventSender;
Matthew Nga8f24262017-12-19 11:54:24 -080092 private final int mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -070093 private final int mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -080094 private final Context mContext;
Matthew Ng2ea93b72018-03-14 19:43:18 +000095 private final Matrix mTransformGlobalMatrix = new Matrix();
96 private final Matrix mTransformLocalMatrix = new Matrix();
Matthew Ng7090a802018-01-19 13:36:22 -080097 private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
Matthew Nga8f24262017-12-19 11:54:24 -080098
Winson Chung661d5f92018-05-21 18:41:39 -070099 private final FloatProperty<QuickStepController> mTrackAlphaProperty =
100 new FloatProperty<QuickStepController>("TrackAlpha") {
101 @Override
102 public void setValue(QuickStepController controller, float alpha) {
103 mTrackAlpha = alpha;
104 mNavigationBarView.invalidate();
105 }
106
107 @Override
108 public Float get(QuickStepController controller) {
109 return mTrackAlpha;
110 }
Matthew Nga8f24262017-12-19 11:54:24 -0800111 };
112
Winson Chung4baf1242018-05-24 14:21:57 -0700113 private final FloatProperty<QuickStepController> mTrackScaleProperty =
114 new FloatProperty<QuickStepController>("TrackScale") {
115 @Override
116 public void setValue(QuickStepController controller, float scale) {
117 mTrackScale = scale;
118 mNavigationBarView.invalidate();
119 }
120
121 @Override
122 public Float get(QuickStepController controller) {
123 return mTrackScale;
124 }
125 };
126
Winson Chung661d5f92018-05-21 18:41:39 -0700127 private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
128 new FloatProperty<QuickStepController>("NavBarAlpha") {
129 @Override
130 public void setValue(QuickStepController controller, float alpha) {
131 if (mCurrentNavigationBarView != null) {
132 mCurrentNavigationBarView.setAlpha(alpha);
133 }
Matthew Nga8f24262017-12-19 11:54:24 -0800134 }
Winson Chung661d5f92018-05-21 18:41:39 -0700135
136 @Override
137 public Float get(QuickStepController controller) {
138 if (mCurrentNavigationBarView != null) {
139 return mCurrentNavigationBarView.getAlpha();
140 }
141 return 1f;
Matthew Nga8f24262017-12-19 11:54:24 -0800142 }
143 };
144
145 private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
146 @Override
147 public void onAnimationEnd(Animator animation) {
Winson Chung661d5f92018-05-21 18:41:39 -0700148 resetQuickScrub();
Matthew Nga8f24262017-12-19 11:54:24 -0800149 }
150 };
151
Matthew Ng2ea93b72018-03-14 19:43:18 +0000152 public QuickStepController(Context context) {
Winson Chung661d5f92018-05-21 18:41:39 -0700153 final Resources res = context.getResources();
Matthew Nga8f24262017-12-19 11:54:24 -0800154 mContext = context;
Matthew Nga8f24262017-12-19 11:54:24 -0800155 mOverviewEventSender = Dependency.get(OverviewProxyService.class);
Winson Chung661d5f92018-05-21 18:41:39 -0700156 mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
157 mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
Winson Chung4baf1242018-05-24 14:21:57 -0700158 mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
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) {
Winson Chungd95a2252018-04-04 17:02:29 +0000187 if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
188 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
Matthew Ng22cf5142018-03-14 12:26:14 -0700189 return false;
190 }
191 mNavigationBarView.requestUnbufferedDispatch(event);
192
Matthew Ng9a223632018-03-30 16:47:22 -0700193 int action = event.getActionMasked();
194 switch (action) {
Matthew Nga8f24262017-12-19 11:54:24 -0800195 case MotionEvent.ACTION_DOWN: {
196 int x = (int) event.getX();
197 int y = (int) event.getY();
Winson Chung661d5f92018-05-21 18:41:39 -0700198
Winson Chung0be8f082018-02-15 15:52:49 -0800199 // End any existing quickscrub animations before starting the new transition
Winson Chung661d5f92018-05-21 18:41:39 -0700200 if (mTrackAnimator != null) {
201 mTrackAnimator.end();
202 mTrackAnimator = null;
Winson Chung0be8f082018-02-15 15:52:49 -0800203 }
Winson Chung661d5f92018-05-21 18:41:39 -0700204
205 mCurrentNavigationBarView = mNavigationBarView.getCurrentView();
206 mHitTarget = mNavigationBarView.getButtonAtPosition(x, y);
207 if (mHitTarget != null) {
208 // Pre-emptively delay the touch feedback for the button that we just touched
209 mHitTarget.setDelayTouchFeedback(true);
210 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000211 mTouchDownX = x;
212 mTouchDownY = y;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000213 mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
214 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
215 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
216 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
217 mQuickStepStarted = false;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000218 mAllowGestureDetection = true;
Matthew Nga8f24262017-12-19 11:54:24 -0800219 break;
220 }
221 case MotionEvent.ACTION_MOVE: {
Winson Chung661d5f92018-05-21 18:41:39 -0700222 if (mQuickStepStarted || !mAllowGestureDetection){
Matthew Ng2ea93b72018-03-14 19:43:18 +0000223 break;
224 }
225 int x = (int) event.getX();
226 int y = (int) event.getY();
227 int xDiff = Math.abs(x - mTouchDownX);
228 int yDiff = Math.abs(y - mTouchDownY);
Matthew Ng9a223632018-03-30 16:47:22 -0700229
Winson Chung661d5f92018-05-21 18:41:39 -0700230 boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000231 int pos, touchDown, offset, trackSize;
Matthew Nge0903c92018-01-17 15:32:41 -0800232
Matthew Ng2ea93b72018-03-14 19:43:18 +0000233 if (mIsVertical) {
Matthew Ngf29ad752018-04-26 11:24:05 -0700234 exceededScrubTouchSlop =
235 yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
236 exceededSwipeUpTouchSlop =
237 xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000238 pos = y;
239 touchDown = mTouchDownY;
240 offset = pos - mTrackRect.top;
241 trackSize = mTrackRect.height();
242 } else {
Matthew Ngf29ad752018-04-26 11:24:05 -0700243 exceededScrubTouchSlop =
244 xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
245 exceededSwipeUpTouchSlop =
246 yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000247 pos = x;
248 touchDown = mTouchDownX;
249 offset = pos - mTrackRect.left;
250 trackSize = mTrackRect.width();
251 }
252 // Decide to start quickstep if dragging away from the navigation bar, otherwise in
253 // the parallel direction, decide to start quickscrub. Only one may run.
Matthew Ng9a223632018-03-30 16:47:22 -0700254 if (!mQuickScrubActive && exceededSwipeUpTouchSlop) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000255 if (mNavigationBarView.isQuickStepSwipeUpEnabled()) {
256 startQuickStep(event);
Winson Chung0e490d922018-03-14 16:08:43 +0000257 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000258 break;
259 }
Winson Chung0e490d922018-03-14 16:08:43 +0000260
Winson Chung661d5f92018-05-21 18:41:39 -0700261 // Do not handle quick scrub if disabled
262 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000263 break;
264 }
265
266 if (!mDragPositive) {
267 offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
268 }
269
Matthew Ng9a223632018-03-30 16:47:22 -0700270 final boolean allowDrag = !mDragPositive
271 ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
Winson Chung661d5f92018-05-21 18:41:39 -0700272 float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
Matthew Ng9a223632018-03-30 16:47:22 -0700273 if (allowDrag) {
Matthew Ng9a223632018-03-30 16:47:22 -0700274 // Passing the drag slop then touch slop will start quick step
275 if (!mQuickScrubActive && exceededScrubTouchSlop) {
Matthew Ngfba39692018-03-13 18:08:34 -0700276 startQuickScrub();
Winson Chung0e490d922018-03-14 16:08:43 +0000277 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000278 }
Matthew Ng9a223632018-03-30 16:47:22 -0700279
Winson Chung661d5f92018-05-21 18:41:39 -0700280 if (mQuickScrubActive && (mDragPositive && offset >= 0
Matthew Ng2ea93b72018-03-14 19:43:18 +0000281 || !mDragPositive && offset <= 0)) {
Winson Chung661d5f92018-05-21 18:41:39 -0700282 try {
283 mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
284 if (DEBUG_OVERVIEW_PROXY) {
285 Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
Winson Chung0e490d922018-03-14 16:08:43 +0000286 }
Winson Chung661d5f92018-05-21 18:41:39 -0700287 } catch (RemoteException e) {
288 Log.e(TAG, "Failed to send progress of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800289 }
290 }
291 break;
292 }
293 case MotionEvent.ACTION_CANCEL:
294 case MotionEvent.ACTION_UP:
Winson Chungd10ca302018-02-14 10:13:41 -0800295 endQuickScrub(true /* animate */);
Matthew Nga8f24262017-12-19 11:54:24 -0800296 break;
297 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000298
Matthew Ngfba39692018-03-13 18:08:34 -0700299 // Proxy motion events to launcher if not handled by quick scrub
Matthew Ng9a223632018-03-30 16:47:22 -0700300 // Proxy motion events up/cancel that would be sent after long press on any nav button
301 if (!mQuickScrubActive && (mAllowGestureDetection || action == MotionEvent.ACTION_CANCEL
302 || action == MotionEvent.ACTION_UP)) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000303 proxyMotionEvents(event);
304 }
Matthew Ngfba39692018-03-13 18:08:34 -0700305 return mQuickScrubActive || mQuickStepStarted;
Matthew Nga8f24262017-12-19 11:54:24 -0800306 }
307
308 @Override
309 public void onDraw(Canvas canvas) {
Matthew Ngf781bbd2018-03-21 14:58:55 -0700310 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000311 return;
312 }
Matthew Ng7090a802018-01-19 13:36:22 -0800313 int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
314 mDarkTrackColor);
Winson Chung4baf1242018-05-24 14:21:57 -0700315 int colorAlpha = ColorUtils.setAlphaComponent(color,
316 (int) (Color.alpha(color) * mTrackAlpha));
317 mTrackDrawable.setTint(colorAlpha);
318
319 // Scale the track, but apply the inverse scale from the nav bar
320 canvas.save();
321 canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
322 1f / mNavigationBarView.getScaleY(),
323 mTrackRect.centerX(), mTrackRect.centerY());
324 mTrackDrawable.draw(canvas);
325 canvas.restore();
Matthew Nga8f24262017-12-19 11:54:24 -0800326 }
327
328 @Override
329 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson Chung661d5f92018-05-21 18:41:39 -0700330 final int paddingLeft = mNavigationBarView.getPaddingLeft();
331 final int paddingTop = mNavigationBarView.getPaddingTop();
332 final int paddingRight = mNavigationBarView.getPaddingRight();
333 final int paddingBottom = mNavigationBarView.getPaddingBottom();
334 final int width = (right - left) - paddingRight - paddingLeft;
335 final int height = (bottom - top) - paddingBottom - paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800336 final int x1, x2, y1, y2;
337 if (mIsVertical) {
Winson Chung661d5f92018-05-21 18:41:39 -0700338 x1 = (width - mTrackThickness) / 2 + paddingLeft;
Matthew Nga8f24262017-12-19 11:54:24 -0800339 x2 = x1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700340 y1 = paddingTop + mTrackEndPadding;
341 y2 = y1 + height - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800342 } else {
Winson Chung661d5f92018-05-21 18:41:39 -0700343 y1 = (height - mTrackThickness) / 2 + paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800344 y2 = y1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700345 x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
346 x2 = x1 + width - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800347 }
348 mTrackRect.set(x1, y1, x2, y2);
Winson Chung4baf1242018-05-24 14:21:57 -0700349 mTrackDrawable.setBounds(mTrackRect);
Matthew Nga8f24262017-12-19 11:54:24 -0800350 }
351
352 @Override
353 public void onDarkIntensityChange(float intensity) {
Matthew Ng7090a802018-01-19 13:36:22 -0800354 mDarkIntensity = intensity;
355 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800356 }
357
358 @Override
Matthew Nga8f24262017-12-19 11:54:24 -0800359 public void setBarState(boolean isVertical, boolean isRTL) {
Winson Chungd10ca302018-02-14 10:13:41 -0800360 final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
361 if (changed) {
362 // End quickscrub if the state changes mid-transition
363 endQuickScrub(false /* animate */);
364 }
Matthew Nga8f24262017-12-19 11:54:24 -0800365 mIsVertical = isVertical;
366 mIsRTL = isRTL;
367 try {
368 int navbarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
369 mDragPositive = navbarPos == NAV_BAR_LEFT || navbarPos == NAV_BAR_BOTTOM;
370 if (isRTL) {
371 mDragPositive = !mDragPositive;
372 }
373 } catch (RemoteException e) {
374 Slog.e(TAG, "Failed to get nav bar position.", e);
375 }
376 }
377
Matthew Ng2ea93b72018-03-14 19:43:18 +0000378 @Override
379 public void onNavigationButtonLongPress(View v) {
380 mAllowGestureDetection = false;
381 mHandler.removeCallbacksAndMessages(null);
382 }
383
384 private void startQuickStep(MotionEvent event) {
385 mQuickStepStarted = true;
386 event.transform(mTransformGlobalMatrix);
387 try {
388 mOverviewEventSender.getProxy().onQuickStep(event);
389 if (DEBUG_OVERVIEW_PROXY) {
390 Log.d(TAG_OPS, "Quick Step Start");
391 }
392 } catch (RemoteException e) {
393 Log.e(TAG, "Failed to send quick step started.", e);
394 } finally {
395 event.transform(mTransformLocalMatrix);
396 }
397 mOverviewEventSender.notifyQuickStepStarted();
Matthew Ng2ea93b72018-03-14 19:43:18 +0000398 mHandler.removeCallbacksAndMessages(null);
Matthew Ng9a223632018-03-30 16:47:22 -0700399
Winson Chung661d5f92018-05-21 18:41:39 -0700400 if (mHitTarget != null) {
401 mHitTarget.abortCurrentGesture();
402 }
403
404 if (mQuickScrubActive) {
Matthew Ng9a223632018-03-30 16:47:22 -0700405 animateEnd();
406 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000407 }
408
Matthew Nga8f24262017-12-19 11:54:24 -0800409 private void startQuickScrub() {
Winson Chung661d5f92018-05-21 18:41:39 -0700410 if (!mQuickScrubActive) {
Matthew Nga8f24262017-12-19 11:54:24 -0800411 mQuickScrubActive = true;
Matthew Ng7090a802018-01-19 13:36:22 -0800412 mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
413 mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
Matthew Ng6607c3d2018-04-26 15:23:27 -0700414
Winson Chung4baf1242018-05-24 14:21:57 -0700415 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
416 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
417 PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
Winson Chung661d5f92018-05-21 18:41:39 -0700418 trackAnimator.setInterpolator(ALPHA_IN);
419 trackAnimator.setDuration(ANIM_IN_DURATION_MS);
420 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
421 navBarAnimator.setInterpolator(ALPHA_OUT);
422 navBarAnimator.setDuration(ANIM_OUT_DURATION_MS);
423 mTrackAnimator = new AnimatorSet();
424 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
425 mTrackAnimator.start();
Matthew Ng6607c3d2018-04-26 15:23:27 -0700426
Matthew Nga8f24262017-12-19 11:54:24 -0800427 try {
428 mOverviewEventSender.getProxy().onQuickScrubStart();
Matthew Ngbd824572018-01-17 16:25:56 -0800429 if (DEBUG_OVERVIEW_PROXY) {
430 Log.d(TAG_OPS, "Quick Scrub Start");
431 }
Matthew Nga8f24262017-12-19 11:54:24 -0800432 } catch (RemoteException e) {
433 Log.e(TAG, "Failed to send start of quick scrub.", e);
434 }
Tracy Zhou27599052018-04-16 15:47:29 -0700435 mOverviewEventSender.notifyQuickScrubStarted();
Winson Chung661d5f92018-05-21 18:41:39 -0700436
437 if (mHitTarget != null) {
438 mHitTarget.abortCurrentGesture();
439 }
Matthew Nga8f24262017-12-19 11:54:24 -0800440 }
441 }
442
Winson Chungd10ca302018-02-14 10:13:41 -0800443 private void endQuickScrub(boolean animate) {
Winson Chung661d5f92018-05-21 18:41:39 -0700444 if (mQuickScrubActive) {
Matthew Nged166f92018-02-20 16:22:09 -0800445 animateEnd();
Winson Chung661d5f92018-05-21 18:41:39 -0700446 try {
447 mOverviewEventSender.getProxy().onQuickScrubEnd();
448 if (DEBUG_OVERVIEW_PROXY) {
449 Log.d(TAG_OPS, "Quick Scrub End");
Matthew Ngbd824572018-01-17 16:25:56 -0800450 }
Winson Chung661d5f92018-05-21 18:41:39 -0700451 } catch (RemoteException e) {
452 Log.e(TAG, "Failed to send end of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800453 }
Matthew Nged166f92018-02-20 16:22:09 -0800454 }
Winson Chung661d5f92018-05-21 18:41:39 -0700455 if (!animate) {
456 if (mTrackAnimator != null) {
457 mTrackAnimator.end();
458 mTrackAnimator = null;
459 }
Matthew Nga8f24262017-12-19 11:54:24 -0800460 }
Matthew Nga8f24262017-12-19 11:54:24 -0800461 }
462
Winson Chung661d5f92018-05-21 18:41:39 -0700463 private void animateEnd() {
464 if (mTrackAnimator != null) {
465 mTrackAnimator.cancel();
466 }
467
Winson Chung4baf1242018-05-24 14:21:57 -0700468 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
469 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
470 PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
Winson Chung661d5f92018-05-21 18:41:39 -0700471 trackAnimator.setInterpolator(ALPHA_OUT);
472 trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
473 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
474 navBarAnimator.setInterpolator(ALPHA_IN);
475 navBarAnimator.setDuration(ANIM_IN_DURATION_MS);
476 mTrackAnimator = new AnimatorSet();
477 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
478 mTrackAnimator.addListener(mQuickScrubEndListener);
479 mTrackAnimator.start();
480 }
481
482 private void resetQuickScrub() {
483 mQuickScrubActive = false;
484 mAllowGestureDetection = false;
485 mCurrentNavigationBarView = null;
486 }
487
Matthew Ng2ea93b72018-03-14 19:43:18 +0000488 private boolean proxyMotionEvents(MotionEvent event) {
489 final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
490 event.transform(mTransformGlobalMatrix);
491 try {
492 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
493 overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
494 }
495 overviewProxy.onMotionEvent(event);
496 if (DEBUG_OVERVIEW_PROXY) {
497 Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
498 }
499 return true;
500 } catch (RemoteException e) {
501 Log.e(TAG, "Callback failed", e);
502 } finally {
503 event.transform(mTransformLocalMatrix);
Matthew Ngdb2734c2018-02-16 16:02:20 -0800504 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000505 return false;
Matthew Ngdb2734c2018-02-16 16:02:20 -0800506 }
Matthew Nga8f24262017-12-19 11:54:24 -0800507}