diff options
| author | 2025-02-10 18:01:52 -0800 | |
|---|---|---|
| committer | 2025-02-10 18:01:52 -0800 | |
| commit | a61edd0dc9cc07a67ec808506a2fae2f0a22b47c (patch) | |
| tree | d5e966470239812825576c8beae160509a452931 | |
| parent | 4c2d1bb9d7c0d7a02d92bf5e8181bd0fefd553c2 (diff) | |
| parent | 781b21497ef9817c731df04e8341a530cc6327ec (diff) | |
Merge "Remove AppTransitionController" into main
18 files changed, 29 insertions, 3586 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d84016b3816e..e3070ef31dcc 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -113,7 +113,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED; import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING; import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static android.view.WindowManager.TRANSIT_RELAUNCH; import static android.view.WindowManager.hasWindowExtensionsEnabled; @@ -856,12 +855,6 @@ final class ActivityRecord extends WindowToken { }) @interface SplashScreenBehavior { } - // Force an app transition to be ran in the case the visibility of the app did not change. - // We use this for the case of moving a Root Task to the back with multiple activities, and the - // top activity enters PIP; the bottom activity's visibility stays the same, but we need to - // run the transition. - boolean mRequestForceTransition; - boolean mEnteringAnimation; boolean mOverrideTaskTransition; boolean mDismissKeyguardIfInsecure; @@ -1788,7 +1781,6 @@ final class ActivityRecord extends WindowToken { if (prevDc.mOpeningApps.remove(this)) { // Transfer opening transition to new display. mDisplayContent.mOpeningApps.add(this); - mDisplayContent.transferAppTransitionFrom(prevDc); mDisplayContent.executeAppTransition(); } @@ -4631,12 +4623,6 @@ final class ActivityRecord extends WindowToken { } } - // In this case, the starting icon has already been displayed, so start - // letting windows get shown immediately without any more transitions. - if (fromActivity.mVisible) { - mDisplayContent.mSkipAppTransitionAnimation = true; - } - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s" + " from %s to %s", tStartingWindow, fromActivity, this); @@ -5667,76 +5653,17 @@ final class ActivityRecord extends WindowToken { mTransitionController.mValidateCommitVis.add(this); return; } - // If we are preparing an app transition, then delay changing - // the visibility of this token until we execute that transition. - if (deferCommitVisibilityChange(visible)) { - return; - } commitVisibility(visible, true /* performLayout */); updateReportedVisibilityLocked(); } - /** - * Returns {@code true} if this activity is either added to opening-apps or closing-apps. - * Then its visibility will be committed until the transition is ready. - */ - private boolean deferCommitVisibilityChange(boolean visible) { - if (mTransitionController.isShellTransitionsEnabled()) { - // Shell transition doesn't use opening/closing sets. - return false; - } - if (!mDisplayContent.mAppTransition.isTransitionSet()) { - return false; - } - if (mWaitForEnteringPinnedMode && mVisible == visible) { - // If the visibility is not changed during enter PIP, we don't want to include it in - // app transition to affect the animation theme, because the Pip organizer will - // animate the entering PIP instead. - return false; - } - - // The animation will be visible soon so do not skip by screen off. - final boolean ignoreScreenOn = canTurnScreenOn() || mTaskSupervisor.getKeyguardController() - .isKeyguardGoingAway(mDisplayContent.mDisplayId); - // Ignore display frozen so the opening / closing transition type can be updated correctly - // even if the display is frozen. And it's safe since in applyAnimation will still check - // DC#okToAnimate again if the transition animation is fine to apply. - if (!okToAnimate(true /* ignoreFrozen */, ignoreScreenOn)) { - return false; - } - if (visible) { - mDisplayContent.mOpeningApps.add(this); - mEnteringAnimation = true; - } else if (mVisible) { - mDisplayContent.mClosingApps.add(this); - mEnteringAnimation = false; - } - if ((mDisplayContent.mAppTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0) { - // Add the launching-behind activity to mOpeningApps. - final WindowState win = mDisplayContent.findFocusedWindow(); - if (win != null) { - final ActivityRecord focusedActivity = win.mActivityRecord; - if (focusedActivity != null) { - ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, - "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", - focusedActivity); - // Force animation to be loaded. - mDisplayContent.mOpeningApps.add(focusedActivity); - } - } - } - return true; - } - @Override boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) { if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { return false; } - // If it was set to true, reset the last request to force the transition. - mRequestForceTransition = false; return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources); } @@ -5899,27 +5826,6 @@ final class ActivityRecord extends WindowToken { } /** - * Check if visibility of this {@link ActivityRecord} should be updated as part of an app - * transition. - * - * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is - * already set to {@link #mVisible}, we don't need to update the visibility. So {@code false} is - * returned.</p> - * - * @param visible {@code true} if this {@link ActivityRecord} should become visible, - * {@code false} if this should become invisible. - * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and - * an app transition animation should be run. - */ - boolean shouldApplyAnimation(boolean visible) { - // Allow for state update and animation to be applied if: - // * activity is transitioning visibility state - // * or the activity was marked as hidden and is exiting before we had a chance to play the - // transition animation - return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting); - } - - /** * See {@link Activity#setRecentsScreenshotEnabled}. */ void setRecentsScreenshotEnabled(boolean enabled) { @@ -7670,17 +7576,7 @@ final class ActivityRecord extends WindowToken { // new layer. if (mNeedsAnimationBoundsLayer) { mTmpRect.setEmpty(); - if (getDisplayContent().mAppTransitionController.isTransitWithinTask( - getTransit(), task)) { - task.getBounds(mTmpRect); - } else { - final Task rootTask = getRootTask(); - if (rootTask == null) { - return; - } - // Set clip rect to root task bounds. - rootTask.getBounds(mTmpRect); - } + task.getBounds(mTmpRect); mAnimationBoundsLayer = createAnimationBoundsLayer(t); // Crop to root task bounds. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 254127dee7a8..819e117e6d05 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4128,22 +4128,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void registerRemoteAnimationsForDisplay(int displayId, RemoteAnimationDefinition definition) { - mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, - "registerRemoteAnimations"); - definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); - synchronized (mGlobalLock) { - final DisplayContent display = mRootWindowContainer.getDisplayContent(displayId); - if (display == null) { - Slog.e(TAG, "Couldn't find display with id: " + displayId); - return; - } - final long origId = Binder.clearCallingIdentity(); - try { - display.registerRemoteAnimations(definition); - } finally { - Binder.restoreCallingIdentity(origId); - } - } + // TODO(b/365884835): Remove callers. } /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */ diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 932f26857105..9c4b722feb47 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1462,7 +1462,7 @@ public class AppTransition implements Dump { } boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) { - if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { + if (WindowManagerService.sEnableShellTransitions) { return false; } mNextAppTransitionRequests.add(transit); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java deleted file mode 100644 index d5fe056a2ba4..000000000000 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * Copyright (C) 2018 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 com.android.server.wm; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; -import static android.view.WindowManager.TRANSIT_CHANGE; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; -import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; -import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH; -import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; -import static android.view.WindowManager.TRANSIT_OLD_NONE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK; -import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT; -import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_OPEN; -import static android.view.WindowManager.TRANSIT_OPEN; -import static android.view.WindowManager.TRANSIT_RELAUNCH; -import static android.view.WindowManager.TRANSIT_TO_BACK; -import static android.view.WindowManager.TRANSIT_TO_FRONT; - -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS; -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; -import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; -import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT; -import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN; -import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; -import static com.android.server.wm.AppTransition.isNormalTransit; -import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp; -import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation; -import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import android.annotation.IntDef; -import android.annotation.Nullable; -import android.graphics.Rect; -import android.os.Trace; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Pair; -import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationDefinition; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.view.WindowManager.TransitionFlags; -import android.view.WindowManager.TransitionOldType; -import android.view.WindowManager.TransitionType; -import android.window.ITaskFragmentOrganizer; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.protolog.ProtoLog; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.function.Consumer; -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. - */ -public class AppTransitionController { - private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM; - private final WindowManagerService mService; - private final DisplayContent mDisplayContent; - private final WallpaperController mWallpaperControllerLocked; - private RemoteAnimationDefinition mRemoteAnimationDefinition = null; - - private static final int TYPE_NONE = 0; - private static final int TYPE_ACTIVITY = 1; - private static final int TYPE_TASK_FRAGMENT = 2; - private static final int TYPE_TASK = 3; - - @IntDef(prefix = { "TYPE_" }, value = { - TYPE_NONE, - TYPE_ACTIVITY, - TYPE_TASK_FRAGMENT, - TYPE_TASK - }) - @Retention(RetentionPolicy.SOURCE) - @interface TransitContainerType {} - - private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>(); - private final ArrayList<WindowContainer> mTempTransitionWindows = new ArrayList<>(); - - AppTransitionController(WindowManagerService service, DisplayContent displayContent) { - mService = service; - mDisplayContent = displayContent; - mWallpaperControllerLocked = mDisplayContent.mWallpaperController; - } - - void registerRemoteAnimations(RemoteAnimationDefinition definition) { - mRemoteAnimationDefinition = definition; - } - - /** - * Returns the currently visible window that is associated with the wallpaper in case we are - * transitioning from an activity with a wallpaper to one without. - */ - @Nullable - private WindowState getOldWallpaper() { - final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); - final @TransitionType int firstTransit = - mDisplayContent.mAppTransition.getFirstAppTransition(); - - final ArraySet<WindowContainer> openingWcs = getAnimationTargets( - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, true /* visible */); - final boolean showWallpaper = wallpaperTarget != null - && (wallpaperTarget.hasWallpaper() - // Update task open transition to wallpaper transition when wallpaper is visible. - // (i.e.launching app info activity from recent tasks) - || ((firstTransit == TRANSIT_OPEN || firstTransit == TRANSIT_TO_FRONT) - && (!openingWcs.isEmpty() && openingWcs.valueAt(0).asTask() != null) - && mWallpaperControllerLocked.isWallpaperVisible())); - // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set, - // don't consider upgrading to wallpaper transition. - return (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper) - ? null : wallpaperTarget; - } - - /** - * Handle application transition for given display. - */ - void handleAppTransitionReady() { - mTempTransitionReasons.clear(); - if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons) - || !transitionGoodToGo(mDisplayContent.mChangingContainers, mTempTransitionReasons) - || !transitionGoodToGoForTaskFragments()) { - return; - } - - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady"); - - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO"); - // TODO(b/205335975): Remove window which stuck in animatingExit status. Find actual cause. - mDisplayContent.forAllWindows(WindowState::cleanupAnimatingExitWindow, - true /* traverseTopToBottom */); - // TODO(new-app-transition): Remove code using appTransition.getAppTransition() - final AppTransition appTransition = mDisplayContent.mAppTransition; - - mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear(); - - appTransition.removeAppTransitionTimeoutCallbacks(); - - mDisplayContent.mWallpaperMayChange = false; - - int appCount = mDisplayContent.mOpeningApps.size(); - for (int i = 0; i < appCount; ++i) { - // Clearing the mAnimatingExit flag before entering animation. It's set to true if app - // window is removed, or window relayout to invisible. This also affects window - // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the - // transition selection depends on wallpaper target visibility. - mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags(); - } - appCount = mDisplayContent.mChangingContainers.size(); - for (int i = 0; i < appCount; ++i) { - // Clearing for same reason as above. - final ActivityRecord activity = getAppFromContainer( - mDisplayContent.mChangingContainers.valueAtUnchecked(i)); - if (activity != null) { - activity.clearAnimatingFlags(); - } - } - - // Adjust wallpaper before we pull the lower/upper target, since pending changes - // (like the clearAnimatingFlags() above) might affect wallpaper target result. - // Or, the opening app window should be a wallpaper target. - mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded( - mDisplayContent.mOpeningApps); - - ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps; - ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps; - if (mDisplayContent.mAtmService.mBackNavigationController.isMonitoringFinishTransition()) { - tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps); - tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); - } - - @TransitionOldType final int transit = getTransitCompatType( - mDisplayContent.mAppTransition, tmpOpenApps, - tmpCloseApps, mDisplayContent.mChangingContainers, - mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(), - mDisplayContent.mSkipAppTransitionAnimation); - mDisplayContent.mSkipAppTransitionAnimation = false; - - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "handleAppTransitionReady: displayId=%d appTransition={%s}" - + " openingApps=[%s] closingApps=[%s] transit=%s", - mDisplayContent.mDisplayId, appTransition.toString(), tmpOpenApps, - tmpCloseApps, AppTransition.appTransitionOldToString(transit)); - - // Find the layout params of the top-most application window in the tokens, which is - // what will control the animation theme. If all closing windows are obscured, then there is - // no need to do an animation. This is the case, for example, when this transition is being - // done behind a dream window. - final ArraySet<Integer> activityTypes = collectActivityTypes(tmpOpenApps, - tmpCloseApps, mDisplayContent.mChangingContainers); - final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes, - tmpOpenApps, tmpCloseApps, mDisplayContent.mChangingContainers); - final ActivityRecord topOpeningApp = - getTopApp(tmpOpenApps, false /* ignoreHidden */); - final ActivityRecord topClosingApp = - getTopApp(tmpCloseApps, false /* ignoreHidden */); - final ActivityRecord topChangingApp = - getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */); - final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity); - - // Check if there is any override - if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) { - // Unfreeze the windows that were previously frozen for TaskFragment animation. - overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes); - } - - final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps) - || containsVoiceInteraction(mDisplayContent.mOpeningApps); - - final int layoutRedo; - mService.mSurfaceAnimationRunner.deferStartingAnimations(); - try { - applyAnimations(tmpOpenApps, tmpCloseApps, transit, animLp, voiceInteraction); - handleClosingApps(); - handleOpeningApps(); - handleChangingApps(transit); - handleClosingChangingContainers(); - - appTransition.setLastAppTransition(transit, topOpeningApp, - topClosingApp, topChangingApp); - - final int flags = appTransition.getTransitFlags(); - layoutRedo = appTransition.goodToGo(transit, topOpeningApp); - appTransition.postAnimationCallback(); - } finally { - appTransition.clear(); - mService.mSurfaceAnimationRunner.continueStartingAnimations(); - } - - mService.mSnapshotController.onTransitionStarting(mDisplayContent); - - mDisplayContent.mOpeningApps.clear(); - mDisplayContent.mClosingApps.clear(); - mDisplayContent.mChangingContainers.clear(); - mDisplayContent.mUnknownAppVisibilityController.clear(); - mDisplayContent.mClosingChangingContainers.clear(); - - // This has changed the visibility of windows, so perform - // a new layout to get them all up-to-date. - mDisplayContent.setLayoutNeeded(); - - mDisplayContent.computeImeTarget(true /* updateImeTarget */); - - mService.mAtmService.mTaskSupervisor.getActivityMetricsLogger().notifyTransitionStarting( - mTempTransitionReasons); - - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); - - mDisplayContent.pendingLayoutChanges |= - layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG; - } - - /** - * Get old transit type based on the current transit requests. - * - * @param appTransition {@link AppTransition} for managing app transition state. - * @param openingApps {@link ActivityRecord}s which are becoming visible. - * @param closingApps {@link ActivityRecord}s which are becoming invisible. - * @param changingContainers {@link WindowContainer}s which are changed in configuration. - * @param wallpaperTarget If non-null, this is the currently visible window that is associated - * with the wallpaper. - * @param oldWallpaper The currently visible window that is associated with the wallpaper in - * case we are transitioning from an activity with a wallpaper to one - * without. Otherwise null. - */ - @TransitionOldType static int getTransitCompatType(AppTransition appTransition, - ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps, - ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget, - @Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) { - - final ActivityRecord topOpeningApp = getTopApp(openingApps, false /* ignoreHidden */); - final ActivityRecord topClosingApp = getTopApp(closingApps, true /* ignoreHidden */); - - // Determine if closing and opening app token sets are wallpaper targets, in which case - // special animations are needed. - final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps) - && wallpaperTarget != null; - final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps) - && wallpaperTarget != null; - - // Keyguard transit has high priority. - switch (appTransition.getKeyguardTransition()) { - case TRANSIT_KEYGUARD_GOING_AWAY: - return openingAppHasWallpaper ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER - : TRANSIT_OLD_KEYGUARD_GOING_AWAY; - case TRANSIT_KEYGUARD_OCCLUDE: - // When there is a closing app, the keyguard has already been occluded by an - // activity, and another activity has started on top of that activity, so normal - // app transition animation should be used. - if (!closingApps.isEmpty()) { - return TRANSIT_OLD_ACTIVITY_OPEN; - } - if (!openingApps.isEmpty() && openingApps.valueAt(0).getActivityType() - == ACTIVITY_TYPE_DREAM) { - return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM; - } - return TRANSIT_OLD_KEYGUARD_OCCLUDE; - case TRANSIT_KEYGUARD_UNOCCLUDE: - return TRANSIT_OLD_KEYGUARD_UNOCCLUDE; - } - - // Determine whether the top opening and closing activity is a dream activity. If so, this - // has higher priority than others except keyguard transit. - if (topOpeningApp != null && topOpeningApp.getActivityType() == ACTIVITY_TYPE_DREAM) { - return TRANSIT_OLD_DREAM_ACTIVITY_OPEN; - } else if (topClosingApp != null - && topClosingApp.getActivityType() == ACTIVITY_TYPE_DREAM) { - return TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; - } - - // This is not keyguard transition and one of the app has request to skip app transition. - if (skipAppTransitionAnimation) { - return WindowManager.TRANSIT_OLD_UNSET; - } - @TransitionFlags final int flags = appTransition.getTransitFlags(); - @TransitionType final int firstTransit = appTransition.getFirstAppTransition(); - - // Special transitions - // TODO(new-app-transitions): Revisit if those can be rewritten by using flags. - if (appTransition.containsTransitRequest(TRANSIT_CHANGE) && !changingContainers.isEmpty()) { - @TransitContainerType int changingType = - getTransitContainerType(changingContainers.valueAt(0)); - switch (changingType) { - case TYPE_TASK: - return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; - case TYPE_TASK_FRAGMENT: - return TRANSIT_OLD_TASK_FRAGMENT_CHANGE; - default: - throw new IllegalStateException( - "TRANSIT_CHANGE with unrecognized changing type=" + changingType); - } - } - if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) { - return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; - } - if (firstTransit == TRANSIT_NONE) { - return TRANSIT_OLD_NONE; - } - - /* - * There are cases where we open/close a new task/activity, but in reality only a - * translucent activity on top of existing activities is opening/closing. For that one, we - * have a different animation because non of the task/activity animations actually work well - * with translucent apps. - */ - if (isNormalTransit(firstTransit)) { - boolean allOpeningVisible = true; - boolean allTranslucentOpeningApps = !openingApps.isEmpty(); - for (int i = openingApps.size() - 1; i >= 0; i--) { - final ActivityRecord activity = openingApps.valueAt(i); - if (!activity.isVisible()) { - allOpeningVisible = false; - if (activity.fillsParent()) { - allTranslucentOpeningApps = false; - } - } - } - boolean allTranslucentClosingApps = !closingApps.isEmpty(); - for (int i = closingApps.size() - 1; i >= 0; i--) { - if (closingApps.valueAt(i).fillsParent()) { - allTranslucentClosingApps = false; - break; - } - } - - if (allTranslucentClosingApps && allOpeningVisible) { - return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE; - } - if (allTranslucentOpeningApps && closingApps.isEmpty()) { - return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN; - } - } - - if (closingAppHasWallpaper && openingAppHasWallpaper) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!"); - switch (firstTransit) { - case TRANSIT_OPEN: - case TRANSIT_TO_FRONT: - return TRANSIT_OLD_WALLPAPER_INTRA_OPEN; - case TRANSIT_CLOSE: - case TRANSIT_TO_BACK: - return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE; - } - } else if (oldWallpaper != null && !openingApps.isEmpty() - && !openingApps.contains(oldWallpaper.mActivityRecord) - && closingApps.contains(oldWallpaper.mActivityRecord) - && topClosingApp == oldWallpaper.mActivityRecord) { - // We are transitioning from an activity with a wallpaper to one without. - return TRANSIT_OLD_WALLPAPER_CLOSE; - } else if (wallpaperTarget != null && wallpaperTarget.isVisible() - && openingApps.contains(wallpaperTarget.mActivityRecord) - && topOpeningApp == wallpaperTarget.mActivityRecord - /* && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE */) { - // We are transitioning from an activity without - // a wallpaper to now showing the wallpaper - return TRANSIT_OLD_WALLPAPER_OPEN; - } - - final ArraySet<WindowContainer> openingWcs = getAnimationTargets( - openingApps, closingApps, true /* visible */); - final ArraySet<WindowContainer> closingWcs = getAnimationTargets( - openingApps, closingApps, false /* visible */); - final WindowContainer<?> openingContainer = !openingWcs.isEmpty() - ? openingWcs.valueAt(0) : null; - final WindowContainer<?> closingContainer = !closingWcs.isEmpty() - ? closingWcs.valueAt(0) : null; - @TransitContainerType int openingType = getTransitContainerType(openingContainer); - @TransitContainerType int closingType = getTransitContainerType(closingContainer); - if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) { - if (topOpeningApp != null && topOpeningApp.isActivityTypeHome()) { - // If we are opening the home task, we want to play an animation as if - // the task on top is being brought to back. - return TRANSIT_OLD_TASK_TO_BACK; - } - return TRANSIT_OLD_TASK_TO_FRONT; - } - if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) { - return TRANSIT_OLD_TASK_TO_BACK; - } - if (appTransition.containsTransitRequest(TRANSIT_OPEN)) { - if (openingType == TYPE_TASK) { - return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0 - ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN; - } - if (openingType == TYPE_ACTIVITY) { - return TRANSIT_OLD_ACTIVITY_OPEN; - } - if (openingType == TYPE_TASK_FRAGMENT) { - return TRANSIT_OLD_TASK_FRAGMENT_OPEN; - } - } - if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) { - if (closingType == TYPE_TASK) { - return TRANSIT_OLD_TASK_CLOSE; - } - if (closingType == TYPE_TASK_FRAGMENT) { - return TRANSIT_OLD_TASK_FRAGMENT_CLOSE; - } - if (closingType == TYPE_ACTIVITY) { - for (int i = closingApps.size() - 1; i >= 0; i--) { - if (closingApps.valueAt(i).visibleIgnoringKeyguard) { - return TRANSIT_OLD_ACTIVITY_CLOSE; - } - } - // Skip close activity transition since no closing app can be visible - return WindowManager.TRANSIT_OLD_UNSET; - } - } - if (appTransition.containsTransitRequest(TRANSIT_RELAUNCH) - && !openingWcs.isEmpty() && !openingApps.isEmpty()) { - return TRANSIT_OLD_ACTIVITY_RELAUNCH; - } - return TRANSIT_OLD_NONE; - } - - @TransitContainerType - private static int getTransitContainerType(@Nullable WindowContainer<?> container) { - if (container == null) { - return TYPE_NONE; - } - if (container.asTask() != null) { - return TYPE_TASK; - } - if (container.asTaskFragment() != null) { - return TYPE_TASK_FRAGMENT; - } - if (container.asActivityRecord() != null) { - return TYPE_ACTIVITY; - } - return TYPE_NONE; - } - - @Nullable - private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) { - final WindowState mainWindow = activity != null ? activity.findMainWindow() : null; - return mainWindow != null ? mainWindow.mAttrs : null; - } - - RemoteAnimationAdapter getRemoteAnimationOverride(@Nullable WindowContainer container, - @TransitionOldType int transit, ArraySet<Integer> activityTypes) { - if (container != null) { - final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition(); - if (definition != null) { - final RemoteAnimationAdapter adapter = definition.getAdapter(transit, - activityTypes); - if (adapter != null) { - return adapter; - } - } - } - return mRemoteAnimationDefinition != null - ? mRemoteAnimationDefinition.getAdapter(transit, activityTypes) - : null; - } - - private boolean transitionMayContainNonAppWindows(@TransitionOldType int transit) { - // We don't want to have the client to animate any non-app windows. - // Having {@code transit} of those types doesn't mean it will contain non-app windows, but - // non-app windows will only be included with those transition types. And we don't currently - // have any use case of those for TaskFragment transition. - return shouldStartNonAppWindowAnimationsForKeyguardExit(transit) - || shouldAttachNavBarToApp(mService, mDisplayContent, transit) - || shouldStartWallpaperAnimation(mDisplayContent); - } - - /** - * Whether the transition contains any embedded {@link TaskFragment} that does not fill the - * parent {@link Task} before or after the transition. - */ - private boolean transitionContainsTaskFragmentWithBoundsOverride() { - for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) { - final WindowContainer wc = mDisplayContent.mChangingContainers.valueAt(i); - if (wc.isEmbedded()) { - // Contains embedded TaskFragment with bounds changed. - return true; - } - } - mTempTransitionWindows.clear(); - mTempTransitionWindows.addAll(mDisplayContent.mClosingApps); - mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps); - boolean containsTaskFragmentWithBoundsOverride = false; - for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) { - final ActivityRecord r = mTempTransitionWindows.get(i).asActivityRecord(); - final TaskFragment tf = r.getTaskFragment(); - if (tf != null && tf.isEmbeddedWithBoundsOverride()) { - containsTaskFragmentWithBoundsOverride = true; - break; - } - } - mTempTransitionWindows.clear(); - return containsTaskFragmentWithBoundsOverride; - } - - /** - * Finds the common parent {@link Task} that is parent of all embedded app windows in the - * current transition. - * @return {@code null} if app windows in the transition are not children of the same Task, or - * if none of the app windows is embedded. - */ - @Nullable - private Task findParentTaskForAllEmbeddedWindows() { - mTempTransitionWindows.clear(); - mTempTransitionWindows.addAll(mDisplayContent.mClosingApps); - mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps); - mTempTransitionWindows.addAll(mDisplayContent.mChangingContainers); - - // It should only animated by the organizer if all windows are below the same leaf Task. - Task leafTask = null; - for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) { - final ActivityRecord r = getAppFromContainer(mTempTransitionWindows.get(i)); - if (r == null) { - leafTask = null; - break; - } - // There are also cases where the Task contains non-embedded activity, such as launching - // split TaskFragments from a non-embedded activity. - // The hierarchy may looks like this: - // - Task - // - Activity - // - TaskFragment - // - Activity - // - TaskFragment - // - Activity - // We also want to have the organizer handle the transition for such case. - final Task task = r.getTask(); - // We don't support embedding in PiP, leave the animation to the PipTaskOrganizer. - if (task == null || task.inPinnedWindowingMode()) { - leafTask = null; - break; - } - // We don't want the organizer to handle transition of other non-embedded Task. - if (leafTask != null && leafTask != task) { - leafTask = null; - break; - } - final ActivityRecord rootActivity = task.getRootActivity(); - // We don't want the organizer to handle transition when the whole app is closing. - if (rootActivity == null) { - leafTask = null; - break; - } - // We don't want the organizer to handle transition of non-embedded activity of other - // app. - if (r.getUid() != task.effectiveUid && !r.isEmbedded()) { - leafTask = null; - break; - } - leafTask = task; - } - mTempTransitionWindows.clear(); - return leafTask; - } - - /** - * Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all embedded - * {@link TaskFragment} belong to the given {@link Task}. - * @return {@code null} if there is no such organizer, or if there are more than one. - */ - @Nullable - private ITaskFragmentOrganizer findTaskFragmentOrganizer(@Nullable Task task) { - if (task == null) { - return null; - } - // We don't support remote animation for Task with multiple TaskFragmentOrganizers. - final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1]; - final boolean hasMultipleOrganizers = task.forAllLeafTaskFragments(taskFragment -> { - final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer(); - if (tfOrganizer == null) { - return false; - } - if (organizer[0] != null && !organizer[0].asBinder().equals(tfOrganizer.asBinder())) { - return true; - } - organizer[0] = tfOrganizer; - return false; - }); - if (hasMultipleOrganizers) { - ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for" - + " Task with multiple TaskFragmentOrganizers."); - return null; - } - return organizer[0]; - } - - /** - * Overrides the pending transition with the remote animation defined by the - * {@link ITaskFragmentOrganizer} if all windows in the transition are children of - * {@link TaskFragment} that are organized by the same organizer. - * - * @return {@code true} if the transition is overridden. - */ - private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, - ArraySet<Integer> activityTypes) { - if (transitionMayContainNonAppWindows(transit)) { - return false; - } - if (!transitionContainsTaskFragmentWithBoundsOverride()) { - // No need to play TaskFragment remote animation if all embedded TaskFragment in the - // transition fill the Task. - return false; - } - - final Task task = findParentTaskForAllEmbeddedWindows(); - final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task); - final RemoteAnimationDefinition definition = organizer != null - ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController - .getRemoteAnimationDefinition(organizer) - : null; - final RemoteAnimationAdapter adapter = definition != null - ? definition.getAdapter(transit, activityTypes) - : null; - if (adapter == null) { - return false; - } - mDisplayContent.mAppTransition.overridePendingAppTransitionRemote( - adapter, false /* sync */, true /*isActivityEmbedding*/); - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Override with TaskFragment remote animation for transit=%s", - AppTransition.appTransitionOldToString(transit)); - - final int organizerUid = mDisplayContent.mAtmService.mTaskFragmentOrganizerController - .getTaskFragmentOrganizerUid(organizer); - final boolean shouldDisableInputForRemoteAnimation = !task.isFullyTrustedEmbedding( - organizerUid); - final RemoteAnimationController remoteAnimationController = - mDisplayContent.mAppTransition.getRemoteAnimationController(); - if (shouldDisableInputForRemoteAnimation && remoteAnimationController != null) { - // We are going to use client-driven animation, Disable all input on activity windows - // during the animation (unless it is fully trusted) to ensure it is safe to allow - // client to animate the surfaces. - // This is needed for all activity windows in the animation Task. - remoteAnimationController.setOnRemoteAnimationReady(() -> { - final Consumer<ActivityRecord> updateActivities = - activity -> activity.setDropInputForAnimation(true); - task.forAllActivities(updateActivities); - }); - ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment." - + " Disabled all input during TaskFragment remote animation.", task.mTaskId); - } - return true; - } - - /** - * Overrides the pending transition with the remote animation defined for the transition in the - * set of defined remote animations in the app window token. - */ - private void overrideWithRemoteAnimationIfSet(@Nullable ActivityRecord animLpActivity, - @TransitionOldType int transit, ArraySet<Integer> activityTypes) { - RemoteAnimationAdapter adapter = null; - if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) { - // The crash transition has higher priority than any involved remote animations. - } else if (AppTransition.isKeyguardGoingAwayTransitOld(transit)) { - adapter = mRemoteAnimationDefinition != null - ? mRemoteAnimationDefinition.getAdapter(transit, activityTypes) - : null; - } else if (mDisplayContent.mAppTransition.getRemoteAnimationController() == null) { - adapter = getRemoteAnimationOverride(animLpActivity, transit, activityTypes); - } - if (adapter != null) { - mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter); - } - } - - @Nullable - static Task findRootTaskFromContainer(WindowContainer wc) { - return wc.asTaskFragment() != null ? wc.asTaskFragment().getRootTask() - : wc.asActivityRecord().getRootTask(); - } - - @Nullable - static ActivityRecord getAppFromContainer(WindowContainer wc) { - return wc.asTaskFragment() != null ? wc.asTaskFragment().getTopNonFinishingActivity() - : wc.asActivityRecord(); - } - - /** - * @return The window token that determines the animation theme. - */ - @Nullable - private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit, - ArraySet<Integer> activityTypes, ArraySet<ActivityRecord> openingApps, - ArraySet<ActivityRecord> closingApps, ArraySet<WindowContainer> changingApps) { - ActivityRecord result; - - // Remote animations always win, but fullscreen tokens override non-fullscreen tokens. - result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps, - w -> w.getRemoteAnimationDefinition() != null - && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes)); - if (result != null) { - return result; - } - result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps, - w -> w.fillsParent() && w.findMainWindow() != null); - if (result != null) { - return result; - } - return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps, - w -> w.findMainWindow() != null); - } - - /** - * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set - * of apps in {@code array1}, {@code array2}, and {@code array3}. - */ - private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1, - ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3) { - final ArraySet<Integer> result = new ArraySet<>(); - for (int i = array1.size() - 1; i >= 0; i--) { - result.add(array1.valueAt(i).getActivityType()); - } - for (int i = array2.size() - 1; i >= 0; i--) { - result.add(array2.valueAt(i).getActivityType()); - } - for (int i = array3.size() - 1; i >= 0; i--) { - result.add(array3.valueAt(i).getActivityType()); - } - return result; - } - - private static ActivityRecord lookForHighestTokenWithFilter(ArraySet<ActivityRecord> array1, - ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3, - Predicate<ActivityRecord> filter) { - final int array2base = array1.size(); - final int array3base = array2.size() + array2base; - final int count = array3base + array3.size(); - int bestPrefixOrderIndex = Integer.MIN_VALUE; - ActivityRecord bestToken = null; - for (int i = 0; i < count; i++) { - final WindowContainer wtoken = i < array2base - ? array1.valueAt(i) - : (i < array3base - ? array2.valueAt(i - array2base) - : array3.valueAt(i - array3base)); - final int prefixOrderIndex = wtoken.getPrefixOrderIndex(); - final ActivityRecord r = getAppFromContainer(wtoken); - if (r != null && filter.test(r) && prefixOrderIndex > bestPrefixOrderIndex) { - bestPrefixOrderIndex = prefixOrderIndex; - bestToken = r; - } - } - return bestToken; - } - - private boolean containsVoiceInteraction(ArraySet<ActivityRecord> apps) { - for (int i = apps.size() - 1; i >= 0; i--) { - if (apps.valueAt(i).mVoiceInteraction) { - return true; - } - } - return false; - } - - /** - * Apply animation to the set of window containers. - * - * @param wcs The list of {@link WindowContainer}s to which an app transition animation applies. - * @param apps The list of {@link ActivityRecord}s being transitioning. - * @param transit The current transition type. - * @param visible {@code true} if the apps becomes visible, {@code false} if the apps becomes - * invisible. - * @param animLp Layout parameters in which an app transition animation runs. - * @param voiceInteraction {@code true} if one of the apps in this transition belongs to a voice - * interaction session driving task. - */ - private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps, - @TransitionOldType int transit, boolean visible, LayoutParams animLp, - boolean voiceInteraction) { - final int wcsCount = wcs.size(); - for (int i = 0; i < wcsCount; i++) { - final WindowContainer wc = wcs.valueAt(i); - // If app transition animation target is promoted to higher level, SurfaceAnimator - // 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> transitioningDescendants = new ArrayList<>(); - for (int j = 0; j < apps.size(); ++j) { - final ActivityRecord app = apps.valueAt(j); - if (app.isDescendantOf(wc)) { - transitioningDescendants.add(app); - } - } - wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants); - } - } - - /** - * Returns {@code true} if a given {@link WindowContainer} is an embedded Task in - * {@link TaskView}. - * - * Note that this is a short term workaround to support Android Auto until it migrate to - * ShellTransition. This should only be used by {@link #getAnimationTargets}. - * - * TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled. - */ - static boolean isTaskViewTask(WindowContainer wc) { - // Use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and - // it is not guaranteed to work this logic in the future version. - boolean isTaskViewTask = wc instanceof Task && ((Task) wc).mRemoveWithTaskOrganizer; - if (isTaskViewTask) { - return true; - } - - WindowContainer parent = wc.getParent(); - boolean isParentATaskViewTask = parent != null - && parent instanceof Task - && ((Task) parent).mRemoveWithTaskOrganizer; - return isParentATaskViewTask; - } - - /** - * Find WindowContainers to be animated from a set of opening and closing apps. We will promote - * animation targets to higher level in the window hierarchy if possible. - * - * @param visible {@code true} to get animation targets for opening apps, {@code false} to get - * animation targets for closing apps. - * @return {@link WindowContainer}s to be animated. - */ - @VisibleForTesting - static ArraySet<WindowContainer> getAnimationTargets( - ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps, - boolean visible) { - - // The candidates of animation targets, which might be able to promote to higher level. - final ArrayDeque<WindowContainer> candidates = new ArrayDeque<>(); - final ArraySet<ActivityRecord> apps = visible ? openingApps : closingApps; - for (int i = 0; i < apps.size(); ++i) { - final ActivityRecord app = apps.valueAt(i); - if (app.shouldApplyAnimation(visible)) { - candidates.add(app); - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Changing app %s visible=%b performLayout=%b", - app, app.isVisible(), false); - } - } - - final ArraySet<ActivityRecord> otherApps = visible ? closingApps : openingApps; - // Ancestors of closing apps while finding animation targets for opening apps, or ancestors - // of opening apps while finding animation targets for closing apps. - final ArraySet<WindowContainer> otherAncestors = new ArraySet<>(); - for (int i = 0; i < otherApps.size(); ++i) { - for (WindowContainer wc = otherApps.valueAt(i); wc != null; wc = wc.getParent()) { - otherAncestors.add(wc); - } - } - - // The final animation targets which cannot promote to higher level anymore. - final ArraySet<WindowContainer> targets = new ArraySet<>(); - final ArrayList<WindowContainer> siblings = new ArrayList<>(); - while (!candidates.isEmpty()) { - final WindowContainer current = candidates.removeFirst(); - final WindowContainer parent = current.getParent(); - siblings.clear(); - siblings.add(current); - boolean canPromote = true; - - if (isTaskViewTask(current)) { - // Don't animate an embedded Task in app transition. This is a short term workaround - // to prevent conflict of surface hierarchy changes between legacy app transition - // and TaskView (b/205189147). - // TODO(b/213312721): Remove this once ShellTransition is enabled. - continue; - } else if (parent == null || !parent.canCreateRemoteAnimationTarget() - // We cannot promote the animation on Task's parent when the task is in - // clearing task in case the animating get stuck when performing the opening - // task that behind it. - || (current.asTask() != null && current.asTask().mInRemoveTask) - // We cannot promote the animation to changing window. This may happen when an - // activity is open in a TaskFragment that is resizing, while the existing - // activity in the TaskFragment is reparented to another TaskFragment. - || parent.isChangingAppTransition()) { - canPromote = false; - } else { - // In case a descendant of the parent belongs to the other group, we cannot promote - // the animation target from "current" to the parent. - // - // Example: Imagine we're checking if we can animate a Task instead of a set of - // ActivityRecords. In case an activity starts a new activity within a same Task, - // an ActivityRecord of an existing activity belongs to the opening apps, at the - // same time, the other ActivityRecord of a new activity belongs to the closing - // apps. In this case, we cannot promote the animation target to Task level, but - // need to animate each individual activity. - // - // [Task] +- [ActivityRecord1] (in opening apps) - // +- [ActivityRecord2] (in closing apps) - if (otherAncestors.contains(parent)) { - canPromote = false; - } - - // If the current window container is a task with adjacent task set, the both - // adjacent tasks will be opened or closed together. To get their opening or - // closing animation target independently, skip promoting their animation targets. - if (current.asTask() != null && current.asTask().hasAdjacentTask()) { - canPromote = false; - } - - // Find all siblings of the current WindowContainer in "candidates", move them into - // a separate list "siblings", and checks if an animation target can be promoted - // to its parent. - // - // We can promote an animation target to its parent if and only if all visible - // siblings will be animating. - // - // Example: Imagine that a Task contains two visible activity record, but only one - // of them is included in the opening apps and the other belongs to neither opening - // or closing apps. This happens when an activity launches another translucent - // activity in the same Task. In this case, we cannot animate Task, but have to - // animate each activity, otherwise an activity behind the translucent activity also - // animates. - // - // [Task] +- [ActivityRecord1] (visible, in opening apps) - // +- [ActivityRecord2] (visible, not in opening apps) - for (int j = 0; j < parent.getChildCount(); ++j) { - final WindowContainer sibling = parent.getChildAt(j); - if (candidates.remove(sibling)) { - if (!isTaskViewTask(sibling)) { - // Don't animate an embedded Task in app transition. This is a short - // term workaround to prevent conflict of surface hierarchy changes - // between legacy app transition and TaskView (b/205189147). - // TODO(b/213312721): Remove this once ShellTransition is enabled. - siblings.add(sibling); - } - } else if (sibling != current && sibling.isVisible()) { - canPromote = false; - } - } - } - - if (canPromote) { - candidates.add(parent); - } else { - targets.addAll(siblings); - } - } - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "getAnimationTarget in=%s, out=%s", - apps, targets); - return targets; - } - - /** - * Apply an app transition animation based on a set of {@link ActivityRecord} - * - * @param openingApps The list of opening apps to which an app transition animation applies. - * @param closingApps The list of closing apps to which an app transition animation applies. - * @param transit The current transition type. - * @param animLp Layout parameters in which an app transition animation runs. - * @param voiceInteraction {@code true} if one of the apps in this transition belongs to a voice - * interaction session driving task. - */ - private void applyAnimations(ArraySet<ActivityRecord> openingApps, - ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit, - LayoutParams animLp, boolean voiceInteraction) { - if (transit == WindowManager.TRANSIT_OLD_UNSET - || (openingApps.isEmpty() && closingApps.isEmpty())) { - return; - } - - if (AppTransition.isActivityTransitOld(transit)) { - final ArrayList<Pair<ActivityRecord, Rect>> closingLetterboxes = new ArrayList(); - for (int i = 0; i < closingApps.size(); ++i) { - ActivityRecord closingApp = closingApps.valueAt(i); - if (closingApp.areBoundsLetterboxed()) { - final Rect insets = closingApp.getLetterboxInsets(); - closingLetterboxes.add(new Pair(closingApp, insets)); - } - } - - for (int i = 0; i < openingApps.size(); ++i) { - ActivityRecord openingApp = openingApps.valueAt(i); - if (openingApp.areBoundsLetterboxed()) { - final Rect openingInsets = openingApp.getLetterboxInsets(); - for (Pair<ActivityRecord, Rect> closingLetterbox : closingLetterboxes) { - final Rect closingInsets = closingLetterbox.second; - if (openingInsets.equals(closingInsets)) { - ActivityRecord closingApp = closingLetterbox.first; - openingApp.setNeedsLetterboxedAnimation(true); - closingApp.setNeedsLetterboxedAnimation(true); - } - } - } - } - } - - final ArraySet<WindowContainer> openingWcs = getAnimationTargets( - openingApps, closingApps, true /* visible */); - final ArraySet<WindowContainer> closingWcs = getAnimationTargets( - openingApps, closingApps, false /* visible */); - applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp, - voiceInteraction); - applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp, - voiceInteraction); - - for (int i = 0; i < openingApps.size(); ++i) { - openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false; - } - for (int i = 0; i < closingApps.size(); ++i) { - closingApps.valueAtUnchecked(i).mOverrideTaskTransition = false; - } - - final AccessibilityController accessibilityController = - mDisplayContent.mWmService.mAccessibilityController; - if (accessibilityController.hasCallbacks()) { - accessibilityController.onAppWindowTransition(mDisplayContent.getDisplayId(), transit); - } - } - - private void handleOpeningApps() { - final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps; - final int appsCount = openingApps.size(); - - for (int i = 0; i < appsCount; i++) { - final ActivityRecord app = openingApps.valueAt(i); - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app); - - app.commitVisibility(true /* visible */, false /* performLayout */); - - // 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. - mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(app.token); - } - app.updateReportedVisibilityLocked(); - app.showAllWindowsLocked(); - - if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) { - app.attachThumbnailAnimation(); - } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) { - app.attachCrossProfileAppsThumbnailAnimation(); - } - } - } - - private void handleClosingApps() { - final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps; - final int appsCount = closingApps.size(); - - for (int i = 0; i < appsCount; i++) { - final ActivityRecord app = closingApps.valueAt(i); - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app); - - app.commitVisibility(false /* visible */, false /* performLayout */); - app.updateReportedVisibilityLocked(); - // Force the allDrawn flag, because we want to start - // this guy's animations regardless of whether it's - // gotten drawn. - app.allDrawn = true; - // Ensure that apps that are mid-starting are also scheduled to have their - // starting windows removed after the animation is complete - if (app.mStartingWindow != null && !app.mStartingWindow.mAnimatingExit) { - app.removeStartingWindow(); - } - - if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) { - app.attachThumbnailAnimation(); - } - } - } - - private void handleClosingChangingContainers() { - final ArrayMap<WindowContainer, Rect> containers = - mDisplayContent.mClosingChangingContainers; - while (!containers.isEmpty()) { - final WindowContainer container = containers.keyAt(0); - containers.remove(container); - - // For closing changing windows that are part of the transition, they should have been - // removed from mClosingChangingContainers in WindowContainer#getAnimationAdapter() - // If the closing changing TaskFragment is not part of the transition, update its - // surface after removing it from mClosingChangingContainers. - final TaskFragment taskFragment = container.asTaskFragment(); - if (taskFragment != null) { - taskFragment.updateOrganizedTaskFragmentSurface(); - } - } - } - - private void handleChangingApps(@TransitionOldType int transit) { - final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers; - final int appsCount = apps.size(); - 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 /* sources */); - } - } - - private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps, - ArrayMap<WindowContainer, Integer> outReasons) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Checking %d opening apps (timeout=%b)...", apps.size(), - mDisplayContent.mAppTransition.isTimeout()); - if (mDisplayContent.mAppTransition.isTimeout()) { - return true; - } - - for (int i = 0; i < apps.size(); i++) { - WindowContainer wc = apps.valueAt(i); - final ActivityRecord activity = getAppFromContainer(wc); - if (activity == null) { - continue; - } - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Check opening app=%s: allDrawn=%b startingDisplayed=%b " - + "startingMoved=%b isRelaunching()=%b startingWindow=%s", - activity, activity.allDrawn, activity.isStartingWindowDisplayed(), - activity.startingMoved, activity.isRelaunching(), - activity.mStartingWindow); - final boolean allDrawn = activity.allDrawn && !activity.isRelaunching(); - if (!allDrawn && !activity.isStartingWindowDisplayed() && !activity.startingMoved) { - return false; - } - if (allDrawn) { - outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN); - } else { - outReasons.put(activity, - activity.mStartingData instanceof SplashScreenStartingData - ? APP_TRANSITION_SPLASH_SCREEN - : APP_TRANSITION_SNAPSHOT); - } - } - - // We also need to wait for the specs to be fetched, if needed. - if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true"); - return false; - } - - if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s", - mDisplayContent.mUnknownAppVisibilityController.getDebugMessage()); - return false; - } - - // If the wallpaper is visible, we need to check it's ready too. - return !mWallpaperControllerLocked.isWallpaperVisible() - || mWallpaperControllerLocked.wallpaperTransitionReady(); - } - - private boolean transitionGoodToGoForTaskFragments() { - if (mDisplayContent.mAppTransition.isTimeout()) { - return true; - } - - // Check all Tasks in this transition. This is needed because new TaskFragment created for - // launching activity may not be in the tracking lists, but we still want to wait for the - // activity launch to start the transition. - final ArraySet<Task> rootTasks = new ArraySet<>(); - for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) { - rootTasks.add(mDisplayContent.mOpeningApps.valueAt(i).getRootTask()); - } - for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) { - rootTasks.add(mDisplayContent.mClosingApps.valueAt(i).getRootTask()); - } - for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) { - rootTasks.add( - findRootTaskFromContainer(mDisplayContent.mChangingContainers.valueAt(i))); - } - - // Organized TaskFragment can be empty for two situations: - // 1. New created and is waiting for Activity launch. In this case, we want to wait for - // the Activity launch to trigger the transition. - // 2. Last Activity is just removed. In this case, we want to wait for organizer to - // remove the TaskFragment because it may also want to change other TaskFragments in - // the same transition. - for (int i = rootTasks.size() - 1; i >= 0; i--) { - final Task rootTask = rootTasks.valueAt(i); - if (rootTask == null) { - // It is possible that one activity may have been removed from the hierarchy. No - // need to check for this case. - continue; - } - final boolean notReady = rootTask.forAllLeafTaskFragments(taskFragment -> { - if (!taskFragment.isReadyToTransit()) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Organized TaskFragment is not ready= %s", - taskFragment); - return true; - } - return false; - }); - if (notReady) { - return false; - } - } - return true; - } - - /** - * Identifies whether the current transition occurs within a single task or not. This is used - * to determine whether animations should be clipped to the task bounds instead of root task - * bounds. - */ - @VisibleForTesting - boolean isTransitWithinTask(@TransitionOldType int transit, Task task) { - if (task == null - || !mDisplayContent.mChangingContainers.isEmpty()) { - // if there is no task, then we can't constrain to the task. - // if anything is changing, it can animate outside its task. - return false; - } - if (!(transit == TRANSIT_OLD_ACTIVITY_OPEN - || transit == TRANSIT_OLD_ACTIVITY_CLOSE - || transit == TRANSIT_OLD_ACTIVITY_RELAUNCH)) { - // only activity-level transitions will be within-task. - return false; - } - // check that all components are in the task. - for (ActivityRecord activity : mDisplayContent.mOpeningApps) { - Task activityTask = activity.getTask(); - if (activityTask != task) { - return false; - } - } - for (ActivityRecord activity : mDisplayContent.mClosingApps) { - if (activity.getTask() != task) { - return false; - } - } - return true; - } - - private static boolean canBeWallpaperTarget(ArraySet<ActivityRecord> apps) { - for (int i = apps.size() - 1; i >= 0; i--) { - if (apps.valueAt(i).windowsCanBeWallpaperTarget()) { - return true; - } - } - return false; - } - - /** - * Finds the top app in a list of apps, using its {@link ActivityRecord#getPrefixOrderIndex} to - * compare z-order. - * - * @param apps The list of apps to search. - * @param ignoreInvisible If set to true, ignores apps that are not - * {@link ActivityRecord#isVisible}. - * @return The top {@link ActivityRecord}. - */ - private static ActivityRecord getTopApp(ArraySet<? extends WindowContainer> apps, - boolean ignoreInvisible) { - int topPrefixOrderIndex = Integer.MIN_VALUE; - ActivityRecord topApp = null; - for (int i = apps.size() - 1; i >= 0; i--) { - final ActivityRecord app = getAppFromContainer(apps.valueAt(i)); - if (app == null || ignoreInvisible && !app.isVisible()) { - continue; - } - final int prefixOrderIndex = app.getPrefixOrderIndex(); - if (prefixOrderIndex > topPrefixOrderIndex) { - topPrefixOrderIndex = prefixOrderIndex; - topApp = app; - } - } - return topApp; - } -} diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c87087f84399..682f3d8cf1e5 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -226,7 +226,6 @@ import android.view.InsetsSource; import android.view.InsetsState; import android.view.MagnificationSpec; import android.view.PrivacyIndicatorBounds; -import android.view.RemoteAnimationDefinition; import android.view.RoundedCorners; import android.view.Surface; import android.view.Surface.Rotation; @@ -367,8 +366,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private int mMaxUiWidth = 0; final AppTransition mAppTransition; - final AppTransitionController mAppTransitionController; - boolean mSkipAppTransitionAnimation = false; final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>(); final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>(); @@ -1161,7 +1158,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mAppTransition = new AppTransition(mWmService.mContext, mWmService, this); mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier); mAppTransition.registerListenerLocked(mFixedRotationTransitionListener); - mAppTransitionController = new AppTransitionController(mWmService, this); mTransitionController.registerLegacyListener(mFixedRotationTransitionListener); mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this); mRemoteDisplayChangeController = new RemoteDisplayChangeController(this); @@ -1553,10 +1549,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mInputMethodSurfaceParentWindow; } - void registerRemoteAnimations(RemoteAnimationDefinition definition) { - mAppTransitionController.registerRemoteAnimations(definition); - } - void reconfigureDisplayLocked() { if (!isReady()) { return; @@ -5604,20 +5596,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** - * Transfer app transition from other display to this display. - * - * @param from Display from where the app transition is transferred. - * - * TODO(new-app-transition): Remove this once the shell handles app transition. - */ - void transferAppTransitionFrom(DisplayContent from) { - final boolean prepared = mAppTransition.transferFrom(from.mAppTransition); - if (prepared && okToAnimate()) { - mSkipAppTransitionAnimation = false; - } - } - - /** * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)} */ @Deprecated @@ -5631,10 +5609,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Deprecated void prepareAppTransition(@WindowManager.TransitionType int transit, @WindowManager.TransitionFlags int flags) { - final boolean prepared = mAppTransition.prepareAppTransition(transit, flags); - if (prepared && okToAnimate() && transit != TRANSIT_NONE) { - mSkipAppTransitionAnimation = false; - } + mAppTransition.prepareAppTransition(transit, flags); } /** diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 95d9b3e612ac..c93efd327096 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -35,7 +35,6 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_SLEEP; -import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_WAKE; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS_LIGHT; @@ -68,7 +67,6 @@ import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList; import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; -import static com.android.server.wm.KeyguardController.KEYGUARD_SLEEP_TOKEN_TAG; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; @@ -803,8 +801,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); mWmService.mSyncEngine.onSurfacePlacement(); - checkAppTransitionReady(surfacePlacer); - mWmService.mAtmService.mBackNavigationController .checkAnimationReady(defaultDisplay.mWallpaperController); @@ -898,38 +894,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit"); } - private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) { - // Trace all displays app transition by Z-order for pending layout change. - for (int i = mChildren.size() - 1; i >= 0; --i) { - final DisplayContent curDisplay = mChildren.get(i); - - // If we are ready to perform an app transition, check through all of the app tokens - // to be shown and see if they are ready to go. - if (curDisplay.mAppTransition.isReady()) { - // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges. - curDisplay.mAppTransitionController.handleAppTransitionReady(); - if (DEBUG_LAYOUT_REPEATS) { - surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady", - curDisplay.pendingLayoutChanges); - } - } - - if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppTransitioning()) { - // We have finished the animation of an app transition. To do this, we have - // delayed a lot of operations like showing and hiding apps, moving apps in - // Z-order, etc. - // The app token list reflects the correct Z-order, but the window list may now - // be out of sync with it. So here we will just rebuild the entire app window - // list. Fun! - curDisplay.handleAnimatingStoppedAndTransition(); - if (DEBUG_LAYOUT_REPEATS) { - surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock", - curDisplay.pendingLayoutChanges); - } - } - } - } - private void applySurfaceChangesTransaction() { // TODO(multi-display): Support these features on secondary screens. final DisplayContent defaultDc = mDefaultDisplay; @@ -2266,20 +2230,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Ensure the leash of new task is in sync with its current bounds after reparent. rootTask.maybeApplyLastRecentsAnimationTransaction(); - - // In the case of this activity entering PIP due to it being moved to the back, - // the old activity would have a TRANSIT_TASK_TO_BACK transition that needs to be - // ran. But, since its visibility did not change (note how it was STOPPED/not - // visible, and with it now at the back stack, it remains not visible), the logic to - // add the transition is automatically skipped. We then add this activity manually - // to the list of apps being closed, and request its transition to be ran. - final ActivityRecord oldTopActivity = task.getTopMostActivity(); - if (oldTopActivity != null && oldTopActivity.isState(STOPPED) - && task.getDisplayContent().mAppTransition.containsTransitRequest( - TRANSIT_TO_BACK)) { - task.getDisplayContent().mClosingApps.add(oldTopActivity); - oldTopActivity.mRequestForceTransition = true; - } } // TODO(remove-legacy-transit): Move this to the `singleActivity` case when removing @@ -2958,20 +2908,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> display.mAllSleepTokens.remove(token); if (display.mAllSleepTokens.isEmpty()) { mService.updateSleepIfNeededLocked(); - // Assuming no lock screen is set and a user launches an activity, turns off the screen - // and turn on the screen again, then the launched activity should be displayed on the - // screen without app transition animation. When the screen turns on, both keyguard - // sleep token and display off sleep token are removed, but the order is - // non-deterministic. - // Note: Display#mSkipAppTransitionAnimation will be ignored when keyguard related - // transition exists, so this affects only when no lock screen is set. Otherwise - // keyguard going away animation will be played. - // See also AppTransitionController#getTransitCompatType for more details. - if ((!mTaskSupervisor.getKeyguardController().isKeyguardOccluded(display.mDisplayId) - && token.mTag.equals(KEYGUARD_SLEEP_TOKEN_TAG)) - || token.mTag.equals(DISPLAY_OFF_SLEEP_TOKEN_TAG)) { - display.mSkipAppTransitionAnimation = true; - } } } diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java index dcdffa416e33..2664dcd3ae3f 100644 --- a/services/core/java/com/android/server/wm/SnapshotController.java +++ b/services/core/java/com/android/server/wm/SnapshotController.java @@ -72,11 +72,6 @@ class SnapshotController { mActivitySnapshotController.notifyAppVisibilityChanged(appWindowToken, visible); } - // For legacy transition, which won't support activity snapshot - void onTransitionStarting(DisplayContent displayContent) { - mTaskSnapshotController.handleClosingApps(displayContent.mClosingApps); - } - // For shell transition, record snapshots before transaction start. void onTransactionReady(@WindowManager.TransitionType int type, ArrayList<Transition.ChangeInfo> changeInfos) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 432ed1d0b61d..8a937721b347 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -113,27 +113,6 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot enableLowResSnapshots, lowResScaleFactor, use16BitFormat); } - // Still needed for legacy transition.(AppTransitionControllerTest) - void handleClosingApps(ArraySet<ActivityRecord> closingApps) { - if (shouldDisableSnapshots()) { - return; - } - // We need to take a snapshot of the task if and only if all activities of the task are - // either closing or hidden. - mTmpTasks.clear(); - for (int i = closingApps.size() - 1; i >= 0; i--) { - final ActivityRecord activity = closingApps.valueAt(i); - if (activity.isActivityTypeHome()) continue; - final Task task = activity.getTask(); - if (task == null) continue; - - getClosingTasksInner(task, mTmpTasks); - } - snapshotTasks(mTmpTasks); - mTmpTasks.clear(); - mSkipClosingAppSnapshotTasks.clear(); - } - /** * Adds the given {@param tasks} to the list of tasks which should not have their snapshots * taken upon the next processing of the set of closing apps. The caller is responsible for diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 55c2668f62d0..7af542f10127 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3359,7 +3359,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) { - if (AppTransitionController.isTaskViewTask(this) || (isOrganized() + if ((isOrganized() // TODO(b/161711458): Clean-up when moved to shell. && getWindowingMode() != WINDOWING_MODE_FULLSCREEN && getWindowingMode() != WINDOWING_MODE_FREEFORM diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index bb669915e366..d699a689459e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -347,7 +347,6 @@ import com.android.server.AnimationThread; import com.android.server.DisplayThread; import com.android.server.FgThread; import com.android.server.LocalServices; -import com.android.server.SystemConfig; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.input.InputManagerService; @@ -449,11 +448,6 @@ public class WindowManagerService extends IWindowManager.Stub /** * Use WMShell for app transition. */ - private static final String ENABLE_SHELL_TRANSITIONS = "persist.wm.debug.shell_transit"; - - /** - * @see #ENABLE_SHELL_TRANSITIONS - */ public static final boolean sEnableShellTransitions = getShellTransitEnabled(); /** @@ -10311,11 +10305,6 @@ public class WindowManagerService extends IWindowManager.Stub } private static boolean getShellTransitEnabled() { - android.content.pm.FeatureInfo autoFeature = SystemConfig.getInstance() - .getAvailableFeatures().get(PackageManager.FEATURE_AUTOMOTIVE); - if (autoFeature != null && autoFeature.version >= 0) { - return SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, true); - } return true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 440f43e9b926..bb296148dad1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2881,7 +2881,6 @@ public class ActivityRecordTests extends WindowTestsBase { activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true, false, true, false, false, false); waitUntilHandlersIdle(); - assertFalse(mDisplayContent.mSkipAppTransitionAnimation); assertNoStartingWindow(activity1); assertHasStartingWindow(activity2); } @@ -2965,7 +2964,6 @@ public class ActivityRecordTests extends WindowTestsBase { false /* newTask */, false /* isTaskSwitch */, null /* options */, null /* sourceRecord */); - assertTrue(mDisplayContent.mSkipAppTransitionAnimation); assertNull(middle.mStartingWindow); assertHasStartingWindow(top); assertTrue(top.isVisible()); @@ -3265,26 +3263,6 @@ public class ActivityRecordTests extends WindowTestsBase { > activity.getConfiguration().windowConfiguration.getAppBounds().height()); } - @Test - public void testSetVisibility_visibleToVisible() { - final ActivityRecord activity = new ActivityBuilder(mAtm) - .setCreateTask(true).build(); - // By default, activity is visible. - assertTrue(activity.isVisible()); - assertTrue(activity.isVisibleRequested()); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); - - // Request the activity to be visible. Although the activity is already visible, app - // transition animation should be applied on this activity. This might be unnecessary, but - // until we verify no logic relies on this behavior, we'll keep this as is. - mDisplayContent.prepareAppTransition(0); - activity.setVisibility(true); - assertTrue(activity.isVisible()); - assertTrue(activity.isVisibleRequested()); - assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); - } - @SetupWindows(addWindows = W_ACTIVITY) @Test public void testSetVisibility_visibleToInvisible() { @@ -3316,50 +3294,30 @@ public class ActivityRecordTests extends WindowTestsBase { public void testSetVisibility_invisibleToVisible() { final ActivityRecord activity = new ActivityBuilder(mAtm) .setCreateTask(true).setVisible(false).build(); - // Activiby is invisible. However ATMS requests it to become visible, since this is a top - // activity. assertFalse(activity.isVisible()); - assertTrue(activity.isVisibleRequested()); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + assertFalse(activity.isVisibleRequested()); // Request the activity to be visible. Since the visibility changes, app transition // animation should be applied on this activity. - activity.setVisibility(true); + requestTransition(activity, WindowManager.TRANSIT_OPEN); + mWm.mRoot.resumeFocusedTasksTopActivities(); assertFalse(activity.isVisible()); assertTrue(activity.isVisibleRequested()); - assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); - - // There should still be animation (add to opening) if keyguard is going away while the - // screen is off because it will be visible after screen is turned on by unlocking. - mDisplayContent.mOpeningApps.remove(activity); - mDisplayContent.mClosingApps.remove(activity); - activity.commitVisibility(false /* visible */, false /* performLayout */); - mDisplayContent.getDisplayPolicy().screenTurnedOff(false /* acquireSleepToken */); - final KeyguardController controller = mSupervisor.getKeyguardController(); - doReturn(true).when(controller).isKeyguardGoingAway(anyInt()); - activity.setVisibility(true); - assertTrue(mDisplayContent.mOpeningApps.contains(activity)); + assertTrue(activity.inTransition()); } @Test public void testSetVisibility_invisibleToInvisible() { final ActivityRecord activity = new ActivityBuilder(mAtm) .setCreateTask(true).setVisible(false).build(); - // Activiby is invisible. However ATMS requests it to become visible, since this is a top - // activity. - assertFalse(activity.isVisible()); - assertTrue(activity.isVisibleRequested()); - assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + requestTransition(activity, WindowManager.TRANSIT_CLOSE); // Request the activity to be invisible. Since the activity is already invisible, no app // transition should be applied on this activity. activity.setVisibility(false); assertFalse(activity.isVisible()); assertFalse(activity.isVisibleRequested()); - assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); - assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + assertFalse(activity.inTransition()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java deleted file mode 100644 index c294bc62c7ac..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * Copyright (C) 2018 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 com.android.server.wm; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.TRANSIT_CHANGE; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_OPEN; -import static android.view.WindowManager.TRANSIT_TO_FRONT; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import android.annotation.Nullable; -import android.graphics.Rect; -import android.gui.DropInputMode; -import android.os.Binder; -import android.os.IBinder; -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; -import android.util.ArraySet; -import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationRunner; -import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationDefinition; -import android.view.RemoteAnimationTarget; -import android.view.WindowManager; -import android.window.ITaskFragmentOrganizer; -import android.window.TaskFragmentOrganizer; - -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Build/Install/Run: - * atest WmTests:AppTransitionControllerTest - */ -@SmallTest -@Presubmit -@RunWith(WindowTestRunner.class) -public class AppTransitionControllerTest extends WindowTestsBase { - - private AppTransitionController mAppTransitionController; - - @Before - public void setUp() throws Exception { - assumeFalse(WindowManagerService.sEnableShellTransitions); - mAppTransitionController = new AppTransitionController(mWm, mDisplayContent); - mWm.mAnimator.ready(); - } - - @Test - public void testSkipOccludedActivityCloseTransition() { - final ActivityRecord behind = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final ActivityRecord topOpening = createActivityRecord(behind.getTask()); - topOpening.setOccludesParent(true); - topOpening.setVisible(true); - - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); - mDisplayContent.mClosingApps.add(behind); - - assertEquals(WindowManager.TRANSIT_OLD_UNSET, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testClearTaskSkipAppExecuteTransition() { - final ActivityRecord behind = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final Task task = behind.getTask(); - final ActivityRecord top = createActivityRecord(task); - top.setState(ActivityRecord.State.RESUMED, "test"); - behind.setState(ActivityRecord.State.STARTED, "test"); - behind.setVisibleRequested(true); - - task.removeActivities("test", false /* excludingTaskOverlay */); - assertFalse(mDisplayContent.mAppTransition.isReady()); - } - - @Test - public void testTranslucentOpen() { - final ActivityRecord behind = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - doReturn(false).when(translucentOpening).fillsParent(); - translucentOpening.setVisible(false); - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); - mDisplayContent.mOpeningApps.add(behind); - mDisplayContent.mOpeningApps.add(translucentOpening); - - assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testTranslucentClose() { - final ActivityRecord behind = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final ActivityRecord translucentClosing = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - doReturn(false).when(translucentClosing).fillsParent(); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); - mDisplayContent.mClosingApps.add(translucentClosing); - assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testDreamActivityOpenTransition() { - final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM); - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); - mDisplayContent.mOpeningApps.add(dreamActivity); - - assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_OPEN, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testDreamActivityCloseTransition() { - final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); - mDisplayContent.mClosingApps.add(dreamActivity); - - assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_CLOSE, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testChangeIsNotOverwritten() { - final ActivityRecord behind = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - translucentOpening.setOccludesParent(false); - translucentOpening.setVisible(false); - mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); - mDisplayContent.mOpeningApps.add(behind); - mDisplayContent.mOpeningApps.add(translucentOpening); - mDisplayContent.mChangingContainers.add(translucentOpening.getTask()); - assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null, null, false)); - } - - @Test - public void testTransitWithinTask() { - final ActivityRecord opening = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); - opening.setOccludesParent(false); - final ActivityRecord closing = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); - closing.setOccludesParent(false); - final Task task = opening.getTask(); - mDisplayContent.mOpeningApps.add(opening); - mDisplayContent.mClosingApps.add(closing); - assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task)); - closing.getTask().removeChild(closing); - task.addChild(closing, 0); - assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task)); - assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_TASK_OPEN, task)); - } - - - @Test - public void testIntraWallpaper_open() { - final ActivityRecord opening = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - opening.setVisible(false); - final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams( - TYPE_BASE_APPLICATION); - attrOpening.setTitle("WallpaperOpening"); - attrOpening.flags |= FLAG_SHOW_WALLPAPER; - final TestWindowState appWindowOpening = createWindowState(attrOpening, opening); - opening.addWindow(appWindowOpening); - - final ActivityRecord closing = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams( - TYPE_BASE_APPLICATION); - attrOpening.setTitle("WallpaperClosing"); - attrClosing.flags |= FLAG_SHOW_WALLPAPER; - final TestWindowState appWindowClosing = createWindowState(attrClosing, closing); - closing.addWindow(appWindowClosing); - - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); - mDisplayContent.mOpeningApps.add(opening); - mDisplayContent.mClosingApps.add(closing); - - assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, appWindowClosing, null, false)); - } - - @Test - public void testIntraWallpaper_toFront() { - final ActivityRecord opening = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - opening.setVisible(false); - final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams( - TYPE_BASE_APPLICATION); - attrOpening.setTitle("WallpaperOpening"); - attrOpening.flags |= FLAG_SHOW_WALLPAPER; - final TestWindowState appWindowOpening = createWindowState(attrOpening, opening); - opening.addWindow(appWindowOpening); - - final ActivityRecord closing = createActivityRecord(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams( - TYPE_BASE_APPLICATION); - attrOpening.setTitle("WallpaperClosing"); - attrClosing.flags |= FLAG_SHOW_WALLPAPER; - final TestWindowState appWindowClosing = createWindowState(attrClosing, closing); - closing.addWindow(appWindowClosing); - - mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT); - mDisplayContent.mOpeningApps.add(opening); - mDisplayContent.mClosingApps.add(closing); - - assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, appWindowClosing, null, false)); - } - - @Test - public void testGetAnimationTargets_visibilityAlreadyUpdated() { - // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible) - // +- [Task2] - [ActivityRecord2] (closing, invisible) - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent); - activity2.setVisible(false); - activity2.setVisibleRequested(false); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // No animation, since visibility of the opening and closing apps are already updated - // outside of AppTransition framework. - assertEquals( - new ArraySet<>(), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested() { - // [DisplayContent] -+- [Task1] - [ActivityRecord1] (closing, invisible) - // +- [Task2] - [ActivityRecord2] (opening, visible) - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(true); - activity1.setVisibleRequested(true); - activity1.mRequestForceTransition = true; - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent); - activity2.setVisible(false); - activity2.setVisibleRequested(false); - activity2.mRequestForceTransition = true; - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // The visibility are already updated, but since forced transition is requested, it will - // be included. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity2.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_exitingBeforeTransition() { - // Create another non-empty task so the animation target won't promote to task display area. - createActivityRecord(mDisplayContent); - final ActivityRecord activity = createActivityRecord(mDisplayContent); - activity.setVisible(false); - activity.mIsExiting = true; - - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity); - - // Animate closing apps even if it's not visible when it is exiting before we had a chance - // to play the transition animation. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity.getRootTask()}), - AppTransitionController.getAnimationTargets( - new ArraySet<>(), closing, false /* visible */)); - } - - @Test - public void testExitAnimationDone_beforeAppTransition() { - final Task task = createTask(mDisplayContent); - final WindowState win = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "Win"); - spyOn(win); - win.mAnimatingExit = true; - mDisplayContent.mAppTransition.setTimeout(); - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); - - verify(win).onExitAnimationDone(); - } - - @Test - public void testGetAnimationTargets_openingClosingInDifferentTask() { - // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) - // | +- [ActivityRecord2] (invisible) - // | - // +- [Task2] -+- [ActivityRecord3] (closing, visible) - // +- [ActivityRecord4] (invisible) - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, - activity1.getTask()); - activity2.setVisible(false); - activity2.setVisibleRequested(false); - - final ActivityRecord activity3 = createActivityRecord(mDisplayContent); - final ActivityRecord activity4 = createActivityRecord(mDisplayContent, - activity3.getTask()); - activity4.setVisible(false); - activity4.setVisibleRequested(false); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity3); - - // Promote animation targets to root Task level. Invisible ActivityRecords don't affect - // promotion decision. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_openingClosingInSameTask() { - // [DisplayContent] - [Task] -+- [ActivityRecord1] (opening, invisible) - // +- [ActivityRecord2] (closing, visible) - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, - activity1.getTask()); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // Don't promote an animation target to Task level, since the same task contains both - // opening and closing app. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity2}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_animateOnlyTranslucentApp() { - // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) - // | +- [ActivityRecord2] (visible) - // | - // +- [Task2] -+- [ActivityRecord3] (closing, visible) - // +- [ActivityRecord4] (visible) - - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - activity1.setOccludesParent(false); - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, - activity1.getTask()); - - final ActivityRecord activity3 = createActivityRecord(mDisplayContent); - activity3.setOccludesParent(false); - final ActivityRecord activity4 = createActivityRecord(mDisplayContent, - activity3.getTask()); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity3); - - // Don't promote an animation target to Task level, since opening (closing) app is - // translucent and is displayed over other non-animating app. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity3}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() { - // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) - // | +- [ActivityRecord2] (opening, invisible) - // | - // +- [Task2] -+- [ActivityRecord3] (closing, visible) - // +- [ActivityRecord4] (closing, visible) - - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - activity1.setOccludesParent(false); - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, - activity1.getTask()); - activity2.setVisible(false); - activity2.setVisibleRequested(true); - - final ActivityRecord activity3 = createActivityRecord(mDisplayContent); - activity3.setOccludesParent(false); - final ActivityRecord activity4 = createActivityRecord(mDisplayContent, - activity3.getTask()); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - opening.add(activity2); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity3); - closing.add(activity4); - - // Promote animation targets to TaskStack level even though opening (closing) app is - // translucent as long as all visible siblings animate at the same time. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_taskContainsMultipleTasks() { - // [DisplayContent] - [Task] -+- [Task1] - [ActivityRecord1] (opening, invisible) - // +- [Task2] - [ActivityRecord2] (closing, visible) - final Task parentTask = createTask(mDisplayContent); - final ActivityRecord activity1 = createActivityRecordWithParentTask(parentTask); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - final ActivityRecord activity2 = createActivityRecordWithParentTask(parentTask); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // Promote animation targets up to Task level, not beyond. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1.getTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity2.getTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_splitScreenOpening() { - // [DisplayContent] - [Task] -+- [split task 1] -+- [Task1] - [AR1] (opening, invisible) - // +- [split task 2] -+- [Task2] - [AR2] (opening, invisible) - final Task singleTopRoot = createTask(mDisplayContent); - final TaskBuilder builder = new TaskBuilder(mSupervisor) - .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW) - .setParentTask(singleTopRoot) - .setCreatedByOrganizer(true); - final Task splitRoot1 = builder.build(); - final Task splitRoot2 = builder.build(); - splitRoot1.setAdjacentTaskFragment(splitRoot2); - final ActivityRecord activity1 = createActivityRecordWithParentTask(splitRoot1); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - final ActivityRecord activity2 = createActivityRecordWithParentTask(splitRoot2); - activity2.setVisible(false); - activity2.setVisibleRequested(true); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - opening.add(activity2); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - - // Promote animation targets up to Task level, not beyond. - assertEquals( - new ArraySet<>(new WindowContainer[]{splitRoot1, splitRoot2}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - } - - @Test - public void testGetAnimationTargets_openingClosingTaskFragment() { - // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible) - // +- [TaskFragment2] - [ActivityRecord2] (closing, visible) - final Task parentTask = createTask(mDisplayContent); - final TaskFragment taskFragment1 = createTaskFragmentWithActivity(parentTask); - final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - - final TaskFragment taskFragment2 = createTaskFragmentWithActivity(parentTask); - final ActivityRecord activity2 = taskFragment2.getTopMostActivity(); - activity2.setVisible(true); - activity2.setVisibleRequested(false); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // Promote animation targets up to TaskFragment level, not beyond. - assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() { - // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible) - // +- [Task2] - [ActivityRecord2] (closing, visible) - final Task task1 = createTask(mDisplayContent); - final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1); - final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent); - activity2.setVisible(true); - activity2.setVisibleRequested(false); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // Promote animation targets up to leaf Task level because there's only one TaskFragment in - // the Task. - assertEquals(new ArraySet<>(new WindowContainer[]{task1}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() { - // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible) - // +- [Task2] - [ActivityRecord2] (opening, invisible) - final Task task1 = createTask(mDisplayContent); - final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1); - final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); - activity1.setVisible(true); - activity1.setVisibleRequested(false); - - final ActivityRecord activity2 = createActivityRecord(mDisplayContent); - activity2.setVisible(false); - activity2.setVisibleRequested(true); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity2); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity1); - - // Promote animation targets up to leaf Task level because there's only one TaskFragment in - // the Task. - assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals(new ArraySet<>(new WindowContainer[]{task1}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - @Test - public void testGetAnimationTargets_embeddedTask() { - // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, invisible) - // +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible) - final ActivityRecord activity1 = createActivityRecord(mDisplayContent); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - - final Task task2 = createTask(mDisplayContent); - task2.mRemoveWithTaskOrganizer = true; - final ActivityRecord activity2 = createActivityRecord(task2); - activity2.setVisible(false); - activity2.setVisibleRequested(true); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - opening.add(activity2); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - - // No animation on the embedded task. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1.getTask()}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - - @Test - public void testGetAnimationTargets_activityInEmbeddedTask() { - // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible) - // +- [ActivityRecord2] (closing, visible) - final Task task = createTask(mDisplayContent); - task.mRemoveWithTaskOrganizer = true; - - final ActivityRecord activity1 = createActivityRecord(task); - activity1.setVisible(false); - activity1.setVisibleRequested(true); - final ActivityRecord activity2 = createActivityRecord(task); - - final ArraySet<ActivityRecord> opening = new ArraySet<>(); - opening.add(activity1); - final ArraySet<ActivityRecord> closing = new ArraySet<>(); - closing.add(activity2); - - // Even though embedded task itself doesn't animate, activities in an embedded task - // animate. - assertEquals( - new ArraySet<>(new WindowContainer[]{activity1}), - AppTransitionController.getAnimationTargets( - opening, closing, true /* visible */)); - assertEquals( - new ArraySet<>(new WindowContainer[]{activity2}), - AppTransitionController.getAnimationTargets( - opening, closing, false /* visible */)); - } - - static class TestRemoteAnimationRunner implements IRemoteAnimationRunner { - private IRemoteAnimationFinishedCallback mFinishedCallback; - - @Override - public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, - IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { - mFinishedCallback = finishedCallback; - } - - @Override - public void onAnimationCancelled() throws RemoteException { - mFinishedCallback = null; - } - - @Override - public IBinder asBinder() { - return new Binder(); - } - - boolean isAnimationStarted() { - return mFinishedCallback != null; - } - - void finishAnimation() { - try { - mFinishedCallback.onAnimationFinished(); - } catch (RemoteException e) { - fail(); - } - } - } - - @Test - public void testGetRemoteAnimationOverrideEmpty() { - final ActivityRecord activity = createActivityRecord(mDisplayContent); - assertNull(mAppTransitionController.getRemoteAnimationOverride(activity, - TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - } - - @Test - public void testGetRemoteAnimationOverrideWindowContainer() { - final ActivityRecord activity = createActivityRecord(mDisplayContent); - final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); - activity.registerRemoteAnimations(definition); - - assertEquals(adapter, - mAppTransitionController.getRemoteAnimationOverride( - activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - assertNull(mAppTransitionController.getRemoteAnimationOverride( - null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - } - - @Test - public void testGetRemoteAnimationOverrideTransitionController() { - final ActivityRecord activity = createActivityRecord(mDisplayContent); - final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); - mAppTransitionController.registerRemoteAnimations(definition); - - assertEquals(adapter, - mAppTransitionController.getRemoteAnimationOverride( - activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - assertEquals(adapter, - mAppTransitionController.getRemoteAnimationOverride( - null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - } - - @Test - public void testGetRemoteAnimationOverrideBoth() { - final ActivityRecord activity = createActivityRecord(mDisplayContent); - final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); - activity.registerRemoteAnimations(definition1); - - final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2); - mAppTransitionController.registerRemoteAnimations(definition2); - - assertEquals(adapter2, - mAppTransitionController.getRemoteAnimationOverride( - activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>())); - assertEquals(adapter2, - mAppTransitionController.getRemoteAnimationOverride( - null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>())); - } - - @Test - public void testGetRemoteAnimationOverrideWindowContainerHasPriority() { - final ActivityRecord activity = createActivityRecord(mDisplayContent); - final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); - activity.registerRemoteAnimations(definition1); - - final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); - final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( - new TestRemoteAnimationRunner(), 10, 1); - definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2); - mAppTransitionController.registerRemoteAnimations(definition2); - - assertEquals(adapter1, - mAppTransitionController.getRemoteAnimationOverride( - activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); - } - - @Test - public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord activity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(activity); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); - waitUntilWindowAnimatorIdle(); - - // Animation run by the remote handler. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() { - final Task task = createTask(mDisplayContent); - final ActivityRecord closingActivity = createActivityRecord(task); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - - // Make sure the TaskFragment is not embedded. - assertFalse(taskFragment.isEmbeddedWithBoundsOverride()); - final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(closingActivity); - prepareActivityForAppTransition(openingActivity); - final int uid = 12345; - closingActivity.info.applicationInfo.uid = uid; - openingActivity.info.applicationInfo.uid = uid; - task.effectiveUid = uid; - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, - null /* changingTaskFragment */); - waitUntilWindowAnimatorIdle(); - - // Animation is not run by the remote handler because the activity is filling the Task. - assertFalse(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() { - final Task task = createTask(mDisplayContent); - final ActivityRecord closingActivity = createActivityRecord(task); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - - // Make sure the TaskFragment is embedded. - taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - final Rect embeddedBounds = new Rect(task.getBounds()); - embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2; - taskFragment.setBounds(embeddedBounds); - assertTrue(taskFragment.isEmbeddedWithBoundsOverride()); - final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(closingActivity); - prepareActivityForAppTransition(openingActivity); - final int uid = 12345; - closingActivity.info.applicationInfo.uid = uid; - openingActivity.info.applicationInfo.uid = uid; - task.effectiveUid = uid; - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, - null /* changingTaskFragment */); - waitUntilWindowAnimatorIdle(); - - // Animation run by the remote handler. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Closing non-embedded activity. - final ActivityRecord closingActivity = createActivityRecord(task); - prepareActivityForAppTransition(closingActivity); - // Opening TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(openingActivity); - task.effectiveUid = openingActivity.getUid(); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); - waitUntilWindowAnimatorIdle(); - - // Animation run by the remote handler. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Closing TaskFragment with embedded activity. - final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord closingActivity = taskFragment1.getTopMostActivity(); - prepareActivityForAppTransition(closingActivity); - closingActivity.info.applicationInfo.uid = 12345; - // Opening TaskFragment with embedded activity with different UID. - final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord openingActivity = taskFragment2.getTopMostActivity(); - prepareActivityForAppTransition(openingActivity); - openingActivity.info.applicationInfo.uid = 54321; - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1); - waitUntilWindowAnimatorIdle(); - - // Animation run by the remote handler. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Closing activity in Task1. - final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); - prepareActivityForAppTransition(closingActivity); - // Opening TaskFragment with embedded activity in Task2. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(openingActivity); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); - waitUntilWindowAnimatorIdle(); - - // Animation not run by the remote handler. - assertFalse(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Closing TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord closingActivity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(closingActivity); - closingActivity.info.applicationInfo.uid = 12345; - task.effectiveUid = closingActivity.getUid(); - // Opening non-embedded activity with different UID. - final ActivityRecord openingActivity = createActivityRecord(task); - prepareActivityForAppTransition(openingActivity); - openingActivity.info.applicationInfo.uid = 54321; - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); - waitUntilWindowAnimatorIdle(); - - // Animation should not run by the remote handler when there are non-embedded activities of - // different UID. - assertFalse(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with embedded activity. - final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); - final ActivityRecord activity = taskFragment.getTopMostActivity(); - prepareActivityForAppTransition(activity); - // Set wallpaper as visible. - final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, - mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); - spyOn(mDisplayContent.mWallpaperController); - doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible(); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); - waitUntilWindowAnimatorIdle(); - - // Animation should not run by the remote handler when there is wallpaper in the transition. - assertFalse(remoteAnimationRunner.isAnimationStarted()); - } - - @Test - public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with embedded activities, one is trusted embedded, and the other - // one is untrusted embedded. - final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .createActivityCount(2) - .setOrganizer(organizer) - .build(); - final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord(); - final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord(); - // Also create a non-embedded activity in the Task. - final ActivityRecord activity2 = new ActivityBuilder(mAtm).build(); - task.addChild(activity2, POSITION_BOTTOM); - prepareActivityForAppTransition(activity0); - prepareActivityForAppTransition(activity1); - prepareActivityForAppTransition(activity2); - doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0); - doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment); - waitUntilWindowAnimatorIdle(); - - // The animation will be animated remotely by client and all activities are input disabled - // for untrusted animation. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - verify(activity0).setDropInputForAnimation(true); - verify(activity1).setDropInputForAnimation(true); - verify(activity2).setDropInputForAnimation(true); - verify(activity0).setDropInputMode(DropInputMode.ALL); - verify(activity1).setDropInputMode(DropInputMode.ALL); - verify(activity2).setDropInputMode(DropInputMode.ALL); - - // Reset input after animation is finished. - clearInvocations(activity0); - clearInvocations(activity1); - clearInvocations(activity2); - remoteAnimationRunner.finishAnimation(); - - verify(activity0).setDropInputForAnimation(false); - verify(activity1).setDropInputForAnimation(false); - verify(activity2).setDropInputForAnimation(false); - verify(activity0).setDropInputMode(DropInputMode.OBSCURED); - verify(activity1).setDropInputMode(DropInputMode.NONE); - verify(activity2).setDropInputMode(DropInputMode.NONE); - } - - /** - * Since we don't have any use case to rely on handling input during animation, disable it even - * if it is trusted embedding so that it could cover some edge-cases when a previously trusted - * host starts doing something bad. - */ - @Test - public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with only trusted embedded activity - final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .createActivityCount(1) - .setOrganizer(organizer) - .build(); - final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord(); - prepareActivityForAppTransition(activity); - doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); - waitUntilWindowAnimatorIdle(); - - // The animation will be animated remotely by client and all activities are input disabled - // for untrusted animation. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - verify(activity).setDropInputForAnimation(true); - verify(activity).setDropInputMode(DropInputMode.ALL); - - // Reset input after animation is finished. - clearInvocations(activity); - remoteAnimationRunner.finishAnimation(); - - verify(activity).setDropInputForAnimation(false); - verify(activity).setDropInputMode(DropInputMode.NONE); - } - - /** - * We don't need to drop input for fully trusted embedding (system app, and embedding in the - * same app). This will allow users to do fast tapping. - */ - @Test - public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() { - final Task task = createTask(mDisplayContent); - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); - - // Create a TaskFragment with only trusted embedded activity - final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .createActivityCount(1) - .setOrganizer(organizer) - .build(); - final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord(); - prepareActivityForAppTransition(activity); - final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid( - getITaskFragmentOrganizer(organizer)); - doReturn(true).when(task).isFullyTrustedEmbedding(uid); - spyOn(mDisplayContent.mAppTransition); - - // Prepare and start transition. - prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); - waitUntilWindowAnimatorIdle(); - - // The animation will be animated remotely by client, but input should not be dropped for - // fully trusted. - assertTrue(remoteAnimationRunner.isAnimationStarted()); - verify(activity, never()).setDropInputForAnimation(true); - verify(activity, never()).setDropInputMode(DropInputMode.ALL); - } - - @Test - public void testTransitionGoodToGoForTaskFragments() { - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final Task task = createTask(mDisplayContent); - final TaskFragment changeTaskFragment = - createTaskFragmentWithEmbeddedActivity(task, organizer); - final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .setOrganizer(organizer) - .build(); - prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity()); - spyOn(mDisplayContent.mAppTransition); - spyOn(emptyTaskFragment); - - prepareAndTriggerAppTransition( - null /* openingActivity */, null /* closingActivity*/, changeTaskFragment); - - // Transition not ready because there is an empty non-finishing TaskFragment. - verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); - - doReturn(true).when(emptyTaskFragment).hasChild(); - emptyTaskFragment.remove(false /* withTransition */, "test"); - - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); - - // Transition ready because the empty (no running activity) TaskFragment is requested to be - // removed. - verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); - } - - @Test - public void testTransitionGoodToGoForTaskFragments_detachedApp() { - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer); - registerTaskFragmentOrganizer(iOrganizer); - final Task task = createTask(mDisplayContent); - final TaskFragment changeTaskFragment = - createTaskFragmentWithEmbeddedActivity(task, organizer); - final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .setOrganizer(organizer) - .build(); - prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity()); - // To make sure that having a detached activity won't cause any issue. - final ActivityRecord detachedActivity = createActivityRecord(task); - detachedActivity.removeImmediately(); - assertNull(detachedActivity.getRootTask()); - spyOn(mDisplayContent.mAppTransition); - spyOn(emptyTaskFragment); - - prepareAndTriggerAppTransition( - null /* openingActivity */, detachedActivity, changeTaskFragment); - - // Transition not ready because there is an empty non-finishing TaskFragment. - verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); - - doReturn(true).when(emptyTaskFragment).hasChild(); - emptyTaskFragment.remove(false /* withTransition */, "test"); - - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); - - // Transition ready because the empty (no running activity) TaskFragment is requested to be - // removed. - verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); - } - - /** Registers remote animation for the organizer. */ - private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, - TestRemoteAnimationRunner remoteAnimationRunner) { - final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - remoteAnimationRunner, 10, 1); - final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer); - final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); - definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); - definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); - definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); - definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); - definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter); - registerTaskFragmentOrganizer(iOrganizer); - mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); - } - - private static ITaskFragmentOrganizer getITaskFragmentOrganizer( - TaskFragmentOrganizer organizer) { - return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); - } - - private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity, - @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) { - if (openingActivity != null) { - mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); - mDisplayContent.mOpeningApps.add(openingActivity); - } - if (closingActivity != null) { - mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0); - mDisplayContent.mClosingApps.add(closingActivity); - } - if (changingTaskFragment != null) { - mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); - mDisplayContent.mChangingContainers.add(changingTaskFragment); - } - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); - } - - private static void prepareActivityForAppTransition(ActivityRecord activity) { - // Transition will wait until all participated activities to be drawn. - activity.allDrawn = true; - // Skip manipulate the SurfaceControl. - doNothing().when(activity).setDropInputMode(anyInt()); - // Assume the activity contains a window. - doReturn(true).when(activity).hasChild(); - // Make sure activity can create remote animation target. - doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget( - any()); - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java deleted file mode 100644 index 8553fbd30ab8..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (C) 2016 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 com.android.server.wm; - -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.TRANSIT_CHANGE; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; -import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; -import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_UNSET; -import static android.view.WindowManager.TRANSIT_OPEN; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.WindowContainer.POSITION_TOP; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; - -import android.graphics.Rect; -import android.os.Binder; -import android.os.IBinder; -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; -import android.util.ArraySet; -import android.view.Display; -import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationRunner; -import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationTarget; -import android.view.SurfaceControl; -import android.view.WindowManager; -import android.view.animation.Animation; -import android.window.ITaskFragmentOrganizer; -import android.window.TaskFragmentOrganizer; - -import androidx.test.filters.SmallTest; - -import com.android.internal.policy.TransitionAnimation; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test class for {@link AppTransition}. - * - * Build/Install/Run: - * atest WmTests:AppTransitionTests - */ -@SmallTest -@Presubmit -@RunWith(WindowTestRunner.class) -public class AppTransitionTests extends WindowTestsBase { - private DisplayContent mDc; - - @Before - public void setUp() throws Exception { - doNothing().when(mWm.mRoot).performSurfacePlacement(); - mDc = mWm.getDefaultDisplayContentLocked(); - } - - @Test - public void testKeyguardOverride() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE); - mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); - mDc.mOpeningApps.add(activity); - assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testKeyguardUnoccludeOcclude() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE); - mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE); - mDc.mOpeningApps.add(activity); - assertEquals(TRANSIT_NONE, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - - } - - @Test - public void testKeyguardKeep() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.mOpeningApps.add(activity); - assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testCrashing() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); - mDc.mClosingApps.add(activity); - assertEquals(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testKeepKeyguard_withCrashing() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); - mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); - mDc.mClosingApps.add(activity); - assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testSkipTransitionAnimation() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - final ActivityRecord activity = createActivityRecord(dc); - - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.prepareAppTransition(TRANSIT_CLOSE); - mDc.mClosingApps.add(activity); - assertEquals(TRANSIT_OLD_UNSET, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, true /*skipAppTransitionAnimation*/)); - } - - @Test - public void testTaskChangeWindowingMode() { - final ActivityRecord activity = createActivityRecord(mDc); - - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.prepareAppTransition(TRANSIT_CHANGE); - mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority - mDc.mChangingContainers.add(activity.getTask()); - - assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testTaskFragmentChange() { - final ActivityRecord activity = createActivityRecord(mDc); - final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(), - true /* createdByOrganizer */, true /* isEmbedded */); - activity.getTask().addChild(taskFragment, POSITION_TOP); - activity.reparent(taskFragment, POSITION_TOP); - - mDc.prepareAppTransition(TRANSIT_OPEN); - mDc.prepareAppTransition(TRANSIT_CHANGE); - mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority - mDc.mChangingContainers.add(taskFragment); - - assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, - AppTransitionController.getTransitCompatType(mDc.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); - } - - @Test - public void testTaskFragmentOpeningTransition() { - final ActivityRecord activity = createHierarchyForTaskFragmentTest(); - activity.setVisible(false); - - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); - mDisplayContent.mOpeningApps.add(activity); - assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /* skipAppTransitionAnimation */)); - } - - @Test - public void testTaskFragmentClosingTransition() { - final ActivityRecord activity = createHierarchyForTaskFragmentTest(); - activity.setVisible(true); - - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); - mDisplayContent.mClosingApps.add(activity); - assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, - AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers, null /* wallpaperTarget */, - null /* oldWallpaper */, false /* skipAppTransitionAnimation */)); - } - - /** - * Creates a {@link Task} with two {@link TaskFragment TaskFragments}. - * The bottom TaskFragment is to prevent - * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation - * target} to promote to Task or above. - * - * @return The Activity to be put in either opening or closing Activity - */ - private ActivityRecord createHierarchyForTaskFragmentTest() { - final Task parentTask = createTask(mDisplayContent); - final TaskFragment bottomTaskFragment = createTaskFragmentWithActivity(parentTask); - final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity(); - bottomActivity.setOccludesParent(true); - bottomActivity.setVisible(true); - - final TaskFragment verifiedTaskFragment = createTaskFragmentWithActivity(parentTask); - final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity(); - activity.setOccludesParent(true); - - return activity; - } - - @Test - public void testAppTransitionStateForMultiDisplay() { - // Create 2 displays & presume both display the state is ON for ready to display & animate. - final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); - final DisplayContent dc2 = createNewDisplay(Display.STATE_ON); - - // Create 2 app window tokens to represent 2 activity window. - final ActivityRecord activity1 = createActivityRecord(dc1); - final ActivityRecord activity2 = createActivityRecord(dc2); - - activity1.allDrawn = true; - activity1.startingMoved = true; - - // Simulate activity resume / finish flows to prepare app transition & set visibility, - // make sure transition is set as expected for each display. - dc1.prepareAppTransition(TRANSIT_OPEN); - dc2.prepareAppTransition(TRANSIT_CLOSE); - // One activity window is visible for resuming & the other activity window is invisible - // for finishing in different display. - activity1.setVisibility(true); - activity2.setVisibility(false); - - // Make sure each display is in animating stage. - assertTrue(dc1.mOpeningApps.size() > 0); - assertTrue(dc2.mClosingApps.size() > 0); - assertTrue(dc1.isAppTransitioning()); - assertTrue(dc2.isAppTransitioning()); - } - - @Test - public void testCleanAppTransitionWhenRootTaskReparent() { - // Create 2 displays & presume both display the state is ON for ready to display & animate. - final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); - final DisplayContent dc2 = createNewDisplay(Display.STATE_ON); - - final Task rootTask1 = createTask(dc1); - final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */); - final ActivityRecord activity1 = createNonAttachedActivityRecord(dc1); - task1.addChild(activity1, 0); - - // Simulate same app is during opening / closing transition set stage. - dc1.mClosingApps.add(activity1); - assertTrue(dc1.mClosingApps.size() > 0); - - dc1.prepareAppTransition(TRANSIT_OPEN); - assertTrue(dc1.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); - assertTrue(dc1.mAppTransition.isTransitionSet()); - - dc1.mOpeningApps.add(activity1); - assertTrue(dc1.mOpeningApps.size() > 0); - - // Move root task to another display. - rootTask1.reparent(dc2.getDefaultTaskDisplayArea(), true); - - // Verify if token are cleared from both pending transition list in former display. - assertFalse(dc1.mOpeningApps.contains(activity1)); - assertFalse(dc1.mOpeningApps.contains(activity1)); - } - - @Test - public void testLoadAnimationSafely() { - DisplayContent dc = createNewDisplay(Display.STATE_ON); - assertNull(dc.mAppTransition.loadAnimationSafely( - getInstrumentation().getTargetContext(), -1)); - } - - @Test - public void testCancelRemoteAnimationWhenFreeze() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - doReturn(false).when(dc).onDescendantOrientationChanged(any()); - final WindowState exitingAppWindow = newWindowBuilder("exiting app", - TYPE_BASE_APPLICATION).setDisplay(dc).build(); - final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord; - // Wait until everything in animation handler get executed to prevent the exiting window - // from being removed during WindowSurfacePlacer Traversal. - waitUntilHandlersIdle(); - - // Set a remote animator. - final TestRemoteAnimationRunner runner = new TestRemoteAnimationRunner(); - final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - runner, 100, 50, true /* changeNeedsSnapshot */); - // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid. - adapter.setCallingPidUid(123, 456); - - // Simulate activity finish flows to prepare app transition & set visibility, - // make sure transition is set as expected. - dc.prepareAppTransition(TRANSIT_CLOSE); - assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_CLOSE)); - dc.mAppTransition.overridePendingAppTransitionRemote(adapter); - exitingActivity.setVisibility(false); - assertTrue(dc.mClosingApps.size() > 0); - - // Make sure window is in animating stage before freeze, and cancel after freeze. - assertTrue(dc.isAppTransitioning()); - assertFalse(runner.mCancelled); - dc.mAppTransition.freeze(); - assertFalse(dc.isAppTransitioning()); - assertTrue(runner.mCancelled); - } - - @Test - public void testGetAnimationStyleResId() { - // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without - // specifying window type. - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); - attrs.windowAnimations = 0x12345678; - assertEquals(attrs.windowAnimations, mDc.mAppTransition.getAnimationStyleResId(attrs)); - - // Verify getAnimationStyleResId will return system resource Id when the window type is - // starting window. - attrs.type = TYPE_APPLICATION_STARTING; - assertEquals(mDc.mAppTransition.getDefaultWindowAnimationStyleResId(), - mDc.mAppTransition.getAnimationStyleResId(attrs)); - } - - @Test - public void testActivityRecordReparentedToTaskFragment() { - final ActivityRecord activity = createActivityRecord(mDc); - final SurfaceControl activityLeash = mock(SurfaceControl.class); - doNothing().when(activity).setDropInputMode(anyInt()); - activity.setVisibility(true); - activity.setSurfaceControl(activityLeash); - final Task task = activity.getTask(); - - // Add a TaskFragment of half of the Task size. - final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final ITaskFragmentOrganizer iOrganizer = - ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); - registerTaskFragmentOrganizer(iOrganizer); - final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .setOrganizer(organizer) - .build(); - final Rect taskBounds = new Rect(); - task.getBounds(taskBounds); - taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom); - spyOn(taskFragment); - - assertTrue(mDc.mChangingContainers.isEmpty()); - assertFalse(mDc.mAppTransition.isTransitionSet()); - - // Schedule app transition when reparent activity to a TaskFragment of different size. - final Rect startBounds = new Rect(activity.getBounds()); - activity.reparent(taskFragment, POSITION_TOP); - - // It should transit at TaskFragment level with snapshot on the activity surface. - verify(taskFragment).initializeChangeTransition(activity.getBounds(), activityLeash); - assertTrue(mDc.mChangingContainers.contains(taskFragment)); - assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)); - } - - @Test - public void testGetNextAppTransitionBackgroundColor() { - assumeFalse(WindowManagerService.sEnableShellTransitions); - - // No override by default. - assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); - - // Override with a custom color. - mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); - final int testColor = 123; - mDc.mAppTransition.overridePendingAppTransition("testPackage", 0 /* enterAnim */, - 0 /* exitAnim */, testColor, null /* startedCallback */, null /* endedCallback */, - false /* overrideTaskTransaction */); - - assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); - assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); - - // Override with ActivityEmbedding remote animation. Background color should be kept. - mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), - false /* sync */, true /* isActivityEmbedding */); - - assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); - assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); - - // Background color should not be cleared anymore after #clear(). - mDc.mAppTransition.clear(); - assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); - assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); - } - - @Test - public void testGetNextAppRequestedAnimation() { - assumeFalse(WindowManagerService.sEnableShellTransitions); - final String packageName = "testPackage"; - final int enterAnimResId = 1; - final int exitAnimResId = 2; - final int testColor = 123; - final Animation enterAnim = mock(Animation.class); - final Animation exitAnim = mock(Animation.class); - final TransitionAnimation transitionAnimation = mDc.mAppTransition.mTransitionAnimation; - spyOn(transitionAnimation); - doReturn(enterAnim).when(transitionAnimation) - .loadAppTransitionAnimation(packageName, enterAnimResId); - doReturn(exitAnim).when(transitionAnimation) - .loadAppTransitionAnimation(packageName, exitAnimResId); - - // No override by default. - assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); - assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); - - // Override with a custom animation. - mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); - mDc.mAppTransition.overridePendingAppTransition(packageName, enterAnimResId, exitAnimResId, - testColor, null /* startedCallback */, null /* endedCallback */, - false /* overrideTaskTransaction */); - - assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); - assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); - assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); - - // Override with ActivityEmbedding remote animation. Custom animation should be kept. - mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), - false /* sync */, true /* isActivityEmbedding */); - - assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); - assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); - assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); - - // Custom animation should not be cleared anymore after #clear(). - mDc.mAppTransition.clear(); - assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); - assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); - } - - private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { - boolean mCancelled = false; - @Override - public void onAnimationStart(@WindowManager.TransitionOldType int transit, - RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, - RemoteAnimationTarget[] nonApps, - IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { - } - - @Override - public void onAnimationCancelled() { - mCancelled = true; - } - - @Override - public IBinder asBinder() { - return null; - } - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 0964ebed9d25..82435b24dad6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1172,11 +1172,12 @@ public class DisplayContentTests extends WindowTestsBase { .setScreenOrientation(getRotatedOrientation(mDisplayContent)).build(); prev.setVisibleRequested(false); final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true) + .setVisible(false) .setScreenOrientation(SCREEN_ORIENTATION_BEHIND).build(); assertNotEquals(WindowConfiguration.ROTATION_UNDEFINED, mDisplayContent.rotationForActivityInDifferentOrientation(top)); - mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0); + requestTransition(top, WindowManager.TRANSIT_OPEN); top.setVisibility(true); mDisplayContent.updateOrientation(); // The top uses "behind", so the orientation is decided by the previous. @@ -1609,8 +1610,7 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord app = mAppWindow.mActivityRecord; app.setVisible(false); app.setVisibleRequested(false); - registerTestTransitionPlayer(); - mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0); + requestTransition(app, WindowManager.TRANSIT_OPEN); app.setVisibility(true); final int newOrientation = getRotatedOrientation(mDisplayContent); app.setRequestedOrientation(newOrientation); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index fc4f54a431d6..e4a1bf603cf0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -454,31 +454,6 @@ public class RootWindowContainerTests extends WindowTestsBase { } @Test - public void testMovingBottomMostRootTaskActivityToPinnedRootTask() { - final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord firstActivity = new ActivityBuilder(mAtm) - .setTask(fullscreenTask).build(); - final Task task = firstActivity.getTask(); - - final ActivityRecord secondActivity = new ActivityBuilder(mAtm) - .setTask(fullscreenTask).build(); - - fullscreenTask.moveTaskToBack(task); - - // Ensure full screen task has both tasks. - ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity); - assertEquals(task.getTopMostActivity(), secondActivity); - firstActivity.setState(STOPPED, "testMovingBottomMostRootTaskActivityToPinnedRootTask"); - - - // Move first activity to pinned root task. - mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove"); - - assertTrue(firstActivity.mRequestForceTransition); - } - - @Test public void testMultipleActivitiesTaskEnterPip() { // Enable shell transition because the order of setting windowing mode is different. registerTestTransitionPlayer(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index dba463a436c0..95bca2b17efb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -1811,9 +1811,9 @@ public class SizeCompatTests extends WindowTestsBase { } addStatusBar(mActivity.mDisplayContent); - mActivity.setVisible(false); - mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN); - mActivity.mDisplayContent.mOpeningApps.add(mActivity); + mActivity.setVisibleRequested(false); + requestTransition(mActivity, WindowManager.TRANSIT_OPEN); + mActivity.setVisibility(true); final float maxAspect = 1.8f; prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 001446550304..edffab801499 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -32,8 +32,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_OPEN; import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -85,12 +83,8 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; -import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationRunner; import android.view.InsetsFrameProvider; import android.view.InsetsSource; -import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowInsets; @@ -1055,25 +1049,6 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testTaskCanApplyAnimation() { - final Task rootTask = createTask(mDisplayContent); - final Task task = createTaskInRootTask(rootTask, 0 /* userId */); - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task); - final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task); - verifyWindowContainerApplyAnimation(task, activity1, activity2); - } - - @Test - public void testRootTaskCanApplyAnimation() { - final Task rootTask = createTask(mDisplayContent); - final ActivityRecord activity2 = createActivityRecord(mDisplayContent, - createTaskInRootTask(rootTask, 0 /* userId */)); - final ActivityRecord activity1 = createActivityRecord(mDisplayContent, - createTaskInRootTask(rootTask, 0 /* userId */)); - verifyWindowContainerApplyAnimation(rootTask, activity1, activity2); - } - - @Test public void testGetDisplayArea() { // WindowContainer final WindowContainer windowContainer = new WindowContainer(mWm); @@ -1103,59 +1078,6 @@ public class WindowContainerTests extends WindowTestsBase { assertEquals(displayArea, displayArea.getDisplayArea()); } - private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act, - ActivityRecord act2) { - // Initial remote animation for app transition. - final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - new IRemoteAnimationRunner.Stub() { - @Override - public void onAnimationStart(@WindowManager.TransitionOldType int transit, - RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, - RemoteAnimationTarget[] nonApps, - IRemoteAnimationFinishedCallback finishedCallback) { - try { - finishedCallback.onAnimationFinished(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - @Override - public void onAnimationCancelled() { - } - }, 0, 0, false); - adapter.setCallingPidUid(123, 456); - wc.getDisplayContent().prepareAppTransition(TRANSIT_OPEN); - wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter); - spyOn(wc); - doReturn(true).when(wc).okToAnimate(); - - // Make sure animating state is as expected after applied animation. - - // 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_OLD_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)); - 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. - wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_OLD_TASK_OPEN, act); - verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any()); - assertFalse(wc.isAnimating()); - assertFalse(act.isAnimating(PARENTS)); - } - @Test public void testRegisterWindowContainerListener() { final WindowContainer container = new WindowContainer(mWm); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index b16f5283d532..7f9e591ca5e3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -961,6 +961,15 @@ public class WindowTestsBase extends SystemServiceTestsBase { return testPlayer; } + void requestTransition(WindowContainer<?> wc, int transit) { + final TransitionController controller = mRootWindowContainer.mTransitionController; + if (controller.getTransitionPlayer() == null) { + registerTestTransitionPlayer(); + } + controller.requestTransitionIfNeeded(transit, 0 /* flags */, null /* trigger */, + wc.mDisplayContent); + } + /** Overrides the behavior of config_reverseDefaultRotation for the given display. */ void setReverseDefaultRotation(DisplayContent dc, boolean reverse) { final DisplayRotation displayRotation = dc.getDisplayRotation(); @@ -1417,7 +1426,9 @@ public class WindowTestsBase extends SystemServiceTestsBase { activity.setProcess(wpc); // Resume top activities to make sure all other signals in the system are connected. - mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); + if (mVisible) { + mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); + } return activity; } } |