• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.N;
4 import static org.robolectric.util.reflector.Reflector.reflector;
5 
6 import android.animation.AnimationHandler;
7 import android.animation.ValueAnimator;
8 import android.app.UiAutomation;
9 import org.robolectric.RuntimeEnvironment;
10 import org.robolectric.annotation.Implementation;
11 import org.robolectric.annotation.Implements;
12 import org.robolectric.annotation.RealObject;
13 import org.robolectric.annotation.Resetter;
14 import org.robolectric.util.ReflectionHelpers;
15 import org.robolectric.util.reflector.Accessor;
16 import org.robolectric.util.reflector.Direct;
17 import org.robolectric.util.reflector.ForType;
18 import org.robolectric.util.reflector.Static;
19 
20 @Implements(ValueAnimator.class)
21 public class ShadowValueAnimator {
22 
23   @RealObject private ValueAnimator realObject;
24 
25   private int actualRepeatCount;
26 
27   @Resetter
reset()28   public static void reset() {
29     /* ValueAnimator.sAnimationHandler is a static thread local that otherwise would survive between
30      * tests. The AnimationHandler.mAnimationScheduled is set to true when the scheduleAnimation() is
31      * called and the reset to false when run() is called by the Choreographer. If an animation is
32      * already scheduled, it will not post to the Choreographer. This is a problem if a previous
33      * test leaves animations on the Choreographers callback queue without running them as it will
34      * cause the AnimationHandler not to post a callback. We reset the thread local here so a new
35      * one will be created for each test with a fresh state.
36      */
37     if (RuntimeEnvironment.getApiLevel() >= N) {
38       ThreadLocal<AnimationHandler> animatorHandlerTL =
39           ReflectionHelpers.getStaticField(AnimationHandler.class, "sAnimatorHandler");
40       animatorHandlerTL.remove();
41     } else {
42       ReflectionHelpers.callStaticMethod(ValueAnimator.class, "clearAllAnimations");
43       ThreadLocal<AnimationHandler> animatorHandlerTL =
44           ReflectionHelpers.getStaticField(ValueAnimator.class, "sAnimationHandler");
45       animatorHandlerTL.remove();
46     }
47 
48     setDurationScale(1);
49   }
50 
51   @Implementation
setRepeatCount(int count)52   protected void setRepeatCount(int count) {
53     actualRepeatCount = count;
54     if (count == ValueAnimator.INFINITE) {
55       count = 1;
56     }
57     reflector(ValueAnimatorReflector.class, realObject).setRepeatCount(count);
58   }
59 
60   /**
61    * Returns the value that was set as the repeat count. This is otherwise the same as
62    * getRepeatCount(), except when the count was set to infinite.
63    *
64    * @return Repeat count.
65    */
getActualRepeatCount()66   public int getActualRepeatCount() {
67     return actualRepeatCount;
68   }
69 
70   /**
71    * Sets the duration scale for value animator. To set this value use {@link
72    * UiAutomation#setAnimationScale(float)} or {@link
73    * ShadowUiAutomation#setAnimationScaleCompat(float)}.
74    */
75   @Implementation
setDurationScale(float duration)76   protected static void setDurationScale(float duration) {
77     reflector(ValueAnimatorReflector.class, null).setDurationScale(duration);
78   }
79 
80   @ForType(ValueAnimator.class)
81   interface ValueAnimatorReflector {
82 
83     @Direct
setRepeatCount(int count)84     void setRepeatCount(int count);
85 
86     @Static
87     @Accessor("sDurationScale")
setDurationScale(float duration)88     void setDurationScale(float duration);
89   }
90 }
91