Add methods to query animation state

Testing utilities want the ability to know whether things in the UI
are in flux and they need to wait before testing on-screen values.
These changes (a subset of what's needed, but will have to do for
a start) allow querying of ActivityTransitions and ProgressBar, two
common/difficult pieces in the puzzle.

Test: CTS tests at ag/1835467
Bug: 30978257 Provide view transition Api to prevent flaky tests

Change-Id: If63b3d0dde2178d826ac1dbfad0fc50e5ed9a780
This commit is contained in:
Chet Haase
2016-12-09 07:17:10 -08:00
parent b3231029b5
commit b64e777f6c
10 changed files with 69 additions and 1 deletions

View File

@@ -3553,6 +3553,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
method public boolean isActivityTransitionRunning();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
@@ -49235,6 +49236,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();

View File

@@ -3675,6 +3675,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
method public boolean isActivityTransitionRunning();
method public boolean isBackgroundVisibleBehind();
method public boolean isChangingConfigurations();
method public final boolean isChild();
@@ -53001,6 +53002,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();

View File

@@ -3555,6 +3555,7 @@ package android.app {
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
method public boolean isActivityTransitionRunning();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
@@ -49554,6 +49555,7 @@ package android.widget {
method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
method public boolean isAnimating();
method public synchronized boolean isIndeterminate();
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();

View File

@@ -4326,6 +4326,18 @@ public class Activity extends ContextThemeWrapper
}
}
/**
* Returns whether there are any activity transitions currently running on this
* activity. A return value of {@code true} can mean that either an enter or
* exit transition is running, including whether the background of the activity
* is animating as a part of that transition.
*
* @return true if a transition is currently running on this activity, false otherwise.
*/
public boolean isActivityTransitionRunning() {
return mActivityTransitionState.isTransitionRunning();
}
private Bundle transferSpringboardActivityOptions(Bundle options) {
if (options == null && (mWindow != null && !mWindow.isActive())) {
final ActivityOptions activityOptions = getActivityOptions();

View File

@@ -208,6 +208,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
private ArrayList<Matrix> mSharedElementParentMatrices;
private boolean mSharedElementTransitionComplete;
private boolean mViewsTransitionComplete;
private boolean mBackgroundAnimatorComplete;
private ArrayList<View> mStrippedTransitioningViews = new ArrayList<>();
public ActivityTransitionCoordinator(Window window,
@@ -884,6 +885,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
startInputWhenTransitionsComplete();
}
protected void backgroundAnimatorComplete() {
mBackgroundAnimatorComplete = true;
}
protected void sharedElementTransitionComplete() {
mSharedElementTransitionComplete = true;
startInputWhenTransitionsComplete();
@@ -966,6 +971,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
}
public boolean isTransitionRunning() {
return !(mViewsTransitionComplete && mSharedElementTransitionComplete &&
mBackgroundAnimatorComplete);
}
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;

View File

@@ -336,6 +336,26 @@ class ActivityTransitionState {
}
}
public boolean isTransitionRunning() {
// Note that *only* enter *or* exit will be running at any given time
if (mEnterTransitionCoordinator != null) {
if (mEnterTransitionCoordinator.isTransitionRunning()) {
return true;
}
}
if (mCalledExitCoordinator != null) {
if (mCalledExitCoordinator.isTransitionRunning()) {
return true;
}
}
if (mReturnExitCoordinator != null) {
if (mReturnExitCoordinator.isTransitionRunning()) {
return true;
}
}
return false;
}
public void startExitOutTransition(Activity activity, Bundle options) {
mEnterTransitionCoordinator = null;
if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||

View File

@@ -587,6 +587,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
public void onAnimationEnd(Animator animation) {
makeOpaque();
backgroundAnimatorComplete();
}
});
mBackgroundAnimator.start();
@@ -598,9 +599,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
makeOpaque();
}
});
backgroundAnimatorComplete();
} else {
makeOpaque();
backgroundAnimatorComplete();
}
} else {
backgroundAnimatorComplete();
}
}

View File

@@ -201,6 +201,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
public void startExit() {
if (!mIsExitStarted) {
backgroundAnimatorComplete();
mIsExitStarted = true;
pauseInput();
ViewGroup decorView = getDecor();
@@ -303,11 +304,13 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
mIsBackgroundReady = true;
notifyComplete();
}
backgroundAnimatorComplete();
}
});
mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.start();
} else {
backgroundAnimatorComplete();
mIsBackgroundReady = true;
}
}

View File

@@ -1924,7 +1924,7 @@ public abstract class Window {
public Transition getEnterTransition() { return null; }
/**
* Returns he Transition that will be used to move Views out of the scene when the Window is
* Returns the Transition that will be used to move Views out of the scene when the Window is
* preparing to close, for example after a call to
* {@link android.app.Activity#finishAfterTransition()}. The exiting
* Views will be those that are regular Views or ViewGroups that have

View File

@@ -2057,6 +2057,18 @@ public class ProgressBar extends View {
stream.addProperty("progress:indeterminate", isIndeterminate());
}
/**
* Returns whether the ProgressBar is animating or not. This is essentially the same
* as whether the ProgressBar is {@link #isIndeterminate() indeterminate} and visible,
* as indeterminate ProgressBars are always animating, and non-indeterminate
* ProgressBars are not animating.
*
* @return true if the ProgressBar is animating, false otherwise.
*/
public boolean isAnimating() {
return isIndeterminate() && getWindowVisibility() == VISIBLE && isShown();
}
/**
* Command for sending an accessibility event.
*/