blob: 2980f11b3cbcc344a534142eac423412fc9400e0 [file] [log] [blame]
Hongwei Wang85cf41f2020-01-15 15:14:47 -08001/*
2 * Copyright (C) 2020 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.pip;
18
Tony Huang4b8795d2020-05-29 16:08:31 +080019import android.animation.AnimationHandler;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080020import android.animation.Animator;
21import android.animation.ValueAnimator;
22import android.annotation.IntDef;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080023import android.content.Context;
24import android.graphics.Rect;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080025import android.view.SurfaceControl;
26import android.view.animation.AnimationUtils;
27import android.view.animation.Interpolator;
28
29import com.android.internal.annotations.VisibleForTesting;
Tony Huang4b8795d2020-05-29 16:08:31 +080030import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080031
32import java.lang.annotation.Retention;
33import java.lang.annotation.RetentionPolicy;
34
Hongwei Wangec3cb3c2020-03-09 10:43:21 -070035import javax.inject.Inject;
36
Hongwei Wang85cf41f2020-01-15 15:14:47 -080037/**
38 * Controller class of PiP animations (both from and to PiP mode).
39 */
40public class PipAnimationController {
41 private static final float FRACTION_START = 0f;
42 private static final float FRACTION_END = 1f;
43
Hongwei Wang85cf41f2020-01-15 15:14:47 -080044 public static final int ANIM_TYPE_BOUNDS = 0;
45 public static final int ANIM_TYPE_ALPHA = 1;
46
47 @IntDef(prefix = { "ANIM_TYPE_" }, value = {
48 ANIM_TYPE_BOUNDS,
49 ANIM_TYPE_ALPHA
50 })
51 @Retention(RetentionPolicy.SOURCE)
52 public @interface AnimationType {}
53
Hongwei Wang221fe3d2020-03-26 13:13:04 -070054 public static final int TRANSITION_DIRECTION_NONE = 0;
55 public static final int TRANSITION_DIRECTION_SAME = 1;
56 public static final int TRANSITION_DIRECTION_TO_PIP = 2;
57 public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
Hongwei Wang5c52ff82020-04-20 16:02:30 -070058 public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
Hongwei Wangdf8bb002020-03-03 17:41:02 -080059
60 @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
61 TRANSITION_DIRECTION_NONE,
62 TRANSITION_DIRECTION_SAME,
63 TRANSITION_DIRECTION_TO_PIP,
Hongwei Wang5c52ff82020-04-20 16:02:30 -070064 TRANSITION_DIRECTION_TO_FULLSCREEN,
65 TRANSITION_DIRECTION_TO_SPLIT_SCREEN
Hongwei Wangdf8bb002020-03-03 17:41:02 -080066 })
67 @Retention(RetentionPolicy.SOURCE)
Hongwei Wang221fe3d2020-03-26 13:13:04 -070068 public @interface TransitionDirection {}
Hongwei Wangdf8bb002020-03-03 17:41:02 -080069
Winson Chungc4d4ee82020-05-05 12:51:06 -070070 public static boolean isInPipDirection(@TransitionDirection int direction) {
71 return direction == TRANSITION_DIRECTION_TO_PIP;
72 }
73
Hongwei Wang5c52ff82020-04-20 16:02:30 -070074 public static boolean isOutPipDirection(@TransitionDirection int direction) {
75 return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
76 || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
77 }
78
Winson Chungd7302542020-06-08 17:09:45 +000079 private final Interpolator mFastOutSlowInInterpolator;
Hongwei Wangec3cb3c2020-03-09 10:43:21 -070080 private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080081
82 private PipTransitionAnimator mCurrentAnimator;
83
Tony Huang4b8795d2020-05-29 16:08:31 +080084 private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
85 ThreadLocal.withInitial(() -> {
86 AnimationHandler handler = new AnimationHandler();
87 handler.setProvider(new SfVsyncFrameCallbackProvider());
88 return handler;
89 });
90
Hongwei Wangec3cb3c2020-03-09 10:43:21 -070091 @Inject
92 PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
Winson Chungd7302542020-06-08 17:09:45 +000093 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
94 com.android.internal.R.interpolator.fast_out_slow_in);
Hongwei Wangec3cb3c2020-03-09 10:43:21 -070095 mSurfaceTransactionHelper = helper;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080096 }
97
Hongwei Wangdf8bb002020-03-03 17:41:02 -080098 @SuppressWarnings("unchecked")
99 PipTransitionAnimator getAnimator(SurfaceControl leash,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800100 Rect destinationBounds, float alphaStart, float alphaEnd) {
101 if (mCurrentAnimator == null) {
102 mCurrentAnimator = setupPipTransitionAnimator(
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800103 PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800104 } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
105 && mCurrentAnimator.isRunning()) {
106 mCurrentAnimator.updateEndValue(alphaEnd);
107 } else {
108 mCurrentAnimator.cancel();
109 mCurrentAnimator = setupPipTransitionAnimator(
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800110 PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800111 }
112 return mCurrentAnimator;
113 }
114
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800115 @SuppressWarnings("unchecked")
Winson Chungd7302542020-06-08 17:09:45 +0000116 PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800117 if (mCurrentAnimator == null) {
118 mCurrentAnimator = setupPipTransitionAnimator(
Winson Chungd7302542020-06-08 17:09:45 +0000119 PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
Winson Chungc4d4ee82020-05-05 12:51:06 -0700120 } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
121 && mCurrentAnimator.isRunning()) {
122 // If we are still animating the fade into pip, then just move the surface and ensure
123 // we update with the new destination bounds, but don't interrupt the existing animation
124 // with a new bounds
125 mCurrentAnimator.setDestinationBounds(endBounds);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800126 } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
127 && mCurrentAnimator.isRunning()) {
128 mCurrentAnimator.setDestinationBounds(endBounds);
129 // construct new Rect instances in case they are recycled
130 mCurrentAnimator.updateEndValue(new Rect(endBounds));
131 } else {
132 mCurrentAnimator.cancel();
133 mCurrentAnimator = setupPipTransitionAnimator(
Winson Chungd7302542020-06-08 17:09:45 +0000134 PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800135 }
136 return mCurrentAnimator;
137 }
138
Hongwei Wang951dc022020-03-30 16:16:16 -0700139 PipTransitionAnimator getCurrentAnimator() {
140 return mCurrentAnimator;
141 }
142
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800143 private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) {
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700144 animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
Winson Chungd7302542020-06-08 17:09:45 +0000145 animator.setInterpolator(mFastOutSlowInInterpolator);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800146 animator.setFloatValues(FRACTION_START, FRACTION_END);
Tony Huang4b8795d2020-05-29 16:08:31 +0800147 animator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800148 return animator;
149 }
150
151 /**
152 * Additional callback interface for PiP animation
153 */
154 public static class PipAnimationCallback {
155 /**
156 * Called when PiP animation is started.
157 */
Winson Chung55701472020-03-04 19:30:30 -0800158 public void onPipAnimationStart(PipTransitionAnimator animator) {}
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800159
160 /**
161 * Called when PiP animation is ended.
162 */
Winson Chung55701472020-03-04 19:30:30 -0800163 public void onPipAnimationEnd(SurfaceControl.Transaction tx,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800164 PipTransitionAnimator animator) {}
165
166 /**
167 * Called when PiP animation is cancelled.
168 */
Winson Chung55701472020-03-04 19:30:30 -0800169 public void onPipAnimationCancel(PipTransitionAnimator animator) {}
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800170 }
171
172 /**
173 * Animator for PiP transition animation which supports both alpha and bounds animation.
174 * @param <T> Type of property to animate, either alpha (float) or bounds (Rect)
175 */
176 public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
177 ValueAnimator.AnimatorUpdateListener,
178 ValueAnimator.AnimatorListener {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800179 private final SurfaceControl mLeash;
180 private final @AnimationType int mAnimationType;
181 private final Rect mDestinationBounds = new Rect();
182
Tony Huang5ebe0192020-05-15 19:27:54 +0800183 protected T mCurrentValue;
184 protected T mStartValue;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800185 private T mEndValue;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800186 private PipAnimationCallback mPipAnimationCallback;
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700187 private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
188 mSurfaceControlTransactionFactory;
189 private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800190 private @TransitionDirection int mTransitionDirection;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800191
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800192 private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType,
193 Rect destinationBounds, T startValue, T endValue) {
Winson Chung55701472020-03-04 19:30:30 -0800194 mLeash = leash;
195 mAnimationType = animationType;
196 mDestinationBounds.set(destinationBounds);
197 mStartValue = startValue;
198 mEndValue = endValue;
199 addListener(this);
200 addUpdateListener(this);
201 mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800202 mTransitionDirection = TRANSITION_DIRECTION_NONE;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800203 }
204
205 @Override
206 public void onAnimationStart(Animator animation) {
207 mCurrentValue = mStartValue;
Hongwei Wang09c1f042020-03-18 13:47:45 -0700208 onStartTransaction(mLeash, newSurfaceControlTransaction());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800209 if (mPipAnimationCallback != null) {
Winson Chung55701472020-03-04 19:30:30 -0800210 mPipAnimationCallback.onPipAnimationStart(this);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800211 }
212 }
213
214 @Override
215 public void onAnimationUpdate(ValueAnimator animation) {
216 applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(),
217 animation.getAnimatedFraction());
218 }
219
220 @Override
221 public void onAnimationEnd(Animator animation) {
222 mCurrentValue = mEndValue;
223 final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
Hongwei Wang09c1f042020-03-18 13:47:45 -0700224 onEndTransaction(mLeash, tx);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800225 if (mPipAnimationCallback != null) {
Winson Chung55701472020-03-04 19:30:30 -0800226 mPipAnimationCallback.onPipAnimationEnd(tx, this);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800227 }
228 }
229
230 @Override
231 public void onAnimationCancel(Animator animation) {
232 if (mPipAnimationCallback != null) {
Winson Chung55701472020-03-04 19:30:30 -0800233 mPipAnimationCallback.onPipAnimationCancel(this);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800234 }
235 }
236
237 @Override public void onAnimationRepeat(Animator animation) {}
238
239 @AnimationType int getAnimationType() {
240 return mAnimationType;
241 }
242
243 PipTransitionAnimator<T> setPipAnimationCallback(PipAnimationCallback callback) {
244 mPipAnimationCallback = callback;
245 return this;
246 }
247
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800248 @TransitionDirection int getTransitionDirection() {
249 return mTransitionDirection;
250 }
251
252 PipTransitionAnimator<T> setTransitionDirection(@TransitionDirection int direction) {
253 if (direction != TRANSITION_DIRECTION_SAME) {
254 mTransitionDirection = direction;
255 }
256 return this;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800257 }
258
259 T getStartValue() {
260 return mStartValue;
261 }
262
263 T getEndValue() {
264 return mEndValue;
265 }
266
267 Rect getDestinationBounds() {
268 return mDestinationBounds;
269 }
270
271 void setDestinationBounds(Rect destinationBounds) {
272 mDestinationBounds.set(destinationBounds);
Hongwei Wang951dc022020-03-30 16:16:16 -0700273 if (mAnimationType == ANIM_TYPE_ALPHA) {
274 onStartTransaction(mLeash, newSurfaceControlTransaction());
275 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800276 }
277
278 void setCurrentValue(T value) {
279 mCurrentValue = value;
280 }
281
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800282 boolean shouldApplyCornerRadius() {
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700283 return !isOutPipDirection(mTransitionDirection);
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800284 }
285
Hongwei Wang09c1f042020-03-18 13:47:45 -0700286 boolean inScaleTransition() {
287 if (mAnimationType != ANIM_TYPE_BOUNDS) return false;
Winson Chungc4d4ee82020-05-05 12:51:06 -0700288 return !isInPipDirection(getTransitionDirection());
Hongwei Wang09c1f042020-03-18 13:47:45 -0700289 }
290
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800291 /**
292 * Updates the {@link #mEndValue}.
293 *
294 * NOTE: Do not forget to call {@link #setDestinationBounds(Rect)} for bounds animation.
295 * This is typically used when we receive a shelf height adjustment during the bounds
296 * animation. In which case we can update the end bounds and keep the existing animation
297 * running instead of cancelling it.
298 */
299 void updateEndValue(T endValue) {
300 mEndValue = endValue;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800301 }
302
303 SurfaceControl.Transaction newSurfaceControlTransaction() {
304 return mSurfaceControlTransactionFactory.getTransaction();
305 }
306
307 @VisibleForTesting
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700308 void setSurfaceControlTransactionFactory(
309 PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800310 mSurfaceControlTransactionFactory = factory;
311 }
312
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700313 PipSurfaceTransactionHelper getSurfaceTransactionHelper() {
314 return mSurfaceTransactionHelper;
315 }
316
317 void setSurfaceTransactionHelper(PipSurfaceTransactionHelper helper) {
318 mSurfaceTransactionHelper = helper;
319 }
320
Hongwei Wang09c1f042020-03-18 13:47:45 -0700321 void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {}
322
323 void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {}
324
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800325 abstract void applySurfaceControlTransaction(SurfaceControl leash,
326 SurfaceControl.Transaction tx, float fraction);
327
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800328 static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800329 Rect destinationBounds, float startValue, float endValue) {
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800330 return new PipTransitionAnimator<Float>(leash, ANIM_TYPE_ALPHA,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800331 destinationBounds, startValue, endValue) {
332 @Override
333 void applySurfaceControlTransaction(SurfaceControl leash,
334 SurfaceControl.Transaction tx, float fraction) {
335 final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction;
336 setCurrentValue(alpha);
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700337 getSurfaceTransactionHelper().alpha(tx, leash, alpha);
Hongwei Wang09c1f042020-03-18 13:47:45 -0700338 tx.apply();
339 }
340
341 @Override
342 void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
343 getSurfaceTransactionHelper()
344 .crop(tx, leash, getDestinationBounds())
345 .round(tx, leash, shouldApplyCornerRadius());
Winson Chung1b5d0552020-04-06 19:28:49 -0700346 tx.show(leash);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800347 tx.apply();
348 }
Tony Huang5ebe0192020-05-15 19:27:54 +0800349
350 @Override
351 void updateEndValue(Float endValue) {
352 super.updateEndValue(endValue);
353 mStartValue = mCurrentValue;
354 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800355 };
356 }
357
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800358 static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
Winson Chungd7302542020-06-08 17:09:45 +0000359 Rect startValue, Rect endValue) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800360 // construct new Rect instances in case they are recycled
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800361 return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800362 endValue, new Rect(startValue), new Rect(endValue)) {
Winson Chungd7302542020-06-08 17:09:45 +0000363 private final Rect mTmpRect = new Rect();
364
365 private int getCastedFractionValue(float start, float end, float fraction) {
366 return (int) (start * (1 - fraction) + end * fraction + .5f);
367 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800368
369 @Override
370 void applySurfaceControlTransaction(SurfaceControl leash,
371 SurfaceControl.Transaction tx, float fraction) {
372 final Rect start = getStartValue();
373 final Rect end = getEndValue();
Winson Chungd7302542020-06-08 17:09:45 +0000374 mTmpRect.set(
375 getCastedFractionValue(start.left, end.left, fraction),
376 getCastedFractionValue(start.top, end.top, fraction),
377 getCastedFractionValue(start.right, end.right, fraction),
378 getCastedFractionValue(start.bottom, end.bottom, fraction));
379 setCurrentValue(mTmpRect);
Hongwei Wang09c1f042020-03-18 13:47:45 -0700380 if (inScaleTransition()) {
Winson Chungc4d4ee82020-05-05 12:51:06 -0700381 if (isOutPipDirection(getTransitionDirection())) {
Winson Chungd7302542020-06-08 17:09:45 +0000382 getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect);
Winson Chungc4d4ee82020-05-05 12:51:06 -0700383 } else {
Winson Chungd7302542020-06-08 17:09:45 +0000384 getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
Winson Chungc4d4ee82020-05-05 12:51:06 -0700385 }
Hongwei Wang09c1f042020-03-18 13:47:45 -0700386 } else {
Winson Chungd7302542020-06-08 17:09:45 +0000387 getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800388 }
389 tx.apply();
390 }
Hongwei Wang09c1f042020-03-18 13:47:45 -0700391
392 @Override
393 void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
394 getSurfaceTransactionHelper()
395 .alpha(tx, leash, 1f)
396 .round(tx, leash, shouldApplyCornerRadius());
Winson Chung1b5d0552020-04-06 19:28:49 -0700397 tx.show(leash);
Hongwei Wang09c1f042020-03-18 13:47:45 -0700398 tx.apply();
399 }
400
401 @Override
402 void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
Winson Chungd7302542020-06-08 17:09:45 +0000403 if (!inScaleTransition()) return;
Hongwei Wang09c1f042020-03-18 13:47:45 -0700404 // NOTE: intentionally does not apply the transaction here.
405 // this end transaction should get executed synchronously with the final
406 // WindowContainerTransaction in task organizer
Winson Chungd7302542020-06-08 17:09:45 +0000407 getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
Robert Carrb80a55c2020-05-05 15:17:51 -0700408 .crop(tx, leash, getDestinationBounds());
Hongwei Wang09c1f042020-03-18 13:47:45 -0700409 }
Tony Huang5ebe0192020-05-15 19:27:54 +0800410
411 @Override
412 void updateEndValue(Rect endValue) {
413 super.updateEndValue(endValue);
414 if (mStartValue != null && mCurrentValue != null) {
415 mStartValue.set(mCurrentValue);
416 }
417 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800418 };
419 }
420 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800421}