Merge "Ensure to trigger Activity#onEnterAnimationComplete" into rvc-dev am: b749be45c7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11838100

Change-Id: Id86cf8c2b0dd45d1205dd1d851636612401a5e47
This commit is contained in:
Issei Suzuki
2020-06-12 11:43:59 +00:00
committed by Automerger Merge Worker
13 changed files with 164 additions and 114 deletions

View File

@@ -311,7 +311,6 @@ import com.android.server.uri.UriPermissionOwner;
import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
import com.android.server.wm.ActivityStack.ActivityState;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.utils.InsetUtils;
@@ -4166,14 +4165,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
boolean applyAnimation(LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
if (mUseTransferredAnimation) {
return false;
}
return super.applyAnimation(lp, transit, enter, isVoiceInteraction,
animationFinishedCallback);
return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources);
}
/**

View File

@@ -49,7 +49,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_W
import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -75,7 +75,6 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.function.Predicate;
/**
* Checks for app transition readiness, resolves animation attributes and performs visibility
* change for apps that animate as part of an app transition.
@@ -375,18 +374,14 @@ public class AppTransitionController {
// triggers WC#onAnimationFinished only on the promoted target. So we need to take care
// of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the
// app transition.
final ArrayList<ActivityRecord> transitioningDecendants = new ArrayList<>();
final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
for (int j = 0; j < apps.size(); ++j) {
final ActivityRecord app = apps.valueAt(j);
if (app.isDescendantOf(wc)) {
transitioningDecendants.add(app);
transitioningDescendants.add(app);
}
}
wc.applyAnimation(animLp, transit, visible, voiceInteraction, (type, anim) -> {
for (int j = 0; j < transitioningDecendants.size(); ++j) {
transitioningDecendants.get(j).onAnimationFinished(type, anim);
}
});
wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
}
}
@@ -540,7 +535,14 @@ public class AppTransitionController {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
app.commitVisibility(true /* visible */, false /* performLayout */);
if (!app.isAnimating(PARENTS | CHILDREN)) {
// In case a trampoline activity is used, it can happen that a new ActivityRecord is
// added and a new app transition starts before the previous app transition animation
// ends. So we cannot simply use app.isAnimating(PARENTS) to determine if the app must
// to be added to the list of tokens to be notified of app transition complete.
final WindowContainer wc = app.getAnimatingContainer(PARENTS,
ANIMATION_TYPE_APP_TRANSITION);
if (wc == null || !wc.getAnimationSources().contains(app)) {
// This token isn't going to be animating. Add it to the list of tokens to
// be notified of app transition complete since the notification will not be
// sent be the app window animator.
@@ -599,8 +601,7 @@ public class AppTransitionController {
for (int i = 0; i < appsCount; i++) {
WindowContainer wc = apps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc);
wc.applyAnimation(null, transit, true, false,
null /* animationFinishedCallback */);
wc.applyAnimation(null, transit, true, false, null /* sources */);
}
}

View File

@@ -22,7 +22,6 @@ import static com.android.server.wm.AlphaAnimationSpecProto.TO;
import static com.android.server.wm.AnimationSpecProto.ALPHA;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -31,7 +30,6 @@ import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -160,8 +158,7 @@ class Dimmer {
@VisibleForTesting
interface SurfaceAnimatorStarter {
void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
AnimationAdapter anim, boolean hidden, @AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback);
AnimationAdapter anim, boolean hidden, @AnimationType int type);
}
Dimmer(WindowContainer host) {
@@ -348,7 +345,7 @@ class Dimmer {
mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter(
new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)),
mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */,
ANIMATION_TYPE_DIMMER, null /* animationFinishedCallback */);
ANIMATION_TYPE_DIMMER);
}
private long getDimDuration(WindowContainer container) {

View File

@@ -280,7 +280,7 @@ class InsetsSourceProvider {
}
final Transaction t = mDisplayContent.getPendingTransaction();
mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
ANIMATION_TYPE_INSETS_CONTROL, null /* animationFinishedCallback */);
ANIMATION_TYPE_INSETS_CONTROL);
// The leash was just created. We cannot dispatch it until its surface transaction is
// applied. Otherwise, the client's operation to the leash might be overwritten by us.

View File

