Merge "Remove AppWindowContainerController and AppWindowContainerListener (39/n)"
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 61168ec..eec22d5 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 @@
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_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_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.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.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 @@
/**
* 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 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
@@ -770,10 +793,16 @@
}
/**
- * 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 {
@@ -993,13 +1022,9 @@
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);
}
@@ -1012,12 +1037,31 @@
// 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);
@@ -1028,17 +1072,49 @@
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());
}
/**
@@ -1046,6 +1122,10 @@
* 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
@@ -1061,8 +1141,7 @@
+ " 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.
@@ -1492,7 +1571,7 @@
void applyOptionsLocked() {
if (pendingOptions != null
&& pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
- mWindowContainerController.applyOptionsLocked(pendingOptions, intent);
+ applyOptionsLocked(pendingOptions, intent);
if (task == null) {
clearOptionsLocked(false /* withAbort */);
} else {
@@ -1502,6 +1581,104 @@
}
}
+ /**
+ * 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;
}
@@ -1534,8 +1711,11 @@
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);
}
}
}
@@ -1544,8 +1724,11 @@
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);
}
}
}
@@ -1567,11 +1750,16 @@
}
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;
@@ -1601,7 +1789,12 @@
// 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();
}
}
@@ -1639,7 +1832,12 @@
}
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() {
@@ -1647,7 +1845,10 @@
// 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);
+ }
}
}
@@ -1859,7 +2060,9 @@
stopped = true;
setState(STOPPED, "activityStoppedLocked");
- mWindowContainerController.notifyAppStopped();
+ if (mAppWindowToken != null) {
+ mAppWindowToken.notifyAppStopped();
+ }
if (finishing) {
clearOptionsLocked();
@@ -1920,14 +2123,33 @@
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);
}
}
@@ -1939,7 +2161,10 @@
info.windowsFullyDrawnDelayMs);
}
}
- @Override
+
+ /**
+ * Called when the starting window for this container is drawn.
+ */
public void onStartingWindowDrawn(long timestamp) {
synchronized (service.mGlobalLock) {
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
@@ -1947,7 +2172,7 @@
}
}
- @Override
+ /** Called when the windows associated app window container are drawn. */
public void onWindowsDrawn(boolean drawn, long timestamp) {
synchronized (service.mGlobalLock) {
mDrawn = drawn;
@@ -1967,7 +2192,7 @@
}
}
- @Override
+ /** Called when the windows associated app window container are visible. */
public void onWindowsVisible() {
synchronized (service.mGlobalLock) {
mStackSupervisor.reportActivityVisibleLocked(this);
@@ -2001,7 +2226,7 @@
}
}
- @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);
@@ -2009,7 +2234,14 @@
}
}
- @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;
@@ -2185,7 +2417,7 @@
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean fromRecents) {
- if (mWindowContainerController == null) {
+ if (mAppWindowToken == null) {
return;
}
if (mTaskOverlay) {
@@ -2200,7 +2432,7 @@
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(),
@@ -2215,12 +2447,12 @@
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) {
@@ -2228,7 +2460,7 @@
final Configuration displayConfig =
mRootActivityContainer.getDisplayOverrideConfiguration(displayId);
- final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
+ final Configuration config = setOrientation(requestedOrientation,
displayId, displayConfig, mayFreezeScreenLocked(app));
if (config != null) {
frozenBeforeDestroy = true;
@@ -2241,8 +2473,36 @@
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);
}
/**
@@ -2290,8 +2550,8 @@
/** 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;
@@ -2920,7 +3180,12 @@
}
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 f49c689..9fbeaf8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3034,7 +3034,7 @@
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;
}
@@ -3064,9 +3064,10 @@
// 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 a71f5f3..3162ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1877,7 +1877,7 @@
"Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> 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 32a6f74..bf00ffb 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 @@
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 @@
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 @@
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 7fdea10..0000000
--- 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<AppWindowToken, AppWindowContainerListener> {
-
- 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 ad27669..0000000
--- 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 6d402f2..a7c9a46 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.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 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.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 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 @@
* 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 @@
private Task mLastParent;
+ // TODO: Remove after unification
+ ActivityRecord mActivityRecord;
+
/**
* See {@link #canTurnScreenOn()}
*/
@@ -273,14 +284,20 @@
/** 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 @@
// 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
@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 @@
}
}
+ 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 @@
startingData = fromToken.startingData;
fromToken.startingData = null;
fromToken.startingMoved = true;
- if (getController() != null) {
- getController().scheduleAddStartingWindow();
- }
+ scheduleAddStartingWindow();
return true;
}
@@ -1471,6 +1614,10 @@
}
}
+ 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 @@
}
}
} else if (w.isDrawnLw()) {
- if (getController() != null) {
- getController().reportStartingWindowDrawn();
+ if (mActivityRecord != null) {
+ mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis());
}
startingDisplayed = true;
}
@@ -1601,6 +1748,266 @@
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 @@
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 9435539..639ed02 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 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;
@@ -112,9 +107,7 @@
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 fd9120a..7f90f1b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -495,9 +495,8 @@
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 a28b875..8a3dbad 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 @@
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 @@
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 59b2055..ec64d2e 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.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 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 f12619c..19d18ca 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 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 @@
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 @@
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 @@
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 415b5d9..0000000
--- 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 552390d..99abbf7 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 @@
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_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 @@
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 @@
"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
@@ -261,6 +267,124 @@
}
@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(
0/* left */, 0 /* top */, 1000 /* right */, 1000 /* bottom */);
@@ -285,4 +409,19 @@
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 d2c0765..792e8a6 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 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<AppWindowToken> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mAppToken);
@@ -64,9 +64,9 @@
"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<AppWindowToken> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mAppToken);
@@ -79,7 +79,7 @@
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<AppWindowToken> 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 1af79e4..bbf508d 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 @@
@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 @@
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 @@
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 60c0459..2e47c35 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 @@
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 @@
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 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 b15b8c1..b6f1817 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.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 4fc73bc..bad7776 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -233,7 +233,7 @@
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);
@@ -245,6 +245,7 @@
mock(WindowProcessListener.class));
wpc.setThread(mock(IApplicationThread.class));
activity.setProcess(wpc);
+ activity.service.mWindowManager.mRoot = mock(RootWindowContainer.class);
return activity;
}
}