diff options
author | Doris Liu <tianliu@google.com> | 2015-04-10 21:47:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-10 21:47:25 +0000 |
commit | 02ecf04097fab8531788ddb941ff2b38ad9fd931 (patch) | |
tree | 4dd0298271aabd2d4766803c5c5784d13d4efdb3 /core/java/android/animation | |
parent | e144bb15d0d64656a1b9dcd587061063a63ac146 (diff) | |
parent | 0084e370955cfa1efbf8ab447ac5e71a5529f5d3 (diff) | |
download | frameworks_base-02ecf04097fab8531788ddb941ff2b38ad9fd931.zip frameworks_base-02ecf04097fab8531788ddb941ff2b38ad9fd931.tar.gz frameworks_base-02ecf04097fab8531788ddb941ff2b38ad9fd931.tar.bz2 |
Merge "Distance based animation duration"
Diffstat (limited to 'core/java/android/animation')
-rw-r--r-- | core/java/android/animation/Animator.java | 118 | ||||
-rw-r--r-- | core/java/android/animation/AnimatorInflater.java | 13 | ||||
-rw-r--r-- | core/java/android/animation/AnimatorSet.java | 1 | ||||
-rw-r--r-- | core/java/android/animation/ValueAnimator.java | 5 |
4 files changed, 136 insertions, 1 deletions
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index da48709..02a329d 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -16,7 +16,12 @@ package android.animation; +import android.content.res.Configuration; import android.content.res.ConstantState; +import android.content.res.Resources; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.animation.AnimationUtils; import java.util.ArrayList; @@ -25,6 +30,29 @@ import java.util.ArrayList; * started, ended, and have <code>AnimatorListeners</code> added to them. */ public abstract class Animator implements Cloneable { + /** + * Set this hint when duration for the animation does not need to be scaled. By default, no + * scaling is applied to the duration. + */ + public static final int HINT_NO_SCALE = 0; + + /** + * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)} when the animation's + * moving distance is proportional to the screen size. (e.g. a view coming in from the bottom of + * the screen to top/center). With this scale hint set, the animation duration will be + * automatically scaled based on screen size. + */ + public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; + + /** + * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)}) if the animation + * has pre-defined moving distance in dp that does not vary from device to device. This is + * extremely useful when the animation needs to run on both phones/tablets and TV, because TV + * has inflated dp and therefore will have a longer visual arc for the same animation than on + * the phone. This hint is used to calculate a scaling factor to compensate for different + * visual arcs while maintaining the same angular velocity for the animation. + */ + public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; /** * The set of listeners to be sent events through the life of an animation. @@ -55,6 +83,24 @@ public abstract class Animator implements Cloneable { private AnimatorConstantState mConstantState; /** + * Scaling factor for an animation that moves across the whole screen. + */ + float mScreenSizeBasedDurationScale = 1.0f; + + /** + * Scaling factor for an animation that is defined to move the same amount of dp across all + * devices. + */ + float mDpBasedDurationScale = 1.0f; + + /** + * By default, the scaling assumes the animation moves across the entire screen. + */ + int mDurationScaleHint = HINT_NO_SCALE; + + private final static boolean ANIM_DEBUG = false; + + /** * Starts this animation. If the animation has a nonzero startDelay, the animation will start * running after that delay elapses. A non-delayed animation will have its initial * value(s) set immediately, followed by calls to @@ -184,6 +230,78 @@ public abstract class Animator implements Cloneable { public abstract long getDuration(); /** + * Hints how duration scaling factor should be calculated. The duration will not be scaled when + * hint is set to {@link #HINT_NO_SCALE}. Otherwise, the duration will be automatically scaled + * per device to achieve the same look and feel across different devices. In order to do + * that, the same angular velocity of the animation will be needed on different devices in + * users' field of view. Therefore, the duration scale factor is determined by the ratio of the + * angular movement on current devices to that on the baseline device (i.e. Nexus 5). + * + * @param hint an indicator on how the animation is defined. The hint could be + * {@link #HINT_NO_SCALE}, {@link #HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE} or + * {@link #HINT_DISTANCE_DEFINED_IN_DP}. + * @param res The resources {@see android.content.res.Resources} for getting display metrics + */ + public void setDurationScaleHint(int hint, Resources res) { + if (ANIM_DEBUG) { + Log.d("ANIM_DEBUG", "distance based duration hint: " + hint); + } + if (hint == mDurationScaleHint) { + return; + } + mDurationScaleHint = hint; + if (hint != HINT_NO_SCALE) { + int uiMode = res.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK; + DisplayMetrics metrics = res.getDisplayMetrics(); + float width = metrics.widthPixels / metrics.xdpi; + float height = metrics.heightPixels / metrics.ydpi; + float viewingDistance = AnimationUtils.getViewingDistance(width, height, uiMode); + if (ANIM_DEBUG) { + Log.d("ANIM_DEBUG", "width, height, viewing distance, uimode: " + + width + ", " + height + ", " + viewingDistance + ", " + uiMode); + } + mScreenSizeBasedDurationScale = AnimationUtils + .getScreenSizeBasedDurationScale(width, height, viewingDistance); + mDpBasedDurationScale = AnimationUtils.getDpBasedDurationScale( + metrics.density, metrics.xdpi, viewingDistance); + if (ANIM_DEBUG) { + Log.d("ANIM_DEBUG", "screen based scale, dp based scale: " + + mScreenSizeBasedDurationScale + ", " + mDpBasedDurationScale); + } + } + } + + // Copies duration scale hint and scaling factors to the new animation. + void copyDurationScaleInfoTo(Animator anim) { + anim.mDurationScaleHint = mDurationScaleHint; + anim.mScreenSizeBasedDurationScale = mScreenSizeBasedDurationScale; + anim.mDpBasedDurationScale = mDpBasedDurationScale; + } + + /** + * @return The scaled duration calculated based on distance of movement (as defined by the + * animation) and perceived velocity (derived from the duration set on the animation for + * baseline device) + */ + public long getDistanceBasedDuration() { + return (long) (getDuration() * getDistanceBasedDurationScale()); + } + + /** + * @return scaling factor of duration based on the duration scale hint. A scaling factor of 1 + * means no scaling will be applied to the duration. + */ + float getDistanceBasedDurationScale() { + if (mDurationScaleHint == HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE) { + return mScreenSizeBasedDurationScale; + } else if (mDurationScaleHint == HINT_DISTANCE_DEFINED_IN_DP) { + return mDpBasedDurationScale; + } else { + return 1f; + } + } + + /** * The time interpolator used in calculating the elapsed fraction of the * animation. The interpolator determines whether the animation runs with * linear or non-linear motion, such as acceleration and deceleration. The diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 4a9ba3b..df5a4cb 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -70,6 +70,13 @@ public class AnimatorInflater { private static final int VALUE_TYPE_COLOR = 3; private static final int VALUE_TYPE_UNDEFINED = 4; + /** + * Enum values used in XML attributes to indicate the duration scale hint. + */ + private static final int HINT_NO_SCALE = 0; + private static final int HINT_PROPORTIONAL_TO_SCREEN = 1; + private static final int HINT_DEFINED_IN_DP = 2; + private static final boolean DBG_ANIMATOR_INFLATER = false; // used to calculate changing configs for resource references @@ -691,6 +698,9 @@ public class AnimatorInflater { int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, pixelSize); + final int hint = a.getInt(R.styleable.Animator_durationScaleHint, + HINT_NO_SCALE); + anim.setDurationScaleHint(hint, res); a.recycle(); } else if (name.equals("propertyValuesHolder")) { PropertyValuesHolder[] values = loadValues(res, theme, parser, @@ -1027,6 +1037,9 @@ public class AnimatorInflater { anim.setInterpolator(interpolator); } + final int hint = arrayAnimator.getInt(R.styleable.Animator_durationScaleHint, + HINT_NO_SCALE); + anim.setDurationScaleHint(hint, res); arrayAnimator.recycle(); if (arrayObjectAnimator != null) { arrayObjectAnimator.recycle(); diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 53d5237..dd5f18e 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -519,6 +519,7 @@ public final class AnimatorSet extends Animator { for (Node node : mNodes) { node.animation.setAllowRunningAsynchronously(false); + copyDurationScaleInfoTo(node.animation); } if (mDuration >= 0) { diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 6ffa5dd..275e78e 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -17,9 +17,12 @@ package android.animation; import android.annotation.CallSuper; +import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Looper; import android.os.Trace; import android.util.AndroidRuntimeException; +import android.util.DisplayMetrics; import android.util.Log; import android.view.Choreographer; import android.view.animation.AccelerateDecelerateInterpolator; @@ -561,7 +564,7 @@ public class ValueAnimator extends Animator { } private void updateScaledDuration() { - mDuration = (long)(mUnscaledDuration * sDurationScale); + mDuration = (long)(mUnscaledDuration * sDurationScale * getDistanceBasedDurationScale()); } /** |