@@ -104,7 +104,7 @@ public class ShellRoot {
0 /* windowCornerRadius */),
mDisplayContent.mWmService.mSurfaceAnimationRunner);
mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */,
ANIMATION_TYPE_WINDOW_ANIMATION, null /* animationFinishedCallback */);
ANIMATION_TYPE_WINDOW_ANIMATION);
}
WindowInfo getWindowInfo() {

View File

@@ -85,7 +85,6 @@ import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK;
@@ -3495,7 +3494,7 @@ class Task extends WindowContainer<WindowContainer> {
@Override
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
int transit, boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback finishedCallback) {
@Nullable ArrayList<WindowContainer> sources) {
final RecentsAnimationController control = mWmService.getRecentsAnimationController();
if (control != null) {
// We let the transition to be controlled by RecentsAnimation, and callback task's
@@ -3504,10 +3503,14 @@ class Task extends WindowContainer<WindowContainer> {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"applyAnimationUnchecked, control: %s, task: %s, transit: %s",
control, asTask(), AppTransition.appTransitionToString(transit));
control.addTaskToTargets(this, finishedCallback);
control.addTaskToTargets(this, (type, anim) -> {
for (int i = 0; i < sources.size(); ++i) {
sources.get(i).onAnimationFinished(type, anim);
}
});
}
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
}
}

View File

