blob: af1d220f46f5a0937782ebe7cce32ecef6101393 [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;
48import android.view.animation.DecelerateInterpolator;
49import android.view.animation.Interpolator;
50import android.support.annotation.DimenRes;
51import com.android.systemui.Dependency;
52import com.android.systemui.OverviewProxyService;
53import com.android.systemui.R;
54import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
55import com.android.systemui.shared.recents.IOverviewProxy;
56import com.android.systemui.shared.recents.utilities.Utilities;
Matthew Ngf29ad752018-04-26 11:24:05 -070057import com.android.systemui.shared.system.NavigationBarCompat;
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 Ng4fa3a9d2018-06-12 16:42:11 -070068 private static final float GRADIENT_WIDTH = .75f;
Matthew Nga8f24262017-12-19 11:54:24 -080069
70 private NavigationBarView mNavigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -080071
Matthew Nga8f24262017-12-19 11:54:24 -080072 private boolean mQuickScrubActive;
Matthew Ng2ea93b72018-03-14 19:43:18 +000073 private boolean mAllowGestureDetection;
74 private boolean mQuickStepStarted;
Matthew Nga8f24262017-12-19 11:54:24 -080075 private int mTouchDownX;
76 private int mTouchDownY;
77 private boolean mDragPositive;
78 private boolean mIsVertical;
79 private boolean mIsRTL;
Matthew Ng7090a802018-01-19 13:36:22 -080080 private float mTrackAlpha;
Winson Chung4baf1242018-05-24 14:21:57 -070081 private float mTrackScale = TRACK_SCALE;
Matthew Ng7090a802018-01-19 13:36:22 -080082 private float mDarkIntensity;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -070083 private RadialGradient mHighlight;
84 private float mHighlightCenter;
Winson Chung661d5f92018-05-21 18:41:39 -070085 private AnimatorSet mTrackAnimator;
86 private ButtonDispatcher mHitTarget;
87 private View mCurrentNavigationBarView;
Matthew Nga8f24262017-12-19 11:54:24 -080088
89 private final Handler mHandler = new Handler();
Matthew Nga8f24262017-12-19 11:54:24 -080090 private final Rect mTrackRect = new Rect();
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 Ng4fa3a9d2018-06-12 16:42:11 -070097 private final Paint mTrackPaint = new Paint();
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);
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700158 mTrackPaint.setAntiAlias(true);
159 mTrackPaint.setDither(true);
Matthew Nga8f24262017-12-19 11:54:24 -0800160 }
161
162 public void setComponents(NavigationBarView navigationBarView) {
163 mNavigationBarView = navigationBarView;
164 }
165
Winson Chung4faf38a2018-02-06 08:53:37 -0800166 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700167 * @return true if we want to intercept touch events for quick scrub and prevent proxying the
168 * event to the overview service.
Winson Chung4faf38a2018-02-06 08:53:37 -0800169 */
Matthew Nga8f24262017-12-19 11:54:24 -0800170 @Override
171 public boolean onInterceptTouchEvent(MotionEvent event) {
Winson Chungde2a1242018-02-07 15:59:43 -0800172 return handleTouchEvent(event);
173 }
174
175 /**
Matthew Ngfba39692018-03-13 18:08:34 -0700176 * @return true if we want to handle touch events for quick scrub or if down event (that will
177 * get consumed and ignored). No events will be proxied to the overview service.
Winson Chungde2a1242018-02-07 15:59:43 -0800178 */
179 @Override
180 public boolean onTouchEvent(MotionEvent event) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000181 // The same down event was just sent on intercept and therefore can be ignored here
182 final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
183 && mOverviewEventSender.getProxy() != null;
184 return ignoreProxyDownEvent || handleTouchEvent(event);
Winson Chungde2a1242018-02-07 15:59:43 -0800185 }
186
187 private boolean handleTouchEvent(MotionEvent event) {
Matthew Ng472d3e42018-06-14 15:16:55 -0700188 final boolean deadZoneConsumed =
189 mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
Winson Chungd95a2252018-04-04 17:02:29 +0000190 if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
191 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
Matthew Ng22cf5142018-03-14 12:26:14 -0700192 return false;
193 }
194 mNavigationBarView.requestUnbufferedDispatch(event);
195
Matthew Ng9a223632018-03-30 16:47:22 -0700196 int action = event.getActionMasked();
197 switch (action) {
Matthew Nga8f24262017-12-19 11:54:24 -0800198 case MotionEvent.ACTION_DOWN: {
199 int x = (int) event.getX();
200 int y = (int) event.getY();
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 Nga8f24262017-12-19 11:54:24 -0800222 break;
223 }
224 case MotionEvent.ACTION_MOVE: {
Winson Chung661d5f92018-05-21 18:41:39 -0700225 if (mQuickStepStarted || !mAllowGestureDetection){
Matthew Ng2ea93b72018-03-14 19:43:18 +0000226 break;
227 }
228 int x = (int) event.getX();
229 int y = (int) event.getY();
230 int xDiff = Math.abs(x - mTouchDownX);
231 int yDiff = Math.abs(y - mTouchDownY);
Matthew Ng9a223632018-03-30 16:47:22 -0700232
Winson Chung661d5f92018-05-21 18:41:39 -0700233 boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000234 int pos, touchDown, offset, trackSize;
Matthew Nge0903c92018-01-17 15:32:41 -0800235
Matthew Ng2ea93b72018-03-14 19:43:18 +0000236 if (mIsVertical) {
Matthew Ngf29ad752018-04-26 11:24:05 -0700237 exceededScrubTouchSlop =
238 yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
239 exceededSwipeUpTouchSlop =
240 xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000241 pos = y;
242 touchDown = mTouchDownY;
243 offset = pos - mTrackRect.top;
244 trackSize = mTrackRect.height();
245 } else {
Matthew Ngf29ad752018-04-26 11:24:05 -0700246 exceededScrubTouchSlop =
247 xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
248 exceededSwipeUpTouchSlop =
249 yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
Matthew Ng2ea93b72018-03-14 19:43:18 +0000250 pos = x;
251 touchDown = mTouchDownX;
252 offset = pos - mTrackRect.left;
253 trackSize = mTrackRect.width();
254 }
255 // Decide to start quickstep if dragging away from the navigation bar, otherwise in
256 // the parallel direction, decide to start quickscrub. Only one may run.
Matthew Ng9a223632018-03-30 16:47:22 -0700257 if (!mQuickScrubActive && exceededSwipeUpTouchSlop) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000258 if (mNavigationBarView.isQuickStepSwipeUpEnabled()) {
259 startQuickStep(event);
Winson Chung0e490d922018-03-14 16:08:43 +0000260 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000261 break;
262 }
Winson Chung0e490d922018-03-14 16:08:43 +0000263
Winson Chung661d5f92018-05-21 18:41:39 -0700264 // Do not handle quick scrub if disabled
265 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000266 break;
267 }
268
269 if (!mDragPositive) {
270 offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
271 }
272
Matthew Ng9a223632018-03-30 16:47:22 -0700273 final boolean allowDrag = !mDragPositive
274 ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
Winson Chung661d5f92018-05-21 18:41:39 -0700275 float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
Matthew Ng9a223632018-03-30 16:47:22 -0700276 if (allowDrag) {
Matthew Ng9a223632018-03-30 16:47:22 -0700277 // Passing the drag slop then touch slop will start quick step
278 if (!mQuickScrubActive && exceededScrubTouchSlop) {
Matthew Ngfba39692018-03-13 18:08:34 -0700279 startQuickScrub();
Winson Chung0e490d922018-03-14 16:08:43 +0000280 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000281 }
Matthew Ng9a223632018-03-30 16:47:22 -0700282
Winson Chung661d5f92018-05-21 18:41:39 -0700283 if (mQuickScrubActive && (mDragPositive && offset >= 0
Matthew Ng2ea93b72018-03-14 19:43:18 +0000284 || !mDragPositive && offset <= 0)) {
Winson Chung661d5f92018-05-21 18:41:39 -0700285 try {
286 mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
287 if (DEBUG_OVERVIEW_PROXY) {
288 Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
Winson Chung0e490d922018-03-14 16:08:43 +0000289 }
Winson Chung661d5f92018-05-21 18:41:39 -0700290 } catch (RemoteException e) {
291 Log.e(TAG, "Failed to send progress of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800292 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700293 mHighlightCenter = x;
294 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800295 }
296 break;
297 }
298 case MotionEvent.ACTION_CANCEL:
299 case MotionEvent.ACTION_UP:
Winson Chungd10ca302018-02-14 10:13:41 -0800300 endQuickScrub(true /* animate */);
Matthew Nga8f24262017-12-19 11:54:24 -0800301 break;
302 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000303
Matthew Ngfba39692018-03-13 18:08:34 -0700304 // Proxy motion events to launcher if not handled by quick scrub
Matthew Ng9a223632018-03-30 16:47:22 -0700305 // Proxy motion events up/cancel that would be sent after long press on any nav button
306 if (!mQuickScrubActive && (mAllowGestureDetection || action == MotionEvent.ACTION_CANCEL
307 || action == MotionEvent.ACTION_UP)) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000308 proxyMotionEvents(event);
309 }
Matthew Ng472d3e42018-06-14 15:16:55 -0700310 return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed;
Matthew Nga8f24262017-12-19 11:54:24 -0800311 }
312
313 @Override
314 public void onDraw(Canvas canvas) {
Matthew Ngf781bbd2018-03-21 14:58:55 -0700315 if (!mNavigationBarView.isQuickScrubEnabled()) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000316 return;
317 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700318 mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
Winson Chung4baf1242018-05-24 14:21:57 -0700319
320 // Scale the track, but apply the inverse scale from the nav bar
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700321 final float radius = mTrackRect.height() / 2;
Winson Chung4baf1242018-05-24 14:21:57 -0700322 canvas.save();
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700323 float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
324 canvas.translate(translate, 0);
Winson Chung4baf1242018-05-24 14:21:57 -0700325 canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
326 1f / mNavigationBarView.getScaleY(),
327 mTrackRect.centerX(), mTrackRect.centerY());
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700328 canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
329 mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
Winson Chung4baf1242018-05-24 14:21:57 -0700330 canvas.restore();
Matthew Nga8f24262017-12-19 11:54:24 -0800331 }
332
333 @Override
334 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson Chung661d5f92018-05-21 18:41:39 -0700335 final int paddingLeft = mNavigationBarView.getPaddingLeft();
336 final int paddingTop = mNavigationBarView.getPaddingTop();
337 final int paddingRight = mNavigationBarView.getPaddingRight();
338 final int paddingBottom = mNavigationBarView.getPaddingBottom();
339 final int width = (right - left) - paddingRight - paddingLeft;
340 final int height = (bottom - top) - paddingBottom - paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800341 final int x1, x2, y1, y2;
342 if (mIsVertical) {
Winson Chung661d5f92018-05-21 18:41:39 -0700343 x1 = (width - mTrackThickness) / 2 + paddingLeft;
Matthew Nga8f24262017-12-19 11:54:24 -0800344 x2 = x1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700345 y1 = paddingTop + mTrackEndPadding;
346 y2 = y1 + height - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800347 } else {
Winson Chung661d5f92018-05-21 18:41:39 -0700348 y1 = (height - mTrackThickness) / 2 + paddingTop;
Matthew Nga8f24262017-12-19 11:54:24 -0800349 y2 = y1 + mTrackThickness;
Winson Chung661d5f92018-05-21 18:41:39 -0700350 x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
351 x2 = x1 + width - 2 * mTrackEndPadding;
Matthew Nga8f24262017-12-19 11:54:24 -0800352 }
353 mTrackRect.set(x1, y1, x2, y2);
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700354 updateHighlight();
Matthew Nga8f24262017-12-19 11:54:24 -0800355 }
356
357 @Override
358 public void onDarkIntensityChange(float intensity) {
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700359 final float oldIntensity = mDarkIntensity;
Matthew Ng7090a802018-01-19 13:36:22 -0800360 mDarkIntensity = intensity;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700361
362 // When in quick scrub, invalidate gradient if changing intensity from black to white and
363 // vice-versa
364 if (mNavigationBarView.isQuickScrubEnabled()
365 && Math.round(intensity) != Math.round(oldIntensity)) {
366 updateHighlight();
367 }
Matthew Ng7090a802018-01-19 13:36:22 -0800368 mNavigationBarView.invalidate();
Matthew Nga8f24262017-12-19 11:54:24 -0800369 }
370
371 @Override
Matthew Nga8f24262017-12-19 11:54:24 -0800372 public void setBarState(boolean isVertical, boolean isRTL) {
Winson Chungd10ca302018-02-14 10:13:41 -0800373 final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
374 if (changed) {
375 // End quickscrub if the state changes mid-transition
376 endQuickScrub(false /* animate */);
377 }
Matthew Nga8f24262017-12-19 11:54:24 -0800378 mIsVertical = isVertical;
379 mIsRTL = isRTL;
380 try {
381 int navbarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
382 mDragPositive = navbarPos == NAV_BAR_LEFT || navbarPos == NAV_BAR_BOTTOM;
383 if (isRTL) {
384 mDragPositive = !mDragPositive;
385 }
386 } catch (RemoteException e) {
387 Slog.e(TAG, "Failed to get nav bar position.", e);
388 }
389 }
390
Matthew Ng2ea93b72018-03-14 19:43:18 +0000391 @Override
392 public void onNavigationButtonLongPress(View v) {
393 mAllowGestureDetection = false;
394 mHandler.removeCallbacksAndMessages(null);
395 }
396
397 private void startQuickStep(MotionEvent event) {
398 mQuickStepStarted = true;
399 event.transform(mTransformGlobalMatrix);
400 try {
401 mOverviewEventSender.getProxy().onQuickStep(event);
402 if (DEBUG_OVERVIEW_PROXY) {
403 Log.d(TAG_OPS, "Quick Step Start");
404 }
405 } catch (RemoteException e) {
406 Log.e(TAG, "Failed to send quick step started.", e);
407 } finally {
408 event.transform(mTransformLocalMatrix);
409 }
410 mOverviewEventSender.notifyQuickStepStarted();
Matthew Ng2ea93b72018-03-14 19:43:18 +0000411 mHandler.removeCallbacksAndMessages(null);
Matthew Ng9a223632018-03-30 16:47:22 -0700412
Winson Chung661d5f92018-05-21 18:41:39 -0700413 if (mHitTarget != null) {
414 mHitTarget.abortCurrentGesture();
415 }
416
417 if (mQuickScrubActive) {
Matthew Ng9a223632018-03-30 16:47:22 -0700418 animateEnd();
419 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000420 }
421
Matthew Nga8f24262017-12-19 11:54:24 -0800422 private void startQuickScrub() {
Winson Chung661d5f92018-05-21 18:41:39 -0700423 if (!mQuickScrubActive) {
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700424 updateHighlight();
Matthew Nga8f24262017-12-19 11:54:24 -0800425 mQuickScrubActive = true;
Winson Chung4baf1242018-05-24 14:21:57 -0700426 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
427 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
428 PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
Winson Chung661d5f92018-05-21 18:41:39 -0700429 trackAnimator.setInterpolator(ALPHA_IN);
430 trackAnimator.setDuration(ANIM_IN_DURATION_MS);
431 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
432 navBarAnimator.setInterpolator(ALPHA_OUT);
433 navBarAnimator.setDuration(ANIM_OUT_DURATION_MS);
434 mTrackAnimator = new AnimatorSet();
435 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
436 mTrackAnimator.start();
Matthew Ng6607c3d2018-04-26 15:23:27 -0700437
Matthew Ng472d3e42018-06-14 15:16:55 -0700438 // Disable slippery for quick scrub to not cancel outside the nav bar
439 mNavigationBarView.updateSlippery();
440
Matthew Nga8f24262017-12-19 11:54:24 -0800441 try {
442 mOverviewEventSender.getProxy().onQuickScrubStart();
Matthew Ngbd824572018-01-17 16:25:56 -0800443 if (DEBUG_OVERVIEW_PROXY) {
444 Log.d(TAG_OPS, "Quick Scrub Start");
445 }
Matthew Nga8f24262017-12-19 11:54:24 -0800446 } catch (RemoteException e) {
447 Log.e(TAG, "Failed to send start of quick scrub.", e);
448 }
Tracy Zhou27599052018-04-16 15:47:29 -0700449 mOverviewEventSender.notifyQuickScrubStarted();
Winson Chung661d5f92018-05-21 18:41:39 -0700450
451 if (mHitTarget != null) {
452 mHitTarget.abortCurrentGesture();
453 }
Matthew Nga8f24262017-12-19 11:54:24 -0800454 }
455 }
456
Winson Chungd10ca302018-02-14 10:13:41 -0800457 private void endQuickScrub(boolean animate) {
Winson Chung661d5f92018-05-21 18:41:39 -0700458 if (mQuickScrubActive) {
Matthew Nged166f92018-02-20 16:22:09 -0800459 animateEnd();
Winson Chung661d5f92018-05-21 18:41:39 -0700460 try {
461 mOverviewEventSender.getProxy().onQuickScrubEnd();
462 if (DEBUG_OVERVIEW_PROXY) {
463 Log.d(TAG_OPS, "Quick Scrub End");
Matthew Ngbd824572018-01-17 16:25:56 -0800464 }
Winson Chung661d5f92018-05-21 18:41:39 -0700465 } catch (RemoteException e) {
466 Log.e(TAG, "Failed to send end of quick scrub.", e);
Matthew Nga8f24262017-12-19 11:54:24 -0800467 }
Matthew Nged166f92018-02-20 16:22:09 -0800468 }
Winson Chung661d5f92018-05-21 18:41:39 -0700469 if (!animate) {
470 if (mTrackAnimator != null) {
471 mTrackAnimator.end();
472 mTrackAnimator = null;
473 }
Matthew Nga8f24262017-12-19 11:54:24 -0800474 }
Matthew Nga8f24262017-12-19 11:54:24 -0800475 }
476
Winson Chung661d5f92018-05-21 18:41:39 -0700477 private void animateEnd() {
478 if (mTrackAnimator != null) {
479 mTrackAnimator.cancel();
480 }
481
Winson Chung4baf1242018-05-24 14:21:57 -0700482 ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
483 PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
484 PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
Winson Chung661d5f92018-05-21 18:41:39 -0700485 trackAnimator.setInterpolator(ALPHA_OUT);
486 trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
487 ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
488 navBarAnimator.setInterpolator(ALPHA_IN);
489 navBarAnimator.setDuration(ANIM_IN_DURATION_MS);
490 mTrackAnimator = new AnimatorSet();
491 mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
492 mTrackAnimator.addListener(mQuickScrubEndListener);
493 mTrackAnimator.start();
494 }
495
496 private void resetQuickScrub() {
497 mQuickScrubActive = false;
498 mAllowGestureDetection = false;
499 mCurrentNavigationBarView = null;
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700500 updateHighlight();
501 }
502
503 private void updateHighlight() {
Matthew Ng908111d2018-06-26 15:22:56 -0700504 if (mTrackRect.isEmpty()) {
505 return;
506 }
Matthew Ng4fa3a9d2018-06-12 16:42:11 -0700507 int colorBase, colorGrad;
508 if (mDarkIntensity > 0.5f) {
509 colorBase = mContext.getColor(R.color.quick_step_track_background_background_dark);
510 colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_dark);
511 } else {
512 colorBase = mContext.getColor(R.color.quick_step_track_background_background_light);
513 colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_light);
514 }
515 mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
516 mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
517 Shader.TileMode.CLAMP);
518 mTrackPaint.setShader(mHighlight);
Winson Chung661d5f92018-05-21 18:41:39 -0700519 }
520
Matthew Ng2ea93b72018-03-14 19:43:18 +0000521 private boolean proxyMotionEvents(MotionEvent event) {
522 final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
523 event.transform(mTransformGlobalMatrix);
524 try {
525 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
526 overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
527 }
528 overviewProxy.onMotionEvent(event);
529 if (DEBUG_OVERVIEW_PROXY) {
530 Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
531 }
532 return true;
533 } catch (RemoteException e) {
534 Log.e(TAG, "Callback failed", e);
535 } finally {
536 event.transform(mTransformLocalMatrix);
Matthew Ngdb2734c2018-02-16 16:02:20 -0800537 }
Matthew Ng2ea93b72018-03-14 19:43:18 +0000538 return false;
Matthew Ngdb2734c2018-02-16 16:02:20 -0800539 }
Matthew Nga8f24262017-12-19 11:54:24 -0800540}