From 0d1c27a713cb49de8f6f4fd0a129baa883153921 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Mon, 3 Nov 2014 18:35:16 +0000 Subject: [PATCH] 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 --- api/current.txt | 1 + core/java/android/animation/TimeAnimator.java | 25 +++++++++++ .../java/android/animation/ValueAnimator.java | 42 ++++++++++++++----- core/java/android/app/ActivityThread.java | 5 +++ core/java/android/content/Intent.java | 2 +- .../android/view/WindowManagerGlobal.java | 11 ++++- 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/api/current.txt b/api/current.txt index 46a09432d0e8f..c0410d24eed3f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3111,6 +3111,7 @@ package android.animation { 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 f9aa00ec25010..1738ade340802 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 @@ public class TimeAnimator extends ValueAnimator { 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 07f79b8b33a29..d65b4905a2ed7 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -79,7 +79,7 @@ public class ValueAnimator extends Animator { * 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 @@ public class ValueAnimator extends Animator { * @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 @@ public class ValueAnimator extends Animator { } mPlayingBackwards = playBackwards; mCurrentIteration = 0; + int prevPlayingState = mPlayingState; mPlayingState = STOPPED; mStarted = true; mStartedDelay = false; @@ -957,7 +975,9 @@ public class ValueAnimator extends Animator { 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 @@ public class ValueAnimator extends Animator { 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 @@ public class ValueAnimator extends Animator { if (mUpdateListeners != null) { anim.mUpdateListeners = new ArrayList(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 e3de44e45d89f..98a096c661be9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -84,6 +84,8 @@ import android.util.Slog; 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 @@ public final class ActivityThread { 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 57f6028cb7b5c..a13a2eab09f77 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3763,7 +3763,7 @@ public class Intent implements Parcelable, Cloneable { * 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. * *

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 82b1073c8bfcb..8e27834bf2bc8 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -124,6 +124,10 @@ public final class WindowManagerGlobal { private WindowManagerGlobal() { } + public static void initialize() { + getWindowManagerService(); + } + public static WindowManagerGlobal getInstance() { synchronized (WindowManagerGlobal.class) { if (sDefaultWindowManager == null) { @@ -138,6 +142,12 @@ public final class WindowManagerGlobal { 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 @@ public final class WindowManagerGlobal { } }, imm.getClient(), imm.getInputContext()); - ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale()); } catch (RemoteException e) { Log.e(TAG, "Failed to open window session", e); }