summaryrefslogtreecommitdiffstats
path: root/core/java/android/animation
diff options
context:
space:
mode:
authorDoris Liu <tianliu@google.com>2015-04-10 21:47:12 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-10 21:47:25 +0000
commit02ecf04097fab8531788ddb941ff2b38ad9fd931 (patch)
tree4dd0298271aabd2d4766803c5c5784d13d4efdb3 /core/java/android/animation
parente144bb15d0d64656a1b9dcd587061063a63ac146 (diff)
parent0084e370955cfa1efbf8ab447ac5e71a5529f5d3 (diff)
downloadframeworks_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.java118
-rw-r--r--core/java/android/animation/AnimatorInflater.java13
-rw-r--r--core/java/android/animation/AnimatorSet.java1
-rw-r--r--core/java/android/animation/ValueAnimator.java5
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());
}
/**