Fix seeking and scaled duration behavior
The animation scaled was not being factored in early enough in the
activity lifecycle. Also, setCurrentPlaytTime() was not accounting for
the scaled duration correctly. Finally, added setCurrentFraction() as
a more general-purpose seeking facility.
Issue #18222006 Animator duration scale ignored in some situations
Issue #17951668 add ability to seek fraction, not just time
Change-Id: Idad401f5ff5026d7046c36eee09d78a4793215dc
diff --git a/api/current.txt b/api/current.txt
index 46a0943..c0410d2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3111,6 +3111,7 @@
method public void removeAllUpdateListeners();
method public void removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
method public void reverse();
+ method public void setCurrentFraction(float);
method public void setCurrentPlayTime(long);
method public android.animation.ValueAnimator setDuration(long);
method public void setEvaluator(android.animation.TypeEvaluator);
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index f9aa00e..1738ade 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -1,5 +1,23 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.animation;
+import android.view.animation.AnimationUtils;
+
/**
* This class provides a simple callback mechanism to listeners that is synchronized with all
* other animators in the system. There is no duration, interpolation, or object value-setting
@@ -29,6 +47,13 @@
return false;
}
+ @Override
+ public void setCurrentPlayTime(long playTime) {
+ long currentTime = AnimationUtils.currentAnimationTimeMillis();
+ mStartTime = Math.max(mStartTime, currentTime - playTime);
+ animationFrame(currentTime);
+ }
+
/**
* Sets a listener that is sent update events throughout the life of
* an animation.
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 07f79b8..d65b490 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -79,7 +79,7 @@
* Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
* to a value.
*/
- long mSeekTime = -1;
+ float mSeekFraction = -1;
/**
* Set on the next frame after pause() is called, used to calculate a new startTime
@@ -537,14 +537,31 @@
* @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
*/
public void setCurrentPlayTime(long playTime) {
+ float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration :
+ playTime == 0 ? 0 : 1;
+ setCurrentFraction(fraction);
+ }
+
+ /**
+ * Sets the position of the animation to the specified fraction. This fraction should
+ * be between 0 and the total fraction of the animation, including any repetition. That is,
+ * a fraction of 0 will position the animation at the beginning, a value of 1 at the end,
+ * and a value of 2 at the beginning of a reversing animator that repeats once. If
+ * the animation has not yet been started, then it will not advance forward after it is
+ * set to this fraction; it will simply set the fraction to this value and perform any
+ * appropriate actions based on that fraction. If the animation is already running, then
+ * setCurrentFraction() will set the current fraction to this value and continue
+ * playing from that point.
+ *
+ * @param fraction The fraction to which the animation is advanced or rewound.
+ */
+ public void setCurrentFraction(float fraction) {
initAnimation();
- long currentTime = AnimationUtils.currentAnimationTimeMillis();
if (mPlayingState != RUNNING) {
- mSeekTime = playTime;
+ mSeekFraction = fraction;
mPlayingState = SEEKED;
}
- mStartTime = currentTime - playTime;
- doAnimationFrame(currentTime);
+ animateValue(fraction);
}
/**
@@ -948,6 +965,7 @@
}
mPlayingBackwards = playBackwards;
mCurrentIteration = 0;
+ int prevPlayingState = mPlayingState;
mPlayingState = STOPPED;
mStarted = true;
mStartedDelay = false;
@@ -957,7 +975,9 @@
animationHandler.mPendingAnimations.add(this);
if (mStartDelay == 0) {
// This sets the initial value of the animation, prior to actually starting it running
- setCurrentPlayTime(0);
+ if (prevPlayingState != SEEKED) {
+ setCurrentPlayTime(0);
+ }
mPlayingState = STOPPED;
mRunning = true;
notifyStartListeners();
@@ -1221,12 +1241,12 @@
final boolean doAnimationFrame(long frameTime) {
if (mPlayingState == STOPPED) {
mPlayingState = RUNNING;
- if (mSeekTime < 0) {
+ if (mSeekFraction < 0) {
mStartTime = frameTime;
} else {
- mStartTime = frameTime - mSeekTime;
- // Now that we're playing, reset the seek time
- mSeekTime = -1;
+ long seekTime = (long) (mDuration * mSeekFraction);
+ mStartTime = frameTime - seekTime;
+ mSeekFraction = -1;
}
}
if (mPaused) {
@@ -1292,7 +1312,7 @@
if (mUpdateListeners != null) {
anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
}
- anim.mSeekTime = -1;
+ anim.mSeekFraction = -1;
anim.mPlayingBackwards = false;
anim.mCurrentIteration = 0;
anim.mInitialized = false;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3de44e..98a096c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -84,6 +84,8 @@
import android.util.SuperNotCalledException;
import android.view.Display;
import android.view.HardwareRenderer;
+import android.view.IWindowManager;
+import android.view.IWindowSessionCallback;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
@@ -2366,6 +2368,9 @@
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
+ // Initialize before creating the activity
+ WindowManagerGlobal.initialize();
+
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 57f6028..a13a2ea 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3763,7 +3763,7 @@
* This flag is used to open a document into a new task rooted at the activity launched
* by this Intent. Through the use of this flag, or its equivalent attribute,
* {@link android.R.attr#documentLaunchMode} multiple instances of the same activity
- * containing different douments will appear in the recent tasks list.
+ * containing different documents will appear in the recent tasks list.
*
* <p>The use of the activity attribute form of this,
* {@link android.R.attr#documentLaunchMode}, is
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 82b1073..8e27834 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -124,6 +124,10 @@
private WindowManagerGlobal() {
}
+ public static void initialize() {
+ getWindowManagerService();
+ }
+
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
@@ -138,6 +142,12 @@
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
+ try {
+ sWindowManagerService = getWindowManagerService();
+ ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
+ }
}
return sWindowManagerService;
}
@@ -157,7 +167,6 @@
}
},
imm.getClient(), imm.getInputContext());
- ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}