@@ -64,6 +64,7 @@ import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
import android.os.Trace;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Pools;
import android.util.Slog;
@@ -181,6 +182,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
final SurfaceFreezer mSurfaceFreezer;
protected final WindowManagerService mWmService;
/**
* Sources which triggered a surface animation on this container. An animation target can be
* promoted to higher level, for example, from a set of {@link ActivityRecord}s to
* {@link ActivityStack}. In this case, {@link ActivityRecord}s are set on this variable while
* the animation is running, and reset after finishing it.
*/
private final ArraySet<WindowContainer> mSurfaceAnimationSources = new ArraySet<>();
private final Point mTmpPos = new Point();
protected final Point mLastSurfacePosition = new Point();
@@ -193,8 +202,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*/
private boolean mCommittedReparentToAnimationLeash;
private final Configuration mTmpConfig = new Configuration();
/** Interface for {@link #isAnimating} to check which cases for the container is animating. */
public interface AnimationFlags {
/**
@@ -872,29 +879,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @see AnimationFlags#PARENTS
* @see AnimationFlags#CHILDREN
*/
boolean isAnimating(int flags, int typesToCheck) {
int animationType = mSurfaceAnimator.getAnimationType();
if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) {
return true;
}
if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
return true;
}
if ((flags & PARENTS) != 0) {
final WindowContainer parent = getParent();
if (parent != null && parent.isAnimating(flags & ~CHILDREN, typesToCheck)) {
return true;
}
}
if ((flags & CHILDREN) != 0) {
for (int i = 0; i < mChildren.size(); ++i) {
final WindowContainer wc = mChildren.get(i);
if (wc.isAnimating(flags & ~PARENTS, typesToCheck)) {
return true;
}
}
}
return false;
final boolean isAnimating(int flags, int typesToCheck) {
return getAnimatingContainer(flags, typesToCheck) != null;
}
/**
@@ -904,16 +890,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* checking animating status.
* @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when
* checking if animating.
*
* @deprecated Use {@link #isAnimating(int, int)}
*/
boolean isAnimatingExcluding(int flags, int typesToExclude) {
@Deprecated
final boolean isAnimatingExcluding(int flags, int typesToExclude) {
return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude);
}
/**
* @see #isAnimating(int, int)
* @deprecated Use {@link #isAnimating(int, int)}
* TODO (b/152333373): Migrate calls to use isAnimating with specified animation type
*/
boolean isAnimating(int flags) {
@Deprecated
final boolean isAnimating(int flags) {
return isAnimating(flags, ANIMATION_TYPE_ALL);
}
@@ -2107,10 +2097,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
void cancelAnimation() {
doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
mSurfaceAnimator.cancelAnimation();
mSurfaceFreezer.unfreeze(getPendingTransaction());
}
ArraySet<WindowContainer> getAnimationSources() {
return mSurfaceAnimationSources;
}
@Override
public SurfaceControl getFreezeSnapshotTarget() {
return null;
@@ -2156,6 +2151,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @param transit The app transition type indicates what kind of transition to be applied.
* @param enter Whether the app transition is entering transition or not.
* @param isVoiceInteraction Whether the container is participating in voice interaction or not.
* @param sources {@link ActivityRecord}s which causes this app transition animation.
*
* @return {@code true} when the container applied the app transition, {@code false} if the
* app transition is disabled or skipped.
@@ -2163,7 +2159,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @see #getAnimationAdapter
*/
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction, @Nullable OnAnimationFinishedCallback finishedCallback) {
boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
if (mWmService.mDisableTransitionAnimation) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: transition animation is disabled or skipped. "
@@ -2178,7 +2174,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
if (okToAnimate()) {
applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
} else {
cancelAnimation();
}
@@ -2276,14 +2272,17 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
int transit, boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback finishedCallback) {
@Nullable ArrayList<WindowContainer> sources) {
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
transit, enter, isVoiceInteraction);
AnimationAdapter adapter = adapters.first;
AnimationAdapter thumbnailAdapter = adapters.second;
if (adapter != null) {
if (sources != null) {
mSurfaceAnimationSources.addAll(sources);
}
startAnimation(getPendingTransaction(), adapter, !isVisible(),
ANIMATION_TYPE_APP_TRANSITION, finishedCallback);
ANIMATION_TYPE_APP_TRANSITION);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
@@ -2411,10 +2410,18 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
updateSurfacePosition(t);
}
private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
}
mSurfaceAnimationSources.clear();
}
/**
* Called when an animation has finished running.
*/
protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
doAnimationFinished(type, anim);
mWmService.onAnimationFinished();
}
@@ -2428,16 +2435,66 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
/**
* @return The {@link WindowContainer} which is running an animation.
*
* It traverses from the current container to its parents recursively. If nothing is animating,
* it will return {@code null}.
* By default this only checks if this container itself is actually running an animation, but
* you can extend the check target over its relatives, or relax the condition so that this can
* return {@code WindowContainer} if an animation starts soon by giving a combination
* of {@link AnimationFlags}.
*
* Note that you can give a combination of bitmask flags to specify targets and condition for
* checking animating status.
* e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this
* container itself or one of its parents is running an animation or waiting for an app
* transition.
*
* Note that TRANSITION propagates to parents and children as well.
*
* @param flags The combination of bitmask flags to specify targets and condition for
* checking animating status.
* @param typesToCheck The combination of bitmask {@link AnimationType} to compare when
* determining if animating.
*
* @see AnimationFlags#TRANSITION
* @see AnimationFlags#PARENTS
* @see AnimationFlags#CHILDREN
*/
@Nullable
WindowContainer getAnimatingContainer() {
if (isAnimating()) {
WindowContainer getAnimatingContainer(int flags, int typesToCheck) {
int animationType = mSurfaceAnimator.getAnimationType();
if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) {
return this;
}
final WindowContainer parent = getParent();
return (parent != null) ? parent.getAnimatingContainer() : null;
if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
return this;
}
if ((flags & PARENTS) != 0) {
final WindowContainer parent = getParent();
if (parent != null) {
final WindowContainer wc = parent.getAnimatingContainer(
flags & ~CHILDREN, typesToCheck);
if (wc != null) {
return wc;
}
}
}
if ((flags & CHILDREN) != 0) {
for (int i = 0; i < mChildren.size(); ++i) {
final WindowContainer wc = mChildren.get(i).getAnimatingContainer(
flags & ~PARENTS, typesToCheck);
if (wc != null) {
return wc;
}
}
}
return null;
}
/**
* @deprecated Use {@link #getAnimatingContainer(int, int)} instead.
*/
@Nullable
@Deprecated
final WindowContainer getAnimatingContainer() {
return getAnimatingContainer(PARENTS, ANIMATION_TYPE_ALL);
}
/**

View File

@@ -133,15 +133,14 @@ class WindowContainerThumbnail implements Animatable {
mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(),
mWindowContainer.getDisplayContent().getWindowCornerRadius()),
mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */,
ANIMATION_TYPE_RECENTS, null /* animationFinishedCallback */);
ANIMATION_TYPE_RECENTS);
}
/**
* Start animation with existing adapter.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS,
null /* animationFinishedCallback */);
mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS);
}
private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {

View File

@@ -5049,16 +5049,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWindowFrames.updateLastInsetValues();
}
@Nullable
@Override
boolean isAnimating(int flags, int typesToCheck) {
// If we are an inset provider, all our animations are driven by the inset client, so we
// aren't really animating.
// TODO: Replace this with a proper animation type system.
WindowContainer<WindowState> getAnimatingContainer(int flags, int typesToCheck) {
if (mControllableInsetProvider != null) {
return false;
return null;
}
return super.isAnimating(flags, typesToCheck);
return super.getAnimatingContainer(flags, typesToCheck);
}
void startAnimation(Animation anim) {
@@ -5101,8 +5098,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private void startAnimation(Transaction t, AnimationAdapter adapter) {
startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION,
null /* animationFinishedCallback */);
startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);
}
@Override

View File

