Remove AppWindowContainerController and AppWindowContainerListener (39/n)
AppWindowToken and ActivityRecord will hold each other as a member and call directly into the other. Unnecessary locks are removed. All AppWindowContainerControllerTests moved to AppWindowTokenTests. Three of the tests needs other works of the hierarchy which can be added back later. Commented out with a TODO. Bug: 80414790 Test: go/wm-smoke Test: atest ActivityRecordTests Test: atest AppWindowTokenTests Test: atest FrameworksServicesTests:AppTransitionTests Test: atest ActivityStackSupervisorTests Test: atest ActivityStackTests Change-Id: Ifa1f692f5c54dbffc3758bd26de124e7d055e0ab
This commit is contained in:
@@ -18,7 +18,17 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
|
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
|
||||||
import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
|
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_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_STACK_ID;
|
||||||
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||||
@@ -63,6 +73,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
|
|||||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
|
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
|
||||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
|
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.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.isFixedOrientationLandscape;
|
||||||
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
|
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
|
||||||
import static android.content.res.Configuration.EMPTY;
|
import static android.content.res.Configuration.EMPTY;
|
||||||
@@ -111,12 +122,18 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
|
|||||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
import static com.android.server.wm.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_FREE_RESIZE;
|
||||||
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
|
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.HASH_CODE;
|
||||||
import static com.android.server.wm.IdentifierProto.TITLE;
|
import static com.android.server.wm.IdentifierProto.TITLE;
|
||||||
import static com.android.server.wm.IdentifierProto.USER_ID;
|
import static com.android.server.wm.IdentifierProto.USER_ID;
|
||||||
import static com.android.server.wm.TaskPersister.DEBUG;
|
import static com.android.server.wm.TaskPersister.DEBUG;
|
||||||
import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
|
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_DOCUMENT;
|
||||||
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
@@ -147,6 +164,7 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.res.CompatibilityInfo;
|
import android.content.res.CompatibilityInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.GraphicBuffer;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -167,11 +185,14 @@ import android.util.MergedConfiguration;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
|
import android.view.AppTransitionAnimationSpec;
|
||||||
|
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||||
import android.view.IApplicationToken;
|
import android.view.IApplicationToken;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
import android.view.WindowManager.LayoutParams;
|
import android.view.WindowManager.LayoutParams;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.app.ResolverActivity;
|
import com.android.internal.app.ResolverActivity;
|
||||||
import com.android.internal.content.ReferrerIntent;
|
import com.android.internal.content.ReferrerIntent;
|
||||||
import com.android.internal.util.XmlUtils;
|
import com.android.internal.util.XmlUtils;
|
||||||
@@ -200,7 +221,7 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* An entry in the history stack, representing an activity.
|
* 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 = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
|
||||||
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
|
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
|
||||||
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
|
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
|
||||||
@@ -225,7 +246,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
|
|
||||||
final ActivityTaskManagerService service; // owner
|
final ActivityTaskManagerService service; // owner
|
||||||
final IApplicationToken.Stub appToken; // window manager token
|
final IApplicationToken.Stub appToken; // window manager token
|
||||||
AppWindowContainerController mWindowContainerController;
|
// TODO: Remove after unification
|
||||||
|
AppWindowToken mAppWindowToken;
|
||||||
|
|
||||||
final ActivityInfo info; // all about me
|
final ActivityInfo info; // all about me
|
||||||
// TODO: This is duplicated state already contained in info.applicationInfo - remove
|
// TODO: This is duplicated state already contained in info.applicationInfo - remove
|
||||||
ApplicationInfo appInfo; // information about activity's app
|
ApplicationInfo appInfo; // information about activity's app
|
||||||
@@ -769,10 +792,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link AppWindowContainerController#setWillCloseOrEnterPip(boolean)}
|
* Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP.
|
||||||
|
* This information helps AWT know that the app is in the process of pausing before it gets the
|
||||||
|
* signal on the WM side.
|
||||||
*/
|
*/
|
||||||
void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
|
void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
|
||||||
getWindowContainerController().setWillCloseOrEnterPip(willCloseOrEnterPip);
|
if (mAppWindowToken == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAppWindowToken.setWillCloseOrEnterPip(willCloseOrEnterPip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Token extends IApplicationToken.Stub {
|
static class Token extends IApplicationToken.Stub {
|
||||||
@@ -991,13 +1020,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
return hasProcess() && app.hasThread();
|
return hasProcess() && app.hasThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
AppWindowContainerController getWindowContainerController() {
|
void createAppWindowToken() {
|
||||||
return mWindowContainerController;
|
if (mAppWindowToken != null) {
|
||||||
}
|
throw new IllegalArgumentException("App Window Token=" + mAppWindowToken
|
||||||
|
|
||||||
void createWindowContainer() {
|
|
||||||
if (mWindowContainerController != null) {
|
|
||||||
throw new IllegalArgumentException("Window container=" + mWindowContainerController
|
|
||||||
+ " already created for r=" + this);
|
+ " already created for r=" + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1010,12 +1035,31 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
// Make sure override configuration is up-to-date before using to create window controller.
|
// Make sure override configuration is up-to-date before using to create window controller.
|
||||||
updateOverrideConfiguration();
|
updateOverrideConfiguration();
|
||||||
|
|
||||||
mWindowContainerController = new AppWindowContainerController(taskController, appToken,
|
// TODO: remove after unification
|
||||||
realActivity, this, Integer.MAX_VALUE /* add on top */, info.screenOrientation,
|
mAppWindowToken = service.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder());
|
||||||
fullscreen, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
|
if (mAppWindowToken != null) {
|
||||||
task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
|
// TODO: Should this throw an exception instead?
|
||||||
appInfo.targetSdkVersion, mRotationAnimationHint,
|
Slog.w(TAG, "Attempted to add existing app token: " + appToken);
|
||||||
ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
|
} 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);
|
task.addActivityToTop(this);
|
||||||
|
|
||||||
@@ -1026,17 +1070,49 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
mLastReportedPictureInPictureMode = inPinnedWindowingMode();
|
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() {
|
void removeWindowContainer() {
|
||||||
// Do not try to remove a window container if we have already removed it.
|
final DisplayContent dc = service.mWindowManager.mRoot.getDisplayContent(
|
||||||
if (mWindowContainerController == null) {
|
getDisplayId());
|
||||||
|
if (dc == null) {
|
||||||
|
Slog.w(TAG, "removeWindowContainer: Attempted to remove token: "
|
||||||
|
+ appToken + " from non-existing displayId=" + getDisplayId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resume key dispatching if it is currently paused before we remove the container.
|
// Resume key dispatching if it is currently paused before we remove the container.
|
||||||
resumeKeyDispatchingLocked();
|
resumeKeyDispatchingLocked();
|
||||||
|
dc.removeAppToken(appToken.asBinder());
|
||||||
mWindowContainerController.removeContainer(getDisplayId());
|
|
||||||
mWindowContainerController = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1044,6 +1120,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
* should ensure that the {@param newTask} is not already the parent of this activity.
|
* should ensure that the {@param newTask} is not already the parent of this activity.
|
||||||
*/
|
*/
|
||||||
void reparent(TaskRecord newTask, int position, String reason) {
|
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;
|
final TaskRecord prevTask = task;
|
||||||
if (prevTask == newTask) {
|
if (prevTask == newTask) {
|
||||||
throw new IllegalArgumentException(reason + ": task=" + newTask
|
throw new IllegalArgumentException(reason + ": task=" + newTask
|
||||||
@@ -1059,8 +1139,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
+ " r=" + this + " (" + prevTask.getStackId() + ")");
|
+ " r=" + this + " (" + prevTask.getStackId() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must reparent first in window manager
|
mAppWindowToken.reparent(newTask.getWindowContainerController(), position);
|
||||||
mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
|
|
||||||
|
|
||||||
// Reparenting prevents informing the parent stack of activity removal in the case that
|
// 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.
|
// the new stack has the same parent. we must manually signal here if this is not the case.
|
||||||
@@ -1490,7 +1569,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
void applyOptionsLocked() {
|
void applyOptionsLocked() {
|
||||||
if (pendingOptions != null
|
if (pendingOptions != null
|
||||||
&& pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
|
&& pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
|
||||||
mWindowContainerController.applyOptionsLocked(pendingOptions, intent);
|
applyOptionsLocked(pendingOptions, intent);
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
clearOptionsLocked(false /* withAbort */);
|
clearOptionsLocked(false /* withAbort */);
|
||||||
} else {
|
} else {
|
||||||
@@ -1500,6 +1579,104 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply override app transition base on options & animation type.
|
||||||
|
*/
|
||||||
|
void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) {
|
||||||
|
final int animationType = pendingOptions.getAnimationType();
|
||||||
|
final DisplayContent displayContent = mAppWindowToken.getDisplayContent();
|
||||||
|
switch (animationType) {
|
||||||
|
case ANIM_CUSTOM:
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransition(
|
||||||
|
pendingOptions.getPackageName(),
|
||||||
|
pendingOptions.getCustomEnterResId(),
|
||||||
|
pendingOptions.getCustomExitResId(),
|
||||||
|
pendingOptions.getOnAnimationStartListener());
|
||||||
|
break;
|
||||||
|
case ANIM_CLIP_REVEAL:
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
|
||||||
|
pendingOptions.getStartX(), pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getWidth(), pendingOptions.getHeight());
|
||||||
|
if (intent.getSourceBounds() == null) {
|
||||||
|
intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
|
||||||
|
pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getStartX() + pendingOptions.getWidth(),
|
||||||
|
pendingOptions.getStartY() + pendingOptions.getHeight()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIM_SCALE_UP:
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
|
||||||
|
pendingOptions.getStartX(), pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getWidth(), pendingOptions.getHeight());
|
||||||
|
if (intent.getSourceBounds() == null) {
|
||||||
|
intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
|
||||||
|
pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getStartX() + pendingOptions.getWidth(),
|
||||||
|
pendingOptions.getStartY() + pendingOptions.getHeight()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIM_THUMBNAIL_SCALE_UP:
|
||||||
|
case ANIM_THUMBNAIL_SCALE_DOWN:
|
||||||
|
final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
|
||||||
|
final GraphicBuffer buffer = pendingOptions.getThumbnail();
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer,
|
||||||
|
pendingOptions.getStartX(), pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getOnAnimationStartListener(),
|
||||||
|
scaleUp);
|
||||||
|
if (intent.getSourceBounds() == null && buffer != null) {
|
||||||
|
intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
|
||||||
|
pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getStartX() + buffer.getWidth(),
|
||||||
|
pendingOptions.getStartY() + buffer.getHeight()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
|
||||||
|
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
|
||||||
|
final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
|
||||||
|
final IAppTransitionAnimationSpecsFuture specsFuture =
|
||||||
|
pendingOptions.getSpecsFuture();
|
||||||
|
if (specsFuture != null) {
|
||||||
|
// TODO(multidisplay): Shouldn't be really used anymore from next CL.
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
|
||||||
|
specsFuture, pendingOptions.getOnAnimationStartListener(),
|
||||||
|
animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
|
||||||
|
} else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
|
||||||
|
&& specs != null) {
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionMultiThumb(
|
||||||
|
specs, pendingOptions.getOnAnimationStartListener(),
|
||||||
|
pendingOptions.getAnimationFinishedListener(), false);
|
||||||
|
} else {
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb(
|
||||||
|
pendingOptions.getThumbnail(),
|
||||||
|
pendingOptions.getStartX(), pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getWidth(), pendingOptions.getHeight(),
|
||||||
|
pendingOptions.getOnAnimationStartListener(),
|
||||||
|
(animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
|
||||||
|
if (intent.getSourceBounds() == null) {
|
||||||
|
intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
|
||||||
|
pendingOptions.getStartY(),
|
||||||
|
pendingOptions.getStartX() + pendingOptions.getWidth(),
|
||||||
|
pendingOptions.getStartY() + pendingOptions.getHeight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIM_OPEN_CROSS_PROFILE_APPS:
|
||||||
|
displayContent.mAppTransition
|
||||||
|
.overridePendingAppTransitionStartCrossProfileApps();
|
||||||
|
break;
|
||||||
|
case ANIM_REMOTE_ANIMATION:
|
||||||
|
// TODO(multidisplay): Will pass displayId and adjust dependencies from next CL.
|
||||||
|
displayContent.mAppTransition.overridePendingAppTransitionRemote(
|
||||||
|
pendingOptions.getRemoteAnimationAdapter());
|
||||||
|
break;
|
||||||
|
case ANIM_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ActivityOptions getOptionsForTargetActivityLocked() {
|
ActivityOptions getOptionsForTargetActivityLocked() {
|
||||||
return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
|
return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
|
||||||
}
|
}
|
||||||
@@ -1532,8 +1709,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
if (!keysPaused) {
|
if (!keysPaused) {
|
||||||
keysPaused = true;
|
keysPaused = true;
|
||||||
|
|
||||||
if (mWindowContainerController != null) {
|
// TODO: remove the check after unification with AppWindowToken. The DC check is not
|
||||||
mWindowContainerController.pauseKeyDispatching();
|
// needed after no mock mAppWindowToken in tests.
|
||||||
|
if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) {
|
||||||
|
mAppWindowToken.getDisplayContent().getInputMonitor().pauseDispatchingLw(
|
||||||
|
mAppWindowToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1542,8 +1722,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
if (keysPaused) {
|
if (keysPaused) {
|
||||||
keysPaused = false;
|
keysPaused = false;
|
||||||
|
|
||||||
if (mWindowContainerController != null) {
|
// TODO: remove the check after unification with AppWindowToken. The DC check is not
|
||||||
mWindowContainerController.resumeKeyDispatching();
|
// needed after no mock mAppWindowToken in tests.
|
||||||
|
if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) {
|
||||||
|
mAppWindowToken.getDisplayContent().getInputMonitor().resumeDispatchingLw(
|
||||||
|
mAppWindowToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1565,11 +1748,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setVisibility(boolean visible) {
|
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);
|
mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Look into merging with #setVisibility()
|
// TODO: Look into merging with #commitVisibility()
|
||||||
void setVisible(boolean newVisible) {
|
void setVisible(boolean newVisible) {
|
||||||
visible = newVisible;
|
visible = newVisible;
|
||||||
mDeferHidingClient = !visible && mDeferHidingClient;
|
mDeferHidingClient = !visible && mDeferHidingClient;
|
||||||
@@ -1599,7 +1787,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
// an indication that the Surface will eventually be destroyed.
|
// an indication that the Surface will eventually be destroyed.
|
||||||
// This however isn't necessarily true if we are going to sleep.
|
// This however isn't necessarily true if we are going to sleep.
|
||||||
if (state == STOPPING && !isSleeping()) {
|
if (state == STOPPING && !isSleeping()) {
|
||||||
mWindowContainerController.notifyAppStopping();
|
if (mAppWindowToken == null) {
|
||||||
|
Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
|
||||||
|
+ appToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mAppWindowToken.detachChildren();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1637,7 +1830,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void notifyAppResumed(boolean wasStopped) {
|
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() {
|
void notifyUnknownVisibilityLaunched() {
|
||||||
@@ -1645,7 +1843,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
// No display activities never add a window, so there is no point in waiting them for
|
// No display activities never add a window, so there is no point in waiting them for
|
||||||
// relayout.
|
// relayout.
|
||||||
if (!noDisplay) {
|
if (!noDisplay) {
|
||||||
mWindowContainerController.notifyUnknownVisibilityLaunched();
|
if (mAppWindowToken != null) {
|
||||||
|
mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController
|
||||||
|
.notifyLaunched(mAppWindowToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1857,7 +2058,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
stopped = true;
|
stopped = true;
|
||||||
setState(STOPPED, "activityStoppedLocked");
|
setState(STOPPED, "activityStoppedLocked");
|
||||||
|
|
||||||
mWindowContainerController.notifyAppStopped();
|
if (mAppWindowToken != null) {
|
||||||
|
mAppWindowToken.notifyAppStopped();
|
||||||
|
}
|
||||||
|
|
||||||
if (finishing) {
|
if (finishing) {
|
||||||
clearOptionsLocked();
|
clearOptionsLocked();
|
||||||
@@ -1918,14 +2121,33 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
|
|
||||||
public void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
|
public void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
|
||||||
if (mayFreezeScreenLocked(app)) {
|
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) {
|
public void stopFreezingScreenLocked(boolean force) {
|
||||||
if (force || frozenBeforeDestroy) {
|
if (force || frozenBeforeDestroy) {
|
||||||
frozenBeforeDestroy = false;
|
frozenBeforeDestroy = false;
|
||||||
mWindowContainerController.stopFreezingScreen(force);
|
if (mAppWindowToken == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DEBUG_ORIENTATION) {
|
||||||
|
Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden="
|
||||||
|
+ mAppWindowToken.isHidden() + " freezing="
|
||||||
|
+ mAppWindowToken.isFreezingScreen());
|
||||||
|
}
|
||||||
|
mAppWindowToken.stopFreezingScreen(true, force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1937,7 +2159,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
info.windowsFullyDrawnDelayMs);
|
info.windowsFullyDrawnDelayMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
/**
|
||||||
|
* Called when the starting window for this container is drawn.
|
||||||
|
*/
|
||||||
public void onStartingWindowDrawn(long timestamp) {
|
public void onStartingWindowDrawn(long timestamp) {
|
||||||
synchronized (service.mGlobalLock) {
|
synchronized (service.mGlobalLock) {
|
||||||
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
|
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
|
||||||
@@ -1945,7 +2170,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/** Called when the windows associated app window container are drawn. */
|
||||||
public void onWindowsDrawn(boolean drawn, long timestamp) {
|
public void onWindowsDrawn(boolean drawn, long timestamp) {
|
||||||
synchronized (service.mGlobalLock) {
|
synchronized (service.mGlobalLock) {
|
||||||
mDrawn = drawn;
|
mDrawn = drawn;
|
||||||
@@ -1965,7 +2190,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/** Called when the windows associated app window container are visible. */
|
||||||
public void onWindowsVisible() {
|
public void onWindowsVisible() {
|
||||||
synchronized (service.mGlobalLock) {
|
synchronized (service.mGlobalLock) {
|
||||||
mStackSupervisor.reportActivityVisibleLocked(this);
|
mStackSupervisor.reportActivityVisibleLocked(this);
|
||||||
@@ -1999,7 +2224,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/** Called when the windows associated app window container are no longer visible. */
|
||||||
public void onWindowsGone() {
|
public void onWindowsGone() {
|
||||||
synchronized (service.mGlobalLock) {
|
synchronized (service.mGlobalLock) {
|
||||||
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
|
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
|
||||||
@@ -2007,7 +2232,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* Called when the key dispatching to a window associated with the app window container
|
||||||
|
* timed-out.
|
||||||
|
*
|
||||||
|
* @param reason The reason for the key dispatching time out.
|
||||||
|
* @param windowPid The pid of the window key dispatching timed out on.
|
||||||
|
* @return True if input dispatching should be aborted.
|
||||||
|
*/
|
||||||
public boolean keyDispatchingTimedOut(String reason, int windowPid) {
|
public boolean keyDispatchingTimedOut(String reason, int windowPid) {
|
||||||
ActivityRecord anrActivity;
|
ActivityRecord anrActivity;
|
||||||
WindowProcessController anrApp;
|
WindowProcessController anrApp;
|
||||||
@@ -2183,7 +2415,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
|
|
||||||
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
|
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
|
||||||
boolean fromRecents) {
|
boolean fromRecents) {
|
||||||
if (mWindowContainerController == null) {
|
if (mAppWindowToken == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mTaskOverlay) {
|
if (mTaskOverlay) {
|
||||||
@@ -2198,7 +2430,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
|
|
||||||
final CompatibilityInfo compatInfo =
|
final CompatibilityInfo compatInfo =
|
||||||
service.compatibilityInfoForPackageLocked(info.applicationInfo);
|
service.compatibilityInfoForPackageLocked(info.applicationInfo);
|
||||||
final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
|
final boolean shown = addStartingWindow(packageName, theme,
|
||||||
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
|
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
|
||||||
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
|
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
|
||||||
allowTaskSnapshot(),
|
allowTaskSnapshot(),
|
||||||
@@ -2213,12 +2445,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) {
|
if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) {
|
||||||
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
|
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
|
||||||
mStartingWindowState = STARTING_WINDOW_REMOVED;
|
mStartingWindowState = STARTING_WINDOW_REMOVED;
|
||||||
mWindowContainerController.removeStartingWindow();
|
mAppWindowToken.removeStartingWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRequestedOrientation() {
|
int getRequestedOrientation() {
|
||||||
return mWindowContainerController.getOrientation();
|
return getOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRequestedOrientation(int requestedOrientation) {
|
void setRequestedOrientation(int requestedOrientation) {
|
||||||
@@ -2226,7 +2458,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
final Configuration displayConfig =
|
final Configuration displayConfig =
|
||||||
mStackSupervisor.getDisplayOverrideConfiguration(displayId);
|
mStackSupervisor.getDisplayOverrideConfiguration(displayId);
|
||||||
|
|
||||||
final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
|
final Configuration config = setOrientation(requestedOrientation,
|
||||||
displayId, displayConfig, mayFreezeScreenLocked(app));
|
displayId, displayConfig, mayFreezeScreenLocked(app));
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
frozenBeforeDestroy = true;
|
frozenBeforeDestroy = true;
|
||||||
@@ -2239,8 +2471,36 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
task.taskId, requestedOrientation);
|
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) {
|
void setDisablePreviewScreenshots(boolean disable) {
|
||||||
mWindowContainerController.setDisablePreviewScreenshots(disable);
|
if (mAppWindowToken == null) {
|
||||||
|
Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
|
||||||
|
+ " token: " + appToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mAppWindowToken.setDisablePreviewScreenshots(disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2288,8 +2548,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
|
|
||||||
/** Returns true if the configuration is compatible with this activity. */
|
/** Returns true if the configuration is compatible with this activity. */
|
||||||
boolean isConfigurationCompatible(Configuration config) {
|
boolean isConfigurationCompatible(Configuration config) {
|
||||||
final int orientation = mWindowContainerController != null
|
final int orientation = mAppWindowToken != null
|
||||||
? mWindowContainerController.getOrientation() : info.screenOrientation;
|
? getOrientation() : info.screenOrientation;
|
||||||
if (isFixedOrientationPortrait(orientation)
|
if (isFixedOrientationPortrait(orientation)
|
||||||
&& config.orientation != ORIENTATION_PORTRAIT) {
|
&& config.orientation != ORIENTATION_PORTRAIT) {
|
||||||
return false;
|
return false;
|
||||||
@@ -2918,7 +3178,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void registerRemoteAnimations(RemoteAnimationDefinition definition) {
|
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
|
@Override
|
||||||
|
|||||||
@@ -3043,7 +3043,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
|||||||
if (!startIt) {
|
if (!startIt) {
|
||||||
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
|
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
|
||||||
+ task, new RuntimeException("here").fillInStackTrace());
|
+ task, new RuntimeException("here").fillInStackTrace());
|
||||||
r.createWindowContainer();
|
r.createAppWindowToken();
|
||||||
ActivityOptions.abort(options);
|
ActivityOptions.abort(options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3073,9 +3073,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
|||||||
// TODO: Need to investigate if it is okay for the controller to already be created by the
|
// 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.
|
// 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.
|
// Use test in b/34179495 to trace the call path.
|
||||||
if (r.getWindowContainerController() == null) {
|
if (r.mAppWindowToken == null) {
|
||||||
r.createWindowContainer();
|
r.createAppWindowToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
task.setFrontOfTask();
|
task.setFrontOfTask();
|
||||||
|
|
||||||
if (!isHomeOrRecentsStack() || numActivities() > 0) {
|
if (!isHomeOrRecentsStack() || numActivities() > 0) {
|
||||||
|
|||||||
@@ -3174,7 +3174,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
|||||||
"Added restored task=" + task + " to stack=" + stack);
|
"Added restored task=" + task + " to stack=" + stack);
|
||||||
final ArrayList<ActivityRecord> activities = task.mActivities;
|
final ArrayList<ActivityRecord> activities = task.mActivities;
|
||||||
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
|
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
|
||||||
activities.get(activityNdx).createWindowContainer();
|
activities.get(activityNdx).createAppWindowToken();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ public class AppTransitionController {
|
|||||||
AppWindowToken wtoken = openingApps.valueAt(i);
|
AppWindowToken wtoken = openingApps.valueAt(i);
|
||||||
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
|
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
|
// 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
|
// be notified of app transition complete since the notification will not be
|
||||||
// sent be the app window animator.
|
// sent be the app window animator.
|
||||||
@@ -341,7 +341,7 @@ public class AppTransitionController {
|
|||||||
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
|
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
|
||||||
// TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
|
// TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
|
||||||
// animating?
|
// animating?
|
||||||
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
|
wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
|
||||||
wtoken.updateReportedVisibilityLocked();
|
wtoken.updateReportedVisibilityLocked();
|
||||||
// Force the allDrawn flag, because we want to start
|
// Force the allDrawn flag, because we want to start
|
||||||
// this guy's animations regardless of whether it's
|
// this guy's animations regardless of whether it's
|
||||||
@@ -350,9 +350,8 @@ public class AppTransitionController {
|
|||||||
wtoken.deferClearAllDrawn = false;
|
wtoken.deferClearAllDrawn = false;
|
||||||
// Ensure that apps that are mid-starting are also scheduled to have their
|
// Ensure that apps that are mid-starting are also scheduled to have their
|
||||||
// starting windows removed after the animation is complete
|
// starting windows removed after the animation is complete
|
||||||
if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
|
if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
|
||||||
&& wtoken.getController() != null) {
|
wtoken.removeStartingWindow();
|
||||||
wtoken.getController().removeStartingWindow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
|
if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
|
||||||
|
|||||||
@@ -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
|
|
||||||
+ "}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -28,10 +28,12 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
|||||||
import static android.view.Display.DEFAULT_DISPLAY;
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
|
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
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.FLAG_SHOW_WHEN_LOCKED;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
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_UNSET;
|
||||||
import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
|
import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
|
||||||
|
|
||||||
@@ -81,7 +83,9 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
|
|||||||
|
|
||||||
import android.annotation.CallSuper;
|
import android.annotation.CallSuper;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.res.CompatibilityInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.GraphicBuffer;
|
import android.graphics.GraphicBuffer;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
@@ -90,6 +94,7 @@ import android.os.Binder;
|
|||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.os.Trace;
|
import android.os.Trace;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
@@ -106,6 +111,8 @@ import android.view.animation.Animation;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.ToBooleanFunction;
|
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.policy.WindowManagerPolicy.StartingSurface;
|
||||||
import com.android.server.wm.WindowManagerService.H;
|
import com.android.server.wm.WindowManagerService.H;
|
||||||
|
|
||||||
@@ -121,7 +128,8 @@ class AppTokenList extends ArrayList<AppWindowToken> {
|
|||||||
* Version of WindowToken that is specifically for a particular application (or
|
* Version of WindowToken that is specifically for a particular application (or
|
||||||
* really activity) that is displaying windows.
|
* 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;
|
private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -226,6 +234,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
|
|
||||||
private Task mLastParent;
|
private Task mLastParent;
|
||||||
|
|
||||||
|
// TODO: Remove after unification
|
||||||
|
ActivityRecord mActivityRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link #canTurnScreenOn()}
|
* See {@link #canTurnScreenOn()}
|
||||||
*/
|
*/
|
||||||
@@ -273,14 +284,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
/** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
|
/** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
|
||||||
boolean mNeedsAnimationBoundsLayer;
|
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,
|
AppWindowToken(WindowManagerService service, IApplicationToken token,
|
||||||
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
|
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
|
||||||
long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
|
long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
|
||||||
int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
|
int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
|
||||||
boolean launchTaskBehind, boolean alwaysFocusable,
|
boolean launchTaskBehind, boolean alwaysFocusable,
|
||||||
AppWindowContainerController controller) {
|
ActivityRecord activityRecord) {
|
||||||
this(service, token, activityComponent, voiceInteraction, dc, fullscreen);
|
this(service, token, activityComponent, voiceInteraction, dc, fullscreen);
|
||||||
setController(controller);
|
// TODO: remove after unification
|
||||||
|
mActivityRecord = activityRecord;
|
||||||
|
mActivityRecord.registerConfigurationChangeListener(this);
|
||||||
mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
|
mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
|
||||||
mShowForAllUsers = showForAllUsers;
|
mShowForAllUsers = showForAllUsers;
|
||||||
mTargetSdk = targetSdk;
|
mTargetSdk = targetSdk;
|
||||||
@@ -320,9 +337,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
// it from behind the starting window, so there is no need for it to also be doing its
|
// it from behind the starting window, so there is no need for it to also be doing its
|
||||||
// own stuff.
|
// own stuff.
|
||||||
win.cancelAnimation();
|
win.cancelAnimation();
|
||||||
if (getController() != null) {
|
removeStartingWindow();
|
||||||
getController().removeStartingWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updateReportedVisibilityLocked();
|
updateReportedVisibilityLocked();
|
||||||
}
|
}
|
||||||
@@ -360,16 +375,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
}
|
}
|
||||||
if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
|
if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
|
||||||
+ numInteresting + " visible=" + numVisible);
|
+ numInteresting + " visible=" + numVisible);
|
||||||
final AppWindowContainerController controller = getController();
|
|
||||||
if (nowDrawn != reportedDrawn) {
|
if (nowDrawn != reportedDrawn) {
|
||||||
if (nowDrawn) {
|
if (mActivityRecord != null) {
|
||||||
if (controller != null) {
|
mActivityRecord.onWindowsDrawn(nowDrawn, SystemClock.uptimeMillis());
|
||||||
controller.reportWindowsDrawn();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (controller != null) {
|
|
||||||
controller.reportWindowsNotDrawn();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
reportedDrawn = nowDrawn;
|
reportedDrawn = nowDrawn;
|
||||||
}
|
}
|
||||||
@@ -377,16 +385,36 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
if (DEBUG_VISIBILITY) Slog.v(TAG,
|
if (DEBUG_VISIBILITY) Slog.v(TAG,
|
||||||
"Visibility changed in " + this + ": vis=" + nowVisible);
|
"Visibility changed in " + this + ": vis=" + nowVisible);
|
||||||
reportedVisible = nowVisible;
|
reportedVisible = nowVisible;
|
||||||
if (controller != null) {
|
if (mActivityRecord != null) {
|
||||||
if (nowVisible) {
|
if (nowVisible) {
|
||||||
controller.reportWindowsVisible();
|
onWindowsVisible();
|
||||||
} else {
|
} 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() {
|
boolean isClientHidden() {
|
||||||
return mClientHidden;
|
return mClientHidden;
|
||||||
}
|
}
|
||||||
@@ -401,7 +429,116 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
sendAppVisibilityToClients();
|
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 visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
|
||||||
|
|
||||||
boolean delayed = false;
|
boolean delayed = false;
|
||||||
@@ -461,8 +598,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
|
forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
|
if (DEBUG_APP_TRANSITIONS) {
|
||||||
+ ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
|
Slog.v(TAG_WM, "commitVisibility: " + this
|
||||||
|
+ ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
|
||||||
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
|
getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
|
||||||
@@ -499,10 +638,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
|
mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're becoming visible, immediately change client visibility as well although it
|
// If we're becoming visible, immediately change client visibility as well. there seem
|
||||||
// usually gets changed in AppWindowContainerController.setVisibility already. However,
|
// to be some edge cases where we change our visibility but client visibility never gets
|
||||||
// there seem to be some edge cases where we change our visibility but client visibility
|
// updated.
|
||||||
// never gets updated.
|
|
||||||
// If we're becoming invisible, update the client visibility if we are not running an
|
// If we're becoming invisible, update the client visibility if we are not running an
|
||||||
// animation. Otherwise, we'll update client visibility in onAnimationFinished.
|
// animation. Otherwise, we'll update client visibility in onAnimationFinished.
|
||||||
if (visible || !isReallyAnimating()) {
|
if (visible || !isReallyAnimating()) {
|
||||||
@@ -596,11 +734,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
|
return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppWindowContainerController getController() {
|
|
||||||
final WindowContainerController controller = super.getController();
|
|
||||||
return controller != null ? (AppWindowContainerController) controller : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isVisible() {
|
boolean isVisible() {
|
||||||
// If the app token isn't hidden then it is considered visible and there is no need to check
|
// If the app token isn't hidden then it is considered visible and there is no need to check
|
||||||
@@ -637,7 +770,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
|
|
||||||
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
|
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().mOpeningApps.remove(this);
|
||||||
getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
|
getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
|
||||||
@@ -656,8 +789,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
|
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
|
||||||
+ this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
|
+ this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
|
||||||
|
|
||||||
if (startingData != null && getController() != null) {
|
if (startingData != null) {
|
||||||
getController().removeStartingWindow();
|
removeStartingWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this window was animating, then we need to ensure that the app transition notifies
|
// If this window was animating, then we need to ensure that the app transition notifies
|
||||||
@@ -768,9 +901,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
mAppStopped = true;
|
mAppStopped = true;
|
||||||
destroySurfaces();
|
destroySurfaces();
|
||||||
// Remove any starting window that was added for this app if they are still around.
|
// Remove any starting window that was added for this app if they are still around.
|
||||||
if (getController() != null) {
|
removeStartingWindow();
|
||||||
getController().removeStartingWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearAllDrawn() {
|
void clearAllDrawn() {
|
||||||
@@ -826,9 +957,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
// TODO: Something smells about the code below...Is there a better way?
|
// TODO: Something smells about the code below...Is there a better way?
|
||||||
if (startingWindow == win) {
|
if (startingWindow == win) {
|
||||||
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
|
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
|
||||||
if (getController() != null) {
|
removeStartingWindow();
|
||||||
getController().removeStartingWindow();
|
|
||||||
}
|
|
||||||
} else if (mChildren.size() == 0) {
|
} else if (mChildren.size() == 0) {
|
||||||
// If this is the last window and we had requested a starting transition window,
|
// If this is the last window and we had requested a starting transition window,
|
||||||
// well there is no point now.
|
// well there is no point now.
|
||||||
@@ -845,9 +974,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
// we need to get rid of the starting transition.
|
// we need to get rid of the starting transition.
|
||||||
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
|
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
|
||||||
+ win);
|
+ win);
|
||||||
if (getController() != null) {
|
removeStartingWindow();
|
||||||
getController().removeStartingWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,6 +1148,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void removeChild(WindowState child) {
|
void removeChild(WindowState child) {
|
||||||
|
if (!mChildren.contains(child)) {
|
||||||
|
// This can be true when testing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.removeChild(child);
|
super.removeChild(child);
|
||||||
checkKeyguardFlagsChanged();
|
checkKeyguardFlagsChanged();
|
||||||
updateLetterboxSurface(child);
|
updateLetterboxSurface(child);
|
||||||
@@ -1042,6 +1173,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reparent(TaskWindowContainerController taskController, int position) {
|
||||||
|
if (DEBUG_ADD_REMOVE) {
|
||||||
|
Slog.i(TAG_WM, "reparent: moving app token=" + this
|
||||||
|
+ " to task=" + taskController + " at " + position);
|
||||||
|
}
|
||||||
|
final Task task = taskController.mContainer;
|
||||||
|
if (task == null) {
|
||||||
|
throw new IllegalArgumentException("reparent: could not find task="
|
||||||
|
+ taskController);
|
||||||
|
}
|
||||||
|
reparent(task, position);
|
||||||
|
getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
void reparent(Task task, int position) {
|
void reparent(Task task, int position) {
|
||||||
final Task currentTask = getTask();
|
final Task currentTask = getTask();
|
||||||
if (task == currentTask) {
|
if (task == currentTask) {
|
||||||
@@ -1300,9 +1445,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
startingData = fromToken.startingData;
|
startingData = fromToken.startingData;
|
||||||
fromToken.startingData = null;
|
fromToken.startingData = null;
|
||||||
fromToken.startingMoved = true;
|
fromToken.startingMoved = true;
|
||||||
if (getController() != null) {
|
scheduleAddStartingWindow();
|
||||||
getController().scheduleAddStartingWindow();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1471,6 +1614,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean keyDispatchingTimedOut(String reason, int windowPid) {
|
||||||
|
return mActivityRecord != null && mActivityRecord.keyDispatchingTimedOut(reason, windowPid);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updated this app token tracking states for interesting and drawn windows based on the window.
|
* Updated this app token tracking states for interesting and drawn windows based on the window.
|
||||||
*
|
*
|
||||||
@@ -1533,8 +1680,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (w.isDrawnLw()) {
|
} else if (w.isDrawnLw()) {
|
||||||
if (getController() != null) {
|
if (mActivityRecord != null) {
|
||||||
getController().reportStartingWindowDrawn();
|
mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis());
|
||||||
}
|
}
|
||||||
startingDisplayed = true;
|
startingDisplayed = true;
|
||||||
}
|
}
|
||||||
@@ -1601,6 +1748,266 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
return this;
|
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
|
@Override
|
||||||
boolean fillsParent() {
|
boolean fillsParent() {
|
||||||
return mFillsParent;
|
return mFillsParent;
|
||||||
@@ -2215,9 +2622,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
|||||||
if (mPendingRelaunchCount != 0) {
|
if (mPendingRelaunchCount != 0) {
|
||||||
pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
|
pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
|
||||||
}
|
}
|
||||||
if (getController() != null) {
|
|
||||||
pw.print(prefix); pw.print("controller="); pw.println(getController());
|
|
||||||
}
|
|
||||||
if (mRemovingFromDisplay) {
|
if (mRemovingFromDisplay) {
|
||||||
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
|
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,16 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
|||||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
|
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
|
||||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.view.InputApplicationHandle;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import android.view.InputApplicationHandle;
|
|
||||||
import com.android.server.input.InputManagerService;
|
import com.android.server.input.InputManagerService;
|
||||||
import android.view.InputWindowHandle;
|
|
||||||
import android.view.InputChannel;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
|
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
|
||||||
private final WindowManagerService mService;
|
private final WindowManagerService mService;
|
||||||
@@ -116,9 +111,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
|
|||||||
if (appWindowToken != null && appWindowToken.appToken != null) {
|
if (appWindowToken != null && appWindowToken.appToken != null) {
|
||||||
// Notify the activity manager about the timeout and let it decide whether
|
// Notify the activity manager about the timeout and let it decide whether
|
||||||
// to abort dispatching or keep waiting.
|
// to abort dispatching or keep waiting.
|
||||||
final AppWindowContainerController controller = appWindowToken.getController();
|
final boolean abort = appWindowToken.keyDispatchingTimedOut(reason,
|
||||||
final boolean abort = controller != null
|
|
||||||
&& controller.keyDispatchingTimedOut(reason,
|
|
||||||
(windowState != null) ? windowState.mSession.mPid : -1);
|
(windowState != null) ? windowState.mSession.mPid : -1);
|
||||||
if (!abort) {
|
if (!abort) {
|
||||||
// The activity manager declined to abort dispatching.
|
// The activity manager declined to abort dispatching.
|
||||||
|
|||||||
@@ -497,9 +497,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
|
|||||||
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
|
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
|
||||||
"RECOVER DESTROY", false);
|
"RECOVER DESTROY", false);
|
||||||
winAnimator.destroySurface();
|
winAnimator.destroySurface();
|
||||||
if (winAnimator.mWin.mAppToken != null
|
if (winAnimator.mWin.mAppToken != null) {
|
||||||
&& winAnimator.mWin.mAppToken.getController() != null) {
|
winAnimator.mWin.mAppToken.removeStartingWindow();
|
||||||
winAnimator.mWin.mAppToken.getController().removeStartingWindow();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1182,7 +1182,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont
|
|||||||
mActivities.add(newTop);
|
mActivities.add(newTop);
|
||||||
|
|
||||||
// Make sure window manager is aware of the position change.
|
// Make sure window manager is aware of the position change.
|
||||||
mWindowContainerController.positionChildAtTop(newTop.mWindowContainerController);
|
mWindowContainerController.positionChildAtTop(newTop.mAppWindowToken);
|
||||||
updateEffectiveIntent();
|
updateEffectiveIntent();
|
||||||
|
|
||||||
setFrontOfTask();
|
setFrontOfTask();
|
||||||
@@ -1264,12 +1264,10 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont
|
|||||||
mService.notifyTaskPersisterLocked(this, false);
|
mService.notifyTaskPersisterLocked(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync. with window manager
|
if (r.mAppWindowToken != null) {
|
||||||
final AppWindowContainerController appController = r.getWindowContainerController();
|
|
||||||
if (appController != null) {
|
|
||||||
// Only attempt to move in WM if the child has a controller. It is possible we haven't
|
// 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.
|
// 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
|
// Make sure the list of display UID whitelists is updated
|
||||||
|
|||||||
@@ -16,6 +16,14 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
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.TaskDescription;
|
||||||
import android.app.ActivityManager.TaskSnapshot;
|
import android.app.ActivityManager.TaskSnapshot;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@@ -24,18 +32,11 @@ import android.os.Looper;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.EventLog;
|
import android.util.EventLog;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
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
|
* Controller for the task container. This is created by activity manager to link task records to
|
||||||
* the task container they use in window manager.
|
* the task container they use in window manager.
|
||||||
@@ -103,16 +104,15 @@ public class TaskWindowContainerController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void positionChildAtTop(AppWindowContainerController childController) {
|
void positionChildAtTop(AppWindowToken aToken) {
|
||||||
positionChildAt(childController, POSITION_TOP);
|
positionChildAt(aToken, POSITION_TOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void positionChildAt(AppWindowContainerController childController, int position) {
|
void positionChildAt(AppWindowToken aToken, int position) {
|
||||||
synchronized (mService.mGlobalLock) {
|
synchronized (mService.mGlobalLock) {
|
||||||
final AppWindowToken aToken = childController.mContainer;
|
|
||||||
if (aToken == null) {
|
if (aToken == null) {
|
||||||
Slog.w(TAG_WM,
|
Slog.w(TAG_WM,
|
||||||
"Attempted to position of non-existing app : " + childController);
|
"Attempted to position of non-existing app");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import static org.mockito.Mockito.spy;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.IApplicationToken;
|
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -111,16 +110,9 @@ public class AppTransitionTests extends WindowTestsBase {
|
|||||||
final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2,
|
final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2,
|
||||||
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
|
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.allDrawn = true;
|
||||||
token1.startingDisplayed = true;
|
token1.startingDisplayed = true;
|
||||||
token1.startingMoved = true;
|
token1.startingMoved = true;
|
||||||
controller2.setContainer(token2);
|
|
||||||
|
|
||||||
// Simulate activity resume / finish flows to prepare app transition & set visibility,
|
// Simulate activity resume / finish flows to prepare app transition & set visibility,
|
||||||
// make sure transition is set as expected for each display.
|
// make sure transition is set as expected for each display.
|
||||||
@@ -132,8 +124,8 @@ public class AppTransitionTests extends WindowTestsBase {
|
|||||||
assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
|
assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
|
||||||
// One activity window is visible for resuming & the other activity window is invisible
|
// One activity window is visible for resuming & the other activity window is invisible
|
||||||
// for finishing in different display.
|
// for finishing in different display.
|
||||||
controller1.setVisibility(true, false);
|
token1.setVisibility(true, false);
|
||||||
controller2.setVisibility(false, false);
|
token2.setVisibility(false, false);
|
||||||
|
|
||||||
// Make sure each display is in animating stage.
|
// Make sure each display is in animating stage.
|
||||||
assertTrue(dc1.mOpeningApps.size() > 0);
|
assertTrue(dc1.mOpeningApps.size() > 0);
|
||||||
@@ -174,16 +166,4 @@ public class AppTransitionTests extends WindowTestsBase {
|
|||||||
assertFalse(dc1.mOpeningApps.contains(token1));
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,6 +18,7 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
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_BEHIND;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
||||||
@@ -31,8 +32,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
|||||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||||
import static android.view.WindowManager.TRANSIT_UNSET;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
@@ -66,6 +70,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
|
|||||||
Task mTask;
|
Task mTask;
|
||||||
WindowTestUtils.TestAppWindowToken mToken;
|
WindowTestUtils.TestAppWindowToken mToken;
|
||||||
|
|
||||||
|
private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mStack = createTaskStackOnDisplay(mDisplayContent);
|
mStack = createTaskStackOnDisplay(mDisplayContent);
|
||||||
@@ -251,7 +257,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
|
|||||||
"closingWindow");
|
"closingWindow");
|
||||||
closingWindow.mAnimatingExit = true;
|
closingWindow.mAnimatingExit = true;
|
||||||
closingWindow.mRemoveOnExit = true;
|
closingWindow.mRemoveOnExit = true;
|
||||||
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
|
closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
|
||||||
true /* performLayout */, false /* isVoiceInteraction */);
|
true /* performLayout */, false /* isVoiceInteraction */);
|
||||||
|
|
||||||
// We pretended that we were running an exit animation, but that should have been cleared up
|
// We pretended that we were running an exit animation, but that should have been cleared up
|
||||||
@@ -260,6 +266,124 @@ public class AppWindowTokenTests extends WindowTestsBase {
|
|||||||
assertTrue(closingWindow.mRemoved);
|
assertTrue(closingWindow.mRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetOrientation() {
|
||||||
|
// Assert orientation is unspecified to start.
|
||||||
|
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mToken.getOrientation());
|
||||||
|
|
||||||
|
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
|
||||||
|
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
|
||||||
|
|
||||||
|
mDisplayContent.removeAppToken(mToken.token);
|
||||||
|
// Assert orientation is unset to after container is removed.
|
||||||
|
assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
|
||||||
|
|
||||||
|
// Reset display frozen state
|
||||||
|
mWm.mDisplayFrozen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRemoveStartingWindow() {
|
||||||
|
mToken.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
|
||||||
|
false, false);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
assertHasStartingWindow(mToken);
|
||||||
|
mToken.removeStartingWindow();
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
assertNoStartingWindow(mToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddRemoveRace() {
|
||||||
|
// There was once a race condition between adding and removing starting windows
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
final WindowTestUtils.TestAppWindowToken appToken = createIsolatedTestAppWindowToken();
|
||||||
|
|
||||||
|
appToken.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
|
||||||
|
false, false);
|
||||||
|
appToken.removeStartingWindow();
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
assertNoStartingWindow(appToken);
|
||||||
|
|
||||||
|
appToken.getParent().getParent().removeImmediately();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransferStartingWindow() {
|
||||||
|
final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken();
|
||||||
|
final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken();
|
||||||
|
token1.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
|
||||||
|
false, false);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
token2.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, token1.appToken.asBinder(),
|
||||||
|
true, true, false, true, false, false);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
assertNoStartingWindow(token1);
|
||||||
|
assertHasStartingWindow(token2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransferStartingWindowWhileCreating() {
|
||||||
|
final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken();
|
||||||
|
final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken();
|
||||||
|
((TestWindowManagerPolicy) token1.mService.mPolicy).setRunnableWhenAddingSplashScreen(
|
||||||
|
() -> {
|
||||||
|
// Surprise, ...! Transfer window in the middle of the creation flow.
|
||||||
|
token2.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
|
||||||
|
token1.appToken.asBinder(), true, true, false,
|
||||||
|
true, false, false);
|
||||||
|
});
|
||||||
|
token1.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
|
||||||
|
false, false);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
assertNoStartingWindow(token1);
|
||||||
|
assertHasStartingWindow(token2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WindowTestUtils.TestAppWindowToken createIsolatedTestAppWindowToken() {
|
||||||
|
final TaskStack taskStack = createTaskStackOnDisplay(mDisplayContent);
|
||||||
|
final Task task = createTaskInStack(taskStack, 0 /* userId */);
|
||||||
|
return createTestAppWindowTokenForGivenTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WindowTestUtils.TestAppWindowToken createTestAppWindowTokenForGivenTask(Task task) {
|
||||||
|
final WindowTestUtils.TestAppWindowToken appToken =
|
||||||
|
WindowTestUtils.createTestAppWindowToken(mDisplayContent);
|
||||||
|
task.addChild(appToken, 0);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
return appToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTryTransferStartingWindowFromHiddenAboveToken() {
|
||||||
|
// Add two tasks on top of each other.
|
||||||
|
final WindowTestUtils.TestAppWindowToken tokenTop = createIsolatedTestAppWindowToken();
|
||||||
|
final WindowTestUtils.TestAppWindowToken tokenBottom =
|
||||||
|
createTestAppWindowTokenForGivenTask(tokenTop.getTask());
|
||||||
|
|
||||||
|
// Add a starting window.
|
||||||
|
tokenTop.addStartingWindow(mPackageName,
|
||||||
|
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
|
||||||
|
false, false);
|
||||||
|
waitUntilHandlersIdle();
|
||||||
|
|
||||||
|
// Make the top one invisible, and try transferring the starting window from the top to the
|
||||||
|
// bottom one.
|
||||||
|
tokenTop.setVisibility(false, false);
|
||||||
|
tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
|
||||||
|
|
||||||
|
// Assert that the bottom window now has the starting window.
|
||||||
|
assertNoStartingWindow(tokenTop);
|
||||||
|
assertHasStartingWindow(tokenBottom);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransitionAnimationPositionAndBounds() {
|
public void testTransitionAnimationPositionAndBounds() {
|
||||||
final Rect stackBounds = new Rect(
|
final Rect stackBounds = new Rect(
|
||||||
@@ -285,4 +409,19 @@ public class AppWindowTokenTests extends WindowTestsBase {
|
|||||||
assertEquals(expectedY, outPosition.y);
|
assertEquals(expectedY, outPosition.y);
|
||||||
assertEquals(expectedBounds, outBounds);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
|
|||||||
public void testGetClosingApps_closing() {
|
public void testGetClosingApps_closing() {
|
||||||
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
|
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
|
||||||
"closingWindow");
|
"closingWindow");
|
||||||
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
|
closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
|
||||||
true /* performLayout */, false /* isVoiceInteraction */);
|
true /* performLayout */, false /* isVoiceInteraction */);
|
||||||
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
||||||
closingApps.add(closingWindow.mAppToken);
|
closingApps.add(closingWindow.mAppToken);
|
||||||
@@ -64,9 +64,9 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
|
|||||||
"closingWindow");
|
"closingWindow");
|
||||||
final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
|
final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
|
||||||
FIRST_APPLICATION_WINDOW, "openingWindow");
|
FIRST_APPLICATION_WINDOW, "openingWindow");
|
||||||
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
|
closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
|
||||||
true /* performLayout */, false /* isVoiceInteraction */);
|
true /* performLayout */, false /* isVoiceInteraction */);
|
||||||
openingWindow.mAppToken.setVisibility(null, true /* visible */, TRANSIT_UNSET,
|
openingWindow.mAppToken.commitVisibility(null, true /* visible */, TRANSIT_UNSET,
|
||||||
true /* performLayout */, false /* isVoiceInteraction */);
|
true /* performLayout */, false /* isVoiceInteraction */);
|
||||||
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
||||||
closingApps.add(closingWindow.mAppToken);
|
closingApps.add(closingWindow.mAppToken);
|
||||||
@@ -79,7 +79,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
|
|||||||
public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
|
public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
|
||||||
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
|
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
|
||||||
"closingWindow");
|
"closingWindow");
|
||||||
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
|
closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
|
||||||
true /* performLayout */, false /* isVoiceInteraction */);
|
true /* performLayout */, false /* isVoiceInteraction */);
|
||||||
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
|
||||||
closingApps.add(closingWindow.mAppToken);
|
closingApps.add(closingWindow.mAppToken);
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
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 static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
@@ -37,6 +35,7 @@ import org.junit.Test;
|
|||||||
@Presubmit
|
@Presubmit
|
||||||
public class TaskWindowContainerControllerTests extends WindowTestsBase {
|
public class TaskWindowContainerControllerTests extends WindowTestsBase {
|
||||||
|
|
||||||
|
/* Comment out due to removal of AppWindowContainerController
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveContainer() {
|
public void testRemoveContainer() {
|
||||||
final WindowTestUtils.TestTaskWindowContainerController taskController =
|
final WindowTestUtils.TestTaskWindowContainerController taskController =
|
||||||
@@ -49,7 +48,9 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
|
|||||||
assertNull(taskController.mContainer);
|
assertNull(taskController.mContainer);
|
||||||
assertNull(appController.mContainer);
|
assertNull(appController.mContainer);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Comment out due to removal of AppWindowContainerController
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveContainer_deferRemoval() {
|
public void testRemoveContainer_deferRemoval() {
|
||||||
final WindowTestUtils.TestTaskWindowContainerController taskController =
|
final WindowTestUtils.TestTaskWindowContainerController taskController =
|
||||||
@@ -74,6 +75,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
|
|||||||
assertNull(appController.mContainer);
|
assertNull(appController.mContainer);
|
||||||
assertNull(app.getController());
|
assertNull(app.getController());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReparent() {
|
public void testReparent() {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static android.app.AppOpsManager.OP_NONE;
|
import static android.app.AppOpsManager.OP_NONE;
|
||||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
|
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;
|
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||||
|
|
||||||
@@ -116,12 +115,11 @@ public class WindowTestUtils {
|
|||||||
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
|
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
|
||||||
long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
|
long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
|
||||||
int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
|
int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
|
||||||
boolean launchTaskBehind, boolean alwaysFocusable,
|
boolean launchTaskBehind, boolean alwaysFocusable, ActivityRecord activityRecord) {
|
||||||
AppWindowContainerController controller) {
|
|
||||||
super(service, token, activityComponent, voiceInteraction, dc,
|
super(service, token, activityComponent, voiceInteraction, dc,
|
||||||
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
|
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
|
||||||
orientation, rotationAnimationHint, configChanges, launchTaskBehind,
|
orientation, rotationAnimationHint, configChanges, launchTaskBehind,
|
||||||
alwaysFocusable, controller);
|
alwaysFocusable, activityRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getWindowsCount() {
|
int getWindowsCount() {
|
||||||
@@ -275,45 +273,6 @@ public class WindowTestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestAppWindowContainerController extends AppWindowContainerController {
|
|
||||||
|
|
||||||
final IApplicationToken mToken;
|
|
||||||
|
|
||||||
TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
|
|
||||||
this(taskController, new TestIApplicationToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
TestAppWindowContainerController(TestTaskWindowContainerController taskController,
|
|
||||||
IApplicationToken token) {
|
|
||||||
super(taskController, token, new ComponentName("", "") /* activityComponent */,
|
|
||||||
null /* listener */, 0 /* index */, SCREEN_ORIENTATION_UNSPECIFIED,
|
|
||||||
true /* fullscreen */, true /* showForAllUsers */, 0 /* configChanges */,
|
|
||||||
false /* voiceInteraction */, false /* launchTaskBehind */,
|
|
||||||
false /* alwaysFocusable */, 0 /* targetSdkVersion */,
|
|
||||||
0 /* rotationAnimationHint */, 0 /* inputDispatchingTimeoutNanos */,
|
|
||||||
taskController.mService);
|
|
||||||
mToken = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
|
|
||||||
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
|
|
||||||
long inputDispatchingTimeoutNanos,
|
|
||||||
boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
|
|
||||||
int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
|
|
||||||
boolean alwaysFocusable, AppWindowContainerController controller) {
|
|
||||||
return new TestAppWindowToken(service, token, activityComponent, voiceInteraction, dc,
|
|
||||||
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
|
|
||||||
orientation,
|
|
||||||
rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
|
|
||||||
controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppWindowToken getAppWindowToken(DisplayContent dc) {
|
|
||||||
return (AppWindowToken) dc.getWindowToken(mToken.asBinder());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestIApplicationToken implements IApplicationToken {
|
public static class TestIApplicationToken implements IApplicationToken {
|
||||||
|
|
||||||
private final Binder mBinder = new Binder();
|
private final Binder mBinder = new Binder();
|
||||||
|
|||||||
@@ -29,10 +29,9 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
|
|||||||
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
|
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
|
||||||
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class ActivityTestsBase {
|
|||||||
aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
|
aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
|
||||||
0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
|
0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
|
||||||
mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
|
mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
|
||||||
activity.mWindowContainerController = mock(AppWindowContainerController.class);
|
activity.mAppWindowToken = mock(AppWindowToken.class);
|
||||||
|
|
||||||
if (mTaskRecord != null) {
|
if (mTaskRecord != null) {
|
||||||
mTaskRecord.addActivityToTop(activity);
|
mTaskRecord.addActivityToTop(activity);
|
||||||
@@ -243,6 +243,7 @@ class ActivityTestsBase {
|
|||||||
mock(WindowProcessListener.class));
|
mock(WindowProcessListener.class));
|
||||||
wpc.setThread(mock(IApplicationThread.class));
|
wpc.setThread(mock(IApplicationThread.class));
|
||||||
activity.setProcess(wpc);
|
activity.setProcess(wpc);
|
||||||
|
activity.service.mWindowManager.mRoot = mock(RootWindowContainer.class);
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user