diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5e92b9e4d46ad..6a68fabbe45ee 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -18,7 +18,17 @@ package com.android.server.wm; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX; +import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; +import static android.app.ActivityOptions.ANIM_CUSTOM; +import static android.app.ActivityOptions.ANIM_NONE; +import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; +import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION; +import static android.app.ActivityOptions.ANIM_SCALE_UP; import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.AppOpsManager.MODE_ALLOWED; @@ -63,6 +73,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; import static android.content.res.Configuration.EMPTY; @@ -111,12 +122,18 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; -import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService + .RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.TaskPersister.DEBUG; import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; @@ -147,6 +164,7 @@ import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.os.Binder; import android.os.Build; @@ -167,11 +185,14 @@ import android.util.MergedConfiguration; import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import android.view.AppTransitionAnimationSpec; +import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.RemoteAnimationDefinition; import android.view.WindowManager.LayoutParams; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.util.XmlUtils; @@ -200,7 +221,7 @@ import java.util.Objects; /** * An entry in the history stack, representing an activity. */ -final class ActivityRecord extends ConfigurationContainer implements AppWindowContainerListener { +final class ActivityRecord extends ConfigurationContainer { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE; @@ -225,7 +246,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo final ActivityTaskManagerService service; // owner final IApplicationToken.Stub appToken; // window manager token - AppWindowContainerController mWindowContainerController; + // TODO: Remove after unification + AppWindowToken mAppWindowToken; + final ActivityInfo info; // all about me // TODO: This is duplicated state already contained in info.applicationInfo - remove ApplicationInfo appInfo; // information about activity's app @@ -769,10 +792,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } /** - * See {@link AppWindowContainerController#setWillCloseOrEnterPip(boolean)} + * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP. + * This information helps AWT know that the app is in the process of pausing before it gets the + * signal on the WM side. */ void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { - getWindowContainerController().setWillCloseOrEnterPip(willCloseOrEnterPip); + if (mAppWindowToken == null) { + return; + } + + mAppWindowToken.setWillCloseOrEnterPip(willCloseOrEnterPip); } static class Token extends IApplicationToken.Stub { @@ -991,13 +1020,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return hasProcess() && app.hasThread(); } - AppWindowContainerController getWindowContainerController() { - return mWindowContainerController; - } - - void createWindowContainer() { - if (mWindowContainerController != null) { - throw new IllegalArgumentException("Window container=" + mWindowContainerController + void createAppWindowToken() { + if (mAppWindowToken != null) { + throw new IllegalArgumentException("App Window Token=" + mAppWindowToken + " already created for r=" + this); } @@ -1010,12 +1035,31 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // Make sure override configuration is up-to-date before using to create window controller. updateOverrideConfiguration(); - mWindowContainerController = new AppWindowContainerController(taskController, appToken, - realActivity, this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, - fullscreen, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges, - task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(), - appInfo.targetSdkVersion, mRotationAnimationHint, - ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L); + // TODO: remove after unification + mAppWindowToken = service.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder()); + if (mAppWindowToken != null) { + // TODO: Should this throw an exception instead? + Slog.w(TAG, "Attempted to add existing app token: " + appToken); + } else { + final Task container = taskController.mContainer; + if (container == null) { + throw new IllegalArgumentException("AppWindowContainerController: invalid " + + " controller=" + taskController); + } + mAppWindowToken = createAppWindow(service.mWindowManager, appToken, + task.voiceSession != null, container.getDisplayContent(), + ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) + * 1000000L, fullscreen, + (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion, + info.screenOrientation, mRotationAnimationHint, info.configChanges, + mLaunchTaskBehind, isAlwaysFocusable()); + if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) { + Slog.v(TAG, "addAppToken: " + + mAppWindowToken + " controller=" + taskController + " at " + + Integer.MAX_VALUE); + } + container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */); + } task.addActivityToTop(this); @@ -1026,17 +1070,49 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo mLastReportedPictureInPictureMode = inPinnedWindowingMode(); } + boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, + CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, + IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, + boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "setAppStartingWindow: token=" + appToken + + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask + + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning + + " allowTaskSnapshot=" + allowTaskSnapshot); + } + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken); + return false; + } + return mAppWindowToken.addStartingWindow(pkg, theme, compatInfo, nonLocalizedLabel, + labelRes, icon, logo, windowFlags, transferFrom, newTask, taskSwitch, + processRunning, allowTaskSnapshot, activityCreated, fromRecents); + } + + // TODO: Remove after unification + @VisibleForTesting + AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, + boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, + boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, + int rotationAnimationHint, int configChanges, boolean launchTaskBehind, + boolean alwaysFocusable) { + return new AppWindowToken(service, token, realActivity, voiceInteraction, dc, + inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, + rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, + this); + } + void removeWindowContainer() { - // Do not try to remove a window container if we have already removed it. - if (mWindowContainerController == null) { + final DisplayContent dc = service.mWindowManager.mRoot.getDisplayContent( + getDisplayId()); + if (dc == null) { + Slog.w(TAG, "removeWindowContainer: Attempted to remove token: " + + appToken + " from non-existing displayId=" + getDisplayId()); return; } - // Resume key dispatching if it is currently paused before we remove the container. resumeKeyDispatchingLocked(); - - mWindowContainerController.removeContainer(getDisplayId()); - mWindowContainerController = null; + dc.removeAppToken(appToken.asBinder()); } /** @@ -1044,6 +1120,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * should ensure that the {@param newTask} is not already the parent of this activity. */ void reparent(TaskRecord newTask, int position, String reason) { + if (mAppWindowToken == null) { + Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken); + return; + } final TaskRecord prevTask = task; if (prevTask == newTask) { throw new IllegalArgumentException(reason + ": task=" + newTask @@ -1059,8 +1139,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo + " r=" + this + " (" + prevTask.getStackId() + ")"); } - // Must reparent first in window manager - mWindowContainerController.reparent(newTask.getWindowContainerController(), position); + mAppWindowToken.reparent(newTask.getWindowContainerController(), position); // Reparenting prevents informing the parent stack of activity removal in the case that // the new stack has the same parent. we must manually signal here if this is not the case. @@ -1490,7 +1569,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void applyOptionsLocked() { if (pendingOptions != null && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) { - mWindowContainerController.applyOptionsLocked(pendingOptions, intent); + applyOptionsLocked(pendingOptions, intent); if (task == null) { clearOptionsLocked(false /* withAbort */); } else { @@ -1500,6 +1579,104 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } + /** + * Apply override app transition base on options & animation type. + */ + void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { + final int animationType = pendingOptions.getAnimationType(); + final DisplayContent displayContent = mAppWindowToken.getDisplayContent(); + switch (animationType) { + case ANIM_CUSTOM: + displayContent.mAppTransition.overridePendingAppTransition( + pendingOptions.getPackageName(), + pendingOptions.getCustomEnterResId(), + pendingOptions.getCustomExitResId(), + pendingOptions.getOnAnimationStartListener()); + break; + case ANIM_CLIP_REVEAL: + displayContent.mAppTransition.overridePendingAppTransitionClipReveal( + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getWidth(), pendingOptions.getHeight()); + if (intent.getSourceBounds() == null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX() + pendingOptions.getWidth(), + pendingOptions.getStartY() + pendingOptions.getHeight())); + } + break; + case ANIM_SCALE_UP: + displayContent.mAppTransition.overridePendingAppTransitionScaleUp( + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getWidth(), pendingOptions.getHeight()); + if (intent.getSourceBounds() == null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX() + pendingOptions.getWidth(), + pendingOptions.getStartY() + pendingOptions.getHeight())); + } + break; + case ANIM_THUMBNAIL_SCALE_UP: + case ANIM_THUMBNAIL_SCALE_DOWN: + final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP); + final GraphicBuffer buffer = pendingOptions.getThumbnail(); + displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getOnAnimationStartListener(), + scaleUp); + if (intent.getSourceBounds() == null && buffer != null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX() + buffer.getWidth(), + pendingOptions.getStartY() + buffer.getHeight())); + } + break; + case ANIM_THUMBNAIL_ASPECT_SCALE_UP: + case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: + final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); + final IAppTransitionAnimationSpecsFuture specsFuture = + pendingOptions.getSpecsFuture(); + if (specsFuture != null) { + // TODO(multidisplay): Shouldn't be really used anymore from next CL. + displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( + specsFuture, pendingOptions.getOnAnimationStartListener(), + animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); + } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN + && specs != null) { + displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( + specs, pendingOptions.getOnAnimationStartListener(), + pendingOptions.getAnimationFinishedListener(), false); + } else { + displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( + pendingOptions.getThumbnail(), + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getWidth(), pendingOptions.getHeight(), + pendingOptions.getOnAnimationStartListener(), + (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); + if (intent.getSourceBounds() == null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX() + pendingOptions.getWidth(), + pendingOptions.getStartY() + pendingOptions.getHeight())); + } + } + break; + case ANIM_OPEN_CROSS_PROFILE_APPS: + displayContent.mAppTransition + .overridePendingAppTransitionStartCrossProfileApps(); + break; + case ANIM_REMOTE_ANIMATION: + // TODO(multidisplay): Will pass displayId and adjust dependencies from next CL. + displayContent.mAppTransition.overridePendingAppTransitionRemote( + pendingOptions.getRemoteAnimationAdapter()); + break; + case ANIM_NONE: + break; + default: + Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType); + break; + } + } + ActivityOptions getOptionsForTargetActivityLocked() { return pendingOptions != null ? pendingOptions.forTargetActivity() : null; } @@ -1532,8 +1709,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (!keysPaused) { keysPaused = true; - if (mWindowContainerController != null) { - mWindowContainerController.pauseKeyDispatching(); + // TODO: remove the check after unification with AppWindowToken. The DC check is not + // needed after no mock mAppWindowToken in tests. + if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) { + mAppWindowToken.getDisplayContent().getInputMonitor().pauseDispatchingLw( + mAppWindowToken); } } } @@ -1542,8 +1722,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (keysPaused) { keysPaused = false; - if (mWindowContainerController != null) { - mWindowContainerController.resumeKeyDispatching(); + // TODO: remove the check after unification with AppWindowToken. The DC check is not + // needed after no mock mAppWindowToken in tests. + if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) { + mAppWindowToken.getDisplayContent().getInputMonitor().resumeDispatchingLw( + mAppWindowToken); } } } @@ -1565,11 +1748,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } void setVisibility(boolean visible) { - mWindowContainerController.setVisibility(visible, mDeferHidingClient); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + + appToken); + return; + } + mAppWindowToken.setVisibility(visible, mDeferHidingClient); mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this); } - // TODO: Look into merging with #setVisibility() + // TODO: Look into merging with #commitVisibility() void setVisible(boolean newVisible) { visible = newVisible; mDeferHidingClient = !visible && mDeferHidingClient; @@ -1599,7 +1787,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // an indication that the Surface will eventually be destroyed. // This however isn't necessarily true if we are going to sleep. if (state == STOPPING && !isSleeping()) { - mWindowContainerController.notifyAppStopping(); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " + + appToken); + return; + } + mAppWindowToken.detachChildren(); } } @@ -1637,7 +1830,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } void notifyAppResumed(boolean wasStopped) { - mWindowContainerController.notifyAppResumed(wasStopped); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + + appToken); + return; + } + mAppWindowToken.notifyAppResumed(wasStopped); } void notifyUnknownVisibilityLaunched() { @@ -1645,7 +1843,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // No display activities never add a window, so there is no point in waiting them for // relayout. if (!noDisplay) { - mWindowContainerController.notifyUnknownVisibilityLaunched(); + if (mAppWindowToken != null) { + mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController + .notifyLaunched(mAppWindowToken); + } } } @@ -1857,7 +2058,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo stopped = true; setState(STOPPED, "activityStoppedLocked"); - mWindowContainerController.notifyAppStopped(); + if (mAppWindowToken != null) { + mAppWindowToken.notifyAppStopped(); + } if (finishing) { clearOptionsLocked(); @@ -1918,14 +2121,33 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo public void startFreezingScreenLocked(WindowProcessController app, int configChanges) { if (mayFreezeScreenLocked(app)) { - mWindowContainerController.startFreezingScreen(configChanges); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, + "Attempted to freeze screen with non-existing app token: " + appToken); + return; + } + + if (configChanges == 0 && mAppWindowToken.okToDisplay()) { + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken); + return; + } + + mAppWindowToken.startFreezingScreen(); } } public void stopFreezingScreenLocked(boolean force) { if (force || frozenBeforeDestroy) { frozenBeforeDestroy = false; - mWindowContainerController.stopFreezingScreen(force); + if (mAppWindowToken == null) { + return; + } + if (DEBUG_ORIENTATION) { + Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden=" + + mAppWindowToken.isHidden() + " freezing=" + + mAppWindowToken.isFreezingScreen()); + } + mAppWindowToken.stopFreezingScreen(true, force); } } @@ -1937,7 +2159,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo info.windowsFullyDrawnDelayMs); } } - @Override + + /** + * Called when the starting window for this container is drawn. + */ public void onStartingWindowDrawn(long timestamp) { synchronized (service.mGlobalLock) { mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn( @@ -1945,7 +2170,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - @Override + /** Called when the windows associated app window container are drawn. */ public void onWindowsDrawn(boolean drawn, long timestamp) { synchronized (service.mGlobalLock) { mDrawn = drawn; @@ -1965,7 +2190,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - @Override + /** Called when the windows associated app window container are visible. */ public void onWindowsVisible() { synchronized (service.mGlobalLock) { mStackSupervisor.reportActivityVisibleLocked(this); @@ -1999,7 +2224,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - @Override + /** Called when the windows associated app window container are no longer visible. */ public void onWindowsGone() { synchronized (service.mGlobalLock) { if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this); @@ -2007,7 +2232,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - @Override + /** + * Called when the key dispatching to a window associated with the app window container + * timed-out. + * + * @param reason The reason for the key dispatching time out. + * @param windowPid The pid of the window key dispatching timed out on. + * @return True if input dispatching should be aborted. + */ public boolean keyDispatchingTimedOut(String reason, int windowPid) { ActivityRecord anrActivity; WindowProcessController anrApp; @@ -2183,7 +2415,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean fromRecents) { - if (mWindowContainerController == null) { + if (mAppWindowToken == null) { return; } if (mTaskOverlay) { @@ -2198,7 +2430,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo final CompatibilityInfo compatInfo = service.compatibilityInfoForPackageLocked(info.applicationInfo); - final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme, + final boolean shown = addStartingWindow(packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(), allowTaskSnapshot(), @@ -2213,12 +2445,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) { if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); mStartingWindowState = STARTING_WINDOW_REMOVED; - mWindowContainerController.removeStartingWindow(); + mAppWindowToken.removeStartingWindow(); } } int getRequestedOrientation() { - return mWindowContainerController.getOrientation(); + return getOrientation(); } void setRequestedOrientation(int requestedOrientation) { @@ -2226,7 +2458,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo final Configuration displayConfig = mStackSupervisor.getDisplayOverrideConfiguration(displayId); - final Configuration config = mWindowContainerController.setOrientation(requestedOrientation, + final Configuration config = setOrientation(requestedOrientation, displayId, displayConfig, mayFreezeScreenLocked(app)); if (config != null) { frozenBeforeDestroy = true; @@ -2239,8 +2471,36 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo task.taskId, requestedOrientation); } + Configuration setOrientation(int requestedOrientation, int displayId, + Configuration displayConfig, boolean freezeScreenIfNeeded) { + if (mAppWindowToken == null) { + Slog.w(TAG_WM, + "Attempted to set orientation of non-existing app token: " + appToken); + return null; + } + + mAppWindowToken.setOrientation(requestedOrientation); + + final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null; + return service.mWindowManager.updateOrientationFromAppTokens(displayConfig, binder, + displayId); + } + + int getOrientation() { + if (mAppWindowToken == null) { + return SCREEN_ORIENTATION_UNSPECIFIED; + } + + return mAppWindowToken.getOrientationIgnoreVisibility(); + } + void setDisablePreviewScreenshots(boolean disable) { - mWindowContainerController.setDisablePreviewScreenshots(disable); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app" + + " token: " + appToken); + return; + } + mAppWindowToken.setDisablePreviewScreenshots(disable); } /** @@ -2288,8 +2548,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { - final int orientation = mWindowContainerController != null - ? mWindowContainerController.getOrientation() : info.screenOrientation; + final int orientation = mAppWindowToken != null + ? getOrientation() : info.screenOrientation; if (isFixedOrientationPortrait(orientation) && config.orientation != ORIENTATION_PORTRAIT) { return false; @@ -2918,7 +3178,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } void registerRemoteAnimations(RemoteAnimationDefinition definition) { - mWindowContainerController.registerRemoteAnimations(definition); + if (mAppWindowToken == null) { + Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app" + + " token: " + appToken); + return; + } + mAppWindowToken.registerRemoteAnimations(definition); } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index bd3e43c380b64..df60961f81e0a 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -3043,7 +3043,7 @@ class ActivityStack extends ConfigurationContai if (!startIt) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); - r.createWindowContainer(); + r.createAppWindowToken(); ActivityOptions.abort(options); return; } @@ -3073,9 +3073,10 @@ class ActivityStack extends ConfigurationContai // TODO: Need to investigate if it is okay for the controller to already be created by the // time we get to this point. I think it is, but need to double check. // Use test in b/34179495 to trace the call path. - if (r.getWindowContainerController() == null) { - r.createWindowContainer(); + if (r.mAppWindowToken == null) { + r.createAppWindowToken(); } + task.setFrontOfTask(); if (!isHomeOrRecentsStack() || numActivities() > 0) { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index c517bd70cbf58..4e32184be93be 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -3174,7 +3174,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D "Added restored task=" + task + " to stack=" + stack); final ArrayList activities = task.mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - activities.get(activityNdx).createWindowContainer(); + activities.get(activityNdx).createAppWindowToken(); } return true; } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 32a6f74b5a11f..bf00ffb302229 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -305,7 +305,7 @@ public class AppTransitionController { AppWindowToken wtoken = openingApps.valueAt(i); if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); - if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) { + if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) { // 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. @@ -341,7 +341,7 @@ public class AppTransitionController { if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken); // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not // animating? - wtoken.setVisibility(animLp, false, transit, false, voiceInteraction); + wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction); wtoken.updateReportedVisibilityLocked(); // Force the allDrawn flag, because we want to start // this guy's animations regardless of whether it's @@ -350,9 +350,8 @@ public class AppTransitionController { wtoken.deferClearAllDrawn = false; // Ensure that apps that are mid-starting are also scheduled to have their // starting windows removed after the animation is complete - if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit - && wtoken.getController() != null) { - wtoken.getController().removeStartingWindow(); + if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) { + wtoken.removeStartingWindow(); } if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) { diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java deleted file mode 100644 index 7fdea10e3e2c1..0000000000000 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ /dev/null @@ -1,912 +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.app.ActivityOptions.ANIM_CLIP_REVEAL; -import static android.app.ActivityOptions.ANIM_CUSTOM; -import static android.app.ActivityOptions.ANIM_NONE; -import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; -import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION; -import static android.app.ActivityOptions.ANIM_SCALE_UP; -import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN; -import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP; -import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; -import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; -import static android.view.WindowManager.TRANSIT_UNSET; - -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import android.app.ActivityManager.TaskSnapshot; -import android.app.ActivityOptions; -import android.content.ComponentName; -import android.content.Intent; -import android.content.res.CompatibilityInfo; -import android.content.res.Configuration; -import android.graphics.GraphicBuffer; -import android.graphics.Rect; -import android.os.Debug; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.util.Slog; -import android.view.AppTransitionAnimationSpec; -import android.view.IAppTransitionAnimationSpecsFuture; -import android.view.IApplicationToken; -import android.view.RemoteAnimationDefinition; -import android.view.WindowManager; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.AttributeCache; -import com.android.server.policy.WindowManagerPolicy.StartingSurface; - -/** - * Controller for the app window token container. This is created by activity manager to link - * activity records to the app window token container they use in window manager. - * - * Test class: {@link AppWindowContainerControllerTests} - */ -public class AppWindowContainerController - extends WindowContainerController { - - private static final int STARTING_WINDOW_TYPE_NONE = 0; - private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; - private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; - - private final IApplicationToken mToken; - private final Handler mHandler; - - private final class H extends Handler { - public static final int NOTIFY_WINDOWS_DRAWN = 1; - public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2; - public static final int NOTIFY_WINDOWS_NOTDRAWN = 3; - - public H(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case NOTIFY_WINDOWS_DRAWN: - if (mListener == null) { - return; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in " - + AppWindowContainerController.this.mToken); - mListener.onWindowsDrawn(true /* drawn */, msg.getWhen()); - break; - case NOTIFY_STARTING_WINDOW_DRAWN: - if (mListener == null) { - return; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting starting window drawn in " - + AppWindowContainerController.this.mToken); - mListener.onStartingWindowDrawn(msg.getWhen()); - break; - case NOTIFY_WINDOWS_NOTDRAWN: - if (mListener == null) { - return; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting not drawn in " - + AppWindowContainerController.this.mToken); - mListener.onWindowsDrawn(false /* drawn */, msg.getWhen()); - break; - default: - break; - } - } - } - - private final Runnable mOnWindowsVisible = () -> { - if (mListener == null) { - return; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in " - + AppWindowContainerController.this.mToken); - mListener.onWindowsVisible(); - }; - - private final Runnable mOnWindowsGone = () -> { - if (mListener == null) { - return; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " - + AppWindowContainerController.this.mToken); - mListener.onWindowsGone(); - }; - - private final Runnable mAddStartingWindow = new Runnable() { - - @Override - public void run() { - final StartingData startingData; - final AppWindowToken container; - - synchronized (mGlobalLock) { - if (mContainer == null) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to" - + " add starting window"); - return; - } - - // There can only be one adding request, silly caller! - mService.mAnimationHandler.removeCallbacks(this); - - startingData = mContainer.startingData; - container = mContainer; - } - - if (startingData == null) { - // Animation has been canceled... do nothing. - if (DEBUG_STARTING_WINDOW) - Slog.v(TAG_WM, "startingData was nulled out before handling" - + " mAddStartingWindow: " + mContainer); - return; - } - - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting " - + AppWindowContainerController.this + ": startingData=" - + container.startingData); - - StartingSurface surface = null; - try { - surface = startingData.createStartingSurface(container); - } catch (Exception e) { - Slog.w(TAG_WM, "Exception when adding starting window", e); - } - if (surface != null) { - boolean abort = false; - synchronized (mGlobalLock) { - // If the window was successfully added, then - // we need to remove it. - if (container.removed || container.startingData == null) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, - "Aborted starting " + container - + ": removed=" + container.removed - + " startingData=" + container.startingData); - container.startingWindow = null; - container.startingData = null; - abort = true; - } else { - container.startingSurface = surface; - } - if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM, - "Added starting " + mContainer - + ": startingWindow=" - + container.startingWindow + " startingView=" - + container.startingSurface); - } - if (abort) { - surface.remove(); - } - } else if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "Surface returned was null: " + mContainer); - } - } - }; - - public AppWindowContainerController(TaskWindowContainerController taskController, - IApplicationToken token, ComponentName activityComponent, - AppWindowContainerListener listener, int index, int requestedOrientation, - boolean fullscreen, boolean showForAllUsers, int configChanges, - boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, - int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) { - this(taskController, token, activityComponent, listener, index, requestedOrientation, - fullscreen, showForAllUsers, configChanges, voiceInteraction, launchTaskBehind, - alwaysFocusable, targetSdkVersion, rotationAnimationHint, - inputDispatchingTimeoutNanos, WindowManagerService.getInstance()); - } - - public AppWindowContainerController(TaskWindowContainerController taskController, - IApplicationToken token, ComponentName activityComponent, - AppWindowContainerListener listener, int index, int requestedOrientation, - boolean fullscreen, boolean showForAllUsers, int configChanges, - boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, - int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos, - WindowManagerService service) { - super(listener, service); - mHandler = new H(service.mH.getLooper()); - mToken = token; - synchronized (mGlobalLock) { - AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder()); - if (atoken != null) { - // TODO: Should this throw an exception instead? - Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken); - return; - } - - final Task task = taskController.mContainer; - if (task == null) { - throw new IllegalArgumentException("AppWindowContainerController: invalid " - + " controller=" + taskController); - } - - atoken = createAppWindow(mService, token, activityComponent, voiceInteraction, - task.getDisplayContent(), inputDispatchingTimeoutNanos, fullscreen, - showForAllUsers, targetSdkVersion, requestedOrientation, rotationAnimationHint, - configChanges, launchTaskBehind, alwaysFocusable, this); - if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken - + " controller=" + taskController + " at " + index); - task.addChild(atoken, index); - } - } - - @VisibleForTesting - AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, - ComponentName component, boolean voiceInteraction, DisplayContent dc, - long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, - int targetSdk, int orientation, int rotationAnimationHint, int configChanges, - boolean launchTaskBehind, boolean alwaysFocusable, - AppWindowContainerController controller) { - return new AppWindowToken(service, token, component, voiceInteraction, dc, - inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, - rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, - controller); - } - - public void removeContainer(int displayId) { - synchronized (mGlobalLock) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " - + mToken + " from non-existing displayId=" + displayId); - return; - } - dc.removeAppToken(mToken.asBinder()); - super.removeContainer(); - } - } - - @Override - public void removeContainer() { - throw new UnsupportedOperationException("Use removeContainer(displayId) instead."); - } - - public void reparent(TaskWindowContainerController taskController, int position) { - synchronized (mGlobalLock) { - if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken - + " to task=" + taskController + " at " + position); - if (mContainer == null) { - if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, - "reparent: could not find app token=" + mToken); - return; - } - final Task task = taskController.mContainer; - if (task == null) { - throw new IllegalArgumentException("reparent: could not find task=" - + taskController); - } - mContainer.reparent(task, position); - mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - } - } - - public Configuration setOrientation(int requestedOrientation, int displayId, - Configuration displayConfig, boolean freezeScreenIfNeeded) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, - "Attempted to set orientation of non-existing app token: " + mToken); - return null; - } - - mContainer.setOrientation(requestedOrientation); - - final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null; - return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId); - - } - } - - public int getOrientation() { - synchronized (mGlobalLock) { - if (mContainer == null) { - return SCREEN_ORIENTATION_UNSPECIFIED; - } - - return mContainer.getOrientationIgnoreVisibility(); - } - } - - public void setDisablePreviewScreenshots(boolean disable) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app" - + " token: " + mToken); - return; - } - mContainer.setDisablePreviewScreenshots(disable); - } - } - - public void setVisibility(boolean visible, boolean deferHidingClient) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " - + mToken); - return; - } - - final AppWindowToken wtoken = mContainer; - final AppTransition appTransition = mContainer.getDisplayContent().mAppTransition; - - // Don't set visibility to false if we were already not visible. This prevents WM from - // adding the app to the closing app list which doesn't make sense for something that is - // already not visible. However, set visibility to true even if we are already visible. - // This makes sure the app is added to the opening apps list so that the right - // transition can be selected. - // TODO: Probably a good idea to separate the concept of opening/closing apps from the - // concept of setting visibility... - if (!visible && wtoken.hiddenRequested) { - - if (!deferHidingClient && wtoken.mDeferHidingClient) { - // We previously deferred telling the client to hide itself when visibility was - // initially set to false. Now we would like it to hide, so go ahead and set it. - wtoken.mDeferHidingClient = deferHidingClient; - wtoken.setClientHidden(true); - } - return; - } - - if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" - + mToken + ", visible=" + visible + "): " + appTransition - + " hidden=" + wtoken.isHidden() + " hiddenRequested=" - + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6)); - - final DisplayContent displayContent = mContainer.getDisplayContent(); - displayContent.mOpeningApps.remove(wtoken); - displayContent.mClosingApps.remove(wtoken); - wtoken.waitingToShow = false; - wtoken.hiddenRequested = !visible; - wtoken.mDeferHidingClient = deferHidingClient; - - if (!visible) { - // If the app is dead while it was visible, we kept its dead window on screen. - // Now that the app is going invisible, we can remove it. It will be restarted - // if made visible again. - wtoken.removeDeadWindows(); - } else { - if (!appTransition.isTransitionSet() - && appTransition.isReady()) { - // Add the app mOpeningApps if transition is unset but ready. This means - // we're doing a screen freeze, and the unfreeze will wait for all opening - // apps to be ready. - displayContent.mOpeningApps.add(wtoken); - } - wtoken.startingMoved = false; - // If the token is currently hidden (should be the common case), or has been - // stopped, then we need to set up to wait for its windows to be ready. - if (wtoken.isHidden() || wtoken.mAppStopped) { - wtoken.clearAllDrawn(); - - // If the app was already visible, don't reset the waitingToShow state. - if (wtoken.isHidden()) { - wtoken.waitingToShow = true; - } - } - - // In the case where we are making an app visible but holding off for a transition, - // we still need to tell the client to make its windows visible so they get drawn. - // Otherwise, we will wait on performing the transition until all windows have been - // drawn, they never will be, and we are sad. - wtoken.setClientHidden(false); - - wtoken.requestUpdateWallpaperIfNeeded(); - - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken); - wtoken.mAppStopped = false; - - mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded(); - } - - // If we are preparing an app transition, then delay changing - // the visibility of this token until we execute that transition. - if (wtoken.okToAnimate() && appTransition.isTransitionSet()) { - wtoken.inPendingTransaction = true; - if (visible) { - displayContent.mOpeningApps.add(wtoken); - wtoken.mEnteringAnimation = true; - } else { - displayContent.mClosingApps.add(wtoken); - wtoken.mEnteringAnimation = false; - } - if (appTransition.getAppTransition() - == WindowManager.TRANSIT_TASK_OPEN_BEHIND) { - // We're launchingBehind, add the launching activity to mOpeningApps. - final WindowState win = mContainer.getDisplayContent().findFocusedWindow(); - if (win != null) { - final AppWindowToken focusedToken = win.mAppToken; - if (focusedToken != null) { - if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, " - + " adding " + focusedToken + " to mOpeningApps"); - // Force animation to be loaded. - focusedToken.setHidden(true); - displayContent.mOpeningApps.add(focusedToken); - } - } - } - return; - } - - wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction); - wtoken.updateReportedVisibilityLocked(); - } - } - - /** - * Notifies that we launched an app that might be visible or not visible depending on what kind - * of Keyguard flags it's going to set on its windows. - */ - public void notifyUnknownVisibilityLaunched() { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getDisplayContent().mUnknownAppVisibilityController.notifyLaunched( - mContainer); - } - } - } - - public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, - CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, - IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, - boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { - synchronized (mGlobalLock) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken - + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask - + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning - + " allowTaskSnapshot=" + allowTaskSnapshot); - - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken); - return false; - } - - // If the display is frozen, we won't do anything until the actual window is - // displayed so there is no reason to put in the starting window. - if (!mContainer.okToDisplay()) { - return false; - } - - if (mContainer.startingData != null) { - return false; - } - - final WindowState mainWin = mContainer.findMainWindow(); - if (mainWin != null && mainWin.mWinAnimator.getShown()) { - // App already has a visible window...why would you want a starting window? - return false; - } - - final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot( - mContainer.getTask().mTaskId, mContainer.getTask().mUserId, - false /* restoreFromDisk */, false /* reducedResolution */); - final int type = getStartingWindowType(newTask, taskSwitch, processRunning, - allowTaskSnapshot, activityCreated, fromRecents, snapshot); - - if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { - return createSnapshot(snapshot); - } - - // If this is a translucent window, then don't show a starting window -- the current - // effect (a full-screen opaque starting window that fades away to the real contents - // when it is ready) does not work for this. - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x" - + Integer.toHexString(theme)); - if (theme != 0) { - AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, - com.android.internal.R.styleable.Window, mService.mCurrentUserId); - if (ent == null) { - // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't - // see that. - return false; - } - final boolean windowIsTranslucent = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsTranslucent, false); - final boolean windowIsFloating = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsFloating, false); - final boolean windowShowWallpaper = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowShowWallpaper, false); - final boolean windowDisableStarting = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowDisablePreview, false); - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent - + " Floating=" + windowIsFloating - + " ShowWallpaper=" + windowShowWallpaper); - if (windowIsTranslucent) { - return false; - } - if (windowIsFloating || windowDisableStarting) { - return false; - } - if (windowShowWallpaper) { - if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget() - == null) { - // If this theme is requesting a wallpaper, and the wallpaper - // is not currently visible, then this effectively serves as - // an opaque window and our starting window transition animation - // can still work. We just need to make sure the starting window - // is also showing the wallpaper. - windowFlags |= FLAG_SHOW_WALLPAPER; - } else { - return false; - } - } - } - - if (mContainer.transferStartingWindow(transferFrom)) { - return true; - } - - // There is no existing starting window, and we don't want to create a splash screen, so - // that's it! - if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) { - return false; - } - - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData"); - mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme, - compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, - mContainer.getMergedOverrideConfiguration()); - scheduleAddStartingWindow(); - } - return true; - } - - private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, - boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents, - TaskSnapshot snapshot) { - if (mContainer.getDisplayContent().mAppTransition.getAppTransition() - == TRANSIT_DOCK_TASK_FROM_RECENTS) { - // TODO(b/34099271): Remove this statement to add back the starting window and figure - // out why it causes flickering, the starting window appears over the thumbnail while - // the docked from recents transition occurs - return STARTING_WINDOW_TYPE_NONE; - } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) { - return STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } else if (taskSwitch && allowTaskSnapshot) { - return snapshot == null ? STARTING_WINDOW_TYPE_NONE - : snapshotOrientationSameAsTask(snapshot) || fromRecents - ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } else { - return STARTING_WINDOW_TYPE_NONE; - } - } - - void scheduleAddStartingWindow() { - // Note: we really want to do sendMessageAtFrontOfQueue() because we - // want to process the message ASAP, before any other queued - // messages. - if (!mService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING"); - mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow); - } - } - - private boolean createSnapshot(TaskSnapshot snapshot) { - if (snapshot == null) { - return false; - } - - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData"); - mContainer.startingData = new SnapshotStartingData(mService, snapshot); - scheduleAddStartingWindow(); - return true; - } - - private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) { - if (snapshot == null) { - return false; - } - return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation(); - } - - public void removeStartingWindow() { - synchronized (mGlobalLock) { - if (mContainer.startingWindow == null) { - if (mContainer.startingData != null) { - // Starting window has not been added yet, but it is scheduled to be added. - // Go ahead and cancel the request. - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, - "Clearing startingData for token=" + mContainer); - mContainer.startingData = null; - } - return; - } - - final StartingSurface surface; - if (mContainer.startingData != null) { - surface = mContainer.startingSurface; - mContainer.startingData = null; - mContainer.startingSurface = null; - mContainer.startingWindow = null; - mContainer.startingDisplayed = false; - if (surface == null) { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't " - + "remove"); - } - return; - } - } else { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:" - + mContainer); - } - return; - } - - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer - + " startingWindow=" + mContainer.startingWindow - + " startingView=" + mContainer.startingSurface - + " Callers=" + Debug.getCallers(5)); - - // Use the same thread to remove the window as we used to add it, as otherwise we end up - // with things in the view hierarchy being called from different threads. - mService.mAnimationHandler.post(() -> { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface); - try { - surface.remove(); - } catch (Exception e) { - Slog.w(TAG_WM, "Exception when removing starting window", e); - } - }); - } - } - - public void pauseKeyDispatching() { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getDisplayContent().getInputMonitor().pauseDispatchingLw(mContainer); - } - } - } - - public void resumeKeyDispatching() { - synchronized (mGlobalLock) { - if (mContainer != null) { - mContainer.getDisplayContent().getInputMonitor().resumeDispatchingLw(mContainer); - } - } - } - - public void notifyAppResumed(boolean wasStopped) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken); - return; - } - mContainer.notifyAppResumed(wasStopped); - } - } - - public void notifyAppStopping() { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " - + mToken); - return; - } - mContainer.detachChildren(); - } - } - - public void notifyAppStopped() { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " - + mToken); - return; - } - mContainer.notifyAppStopped(); - } - } - - public void startFreezingScreen(int configChanges) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, - "Attempted to freeze screen with non-existing app token: " + mContainer); - return; - } - - if (configChanges == 0 && mContainer.okToDisplay()) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken); - return; - } - - mContainer.startFreezingScreen(); - } - } - - public void stopFreezingScreen(boolean force) { - synchronized (mGlobalLock) { - if (mContainer == null) { - return; - } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden=" - + mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen()); - mContainer.stopFreezingScreen(true, force); - } - } - - public void registerRemoteAnimations(RemoteAnimationDefinition definition) { - synchronized (mGlobalLock) { - if (mContainer == null) { - Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app" - + " token: " + mToken); - return; - } - mContainer.registerRemoteAnimations(definition); - } - } - - void reportStartingWindowDrawn() { - mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN)); - } - - void reportWindowsDrawn() { - mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN)); - } - - void reportWindowsNotDrawn() { - mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_NOTDRAWN)); - } - - void reportWindowsVisible() { - mHandler.post(mOnWindowsVisible); - } - - void reportWindowsGone() { - mHandler.post(mOnWindowsGone); - } - - /** Calls directly into activity manager so window manager lock shouldn't held. */ - boolean keyDispatchingTimedOut(String reason, int windowPid) { - return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid); - } - - /** - * Apply override app transition base on options & animation type. - */ - public void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { - synchronized (mGlobalLock) { - final int animationType = pendingOptions.getAnimationType(); - final DisplayContent displayContent = mContainer.getDisplayContent(); - switch (animationType) { - case ANIM_CUSTOM: - displayContent.mAppTransition.overridePendingAppTransition( - pendingOptions.getPackageName(), - pendingOptions.getCustomEnterResId(), - pendingOptions.getCustomExitResId(), - pendingOptions.getOnAnimationStartListener()); - break; - case ANIM_CLIP_REVEAL: - displayContent.mAppTransition.overridePendingAppTransitionClipReveal( - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight()); - if (intent.getSourceBounds() == null) { - intent.setSourceBounds(new Rect(pendingOptions.getStartX(), - pendingOptions.getStartY(), - pendingOptions.getStartX() + pendingOptions.getWidth(), - pendingOptions.getStartY() + pendingOptions.getHeight())); - } - break; - case ANIM_SCALE_UP: - displayContent.mAppTransition.overridePendingAppTransitionScaleUp( - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight()); - if (intent.getSourceBounds() == null) { - intent.setSourceBounds(new Rect(pendingOptions.getStartX(), - pendingOptions.getStartY(), - pendingOptions.getStartX() + pendingOptions.getWidth(), - pendingOptions.getStartY() + pendingOptions.getHeight())); - } - break; - case ANIM_THUMBNAIL_SCALE_UP: - case ANIM_THUMBNAIL_SCALE_DOWN: - final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP); - final GraphicBuffer buffer = pendingOptions.getThumbnail(); - displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getOnAnimationStartListener(), - scaleUp); - if (intent.getSourceBounds() == null && buffer != null) { - intent.setSourceBounds(new Rect(pendingOptions.getStartX(), - pendingOptions.getStartY(), - pendingOptions.getStartX() + buffer.getWidth(), - pendingOptions.getStartY() + buffer.getHeight())); - } - break; - case ANIM_THUMBNAIL_ASPECT_SCALE_UP: - case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: - final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); - final IAppTransitionAnimationSpecsFuture specsFuture = - pendingOptions.getSpecsFuture(); - if (specsFuture != null) { - displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( - specsFuture, pendingOptions.getOnAnimationStartListener(), - animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); - } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN - && specs != null) { - displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( - specs, pendingOptions.getOnAnimationStartListener(), - pendingOptions.getAnimationFinishedListener(), false); - } else { - displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( - pendingOptions.getThumbnail(), - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight(), - pendingOptions.getOnAnimationStartListener(), - (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); - if (intent.getSourceBounds() == null) { - intent.setSourceBounds(new Rect(pendingOptions.getStartX(), - pendingOptions.getStartY(), - pendingOptions.getStartX() + pendingOptions.getWidth(), - pendingOptions.getStartY() + pendingOptions.getHeight())); - } - } - break; - case ANIM_OPEN_CROSS_PROFILE_APPS: - displayContent.mAppTransition - .overridePendingAppTransitionStartCrossProfileApps(); - break; - case ANIM_REMOTE_ANIMATION: - displayContent.mAppTransition.overridePendingAppTransitionRemote( - pendingOptions.getRemoteAnimationAdapter()); - break; - case ANIM_NONE: - break; - default: - Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType); - break; - } - } - } - - /** - * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP. - * This information helps AWT know that the app is in the process of pausing before it gets the - * signal on the WM side. - */ - public void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { - synchronized (mGlobalLock) { - if (mContainer == null) { - return; - } - - mContainer.setWillCloseOrEnterPip(willCloseOrEnterPip); - } - } - - @Override - public String toString() { - return "AppWindowContainerController{" - + " token=" + mToken - + " mContainer=" + mContainer - + " mListener=" + mListener - + "}"; - } -} diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java deleted file mode 100644 index ad27669fc0300..0000000000000 --- a/services/core/java/com/android/server/wm/AppWindowContainerListener.java +++ /dev/null @@ -1,42 +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; - -/** Interface used by the creator of the controller to listen to changes with the container. */ -public interface AppWindowContainerListener extends WindowContainerListener { - /** Called when the windows associated app window container drawn state changes. */ - void onWindowsDrawn(boolean drawn, long timestamp); - /** Called when the windows associated app window container are visible. */ - void onWindowsVisible(); - /** Called when the windows associated app window container are no longer visible. */ - void onWindowsGone(); - - /** - * Called when the starting window for this container is drawn. - */ - void onStartingWindowDrawn(long timestamp); - - /** - * Called when the key dispatching to a window associated with the app window container - * timed-out. - * - * @param reason The reason for the key dispatching time out. - * @param windowPid The pid of the window key dispatching timed out on. - * @return True if input dispatching should be aborted. - */ - boolean keyDispatchingTimedOut(String reason, int windowPid); -} diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 52c78cea439cd..d3c9c25913637 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -28,10 +28,12 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static android.view.WindowManager.TRANSIT_UNSET; import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN; @@ -81,7 +83,9 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import android.annotation.CallSuper; import android.app.Activity; +import android.app.ActivityManager; import android.content.ComponentName; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.GraphicBuffer; import android.graphics.Point; @@ -90,6 +94,7 @@ import android.os.Binder; import android.os.Debug; import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemClock; import android.os.Trace; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -106,6 +111,8 @@ import android.view.animation.Animation; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; +import com.android.server.AttributeCache; +import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.StartingSurface; import com.android.server.wm.WindowManagerService.H; @@ -121,7 +128,8 @@ class AppTokenList extends ArrayList { * Version of WindowToken that is specifically for a particular application (or * really activity) that is displaying windows. */ -class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener { +class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener, + ConfigurationContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM; /** @@ -226,6 +234,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree private Task mLastParent; + // TODO: Remove after unification + ActivityRecord mActivityRecord; + /** * See {@link #canTurnScreenOn()} */ @@ -273,14 +284,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */ boolean mNeedsAnimationBoundsLayer; + private static final int STARTING_WINDOW_TYPE_NONE = 0; + private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; + private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; + AppWindowToken(WindowManagerService service, IApplicationToken token, ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, - AppWindowContainerController controller) { + ActivityRecord activityRecord) { this(service, token, activityComponent, voiceInteraction, dc, fullscreen); - setController(controller); + // TODO: remove after unification + mActivityRecord = activityRecord; + mActivityRecord.registerConfigurationChangeListener(this); mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; mShowForAllUsers = showForAllUsers; mTargetSdk = targetSdk; @@ -320,9 +337,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // it from behind the starting window, so there is no need for it to also be doing its // own stuff. win.cancelAnimation(); - if (getController() != null) { - getController().removeStartingWindow(); - } + removeStartingWindow(); } updateReportedVisibilityLocked(); } @@ -360,16 +375,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" + numInteresting + " visible=" + numVisible); - final AppWindowContainerController controller = getController(); if (nowDrawn != reportedDrawn) { - if (nowDrawn) { - if (controller != null) { - controller.reportWindowsDrawn(); - } - } else { - if (controller != null) { - controller.reportWindowsNotDrawn(); - } + if (mActivityRecord != null) { + mActivityRecord.onWindowsDrawn(nowDrawn, SystemClock.uptimeMillis()); } reportedDrawn = nowDrawn; } @@ -377,16 +385,36 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_VISIBILITY) Slog.v(TAG, "Visibility changed in " + this + ": vis=" + nowVisible); reportedVisible = nowVisible; - if (controller != null) { + if (mActivityRecord != null) { if (nowVisible) { - controller.reportWindowsVisible(); + onWindowsVisible(); } else { - controller.reportWindowsGone(); + onWindowsGone(); } } } } + private void onWindowsGone() { + if (mActivityRecord == null) { + return; + } + if (DEBUG_VISIBILITY) { + Slog.v(TAG_WM, "Reporting gone in " + mActivityRecord.appToken); + } + mActivityRecord.onWindowsGone(); + } + + private void onWindowsVisible() { + if (mActivityRecord == null) { + return; + } + if (DEBUG_VISIBILITY) { + Slog.v(TAG_WM, "Reporting visible in " + mActivityRecord.appToken); + } + mActivityRecord.onWindowsVisible(); + } + boolean isClientHidden() { return mClientHidden; } @@ -401,7 +429,116 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree sendAppVisibilityToClients(); } - boolean setVisibility(WindowManager.LayoutParams lp, + void setVisibility(boolean visible, boolean deferHidingClient) { + final AppTransition appTransition = getDisplayContent().mAppTransition; + + // Don't set visibility to false if we were already not visible. This prevents WM from + // adding the app to the closing app list which doesn't make sense for something that is + // already not visible. However, set visibility to true even if we are already visible. + // This makes sure the app is added to the opening apps list so that the right + // transition can be selected. + // TODO: Probably a good idea to separate the concept of opening/closing apps from the + // concept of setting visibility... + if (!visible && hiddenRequested) { + + if (!deferHidingClient && mDeferHidingClient) { + // We previously deferred telling the client to hide itself when visibility was + // initially set to false. Now we would like it to hide, so go ahead and set it. + mDeferHidingClient = deferHidingClient; + setClientHidden(true); + } + return; + } + + if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) { + Slog.v(TAG_WM, "setAppVisibility(" + + appToken + ", visible=" + visible + "): " + appTransition + + " hidden=" + isHidden() + " hiddenRequested=" + + hiddenRequested + " Callers=" + Debug.getCallers(6)); + } + + final DisplayContent displayContent = getDisplayContent(); + displayContent.mOpeningApps.remove(this); + displayContent.mClosingApps.remove(this); + waitingToShow = false; + hiddenRequested = !visible; + mDeferHidingClient = deferHidingClient; + + if (!visible) { + // If the app is dead while it was visible, we kept its dead window on screen. + // Now that the app is going invisible, we can remove it. It will be restarted + // if made visible again. + removeDeadWindows(); + } else { + if (!appTransition.isTransitionSet() + && appTransition.isReady()) { + // Add the app mOpeningApps if transition is unset but ready. This means + // we're doing a screen freeze, and the unfreeze will wait for all opening + // apps to be ready. + displayContent.mOpeningApps.add(this); + } + startingMoved = false; + // If the token is currently hidden (should be the common case), or has been + // stopped, then we need to set up to wait for its windows to be ready. + if (isHidden() || mAppStopped) { + clearAllDrawn(); + + // If the app was already visible, don't reset the waitingToShow state. + if (isHidden()) { + waitingToShow = true; + } + } + + // In the case where we are making an app visible but holding off for a transition, + // we still need to tell the client to make its windows visible so they get drawn. + // Otherwise, we will wait on performing the transition until all windows have been + // drawn, they never will be, and we are sad. + setClientHidden(false); + + requestUpdateWallpaperIfNeeded(); + + if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this); + mAppStopped = false; + + transferStartingWindowFromHiddenAboveTokenIfNeeded(); + } + + // If we are preparing an app transition, then delay changing + // the visibility of this token until we execute that transition. + if (okToAnimate() && appTransition.isTransitionSet()) { + inPendingTransaction = true; + if (visible) { + displayContent.mOpeningApps.add(this); + mEnteringAnimation = true; + } else { + displayContent.mClosingApps.add(this); + mEnteringAnimation = false; + } + if (appTransition.getAppTransition() + == WindowManager.TRANSIT_TASK_OPEN_BEHIND) { + // We're launchingBehind, add the launching activity to mOpeningApps. + final WindowState win = getDisplayContent().findFocusedWindow(); + if (win != null) { + final AppWindowToken focusedToken = win.mAppToken; + if (focusedToken != null) { + if (DEBUG_APP_TRANSITIONS) { + Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, " + + " adding " + focusedToken + " to mOpeningApps"); + } + // Force animation to be loaded. + focusedToken.setHidden(true); + displayContent.mOpeningApps.add(focusedToken); + } + } + } + return; + } + + commitVisibility(null, visible, TRANSIT_UNSET, true, mVoiceInteraction); + updateReportedVisibilityLocked(); + } + + boolean commitVisibility(WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) { boolean delayed = false; @@ -461,8 +598,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true); } - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this - + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested); + if (DEBUG_APP_TRANSITIONS) { + Slog.v(TAG_WM, "commitVisibility: " + this + + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested); + } if (changed) { getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw(); @@ -499,10 +638,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token); } - // If we're becoming visible, immediately change client visibility as well although it - // usually gets changed in AppWindowContainerController.setVisibility already. However, - // there seem to be some edge cases where we change our visibility but client visibility - // never gets updated. + // If we're becoming visible, immediately change client visibility as well. there seem + // to be some edge cases where we change our visibility but client visibility never gets + // updated. // If we're becoming invisible, update the client visibility if we are not running an // animation. Otherwise, we'll update client visibility in onAnimationFinished. if (visible || !isReallyAnimating()) { @@ -596,11 +734,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable; } - AppWindowContainerController getController() { - final WindowContainerController controller = super.getController(); - return controller != null ? (AppWindowContainerController) controller : null; - } - @Override boolean isVisible() { // If the app token isn't hidden then it is considered visible and there is no need to check @@ -637,7 +770,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); - boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); + boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); getDisplayContent().mOpeningApps.remove(this); getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this); @@ -656,8 +789,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); - if (startingData != null && getController() != null) { - getController().removeStartingWindow(); + if (startingData != null) { + removeStartingWindow(); } // If this window was animating, then we need to ensure that the app transition notifies @@ -768,9 +901,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mAppStopped = true; destroySurfaces(); // Remove any starting window that was added for this app if they are still around. - if (getController() != null) { - getController().removeStartingWindow(); - } + removeStartingWindow(); } void clearAllDrawn() { @@ -826,9 +957,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // TODO: Something smells about the code below...Is there a better way? if (startingWindow == win) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); - if (getController() != null) { - getController().removeStartingWindow(); - } + removeStartingWindow(); } else if (mChildren.size() == 0) { // If this is the last window and we had requested a starting transition window, // well there is no point now. @@ -845,9 +974,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // we need to get rid of the starting transition. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window " + win); - if (getController() != null) { - getController().removeStartingWindow(); - } + removeStartingWindow(); } } @@ -1021,6 +1148,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree @Override void removeChild(WindowState child) { + if (!mChildren.contains(child)) { + // This can be true when testing. + return; + } super.removeChild(child); checkKeyguardFlagsChanged(); updateLetterboxSurface(child); @@ -1042,6 +1173,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } + void reparent(TaskWindowContainerController taskController, int position) { + if (DEBUG_ADD_REMOVE) { + Slog.i(TAG_WM, "reparent: moving app token=" + this + + " to task=" + taskController + " at " + position); + } + final Task task = taskController.mContainer; + if (task == null) { + throw new IllegalArgumentException("reparent: could not find task=" + + taskController); + } + reparent(task, position); + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + } + void reparent(Task task, int position) { final Task currentTask = getTask(); if (task == currentTask) { @@ -1300,9 +1445,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree startingData = fromToken.startingData; fromToken.startingData = null; fromToken.startingMoved = true; - if (getController() != null) { - getController().scheduleAddStartingWindow(); - } + scheduleAddStartingWindow(); return true; } @@ -1471,6 +1614,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } + boolean keyDispatchingTimedOut(String reason, int windowPid) { + return mActivityRecord != null && mActivityRecord.keyDispatchingTimedOut(reason, windowPid); + } + /** * Updated this app token tracking states for interesting and drawn windows based on the window. * @@ -1533,8 +1680,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } } else if (w.isDrawnLw()) { - if (getController() != null) { - getController().reportStartingWindowDrawn(); + if (mActivityRecord != null) { + mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis()); } startingDisplayed = true; } @@ -1601,6 +1748,266 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return this; } + boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, + CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, + IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, + boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { + // If the display is frozen, we won't do anything until the actual window is + // displayed so there is no reason to put in the starting window. + if (!okToDisplay()) { + return false; + } + + if (startingData != null) { + return false; + } + + final WindowState mainWin = findMainWindow(); + if (mainWin != null && mainWin.mWinAnimator.getShown()) { + // App already has a visible window...why would you want a starting window? + return false; + } + + final ActivityManager.TaskSnapshot snapshot = + mService.mTaskSnapshotController.getSnapshot( + getTask().mTaskId, getTask().mUserId, + false /* restoreFromDisk */, false /* reducedResolution */); + final int type = getStartingWindowType(newTask, taskSwitch, processRunning, + allowTaskSnapshot, activityCreated, fromRecents, snapshot); + + if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { + return createSnapshot(snapshot); + } + + // If this is a translucent window, then don't show a starting window -- the current + // effect (a full-screen opaque starting window that fades away to the real contents + // when it is ready) does not work for this. + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "Checking theme of starting window: 0x" + Integer.toHexString(theme)); + } + if (theme != 0) { + AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, + com.android.internal.R.styleable.Window, + mService.mCurrentUserId); + if (ent == null) { + // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't + // see that. + return false; + } + final boolean windowIsTranslucent = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsTranslucent, false); + final boolean windowIsFloating = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsFloating, false); + final boolean windowShowWallpaper = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowShowWallpaper, false); + final boolean windowDisableStarting = ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowDisablePreview, false); + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "Translucent=" + windowIsTranslucent + + " Floating=" + windowIsFloating + + " ShowWallpaper=" + windowShowWallpaper); + } + if (windowIsTranslucent) { + return false; + } + if (windowIsFloating || windowDisableStarting) { + return false; + } + if (windowShowWallpaper) { + if (getDisplayContent().mWallpaperController + .getWallpaperTarget() == null) { + // If this theme is requesting a wallpaper, and the wallpaper + // is not currently visible, then this effectively serves as + // an opaque window and our starting window transition animation + // can still work. We just need to make sure the starting window + // is also showing the wallpaper. + windowFlags |= FLAG_SHOW_WALLPAPER; + } else { + return false; + } + } + + if (transferStartingWindow(transferFrom)) { + return true; + } + + // There is no existing starting window, and we don't want to create a splash screen, so + // that's it! + if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) { + return false; + } + + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData"); + startingData = new SplashScreenStartingData(mService, pkg, + theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, + getMergedOverrideConfiguration()); + scheduleAddStartingWindow(); + } + return true; + } + + + private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) { + if (snapshot == null) { + return false; + } + + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData"); + startingData = new SnapshotStartingData(mService, snapshot); + scheduleAddStartingWindow(); + return true; + } + + void scheduleAddStartingWindow() { + // Note: we really want to do sendMessageAtFrontOfQueue() because we + // want to process the message ASAP, before any other queued + // messages. + if (!mService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) { + if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING"); + mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow); + } + } + + private final Runnable mAddStartingWindow = new Runnable() { + + @Override + public void run() { + synchronized (mService.mGlobalLock) { + // There can only be one adding request, silly caller! + mService.mAnimationHandler.removeCallbacks(this); + } + + if (startingData == null) { + // Animation has been canceled... do nothing. + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "startingData was nulled out before handling" + + " mAddStartingWindow: " + AppWindowToken.this); + } + return; + } + + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData); + } + + WindowManagerPolicy.StartingSurface surface = null; + try { + surface = startingData.createStartingSurface(AppWindowToken.this); + } catch (Exception e) { + Slog.w(TAG, "Exception when adding starting window", e); + } + if (surface != null) { + boolean abort = false; + synchronized (mService.mGlobalLock) { + // If the window was successfully added, then + // we need to remove it. + if (removed || startingData == null) { + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "Aborted starting " + AppWindowToken.this + + ": removed=" + removed + " startingData=" + startingData); + } + startingWindow = null; + startingData = null; + abort = true; + } else { + startingSurface = surface; + } + if (DEBUG_STARTING_WINDOW && !abort) { + Slog.v(TAG, "Added starting " + AppWindowToken.this + ": startingWindow=" + + startingWindow + " startingView=" + startingSurface); + } + } + if (abort) { + surface.remove(); + } + } else if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this); + } + } + }; + + private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, + boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents, + ActivityManager.TaskSnapshot snapshot) { + if (getDisplayContent().mAppTransition.getAppTransition() + == TRANSIT_DOCK_TASK_FROM_RECENTS) { + // TODO(b/34099271): Remove this statement to add back the starting window and figure + // out why it causes flickering, the starting window appears over the thumbnail while + // the docked from recents transition occurs + return STARTING_WINDOW_TYPE_NONE; + } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) { + return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } else if (taskSwitch && allowTaskSnapshot) { + return snapshot == null ? STARTING_WINDOW_TYPE_NONE + : snapshotOrientationSameAsTask(snapshot) || fromRecents + ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } else { + return STARTING_WINDOW_TYPE_NONE; + } + } + + + private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) { + if (snapshot == null) { + return false; + } + return getTask().getConfiguration().orientation == snapshot.getOrientation(); + } + + void removeStartingWindow() { + if (startingWindow == null) { + if (startingData != null) { + // Starting window has not been added yet, but it is scheduled to be added. + // Go ahead and cancel the request. + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG_WM, "Clearing startingData for token=" + this); + } + startingData = null; + } + return; + } + + final WindowManagerPolicy.StartingSurface surface; + if (startingData != null) { + surface = startingSurface; + startingData = null; + startingSurface = null; + startingWindow = null; + startingDisplayed = false; + if (surface == null) { + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't " + + "remove"); + } + return; + } + } else { + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:" + + this); + } + return; + } + + if (DEBUG_STARTING_WINDOW) { + Slog.v(TAG_WM, "Schedule remove starting " + this + + " startingWindow=" + startingWindow + + " startingView=" + startingSurface + + " Callers=" + Debug.getCallers(5)); + } + + // Use the same thread to remove the window as we used to add it, as otherwise we end up + // with things in the view hierarchy being called from different threads. + mService.mAnimationHandler.post(() -> { + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface); + try { + surface.remove(); + } catch (Exception e) { + Slog.w(TAG_WM, "Exception when removing starting window", e); + } + }); + } + @Override boolean fillsParent() { return mFillsParent; @@ -2215,9 +2622,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mPendingRelaunchCount != 0) { pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); } - if (getController() != null) { - pw.print(prefix); pw.print("controller="); pw.println(getController()); - } if (mRemovingFromDisplay) { pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); } diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 92ea1a90735cc..08b1ae08e16c1 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -6,21 +6,16 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import android.app.ActivityManager; import android.os.Debug; import android.os.IBinder; -import android.os.RemoteException; import android.util.Slog; +import android.view.InputApplicationHandle; import android.view.KeyEvent; import android.view.WindowManager; -import android.view.InputApplicationHandle; import com.android.server.input.InputManagerService; -import android.view.InputWindowHandle; -import android.view.InputChannel; import java.io.PrintWriter; -import java.util.HashMap; final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks { private final WindowManagerService mService; @@ -116,9 +111,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal if (appWindowToken != null && appWindowToken.appToken != null) { // Notify the activity manager about the timeout and let it decide whether // to abort dispatching or keep waiting. - final AppWindowContainerController controller = appWindowToken.getController(); - final boolean abort = controller != null - && controller.keyDispatchingTimedOut(reason, + final boolean abort = appWindowToken.keyDispatchingTimedOut(reason, (windowState != null) ? windowState.mSession.mPid : -1); if (!abort) { // The activity manager declined to abort dispatching. diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b483fd3bc6420..c3296cea51950 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -497,9 +497,8 @@ class RootWindowContainer extends WindowContainer { if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin, "RECOVER DESTROY", false); winAnimator.destroySurface(); - if (winAnimator.mWin.mAppToken != null - && winAnimator.mWin.mAppToken.getController() != null) { - winAnimator.mWin.mAppToken.getController().removeStartingWindow(); + if (winAnimator.mWin.mAppToken != null) { + winAnimator.mWin.mAppToken.removeStartingWindow(); } } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index eec10aba5df29..932f7394db6ad 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -1182,7 +1182,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont mActivities.add(newTop); // Make sure window manager is aware of the position change. - mWindowContainerController.positionChildAtTop(newTop.mWindowContainerController); + mWindowContainerController.positionChildAtTop(newTop.mAppWindowToken); updateEffectiveIntent(); setFrontOfTask(); @@ -1264,12 +1264,10 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont mService.notifyTaskPersisterLocked(this, false); } - // Sync. with window manager - final AppWindowContainerController appController = r.getWindowContainerController(); - if (appController != null) { + if (r.mAppWindowToken != null) { // Only attempt to move in WM if the child has a controller. It is possible we haven't // created controller for the activity we are starting yet. - mWindowContainerController.positionChildAt(appController, index); + mWindowContainerController.positionChildAt(r.mAppWindowToken, index); } // Make sure the list of display UID whitelists is updated diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index 59b2055193ae0..ec64d2e82895e 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -16,6 +16,14 @@ package com.android.server.wm; +import static com.android.server.EventLogTags.WM_TASK_CREATED; +import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Rect; @@ -24,18 +32,11 @@ import android.os.Looper; import android.os.Message; import android.util.EventLog; import android.util.Slog; + import com.android.internal.annotations.VisibleForTesting; import java.lang.ref.WeakReference; -import static com.android.server.EventLogTags.WM_TASK_CREATED; -import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - /** * Controller for the task container. This is created by activity manager to link task records to * the task container they use in window manager. @@ -103,16 +104,15 @@ public class TaskWindowContainerController } } - public void positionChildAtTop(AppWindowContainerController childController) { - positionChildAt(childController, POSITION_TOP); + void positionChildAtTop(AppWindowToken aToken) { + positionChildAt(aToken, POSITION_TOP); } - public void positionChildAt(AppWindowContainerController childController, int position) { + void positionChildAt(AppWindowToken aToken, int position) { synchronized (mService.mGlobalLock) { - final AppWindowToken aToken = childController.mContainer; if (aToken == null) { Slog.w(TAG_WM, - "Attempted to position of non-existing app : " + childController); + "Attempted to position of non-existing app"); return; } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java index f12619c6e337c..19d18cab931e0 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java @@ -35,7 +35,6 @@ import static org.mockito.Mockito.spy; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Display; -import android.view.IApplicationToken; import androidx.test.filters.SmallTest; @@ -111,16 +110,9 @@ public class AppTransitionTests extends WindowTestsBase { final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - // Set TestAppWindowContainerController & assign first app token state to be good to go. - final WindowTestUtils.TestAppWindowContainerController controller1 = - createAppWindowController(dc1, token1.appToken); - final WindowTestUtils.TestAppWindowContainerController controller2 = - createAppWindowController(dc1, token2.appToken); - controller1.setContainer(token1); token1.allDrawn = true; token1.startingDisplayed = true; token1.startingMoved = true; - controller2.setContainer(token2); // Simulate activity resume / finish flows to prepare app transition & set visibility, // make sure transition is set as expected for each display. @@ -132,8 +124,8 @@ public class AppTransitionTests extends WindowTestsBase { assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition()); // One activity window is visible for resuming & the other activity window is invisible // for finishing in different display. - controller1.setVisibility(true, false); - controller2.setVisibility(false, false); + token1.setVisibility(true, false); + token2.setVisibility(false, false); // Make sure each display is in animating stage. assertTrue(dc1.mOpeningApps.size() > 0); @@ -174,16 +166,4 @@ public class AppTransitionTests extends WindowTestsBase { assertFalse(dc1.mOpeningApps.contains(token1)); } - private WindowTestUtils.TestAppWindowContainerController createAppWindowController( - DisplayContent dc, IApplicationToken token) { - return createAppWindowController( - new WindowTestUtils.TestTaskWindowContainerController( - createStackControllerOnDisplay(dc)), token); - } - - private WindowTestUtils.TestAppWindowContainerController createAppWindowController( - WindowTestUtils.TestTaskWindowContainerController taskController, - IApplicationToken token) { - return new WindowTestUtils.TestAppWindowContainerController(taskController, token); - } } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java deleted file mode 100644 index 415b5d93d90e1..0000000000000 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2017 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.res.Configuration.EMPTY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - -import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController; - -import org.junit.Test; - -/** - * Test class for {@link AppWindowContainerController}. - * - * atest FrameworksServicesTests:AppWindowContainerControllerTests - */ -@FlakyTest(bugId = 74078662) -@SmallTest -@Presubmit -public class AppWindowContainerControllerTests extends WindowTestsBase { - - private final String mPackageName = getInstrumentation().getTargetContext().getPackageName(); - - @Test - public void testRemoveContainer() { - final WindowTestUtils.TestAppWindowContainerController controller = - createAppWindowController(); - - // Assert token was added to display. - assertNotNull(mDisplayContent.getWindowToken(controller.mToken.asBinder())); - // Assert that the container was created and linked. - assertNotNull(controller.mContainer); - - controller.removeContainer(mDisplayContent.getDisplayId()); - - // Assert token was remove from display. - assertNull(mDisplayContent.getWindowToken(controller.mToken.asBinder())); - // Assert that the container was removed. - assertNull(controller.mContainer); - } - - @Test - public void testSetOrientation() { - final WindowTestUtils.TestAppWindowContainerController controller = - createAppWindowController(); - - // Assert orientation is unspecified to start. - assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); - - controller.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getDisplayId(), - EMPTY /* displayConfig */, false /* freezeScreenIfNeeded */); - assertEquals(SCREEN_ORIENTATION_LANDSCAPE, controller.getOrientation()); - - controller.removeContainer(mDisplayContent.getDisplayId()); - // Assert orientation is unspecified to after container is removed. - assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); - - // Reset display frozen state - mWm.mDisplayFrozen = false; - } - - private void assertHasStartingWindow(AppWindowToken atoken) { - assertNotNull(atoken.startingSurface); - assertNotNull(atoken.startingData); - assertNotNull(atoken.startingWindow); - } - - private void assertNoStartingWindow(AppWindowToken atoken) { - assertNull(atoken.startingSurface); - assertNull(atoken.startingWindow); - assertNull(atoken.startingData); - atoken.forAllWindows(windowState -> { - assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING); - }, true); - } - - @Test - public void testCreateRemoveStartingWindow() { - final WindowTestUtils.TestAppWindowContainerController controller = - createAppWindowController(); - controller.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, - false, false); - waitUntilHandlersIdle(); - final AppWindowToken atoken = controller.getAppWindowToken(mDisplayContent); - assertHasStartingWindow(atoken); - controller.removeStartingWindow(); - waitUntilHandlersIdle(); - assertNoStartingWindow(atoken); - } - - @Test - public void testAddRemoveRace() { - // There was once a race condition between adding and removing starting windows - for (int i = 0; i < 1000; i++) { - final WindowTestUtils.TestAppWindowContainerController controller = - createAppWindowController(); - controller.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, - false, false); - controller.removeStartingWindow(); - waitUntilHandlersIdle(); - assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent)); - - controller.getAppWindowToken( - mDisplayContent).getParent().getParent().removeImmediately(); - } - } - - @Test - public void testTransferStartingWindow() { - final WindowTestUtils.TestAppWindowContainerController controller1 = - createAppWindowController(); - final WindowTestUtils.TestAppWindowContainerController controller2 = - createAppWindowController(); - controller1.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, - false, false); - waitUntilHandlersIdle(); - controller2.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), - true, true, false, true, false, false); - waitUntilHandlersIdle(); - assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent)); - assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent)); - } - - @Test - public void testTransferStartingWindowWhileCreating() { - final WindowTestUtils.TestAppWindowContainerController controller1 = - createAppWindowController(); - final WindowTestUtils.TestAppWindowContainerController controller2 = - createAppWindowController(); - ((TestWindowManagerPolicy) mWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> { - - // Surprise, ...! Transfer window in the middle of the creation flow. - controller2.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), - true, true, false, true, false, false); - }); - controller1.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, - false, false); - waitUntilHandlersIdle(); - assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent)); - assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent)); - } - - @Test - public void testTryTransferStartingWindowFromHiddenAboveToken() { - - // Add two tasks on top of each other. - TestTaskWindowContainerController taskController = - new WindowTestUtils.TestTaskWindowContainerController(this); - final WindowTestUtils.TestAppWindowContainerController controllerTop = - createAppWindowController(taskController); - final WindowTestUtils.TestAppWindowContainerController controllerBottom = - createAppWindowController(taskController); - - // Add a starting window. - controllerTop.addStartingWindow(mPackageName, - android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, - false, false); - waitUntilHandlersIdle(); - - // Make the top one invisible, and try transfering the starting window from the top to the - // bottom one. - controllerTop.setVisibility(false, false); - controllerBottom.mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded(); - - // Assert that the bottom window now has the starting window. - assertNoStartingWindow(controllerTop.getAppWindowToken(mDisplayContent)); - assertHasStartingWindow(controllerBottom.getAppWindowToken(mDisplayContent)); - } - - @Test - public void testReparent() { - final StackWindowController stackController = - createStackControllerOnDisplay(mDisplayContent); - final WindowTestUtils.TestTaskWindowContainerController taskController1 = - new WindowTestUtils.TestTaskWindowContainerController(stackController); - final WindowTestUtils.TestAppWindowContainerController appWindowController1 = - createAppWindowController(taskController1); - final WindowTestUtils.TestTaskWindowContainerController taskController2 = - new WindowTestUtils.TestTaskWindowContainerController(stackController); - final WindowTestUtils.TestAppWindowContainerController appWindowController2 = - createAppWindowController(taskController2); - final WindowTestUtils.TestTaskWindowContainerController taskController3 = - new WindowTestUtils.TestTaskWindowContainerController(stackController); - - try { - appWindowController1.reparent(taskController1, 0); - fail("Should not be able to reparent to the same parent"); - } catch (IllegalArgumentException e) { - // Expected - } - - try { - taskController3.setContainer(null); - appWindowController1.reparent(taskController3, 0); - fail("Should not be able to reparent to a task that doesn't have a container"); - } catch (IllegalArgumentException e) { - // Expected - } - - // Reparent the app window and ensure that it is moved - appWindowController1.reparent(taskController2, 0); - assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent()); - assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer) - .positionInParent()); - assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer) - .positionInParent()); - } - - private WindowTestUtils.TestAppWindowContainerController createAppWindowController() { - return createAppWindowController( - new WindowTestUtils.TestTaskWindowContainerController(this)); - } - - private WindowTestUtils.TestAppWindowContainerController createAppWindowController( - WindowTestUtils.TestTaskWindowContainerController taskController) { - return new WindowTestUtils.TestAppWindowContainerController(taskController); - } -} diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 552390d194190..99abbf7b1f3a4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; @@ -31,8 +32,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_UNSET; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -66,6 +70,8 @@ public class AppWindowTokenTests extends WindowTestsBase { Task mTask; WindowTestUtils.TestAppWindowToken mToken; + private final String mPackageName = getInstrumentation().getTargetContext().getPackageName(); + @Before public void setUp() throws Exception { mStack = createTaskStackOnDisplay(mDisplayContent); @@ -251,7 +257,7 @@ public class AppWindowTokenTests extends WindowTestsBase { "closingWindow"); closingWindow.mAnimatingExit = true; closingWindow.mRemoveOnExit = true; - closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET, true /* performLayout */, false /* isVoiceInteraction */); // We pretended that we were running an exit animation, but that should have been cleared up @@ -260,6 +266,124 @@ public class AppWindowTokenTests extends WindowTestsBase { assertTrue(closingWindow.mRemoved); } + @Test + public void testSetOrientation() { + // Assert orientation is unspecified to start. + assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mToken.getOrientation()); + + mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation()); + + mDisplayContent.removeAppToken(mToken.token); + // Assert orientation is unset to after container is removed. + assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation()); + + // Reset display frozen state + mWm.mDisplayFrozen = false; + } + + @Test + public void testCreateRemoveStartingWindow() { + mToken.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + assertHasStartingWindow(mToken); + mToken.removeStartingWindow(); + waitUntilHandlersIdle(); + assertNoStartingWindow(mToken); + } + + @Test + public void testAddRemoveRace() { + // There was once a race condition between adding and removing starting windows + for (int i = 0; i < 1000; i++) { + final WindowTestUtils.TestAppWindowToken appToken = createIsolatedTestAppWindowToken(); + + appToken.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + appToken.removeStartingWindow(); + waitUntilHandlersIdle(); + assertNoStartingWindow(appToken); + + appToken.getParent().getParent().removeImmediately(); + } + } + + @Test + public void testTransferStartingWindow() { + final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken(); + final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken(); + token1.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + token2.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, token1.appToken.asBinder(), + true, true, false, true, false, false); + waitUntilHandlersIdle(); + assertNoStartingWindow(token1); + assertHasStartingWindow(token2); + } + + @Test + public void testTransferStartingWindowWhileCreating() { + final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken(); + final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken(); + ((TestWindowManagerPolicy) token1.mService.mPolicy).setRunnableWhenAddingSplashScreen( + () -> { + // Surprise, ...! Transfer window in the middle of the creation flow. + token2.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, + token1.appToken.asBinder(), true, true, false, + true, false, false); + }); + token1.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + assertNoStartingWindow(token1); + assertHasStartingWindow(token2); + } + + private WindowTestUtils.TestAppWindowToken createIsolatedTestAppWindowToken() { + final TaskStack taskStack = createTaskStackOnDisplay(mDisplayContent); + final Task task = createTaskInStack(taskStack, 0 /* userId */); + return createTestAppWindowTokenForGivenTask(task); + } + + private WindowTestUtils.TestAppWindowToken createTestAppWindowTokenForGivenTask(Task task) { + final WindowTestUtils.TestAppWindowToken appToken = + WindowTestUtils.createTestAppWindowToken(mDisplayContent); + task.addChild(appToken, 0); + waitUntilHandlersIdle(); + return appToken; + } + + @Test + public void testTryTransferStartingWindowFromHiddenAboveToken() { + // Add two tasks on top of each other. + final WindowTestUtils.TestAppWindowToken tokenTop = createIsolatedTestAppWindowToken(); + final WindowTestUtils.TestAppWindowToken tokenBottom = + createTestAppWindowTokenForGivenTask(tokenTop.getTask()); + + // Add a starting window. + tokenTop.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + + // Make the top one invisible, and try transferring the starting window from the top to the + // bottom one. + tokenTop.setVisibility(false, false); + tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); + + // Assert that the bottom window now has the starting window. + assertNoStartingWindow(tokenTop); + assertHasStartingWindow(tokenBottom); + } + @Test public void testTransitionAnimationPositionAndBounds() { final Rect stackBounds = new Rect( @@ -285,4 +409,19 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(expectedY, outPosition.y); assertEquals(expectedBounds, outBounds); } + + private void assertHasStartingWindow(AppWindowToken atoken) { + assertNotNull(atoken.startingSurface); + assertNotNull(atoken.startingData); + assertNotNull(atoken.startingWindow); + } + + private void assertNoStartingWindow(AppWindowToken atoken) { + assertNull(atoken.startingSurface); + assertNull(atoken.startingWindow); + assertNull(atoken.startingData); + atoken.forAllWindows(windowState -> { + assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING); + }, true); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java index d2c07651d83cb..792e8a6f75824 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -48,7 +48,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { public void testGetClosingApps_closing() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); - closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET, true /* performLayout */, false /* isVoiceInteraction */); final ArraySet closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); @@ -64,9 +64,9 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { "closingWindow"); final WindowState openingWindow = createAppWindow(closingWindow.getTask(), FIRST_APPLICATION_WINDOW, "openingWindow"); - closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET, true /* performLayout */, false /* isVoiceInteraction */); - openingWindow.mAppToken.setVisibility(null, true /* visible */, TRANSIT_UNSET, + openingWindow.mAppToken.commitVisibility(null, true /* visible */, TRANSIT_UNSET, true /* performLayout */, false /* isVoiceInteraction */); final ArraySet closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); @@ -79,7 +79,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { public void testGetClosingApps_skipClosingAppsSnapshotTasks() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); - closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET, true /* performLayout */, false /* isVoiceInteraction */); final ArraySet closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java index 1af79e41fe376..bbf508dd16300 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java @@ -17,8 +17,6 @@ package com.android.server.wm; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; @@ -37,6 +35,7 @@ import org.junit.Test; @Presubmit public class TaskWindowContainerControllerTests extends WindowTestsBase { + /* Comment out due to removal of AppWindowContainerController @Test public void testRemoveContainer() { final WindowTestUtils.TestTaskWindowContainerController taskController = @@ -49,7 +48,9 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { assertNull(taskController.mContainer); assertNull(appController.mContainer); } + */ + /* Comment out due to removal of AppWindowContainerController @Test public void testRemoveContainer_deferRemoval() { final WindowTestUtils.TestTaskWindowContainerController taskController = @@ -74,6 +75,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { assertNull(appController.mContainer); assertNull(app.getController()); } + */ @Test public void testReparent() { diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index 60c045991d696..2e47c353d8c23 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -18,7 +18,6 @@ package com.android.server.wm; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -116,12 +115,11 @@ public class WindowTestUtils { ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, - boolean launchTaskBehind, boolean alwaysFocusable, - AppWindowContainerController controller) { + boolean launchTaskBehind, boolean alwaysFocusable, ActivityRecord activityRecord) { super(service, token, activityComponent, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, launchTaskBehind, - alwaysFocusable, controller); + alwaysFocusable, activityRecord); } int getWindowsCount() { @@ -275,45 +273,6 @@ public class WindowTestUtils { } } - public static class TestAppWindowContainerController extends AppWindowContainerController { - - final IApplicationToken mToken; - - TestAppWindowContainerController(TestTaskWindowContainerController taskController) { - this(taskController, new TestIApplicationToken()); - } - - TestAppWindowContainerController(TestTaskWindowContainerController taskController, - IApplicationToken token) { - super(taskController, token, new ComponentName("", "") /* activityComponent */, - null /* listener */, 0 /* index */, SCREEN_ORIENTATION_UNSPECIFIED, - true /* fullscreen */, true /* showForAllUsers */, 0 /* configChanges */, - false /* voiceInteraction */, false /* launchTaskBehind */, - false /* alwaysFocusable */, 0 /* targetSdkVersion */, - 0 /* rotationAnimationHint */, 0 /* inputDispatchingTimeoutNanos */, - taskController.mService); - mToken = token; - } - - @Override - AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, - ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc, - long inputDispatchingTimeoutNanos, - boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, - int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller) { - return new TestAppWindowToken(service, token, activityComponent, voiceInteraction, dc, - inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, - orientation, - rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, - controller); - } - - AppWindowToken getAppWindowToken(DisplayContent dc) { - return (AppWindowToken) dc.getWindowToken(mToken.asBinder()); - } - } - public static class TestIApplicationToken implements IApplicationToken { private final Binder mBinder = new Binder(); 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 170bd3311de21..d87b57100ce4d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -29,10 +29,9 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static junit.framework.TestCase.assertNotNull; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index c2ab3acd49335..4a57c7dfe8454 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -231,7 +231,7 @@ class ActivityTestsBase { aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, mService.mStackSupervisor, null /* options */, null /* sourceRecord */); - activity.mWindowContainerController = mock(AppWindowContainerController.class); + activity.mAppWindowToken = mock(AppWindowToken.class); if (mTaskRecord != null) { mTaskRecord.addActivityToTop(activity); @@ -243,6 +243,7 @@ class ActivityTestsBase { mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); activity.setProcess(wpc); + activity.service.mWindowManager.mRoot = mock(RootWindowContainer.class); return activity; } }