@@ -38,7 +38,6 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -65,12 +64,12 @@ import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
/**
* Tests for the {@link ActivityRecord} class.
*
@@ -406,12 +405,11 @@ public class AppWindowTokenTests extends WindowTestsBase {
assertHasStartingWindow(activity2);
// Assert that bottom activity is allowed to do animation.
ArrayList<WindowContainer> sources = new ArrayList<>();
sources.add(activity2);
doReturn(true).when(activity2).okToAnimate();
doReturn(true).when(activity2).isAnimating();
final OnAnimationFinishedCallback onAnimationFinishedCallback =
mock(OnAnimationFinishedCallback.class);
assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false,
onAnimationFinishedCallback));
assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false, sources));
}
@Test

View File

@@ -29,18 +29,14 @@ import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
import org.junit.Test;
@@ -119,12 +115,8 @@ public class DimmerTests extends WindowTestsBase {
private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter {
@Override
public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
AnimationAdapter anim, boolean hidden, @AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
AnimationAdapter anim, boolean hidden, @AnimationType int type) {
surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim);
if (animationFinishedCallback != null) {
animationFinishedCallback.onAnimationFinished(type, anim);
}
}
}
@@ -229,7 +221,7 @@ public class DimmerTests extends WindowTestsBase {
mDimmer.updateDims(mTransaction, new Rect());
verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
eq(ANIMATION_TYPE_DIMMER), isNull());
eq(ANIMATION_TYPE_DIMMER));
verify(mHost.getPendingTransaction()).remove(dimLayer);
}
@@ -287,7 +279,7 @@ public class DimmerTests extends WindowTestsBase {
mDimmer.updateDims(mTransaction, new Rect());
verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
eq(ANIMATION_TYPE_DIMMER), isNull());
eq(ANIMATION_TYPE_DIMMER));
verify(mTransaction).remove(dimLayer);
}

View File

@@ -153,7 +153,8 @@ public class TaskStackTests extends WindowTestsBase {
// Stack removal is deferred if one of its child is animating.
doReturn(true).when(stack).hasWindowsAlive();
doReturn(true).when(task).isAnimating(eq(TRANSITION | CHILDREN), anyInt());
doReturn(stack).when(task).getAnimatingContainer(
eq(TRANSITION | CHILDREN), anyInt());
stack.removeIfPossible();
// For the case of deferred removal the task controller will still be connected to the its

View File

@@ -66,14 +66,14 @@ import android.view.SurfaceSession;
import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Comparator;
/**
* Test class for {@link WindowContainer}.
*
@@ -828,17 +828,21 @@ public class WindowContainerTests extends WindowTestsBase {
public void testTaskCanApplyAnimation() {
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
final ActivityRecord activity =
final ActivityRecord activity2 =
WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
verifyWindowContainerApplyAnimation(task, activity);
final ActivityRecord activity1 =
WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
verifyWindowContainerApplyAnimation(task, activity1, activity2);
}
@Test
public void testStackCanApplyAnimation() {
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
createTaskInStack(stack, 0 /* userId */));
verifyWindowContainerApplyAnimation(stack, activity);
final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
createTaskInStack(stack, 0 /* userId */));
verifyWindowContainerApplyAnimation(stack, activity1, activity2);
}
@Test
@@ -871,7 +875,8 @@ public class WindowContainerTests extends WindowTestsBase {
assertEquals(displayArea, displayArea.getDisplayArea());
}
private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act) {
private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act,
ActivityRecord act2) {
// Initial remote animation for app transition.
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
new IRemoteAnimationRunner.Stub() {
@@ -895,17 +900,23 @@ public class WindowContainerTests extends WindowTestsBase {
wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter);
spyOn(wc);
doReturn(true).when(wc).okToAnimate();
final OnAnimationFinishedCallback onAnimationFinishedCallback =
mock(OnAnimationFinishedCallback.class);
// Make sure animating state is as expected after applied animation.
assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false,
onAnimationFinishedCallback));
assertEquals(wc.getTopMostActivity(), act);
// Animation target is promoted from act to wc. act2 is a descendant of wc, but not a source
// of the animation.
ArrayList<WindowContainer<WindowState>> sources = new ArrayList<>();
sources.add(act);
assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false, sources));
assertEquals(act, wc.getTopMostActivity());
assertTrue(wc.isAnimating());
assertTrue(wc.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION));
assertTrue(wc.getAnimationSources().contains(act));
assertFalse(wc.getAnimationSources().contains(act2));
assertTrue(act.isAnimating(PARENTS));
verify(onAnimationFinishedCallback, times(0)).onAnimationFinished(
eq(ANIMATION_TYPE_APP_TRANSITION), any());
assertTrue(act.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
assertEquals(wc, act.getAnimatingContainer(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
// Make sure animation finish callback will be received and reset animating state after
// animation finish.
@@ -914,8 +925,6 @@ public class WindowContainerTests extends WindowTestsBase {
verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any());
assertFalse(wc.isAnimating());
assertFalse(act.isAnimating(PARENTS));
verify(onAnimationFinishedCallback, times(1)).onAnimationFinished(
eq(ANIMATION_TYPE_APP_TRANSITION), any());
}
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */