summaryrefslogtreecommitdiffstats
path: root/core/java/android/animation
diff options
context:
space:
mode:
authorDoris Liu <tianliu@google.com>2015-04-10 12:39:35 -0700
committerDoris Liu <tianliu@google.com>2015-04-10 14:09:30 -0700
commit0084e370955cfa1efbf8ab447ac5e71a5529f5d3 (patch)
tree5d3c79d27d11c35e2b2ab55008169e7bfda3e45c /core/java/android/animation
parent94bf0d9157418d398325e7e8c1662923b848842e (diff)
downloadframeworks_base-0084e370955cfa1efbf8ab447ac5e71a5529f5d3.zip
frameworks_base-0084e370955cfa1efbf8ab447ac5e71a5529f5d3.tar.gz
frameworks_base-0084e370955cfa1efbf8ab447ac5e71a5529f5d3.tar.bz2
Distance based animation duration
In order to preserve the same look and feel of an animation across different devices, we need to maintain the same angular velocity for the animation in users' field of view. Since the animation path may span different angles on different devices, we need to therefore adjust the duration accordingly. Change-Id: Ia37f213e5a894a046edbb1a45a4ced04e406d85d
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 2386007..b0944ff 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());
}
/**