diff options
22 files changed, 1157 insertions, 1095 deletions
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl index 633b40fb7967..b01c0ef55812 100644 --- a/core/java/android/view/IApplicationToken.aidl +++ b/core/java/android/view/IApplicationToken.aidl @@ -20,10 +20,5 @@ package android.view; /** {@hide} */ interface IApplicationToken { - void windowsDrawn(); - void windowsVisible(); - void windowsGone(); - boolean keyDispatchingTimedOut(String reason); - long getKeyDispatchingTimeout(); } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 21875fe168bc..8611d69ba94d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -83,41 +83,9 @@ interface IWindowManager void setOverscan(int displayId, int left, int top, int right, int bottom); // These can only be called when holding the MANAGE_APP_TOKENS permission. - void pauseKeyDispatching(IBinder token); - void resumeKeyDispatching(IBinder token); void setEventDispatching(boolean enabled); void addWindowToken(IBinder token, int type, int displayId); void removeWindowToken(IBinder token, int displayId); - /** - * Creates the object representation for the application token in the window manager and adds it - * to the specified task Id. - * - * @param addPos The position to add the token to in the task. - * @param token The token to add. - * @param taskId The Id of the task we are adding the token to. - * @param requestedOrientation Orientation to use. - * @param fullscreen True if the application token is fullscreen. - * @param showWhenLocked True if the application token should be shown when locked. - * @param configChanges Input configuration changes. - * @param voiceInteraction True if the token is in voice interaction mode. - * @param launchTaskBehind True if the token is been launched from behind. - * @param alwaysFocusable True if the app windows are always focusable regardless of the stack - * they are in. - * @param targetSdkVersion The application's target SDK version - */ - void addAppToken(int addPos, IApplicationToken token, int taskId, int requestedOrientation, - boolean fullscreen, boolean showWhenLocked, int configChanges, boolean voiceInteraction, - boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion, - int rotationAnimationHint); - /** - * Adds an already existing application token on the window manager side to the input task id. - * - * @param token The token we are adding to the input task Id. - * @param taskId The Id of the task we are adding the token to. - */ - void addAppToTask(IBinder token, int taskId); - void setAppOrientation(IApplicationToken token, int requestedOrientation); - int getAppOrientation(IApplicationToken token); void setFocusedApp(IBinder token, boolean moveFocusNow); void prepareAppTransition(int transit, boolean alwaysKeepCurrent); int getPendingAppTransition(); @@ -154,20 +122,6 @@ interface IWindowManager boolean scaleUp); void executeAppTransition(); - /** - * Called to set the starting window for the input token and returns true if the starting - * window was set for the token. - */ - boolean setAppStartingWindow(IBinder token, String pkg, int theme, - in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, - int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded); - void setAppVisibility(IBinder token, boolean visible); - void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface); - void notifyAppStopped(IBinder token); - void startAppFreezingScreen(IBinder token, int configChanges); - void stopAppFreezingScreen(IBinder token, boolean force); - void removeAppToken(IBinder token, int displayId); - /** Used by system ui to report that recents has shown itself. */ void endProlongedAnimations(); @@ -315,15 +269,6 @@ interface IWindowManager boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver); /** - * Create a screenshot of the applications currently displayed. - * - * @param frameScale the scale to apply to the frame, only used when width = -1 and - * height = -1 - */ - Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight, - float frameScale); - - /** * Called by the status bar to notify Views of changes to System UI visiblity. */ oneway void statusBarVisibilityChanged(int visibility); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 66258461fe3a..9643976b5efa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4737,7 +4737,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - return mWindowManager.getAppOrientation(r.appToken); + return r.getRequestedOrientation(); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index ef197002f0a7..0e4ab96cccb4 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -21,17 +21,26 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; +import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; +import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; +import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; +import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; 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_AND_PIPABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.os.Build.VERSION_CODES.HONEYCOMB; +import static android.os.Process.SYSTEM_UID; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE; @@ -92,6 +101,8 @@ import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.am.ActivityStackSupervisor.ActivityContainer; +import com.android.server.wm.AppWindowContainerController; +import com.android.server.wm.AppWindowContainerListener; import java.io.File; import java.io.IOException; @@ -110,7 +121,7 @@ import org.xmlpull.v1.XmlSerializer; /** * An entry in the history stack, representing an activity. */ -final class ActivityRecord { +final class ActivityRecord implements AppWindowContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE; @@ -135,6 +146,7 @@ final class ActivityRecord { final ActivityManagerService service; // owner final IApplicationToken.Stub appToken; // window manager token + AppWindowContainerController mWindowContainerController; final ActivityInfo info; // all about me final ApplicationInfo appInfo; // information about activity's app final int launchedFromUid; // always the uid who started the activity. @@ -150,7 +162,7 @@ final class ActivityRecord { final boolean stateNotNeeded; // As per ActivityInfo.flags boolean fullscreen; // covers the full screen? final boolean noDisplay; // activity is not displayed? - final boolean componentSpecified; // did caller specify an explicit component? + private final boolean componentSpecified; // did caller specify an explicit component? final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? static final int APPLICATION_ACTIVITY_TYPE = 0; @@ -158,18 +170,18 @@ final class ActivityRecord { static final int RECENTS_ACTIVITY_TYPE = 2; int mActivityType; - CharSequence nonLocalizedLabel; // the label information from the package mgr. - int labelRes; // the label information from the package mgr. - int icon; // resource identifier of activity's icon. - int logo; // resource identifier of activity's logo. - int theme; // resource identifier of activity's theme. - int realTheme; // actual theme resource we will use, never 0. - int windowFlags; // custom window flags for preview window. + private CharSequence nonLocalizedLabel; // the label information from the package mgr. + private int labelRes; // the label information from the package mgr. + private int icon; // resource identifier of activity's icon. + private int logo; // resource identifier of activity's logo. + private int theme; // resource identifier of activity's theme. + private int realTheme; // actual theme resource we will use, never 0. + private int windowFlags; // custom window flags for preview window. TaskRecord task; // the task this is in. - long createTime = System.currentTimeMillis(); + private long createTime = System.currentTimeMillis(); long displayStartTime; // when we started launching this activity long fullyDrawnStartTime; // when we started launching this activity - long startTime; // last time this activity was started + private long startTime; // last time this activity was started long lastVisibleTime; // last time this activity became visible long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity long pauseTime; // last time we started pausing the activity @@ -542,70 +554,9 @@ final class ActivityRecord { static class Token extends IApplicationToken.Stub { private final WeakReference<ActivityRecord> weakActivity; - private final ActivityManagerService mService; - Token(ActivityRecord activity, ActivityManagerService service) { + Token(ActivityRecord activity) { weakActivity = new WeakReference<>(activity); - mService = service; - } - - @Override - public void windowsDrawn() { - synchronized (mService) { - ActivityRecord r = tokenToActivityRecordLocked(this); - if (r != null) { - r.windowsDrawnLocked(); - } - } - } - - @Override - public void windowsVisible() { - synchronized (mService) { - ActivityRecord r = tokenToActivityRecordLocked(this); - if (r != null) { - r.windowsVisibleLocked(); - } - } - } - - @Override - public void windowsGone() { - synchronized (mService) { - ActivityRecord r = tokenToActivityRecordLocked(this); - if (r != null) { - if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r); - r.nowVisible = false; - } - } - } - - @Override - public boolean keyDispatchingTimedOut(String reason) { - ActivityRecord r; - ActivityRecord anrActivity; - ProcessRecord anrApp; - synchronized (mService) { - r = tokenToActivityRecordLocked(this); - if (r == null) { - return false; - } - anrActivity = r.getWaitingHistoryRecordLocked(); - anrApp = r.app; - } - return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason); - } - - @Override - public long getKeyDispatchingTimeout() { - synchronized (mService) { - ActivityRecord r = tokenToActivityRecordLocked(this); - if (r == null) { - return 0; - } - r = r.getWaitingHistoryRecordLocked(); - return ActivityManagerService.getInputDispatchingTimeoutLocked(r); - } } private static ActivityRecord tokenToActivityRecordLocked(Token token) { @@ -652,7 +603,7 @@ final class ActivityRecord { ActivityStackSupervisor supervisor, ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) { service = _service; - appToken = new Token(this, service); + appToken = new Token(this); info = aInfo; launchedFromUid = _launchedFromUid; launchedFromPackage = _launchedFromPackage; @@ -700,97 +651,110 @@ final class ActivityRecord { } } - // This starts out true, since the initial state of an activity - // is that we have everything, and we shouldn't never consider it - // lacking in state to be removed if it dies. + // This starts out true, since the initial state of an activity is that we have everything, + // and we shouldn't never consider it lacking in state to be removed if it dies. haveState = true; - if (aInfo != null) { - // If the class name in the intent doesn't match that of the target, this is - // probably an alias. We have to create a new ComponentName object to keep track - // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly. - if (aInfo.targetActivity == null - || (aInfo.targetActivity.equals(_intent.getComponent().getClassName()) - && (aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE - || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP))) { - realActivity = _intent.getComponent(); - } else { - realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity); - } - taskAffinity = aInfo.taskAffinity; - stateNotNeeded = (aInfo.flags& - ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0; - appInfo = aInfo.applicationInfo; - nonLocalizedLabel = aInfo.nonLocalizedLabel; - labelRes = aInfo.labelRes; - if (nonLocalizedLabel == null && labelRes == 0) { - ApplicationInfo app = aInfo.applicationInfo; - nonLocalizedLabel = app.nonLocalizedLabel; - labelRes = app.labelRes; - } - icon = aInfo.getIconResource(); - logo = aInfo.getLogoResource(); - theme = aInfo.getThemeResource(); - realTheme = theme; - if (realTheme == 0) { - realTheme = aInfo.applicationInfo.targetSdkVersion - < Build.VERSION_CODES.HONEYCOMB - ? android.R.style.Theme - : android.R.style.Theme_Holo; - } - if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { - windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED; - } - if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0 - && _caller != null - && (aInfo.applicationInfo.uid == Process.SYSTEM_UID - || aInfo.applicationInfo.uid == _caller.info.uid)) { - processName = _caller.processName; - } else { - processName = aInfo.processName; - } + // If the class name in the intent doesn't match that of the target, this is + // probably an alias. We have to create a new ComponentName object to keep track + // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly. + if (aInfo.targetActivity == null + || (aInfo.targetActivity.equals(_intent.getComponent().getClassName()) + && (aInfo.launchMode == LAUNCH_MULTIPLE + || aInfo.launchMode == LAUNCH_SINGLE_TOP))) { + realActivity = _intent.getComponent(); + } else { + realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity); + } + taskAffinity = aInfo.taskAffinity; + stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; + appInfo = aInfo.applicationInfo; + nonLocalizedLabel = aInfo.nonLocalizedLabel; + labelRes = aInfo.labelRes; + if (nonLocalizedLabel == null && labelRes == 0) { + ApplicationInfo app = aInfo.applicationInfo; + nonLocalizedLabel = app.nonLocalizedLabel; + labelRes = app.labelRes; + } + icon = aInfo.getIconResource(); + logo = aInfo.getLogoResource(); + theme = aInfo.getThemeResource(); + realTheme = theme; + if (realTheme == 0) { + realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB + ? android.R.style.Theme : android.R.style.Theme_Holo; + } + if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { + windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED; + } + if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null + && (aInfo.applicationInfo.uid == SYSTEM_UID + || aInfo.applicationInfo.uid == _caller.info.uid)) { + processName = _caller.processName; + } else { + processName = aInfo.processName; + } - if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) { - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } + if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) { + intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } + + packageName = aInfo.applicationInfo.packageName; + launchMode = aInfo.launchMode; + + AttributeCache.Entry ent = AttributeCache.instance().get(packageName, + realTheme, com.android.internal.R.styleable.Window, userId); + final boolean translucent = ent != null && (ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsTranslucent, false) + || (!ent.array.hasValue( + com.android.internal.R.styleable.Window_windowIsTranslucent) + && ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowSwipeToDismiss, + false))); + fullscreen = ent != null && !ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent; + noDisplay = ent != null && ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowNoDisplay, false); + + setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord); + + immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0; + + requestedVrComponent = (aInfo.requestedVrComponent == null) ? + null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); + } + + void createWindowContainer() { + if (mWindowContainerController != null) { + throw new IllegalArgumentException("Window container=" + mWindowContainerController + + " already created for r=" + this); - packageName = aInfo.applicationInfo.packageName; - launchMode = aInfo.launchMode; - - AttributeCache.Entry ent = AttributeCache.instance().get(packageName, - realTheme, com.android.internal.R.styleable.Window, userId); - final boolean translucent = ent != null && (ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsTranslucent, false) - || (!ent.array.hasValue( - com.android.internal.R.styleable.Window_windowIsTranslucent) - && ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowSwipeToDismiss, - false))); - fullscreen = ent != null && !ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsFloating, false) - && !translucent; - noDisplay = ent != null && ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowNoDisplay, false); - - setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord); - - immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0; - - requestedVrComponent = (aInfo.requestedVrComponent == null) ? - null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); - } else { - realActivity = null; - taskAffinity = null; - stateNotNeeded = false; - appInfo = null; - processName = null; - packageName = null; - fullscreen = true; - noDisplay = false; - mActivityType = APPLICATION_ACTIVITY_TYPE; - immersive = false; - requestedVrComponent = null; } + + inHistory = true; + + task.updateOverrideConfigurationFromLaunchBounds(); + + mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId, + Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen, + (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges, + task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(), + appInfo.targetSdkVersion, mRotationAnimationHint, + ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L); + + task.addActivityToTop(this); + + onOverrideConfigurationSent(); + } + + void removeWindowContainer() { + mWindowContainerController.removeContainer(getDisplayId()); + } + + // TODO: Remove once task record is converted to use controller in which case we can use + // positionChildAt() + void positionWindowContainerAt(int index) { + mWindowContainerController.positionAt(task.taskId, index); } private boolean isHomeIntent(Intent intent) { @@ -890,12 +854,6 @@ final class ActivityRecord { return true; } - void putInHistory() { - if (!inHistory) { - inHistory = true; - } - } - void takeFromHistory() { if (inHistory) { inHistory = false; @@ -931,7 +889,7 @@ final class ActivityRecord { return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) && (intent == null || - (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); + (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); } boolean isFocusable() { @@ -1222,14 +1180,14 @@ final class ActivityRecord { void pauseKeyDispatchingLocked() { if (!keysPaused) { keysPaused = true; - service.mWindowManager.pauseKeyDispatching(appToken); + mWindowContainerController.pauseKeyDispatching(); } } void resumeKeyDispatchingLocked() { if (keysPaused) { keysPaused = false; - service.mWindowManager.resumeKeyDispatching(appToken); + mWindowContainerController.resumeKeyDispatching(); } } @@ -1277,7 +1235,7 @@ final class ActivityRecord { return null; } - final float scale; + float scale = 0; if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot"); // When this flag is set, we currently take the fullscreen screenshot of the activity but @@ -1288,17 +1246,21 @@ final class ActivityRecord { scale = service.mFullscreenThumbnailScale; } - return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h, - scale); + return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale); } + void setVisibility(boolean visible) { + mWindowContainerController.setVisibility(visible); + } + + // TODO: Look into merging with #setVisibility() void setVisible(boolean newVisible) { visible = newVisible; if (!visible && mUpdateTaskThumbnailWhenHidden) { updateThumbnailLocked(screenshotActivityLocked(), null /* description */); mUpdateTaskThumbnailWhenHidden = false; } - service.mWindowManager.setAppVisibility(appToken, visible); + mWindowContainerController.setVisibility(visible); final ArrayList<ActivityContainer> containers = mChildContainers; for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) { final ActivityContainer container = containers.get(containerNdx); @@ -1307,6 +1269,14 @@ final class ActivityRecord { mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; } + void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) { + mWindowContainerController.notifyAppResumed(wasStopped, allowSavedSurface); + } + + void notifyUnknownVisibilityLaunched() { + mWindowContainerController.notifyUnknownVisibilityLaunched(); + } + /** * @return true if the input activity should be made visible, ignoring any effect Keyguard * might have on the visibility @@ -1458,6 +1428,7 @@ final class ActivityRecord { service.notifyTaskPersisterLocked(task, false); } if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle); + if (newIcicle != null) { // If icicle is null, this is happening due to a timeout, so we haven't really saved // the state. @@ -1472,7 +1443,7 @@ final class ActivityRecord { stopped = true; state = ActivityState.STOPPED; - service.mWindowManager.notifyAppStopped(appToken); + mWindowContainerController.notifyAppStopped(); if (stack.getVisibleBehindActivity() == this) { mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */); @@ -1536,14 +1507,14 @@ final class ActivityRecord { public void startFreezingScreenLocked(ProcessRecord app, int configChanges) { if (mayFreezeScreenLocked(app)) { - service.mWindowManager.startAppFreezingScreen(appToken, configChanges); + mWindowContainerController.startFreezingScreen(configChanges); } } public void stopFreezingScreenLocked(boolean force) { if (force || frozenBeforeDestroy) { frozenBeforeDestroy = false; - service.mWindowManager.stopAppFreezingScreen(appToken, force); + mWindowContainerController.stopFreezingScreen(force); } } @@ -1617,48 +1588,73 @@ final class ActivityRecord { stack.mLaunchStartTime = 0; } - void windowsDrawnLocked() { - mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(); - if (displayStartTime != 0) { - reportLaunchTimeLocked(SystemClock.uptimeMillis()); - } - mStackSupervisor.sendWaitingVisibleReportLocked(this); - startTime = 0; - finishLaunchTickingLocked(); - if (task != null) { - task.hasBeenVisible = true; - } - } - - void windowsVisibleLocked() { - mStackSupervisor.reportActivityVisibleLocked(this); - if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this); - if (!nowVisible) { - nowVisible = true; - lastVisibleTime = SystemClock.uptimeMillis(); - if (!idle) { - // Instead of doing the full stop routine here, let's just hide any activities - // we now can, and let them stop when the normal idle happens. - mStackSupervisor.processStoppingActivitiesLocked(false); - } else { - // If this activity was already idle, then we now need to make sure we perform - // the full stop of any activities that are waiting to do so. This is because - // we won't do that while they are still waiting for this one to become visible. - final int size = mStackSupervisor.mWaitingVisibleActivities.size(); - if (size > 0) { - for (int i = 0; i < size; i++) { - ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i); - if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r); + @Override + public void onWindowsDrawn() { + synchronized (service) { + mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(); + if (displayStartTime != 0) { + reportLaunchTimeLocked(SystemClock.uptimeMillis()); + } + mStackSupervisor.sendWaitingVisibleReportLocked(this); + startTime = 0; + finishLaunchTickingLocked(); + if (task != null) { + task.hasBeenVisible = true; + } + } + } + + @Override + public void onWindowsVisible() { + synchronized (service) { + mStackSupervisor.reportActivityVisibleLocked(this); + if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this); + if (!nowVisible) { + nowVisible = true; + lastVisibleTime = SystemClock.uptimeMillis(); + if (!idle) { + // Instead of doing the full stop routine here, let's just hide any activities + // we now can, and let them stop when the normal idle happens. + mStackSupervisor.processStoppingActivitiesLocked(false); + } else { + // If this activity was already idle, then we now need to make sure we perform + // the full stop of any activities that are waiting to do so. This is because + // we won't do that while they are still waiting for this one to become visible. + final int size = mStackSupervisor.mWaitingVisibleActivities.size(); + if (size > 0) { + for (int i = 0; i < size; i++) { + ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i); + if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r); + } + mStackSupervisor.mWaitingVisibleActivities.clear(); + mStackSupervisor.scheduleIdleLocked(); } - mStackSupervisor.mWaitingVisibleActivities.clear(); - mStackSupervisor.scheduleIdleLocked(); } + service.scheduleAppGcsLocked(); } - service.scheduleAppGcsLocked(); } } - ActivityRecord getWaitingHistoryRecordLocked() { + @Override + public void onWindowsGone() { + synchronized (service) { + if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this); + nowVisible = false; + } + } + + @Override + public boolean keyDispatchingTimedOut(String reason) { + ActivityRecord anrActivity; + ProcessRecord anrApp; + synchronized (service) { + anrActivity = getWaitingHistoryRecordLocked(); + anrApp = app; + } + return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason); + } + + private ActivityRecord getWaitingHistoryRecordLocked() { // First find the real culprit... if this activity is waiting for // another activity to start or has stopped, then the key dispatching // timeout should not be caused by this. @@ -1800,25 +1796,40 @@ final class ActivityRecord { void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) { final CompatibilityInfo compatInfo = service.compatibilityInfoForPackageLocked(info.applicationInfo); - final boolean shown = service.mWindowManager.setAppStartingWindow( - appToken, packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon, - logo, windowFlags, prev != null ? prev.appToken : null, createIfNeeded); + final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme, + compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, + prev != null ? prev.appToken : null, createIfNeeded); if (shown) { mStartingWindowState = STARTING_WINDOW_SHOWN; } } + void removeOrphanedStartingWindow(boolean behindFullscreenActivity) { + if (state == ActivityState.INITIALIZING + && mStartingWindowState == STARTING_WINDOW_SHOWN + && behindFullscreenActivity) { + if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); + mStartingWindowState = STARTING_WINDOW_REMOVED; + mWindowContainerController.removeStartingWindow(); + } + } + + int getRequestedOrientation() { + return mWindowContainerController.getOrientation(); + } + void setRequestedOrientation(int requestedOrientation) { if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) { // Fixed screen orientation isn't supported when activities aren't in full screen mode. return; } - service.mWindowManager.setAppOrientation(appToken, requestedOrientation); final int displayId = getDisplayId(); - final Configuration config = service.mWindowManager.updateOrientationFromAppTokens( - mStackSupervisor.getDisplayOverrideConfiguration(displayId), - mayFreezeScreenLocked(app) ? appToken : null, displayId); + final Configuration displayConfig = + mStackSupervisor.getDisplayOverrideConfiguration(displayId); + + final Configuration config = mWindowContainerController.setOrientation(requestedOrientation, + displayId, displayConfig, mayFreezeScreenLocked(app)); if (config != null) { frozenBeforeDestroy = true; if (!service.updateDisplayOverrideConfigurationLocked(config, this, diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index beeadac5d50a..ddef339caa5d 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -61,8 +61,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; -import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED; -import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -2046,15 +2044,7 @@ final class ActivityStack extends ConfigurationContainer { continue; } - if (r.state == ActivityState.INITIALIZING - && r.mStartingWindowState == STARTING_WINDOW_SHOWN - && behindFullscreenActivity) { - if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, - "Found orphaned starting window " + r); - r.mStartingWindowState = STARTING_WINDOW_REMOVED; - mWindowManager.removeAppStartingWindow(r.appToken); - } - + r.removeOrphanedStartingWindow(behindFullscreenActivity); behindFullscreenActivity |= r.fullscreen; } } @@ -2287,7 +2277,7 @@ final class ActivityStack extends ConfigurationContainer { // previous should actually be hidden depending on whether the // new one is found to be full-screen or not. if (prev.finishing) { - mWindowManager.setAppVisibility(prev.appToken, false); + prev.setVisibility(false); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev + ", waitingVisible=" + mStackSupervisor.mWaitingVisibleActivities.contains(prev) @@ -2329,7 +2319,7 @@ final class ActivityStack extends ConfigurationContainer { ? TRANSIT_ACTIVITY_CLOSE : TRANSIT_TASK_CLOSE, false); } - mWindowManager.setAppVisibility(prev.appToken, false); + prev.setVisibility(false); } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev); @@ -2384,7 +2374,7 @@ final class ActivityStack extends ConfigurationContainer { // This activity is now becoming visible. if (!next.visible || next.stopped || lastActivityTranslucent) { - mWindowManager.setAppVisibility(next.appToken, true); + next.setVisibility(true); } // schedule launch ticks to collect information about slow apps. @@ -2433,7 +2423,7 @@ final class ActivityStack extends ConfigurationContainer { mStackSupervisor.scheduleResumeTopActivities(); } if (!next.visible || next.stopped) { - mWindowManager.setAppVisibility(next.appToken, true); + next.setVisibility(true); } next.completeResumeLocked(); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); @@ -2471,7 +2461,7 @@ final class ActivityStack extends ConfigurationContainer { // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. - mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface); + next.notifyAppResumed(next.stopped, allowSavedSurface); EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, System.identityHashCode(next), next.task.taskId, next.shortComponentName); @@ -2669,9 +2659,7 @@ final class ActivityStack extends ConfigurationContainer { if (!startIt) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); - task.addActivityToTop(r); - r.putInHistory(); - addConfigOverride(r, task); + r.createWindowContainer(); ActivityOptions.abort(options); return; } @@ -2682,12 +2670,10 @@ final class ActivityStack extends ConfigurationContainer { } } - // Place a new activity at top of stack, so it is next to interact - // with the user. + // Place a new activity at top of stack, so it is next to interact with the user. - // If we are not placing the new activity frontmost, we do not want - // to deliver the onUserLeaving callback to the actual frontmost - // activity + // If we are not placing the new activity frontmost, we do not want to deliver the + // onUserLeaving callback to the actual frontmost activity if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) { mStackSupervisor.mUserLeaving = false; if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, @@ -2699,10 +2685,9 @@ final class ActivityStack extends ConfigurationContainer { // Slot the activity into the history stack and proceed if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, new RuntimeException("here").fillInStackTrace()); - task.addActivityToTop(r); + r.createWindowContainer(); task.setFrontOfTask(); - r.putInHistory(); if (!isHomeOrRecentsStack() || numActivities() > 0) { // We want to show the starting preview window if we are // switching to a new task, or the next activity's process is @@ -2737,7 +2722,6 @@ final class ActivityStack extends ConfigurationContainer { mWindowManager.prepareAppTransition(transit, keepCurTransition); mNoAnimActivities.remove(r); } - addConfigOverride(r, task); boolean doShow = true; if (newTask) { // Even though this activity is starting fresh, we still need @@ -2756,7 +2740,7 @@ final class ActivityStack extends ConfigurationContainer { if (r.mLaunchTaskBehind) { // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we // tell WindowManager that r is visible even though it is at the back of the stack. - mWindowManager.setAppVisibility(r.appToken, true); + r.setVisibility(true); ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } else if (SHOW_APP_STARTING_PREVIEW && doShow) { // Figure out if we are transitioning from another activity that is @@ -2780,7 +2764,6 @@ final class ActivityStack extends ConfigurationContainer { } else { // If this is the first activity, don't do any fancy animations, // because there is nothing for it to animate on top of. - addConfigOverride(r, task); ActivityOptions.abort(options); } } @@ -2865,8 +2848,6 @@ final class ActivityStack extends ConfigurationContainer { + " out to new task " + target.task); } - setAppTask(target, targetTask); - boolean noOptions = canMoveOptions; final int start = replyChainEnd < 0 ? i : replyChainEnd; for (int srcPos = start; srcPos >= i; --srcPos) { @@ -2889,8 +2870,6 @@ final class ActivityStack extends ConfigurationContainer { "Pushing next activity " + p + " out to target's task " + target.task); p.setTask(targetTask, null); targetTask.addActivityAtBottom(p); - - setAppTask(p, targetTask); } mWindowManager.moveTaskToBottom(targetTask.taskId); @@ -3028,7 +3007,6 @@ final class ActivityStack extends ConfigurationContainer { + " callers=" + Debug.getCallers(3)); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p + " from " + srcPos + " in to resetting task " + task); - setAppTask(p, task); } mWindowManager.moveTaskToTop(taskId); @@ -3223,7 +3201,7 @@ final class ActivityStack extends ConfigurationContainer { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Stopping visible=" + r.visible + " for " + r); if (!r.visible) { - mWindowManager.setAppVisibility(r.appToken, false); + r.setVisibility(false); } EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); @@ -3457,7 +3435,7 @@ final class ActivityStack extends ConfigurationContainer { mWindowManager.prepareAppTransition(transit, false); // Tell window manager to prepare for this one to be removed. - mWindowManager.setAppVisibility(r.appToken, false); + r.setVisibility(false); if (mPausingActivity == null) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r); @@ -3475,7 +3453,7 @@ final class ActivityStack extends ConfigurationContainer { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r); if (r.visible) { mWindowManager.prepareAppTransition(transit, false); - mWindowManager.setAppVisibility(r.appToken, false); + r.setVisibility(false); mWindowManager.executeAppTransition(); if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) { mStackSupervisor.mWaitingVisibleActivities.add(r); @@ -3782,7 +3760,7 @@ final class ActivityStack extends ConfigurationContainer { r.state = ActivityState.DESTROYED; if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r); r.app = null; - mWindowManager.removeAppToken(r.appToken, r.getDisplayId()); + r.removeWindowContainer(); final TaskRecord task = r.task; if (task != null && task.removeActivity(r)) { if (DEBUG_STACK) Slog.i(TAG_STACK, @@ -4981,17 +4959,6 @@ final class ActivityStack extends ConfigurationContainer { } } - void addConfigOverride(ActivityRecord r, TaskRecord task) { - task.updateOverrideConfigurationFromLaunchBounds(); - // TODO: VI deal with activity - mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, - r.task.taskId, r.info.screenOrientation, r.fullscreen, - (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.info.configChanges, - task.voiceSession != null, r.mLaunchTaskBehind, r.isAlwaysFocusable(), - r.appInfo.targetSdkVersion, r.mRotationAnimationHint); - r.onOverrideConfigurationSent(); - } - void moveToFrontAndResumeStateIfNeeded( ActivityRecord r, boolean moveToFront, boolean setResume, String reason) { if (!moveToFront) { @@ -5030,7 +4997,6 @@ final class ActivityStack extends ConfigurationContainer { r.info, r.intent, null, null, true, r.mActivityType); r.setTask(task, null); task.addActivityToTop(r); - setAppTask(r, task); mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack); moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack"); if (wasResumed) { @@ -5038,12 +5004,6 @@ final class ActivityStack extends ConfigurationContainer { } } - private void setAppTask(ActivityRecord r, TaskRecord task) { - task.updateOverrideConfigurationFromLaunchBounds(); - mWindowManager.addAppToTask(r.appToken, task.taskId); - r.onOverrideConfigurationSent(); - } - public int getStackId() { return mStackId; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 028c57117824..8ab3ac39dd5b 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -33,7 +33,6 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -179,8 +178,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; -public class ActivityStackSupervisor extends ConfigurationContainer - implements DisplayListener { +public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM; private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS; private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; @@ -1204,7 +1202,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer if (andResume) { r.startFreezingScreenLocked(app, 0); - mWindowManager.setAppVisibility(r.appToken, true); + r.setVisibility(true); // schedule launch ticks to collect information about slow apps. r.startLaunchTickingLocked(); @@ -1227,7 +1225,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer } if (mKeyguardController.isKeyguardLocked()) { - mWindowManager.notifyUnknownAppVisibilityLaunched(r.appToken); + r.notifyUnknownVisibilityLaunched(); } r.app = app; @@ -2577,7 +2575,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer "Added restored task=" + task + " to stack=" + stack); final ArrayList<ActivityRecord> activities = task.mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - stack.addConfigOverride(activities.get(activityNdx), task); + activities.get(activityNdx).createWindowContainer(); } return true; } @@ -3169,7 +3167,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer task.setLastThumbnailLocked(r.screenshotActivityLocked()); mRecentTasks.addLocked(task); mService.mTaskChangeNotificationController.notifyTaskStackChanged(); - mWindowManager.setAppVisibility(r.appToken, false); + r.setVisibility(false); // When launching tasks behind, update the last active time of the top task after the new // task has been shown briefly @@ -3360,7 +3358,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer // normal flow and hide it once we determine that it is // hidden by the activities in front of it. if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s); - mWindowManager.setAppVisibility(s.appToken, false); + s.setVisibility(false); } } if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 9e28068b8b73..a17cf3b79cab 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -849,6 +849,11 @@ final class TaskRecord extends ConfigurationContainer { if (r.isPersistable()) { mService.notifyTaskPersisterLocked(this, false); } + + // Sync. with window manager + updateOverrideConfigurationFromLaunchBounds(); + r.positionWindowContainerAt(index); + r.onOverrideConfigurationSent(); } /** @return true if this was the last activity in the task */ diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java new file mode 100644 index 000000000000..35004c295681 --- /dev/null +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -0,0 +1,526 @@ +/* + * 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static com.android.server.wm.AppTransition.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_SCREENSHOT; +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 static com.android.server.wm.WindowManagerService.H.ADD_STARTING; + +import android.graphics.Bitmap; +import android.os.Trace; +import com.android.server.AttributeCache; + +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.os.Binder; +import android.os.Debug; +import android.os.IBinder; +import android.os.Message; +import android.util.Slog; +import android.view.IApplicationToken; + +/** + * 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 final IApplicationToken mToken; + + private final Runnable mOnWindowsDrawn = () -> { + if (mListener == null) { + return; + } + if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in " + + AppWindowContainerController.this.mToken); + mListener.onWindowsDrawn(); + }; + + 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(); + }; + + public AppWindowContainerController(IApplicationToken token, + AppWindowContainerListener listener, int taskId, int index, int requestedOrientation, + boolean fullscreen, boolean showForAllUsers, int configChanges, + boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, + int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) { + this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers, + configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable, + targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos, + WindowManagerService.getInstance()); + } + + public AppWindowContainerController(IApplicationToken token, + AppWindowContainerListener listener, int taskId, 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); + mToken = token; + synchronized(mWindowMap) { + 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; + } + + // TODO: Have the controller for the task passed in when task are changed to use + // controller. + final Task task = mService.mTaskIdToTask.get(taskId); + if (task == null) { + throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId); + } + + atoken = new AppWindowToken(mService, token, 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 + + " task=" + taskId + " at " + index); + task.addChild(atoken, index); + } + } + + public void removeContainer(int displayId) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized(mWindowMap) { + 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(); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + // TODO: Move to task window controller when that is created and rename to positionChildAt() + public void positionAt(int taskId, int index) { + synchronized(mService.mWindowMap) { + if (mContainer == null) { + Slog.w(TAG_WM, + "Attempted to position of non-existing app token: " + mToken); + return; + } + + // TODO: Should get the window container from this owner when the task owner stuff is + // hooked-up. + final Task task = mService.mTaskIdToTask.get(taskId); + if (task == null) { + throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId); + } + task.addChild(mContainer, index); + } + + } + + public Configuration setOrientation(int requestedOrientation, int displayId, + Configuration displayConfig, boolean freezeScreenIfNeeded) { + synchronized(mWindowMap) { + 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(mWindowMap) { + if (mContainer == null) { + return SCREEN_ORIENTATION_UNSPECIFIED; + } + + return mContainer.getOrientationIgnoreVisibility(); + } + } + + public void setVisibility(boolean visible) { + synchronized(mWindowMap) { + if (mContainer == null) { + Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + + mToken); + return; + } + + final AppWindowToken wtoken = mContainer; + + if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" + + mToken + ", visible=" + visible + "): " + mService.mAppTransition + + " hidden=" + wtoken.hidden + " hiddenRequested=" + + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6)); + + mService.mOpeningApps.remove(wtoken); + mService.mClosingApps.remove(wtoken); + wtoken.waitingToShow = false; + wtoken.hiddenRequested = !visible; + + 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(); + wtoken.setVisibleBeforeClientHidden(); + } else { + if (!mService.mAppTransition.isTransitionSet() + && mService.mAppTransition.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. + mService.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.hidden || wtoken.mAppStopped) { + wtoken.clearAllDrawn(); + + // If the app was already visible, don't reset the waitingToShow state. + if (wtoken.hidden) { + wtoken.waitingToShow = true; + } + + if (wtoken.clientHidden) { + // 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.clientHidden = false; + wtoken.sendAppVisibilityToClients(); + } + } + wtoken.requestUpdateWallpaperIfNeeded(); + + if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken); + wtoken.mAppStopped = false; + } + + // If we are preparing an app transition, then delay changing + // the visibility of this token until we execute that transition. + if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) { + // A dummy animation is a placeholder animation which informs others that an + // animation is going on (in this case an application transition). If the animation + // was transferred from another application/animator, no dummy animator should be + // created since an animation is already in progress. + if (wtoken.mAppAnimator.usingTransferredAnimation + && wtoken.mAppAnimator.animation == null) { + Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken + + ", using null transferred animation!"); + } + if (!wtoken.mAppAnimator.usingTransferredAnimation && + (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) { + if (DEBUG_APP_TRANSITIONS) Slog.v( + TAG_WM, "Setting dummy animation on: " + wtoken); + wtoken.mAppAnimator.setDummyAnimation(); + } + wtoken.inPendingTransaction = true; + if (visible) { + mService.mOpeningApps.add(wtoken); + wtoken.mEnteringAnimation = true; + } else { + mService.mClosingApps.add(wtoken); + wtoken.mEnteringAnimation = false; + } + if (mService.mAppTransition.getAppTransition() + == AppTransition.TRANSIT_TASK_OPEN_BEHIND) { + // We're launchingBehind, add the launching activity to mOpeningApps. + final WindowState win = + mService.getDefaultDisplayContentLocked().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.hidden = true; + mService.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(mWindowMap) { + if (mContainer != null) { + mService.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 createIfNeeded) { + synchronized(mWindowMap) { + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken + + " pkg=" + pkg + " transferFrom=" + transferFrom); + + 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 (!mService.okToDisplay()) { + return false; + } + + if (mContainer.startingData != null) { + return false; + } + + // 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 the caller doesn't + // want us to create one, so that's it! + if (!createIfNeeded) { + return false; + } + + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); + mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, + labelRes, icon, logo, windowFlags); + final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer); + // Note: we really want to do sendMessageAtFrontOfQueue() because we + // want to process the message ASAP, before any other queued + // messages. + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING"); + mService.mH.sendMessageAtFrontOfQueue(m); + } + return true; + } + + public void removeStartingWindow() { + synchronized (mWindowMap) { + mService.scheduleRemoveStartingWindowLocked(mContainer); + } + } + + public void pauseKeyDispatching() { + synchronized (mWindowMap) { + if (mContainer != null) { + mService.mInputMonitor.pauseDispatchingLw(mContainer); + } + } + } + + public void resumeKeyDispatching() { + synchronized (mWindowMap) { + if (mContainer != null) { + mService.mInputMonitor.resumeDispatchingLw(mContainer); + } + } + } + + public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) { + synchronized(mWindowMap) { + if (mContainer == null) { + Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken); + return; + } + mContainer.notifyAppResumed(wasStopped, allowSavedSurface); + } + } + + public void notifyAppStopped() { + synchronized(mWindowMap) { + 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(mWindowMap) { + if (configChanges == 0 && mService.okToDisplay()) { + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken); + return; + } + + if (mContainer == null) { + Slog.w(TAG_WM, + "Attempted to freeze screen with non-existing app token: " + mContainer); + return; + } + final long origId = Binder.clearCallingIdentity(); + mContainer.startFreezingScreen(); + Binder.restoreCallingIdentity(origId); + } + } + + public void stopFreezingScreen(boolean force) { + synchronized(mWindowMap) { + if (mContainer == null) { + return; + } + final long origId = Binder.clearCallingIdentity(); + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden=" + + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen); + mContainer.stopFreezingScreen(true, force); + Binder.restoreCallingIdentity(origId); + } + } + + /** + * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. + * In portrait mode, it grabs the full screenshot. + * + * @param displayId the Display to take a screenshot of. + * @param width the width of the target bitmap + * @param height the height of the target bitmap + * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 + */ + public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) { + try { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications"); + final DisplayContent dc; + synchronized(mWindowMap) { + dc = mRoot.getDisplayContentOrCreate(displayId); + if (dc == null) { + if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken + + ": returning null. No Display for displayId=" + displayId); + return null; + } + } + return dc.screenshotApplications(mToken.asBinder(), width, height, + false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565, + false /* wallpaperOnly */); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + + + void reportWindowsDrawn() { + mService.mH.post(mOnWindowsDrawn); + } + + void reportWindowsVisible() { + mService.mH.post(mOnWindowsVisible); + } + + void reportWindowsGone() { + mService.mH.post(mOnWindowsGone); + } + + /** Calls directly into activity manager so window manager lock shouldn't held. */ + boolean keyDispatchingTimedOut(String reason) { + return mListener != null && mListener.keyDispatchingTimedOut(reason); + } +} diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java new file mode 100644 index 000000000000..12d4b2fcb132 --- /dev/null +++ b/services/core/java/com/android/server/wm/AppWindowContainerListener.java @@ -0,0 +1,32 @@ +/* + * 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 are drawn. */ + void onWindowsDrawn(); + /** 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 key dispatching to a window associated with the app window container + * timed-out. + */ + boolean keyDispatchingTimedOut(String reason); +} diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 6147885a4a2e..0a4875810aba 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -47,7 +47,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.logWithStack; -import android.content.pm.ActivityInfo; import android.os.Debug; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; @@ -173,8 +172,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree AppWindowToken(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) { + int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, + AppWindowContainerController controller) { this(service, token, voiceInteraction, dc); + setController(controller); mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; mFillsParent = fullscreen; mShowForAllUsers = showForAllUsers; @@ -251,9 +252,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" + numInteresting + " visible=" + numVisible); + final AppWindowContainerController controller = getController(); if (nowDrawn != reportedDrawn) { if (nowDrawn) { - mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget(); + if (controller != null) { + controller.reportWindowsDrawn(); + } } reportedDrawn = nowDrawn; } @@ -261,8 +265,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_VISIBILITY) Slog.v(TAG, "Visibility changed in " + this + ": vis=" + nowVisible); reportedVisible = nowVisible; - mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS, - nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget(); + if (controller != null) { + if (nowVisible) { + controller.reportWindowsVisible(); + } else { + controller.reportWindowsGone(); + } + } } } @@ -399,6 +408,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable; } + AppWindowContainerController getController() { + final WindowContainerController controller = super.getController(); + return controller != null ? (AppWindowContainerController) controller : null; + } + @Override boolean isVisible() { // If the app token isn't hidden then it is considered visible and there is no need to check diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 3fbe36f78112..f754775e286a 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -251,16 +251,14 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } if (appWindowToken != null && appWindowToken.appToken != null) { - try { - // Notify the activity manager about the timeout and let it decide whether - // to abort dispatching or keep waiting. - boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason); - if (! abort) { - // The activity manager declined to abort dispatching. - // Wait a bit longer and timeout again later. - return appWindowToken.mInputDispatchingTimeoutNanos; - } - } catch (RemoteException ex) { + // Notify the activity manager about the timeout and let it decide whether + // to abort dispatching or keep waiting. + final AppWindowContainerController controller = appWindowToken.getController(); + final boolean abort = controller != null && controller.keyDispatchingTimedOut(reason); + if (!abort) { + // The activity manager declined to abort dispatching. + // Wait a bit longer and timeout again later. + return appWindowToken.mInputDispatchingTimeoutNanos; } } else if (windowState != null) { try { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index c9bf4fa55efd..0e6ecde0506a 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -75,6 +75,9 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool = new Pools.SynchronizedPool<>(3); + // The owner/creator for this container. No controller if null. + private WindowContainerController mController; + final protected WindowContainer getParent() { return mParent; } @@ -188,6 +191,10 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon if (mParent != null) { mParent.removeChild(this); } + + if (mController != null) { + setController(null); + } } /** @@ -662,6 +669,23 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon } while (current != null); } + WindowContainerController getController() { + return mController; + } + + void setController(WindowContainerController controller) { + if (mController != null && controller != null) { + throw new IllegalArgumentException("Can't set controller=" + mController + + " for container=" + this + " Already set to=" + mController); + } + if (controller != null) { + controller.setContainer(this); + } else if (mController != null) { + mController.setContainer(null); + } + mController = controller; + } + /** * Dumps the names of this container children in the input print writer indenting each * level with the input prefix. diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java new file mode 100644 index 000000000000..84ffc35b4651 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowContainerController.java @@ -0,0 +1,70 @@ +/* + * 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 android.os.IBinder; + +import java.util.HashMap; + +/** + * Class that allows the owner/creator of a {@link WindowContainer} to communicate directly with the + * container and make changes. + * Note that public calls (mostly in sub-classes) into this class are assumed to be originating from + * outside the window manager so the window manager lock is held and appropriate permissions are + * checked before calls are allowed to proceed. + * + * Test class: {@link WindowContainerControllerTests} + */ +class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener> { + + final WindowManagerService mService; + final RootWindowContainer mRoot; + final HashMap<IBinder, WindowState> mWindowMap; + + // The window container this controller owns. + E mContainer; + // Interface for communicating changes back to the owner. + final I mListener; + + WindowContainerController(I listener, WindowManagerService service) { + mListener = listener; + mService = service; + mRoot = mService != null ? mService.mRoot : null; + mWindowMap = mService != null ? mService.mWindowMap : null; + } + + void setContainer(E container) { + if (mContainer != null && container != null) { + throw new IllegalArgumentException("Can't set container=" + container + + " for controller=" + this + " Already set to=" + mContainer); + } + mContainer = container; + } + + void removeContainer() { + // TODO: See if most uses cases should support removeIfPossible here. + //mContainer.removeIfPossible(); + if (mContainer != null) { + mContainer.setController(null); + mContainer = null; + } + } + + boolean checkCallingPermission(String permission, String func) { + return mService.checkCallingPermission(permission, func); + } +} diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java new file mode 100644 index 000000000000..ab9d71ac2ea8 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowContainerListener.java @@ -0,0 +1,25 @@ +/* + * 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 owner/creator of the container to listen to changes with the container. + * @see WindowContainerController + */ +public interface WindowContainerListener { + +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f6d3881e9485..d5aa01b6a0b7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -90,7 +90,6 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.view.PointerIcon; import android.view.IAppTransitionAnimationSpecsFuture; -import android.view.IApplicationToken; import android.view.IDockedStackListener; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; @@ -133,7 +132,6 @@ import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.WindowManagerPolicyThread; -import com.android.server.AttributeCache; import com.android.server.DisplayThread; import com.android.server.EventLogTags; import com.android.server.FgThread; @@ -228,7 +226,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; -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.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; @@ -240,7 +237,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSA import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static java.lang.Integer.MAX_VALUE; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub @@ -915,16 +911,19 @@ public class WindowManagerService extends IWindowManager.Stub void onAppFreezeTimeout(); } - public static WindowManagerService main(final Context context, - final InputManagerService im, - final boolean haveInputMethods, final boolean showBootMsgs, - final boolean onlyCore, WindowManagerPolicy policy) { - final WindowManagerService[] holder = new WindowManagerService[1]; - DisplayThread.getHandler().runWithScissors(() -> { - holder[0] = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, - onlyCore, policy); - }, 0); - return holder[0]; + private static WindowManagerService sInstance; + + static WindowManagerService getInstance() { + return sInstance; + } + + public static WindowManagerService main(final Context context, final InputManagerService im, + final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore, + WindowManagerPolicy policy) { + DisplayThread.getHandler().runWithScissors(() -> + sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, + onlyCore, policy), 0); + return sInstance; } private void initPolicy() { @@ -2369,7 +2368,7 @@ public class WindowManagerService extends IWindowManager.Stub return atoken.mAppAnimator.animation != null; } - private boolean checkCallingPermission(String permission, String func) { + boolean checkCallingPermission(String permission, String func) { // Quick check: if the calling permission is me, it's all okay. if (Binder.getCallingPid() == Process.myPid()) { return true; @@ -2442,73 +2441,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void addAppToken(int addPos, IApplicationToken token, int taskId, - int requestedOrientation, boolean fullscreen, boolean showForAllUsers, - int configChanges, boolean voiceInteraction, boolean launchTaskBehind, - boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - // Get the dispatching timeout here while we are not holding any locks so that it - // can be cached by the AppWindowToken. The timeout value is used later by the - // input dispatcher in code that does hold locks. If we did not cache the value - // here we would run the chance of introducing a deadlock between the window manager - // (which holds locks while updating the input dispatcher state) and the activity manager - // (which holds locks while querying the application token). - long inputDispatchingTimeoutNanos; - try { - inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L; - } catch (RemoteException ex) { - Slog.w(TAG_WM, "Could not get dispatching timeout.", ex); - inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - } - - synchronized(mWindowMap) { - AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder()); - if (atoken != null) { - Slog.w(TAG_WM, "Attempted to add existing app token: " + token); - return; - } - - Task task = mTaskIdToTask.get(taskId); - if (task == null) { - throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId); - } - - atoken = new AppWindowToken(this, token, voiceInteraction, task.getDisplayContent(), - inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion, - requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind, - alwaysFocusable); - if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken - + " task=" + taskId + " at " + addPos); - - task.addChild(atoken, addPos); - } - } - - @Override - public void addAppToTask(IBinder token, int taskId) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken atoken = mRoot.getAppWindowToken(token); - if (atoken == null) { - Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token); - return; - } - - Task task = mTaskIdToTask.get(taskId); - if (task == null) { - throw new IllegalArgumentException("setAppTask: invalid taskId=" + taskId); - } - task.addChild(atoken, MAX_VALUE /* at top */); - } - } - public void addTask(int taskId, int stackId, int userId, Rect bounds, Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers) { @@ -2675,35 +2607,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void setAppOrientation(IApplicationToken token, int requestedOrientation) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder()); - if (atoken == null) { - Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token); - return; - } - - atoken.setOrientation(requestedOrientation); - } - } - - @Override - public int getAppOrientation(IApplicationToken token) { - synchronized(mWindowMap) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token.asBinder()); - if (wtoken == null) { - return SCREEN_ORIENTATION_UNSPECIFIED; - } - - return wtoken.getOrientationIgnoreVisibility(); - } - } - void setFocusTaskRegionLocked() { final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null; if (focusedTask != null) { @@ -2912,113 +2815,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public boolean setAppStartingWindow(IBinder token, String pkg, - int theme, CompatibilityInfo compatInfo, - CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, - int windowFlags, IBinder transferFrom, boolean createIfNeeded) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - if (DEBUG_STARTING_WINDOW) Slog.v( - TAG_WM, "setAppStartingWindow: token=" + token + " pkg=" + pkg - + " transferFrom=" + transferFrom); - - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + token); - 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 (!okToDisplay()) { - return false; - } - - if (wtoken.startingData != null) { - return false; - } - - // 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, 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 (wtoken.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 (wtoken.transferStartingWindow(transferFrom)) { - return true; - } - - // There is no existing starting window, and the caller doesn't - // want us to create one, so that's it! - if (!createIfNeeded) { - return false; - } - - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); - wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, - labelRes, icon, logo, windowFlags); - Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); - // Note: we really want to do sendMessageAtFrontOfQueue() because we - // want to process the message ASAP, before any other queued - // messages. - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING"); - mH.sendMessageAtFrontOfQueue(m); - } - return true; - } - - public void removeAppStartingWindow(IBinder token) { - synchronized (mWindowMap) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - scheduleRemoveStartingWindowLocked(wtoken); - } - } - public void setAppFullscreen(IBinder token, boolean toOpaque) { synchronized (mWindowMap) { final AppWindowToken atoken = mRoot.getAppWindowToken(token); @@ -3055,233 +2851,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token); - return; - } - wtoken.notifyAppResumed(wasStopped, allowSavedSurface); - } - } - - @Override - public void notifyAppStopped(IBinder token) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken wtoken; - wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token); - return; - } - wtoken.notifyAppStopped(); - } - } - - @Override - public void setAppVisibility(IBinder token, boolean visible) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - AppWindowToken wtoken; - - synchronized(mWindowMap) { - wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null) { - Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token); - return; - } - - if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" + - token + ", visible=" + visible + "): " + mAppTransition + - " hidden=" + wtoken.hidden + " hiddenRequested=" + - wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6)); - - mOpeningApps.remove(wtoken); - mClosingApps.remove(wtoken); - wtoken.waitingToShow = false; - wtoken.hiddenRequested = !visible; - - 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(); - wtoken.setVisibleBeforeClientHidden(); - } else if (visible) { - if (!mAppTransition.isTransitionSet() && mAppTransition.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. - 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.hidden || wtoken.mAppStopped) { - wtoken.clearAllDrawn(); - - // If the app was already visible, don't reset the waitingToShow state. - if (wtoken.hidden) { - wtoken.waitingToShow = true; - } - - if (wtoken.clientHidden) { - // 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.clientHidden = false; - wtoken.sendAppVisibilityToClients(); - } - } - wtoken.requestUpdateWallpaperIfNeeded(); - - if (DEBUG_ADD_REMOVE) Slog.v( - TAG_WM, "No longer Stopped: " + wtoken); - wtoken.mAppStopped = false; - } - - // If we are preparing an app transition, then delay changing - // the visibility of this token until we execute that transition. - if (okToDisplay() && mAppTransition.isTransitionSet()) { - // A dummy animation is a placeholder animation which informs others that an - // animation is going on (in this case an application transition). If the animation - // was transferred from another application/animator, no dummy animator should be - // created since an animation is already in progress. - if (wtoken.mAppAnimator.usingTransferredAnimation - && wtoken.mAppAnimator.animation == null) { - Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken - + ", using null transfered animation!"); - } - if (!wtoken.mAppAnimator.usingTransferredAnimation && - (!wtoken.startingDisplayed || mSkipAppTransitionAnimation)) { - if (DEBUG_APP_TRANSITIONS) Slog.v( - TAG_WM, "Setting dummy animation on: " + wtoken); - wtoken.mAppAnimator.setDummyAnimation(); - } - wtoken.inPendingTransaction = true; - if (visible) { - mOpeningApps.add(wtoken); - wtoken.mEnteringAnimation = true; - } else { - mClosingApps.add(wtoken); - wtoken.mEnteringAnimation = false; - } - if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) { - // We're launchingBehind, add the launching activity to mOpeningApps. - final WindowState win = getDefaultDisplayContentLocked().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.hidden = true; - mOpeningApps.add(focusedToken); - } - } - } - return; - } - - final long origId = Binder.clearCallingIdentity(); - wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction); - wtoken.updateReportedVisibilityLocked(); - Binder.restoreCallingIdentity(origId); - } - } - - /** - * 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 notifyUnknownAppVisibilityLaunched(IBinder token) { - synchronized(mWindowMap) { - AppWindowToken appWindow = mRoot.getAppWindowToken(token); - if (appWindow != null) { - mUnknownAppVisibilityController.notifyLaunched(appWindow); - } - } - } - - @Override - public void startAppFreezingScreen(IBinder token, int configChanges) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - if (configChanges == 0 && okToDisplay()) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + token); - return; - } - - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null || wtoken.appToken == null) { - Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + wtoken); - return; - } - final long origId = Binder.clearCallingIdentity(); - wtoken.startFreezingScreen(); - Binder.restoreCallingIdentity(origId); - } - } - - @Override - public void stopAppFreezingScreen(IBinder token, boolean force) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - if (wtoken == null || wtoken.appToken == null) { - return; - } - final long origId = Binder.clearCallingIdentity(); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden=" - + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen); - wtoken.stopFreezingScreen(true, force); - Binder.restoreCallingIdentity(origId); - } - } - - @Override - public void removeAppToken(IBinder binder, int displayId) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - final long origId = Binder.clearCallingIdentity(); - try { - synchronized(mWindowMap) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " + binder - + " from non-existing displayId=" + displayId); - return; - } - dc.removeAppToken(binder); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) { if (wtoken == null) { return; @@ -4523,7 +4092,7 @@ public class WindowManagerService extends IWindowManager.Stub } try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); - return screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, + return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */, Bitmap.Config.ARGB_8888, true /* wallpaperOnly */); } finally { @@ -4544,7 +4113,7 @@ public class WindowManagerService extends IWindowManager.Stub } FgThread.getHandler().post(() -> { - Bitmap bm = screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, + Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */); try { @@ -4563,37 +4132,12 @@ public class WindowManagerService extends IWindowManager.Stub * @param displayId the Display to take a screenshot of. * @param width the width of the target bitmap * @param height the height of the target bitmap - * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 - */ - @Override - public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, - float frameScale) { - if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER, - "screenshotApplications()")) { - throw new SecurityException("Requires READ_FRAME_BUFFER permission"); - } - try { - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications"); - return screenshotApplicationsInner(appToken, displayId, width, height, false, - frameScale, Bitmap.Config.RGB_565, false); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); - } - } - - /** - * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. - * In portrait mode, it grabs the full screenshot. - * - * @param displayId the Display to take a screenshot of. - * @param width the width of the target bitmap - * @param height the height of the target bitmap * @param includeFullDisplay true if the screen should not be cropped before capture * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 * @param config of the output bitmap * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot */ - private Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, + private Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config, boolean wallpaperOnly) { final DisplayContent displayContent; @@ -5907,34 +5451,6 @@ public class WindowManagerService extends IWindowManager.Stub private boolean mEventDispatchingEnabled; @Override - public void pauseKeyDispatching(IBinder binder) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized (mWindowMap) { - WindowToken token = mRoot.getAppWindowToken(binder); - if (token != null) { - mInputMonitor.pauseDispatchingLw(token); - } - } - } - - @Override - public void resumeKeyDispatching(IBinder binder) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized (mWindowMap) { - WindowToken token = mRoot.getAppWindowToken(binder); - if (token != null) { - mInputMonitor.resumeDispatchingLw(token); - } - } - } - - @Override public void setEventDispatching(boolean enabled) { if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -6065,8 +5581,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int ADD_STARTING = 5; public static final int REMOVE_STARTING = 6; public static final int FINISHED_STARTING = 7; - public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8; - public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9; public static final int WINDOW_FREEZE_TIMEOUT = 11; public static final int APP_TRANSITION_TIMEOUT = 13; @@ -6328,37 +5842,6 @@ public class WindowManagerService extends IWindowManager.Stub } } break; - case REPORT_APPLICATION_TOKEN_DRAWN: { - final AppWindowToken wtoken = (AppWindowToken)msg.obj; - - try { - if (DEBUG_VISIBILITY) Slog.v( - TAG_WM, "Reporting drawn in " + wtoken); - wtoken.appToken.windowsDrawn(); - } catch (RemoteException ex) { - } - } break; - - case REPORT_APPLICATION_TOKEN_WINDOWS: { - final AppWindowToken wtoken = (AppWindowToken)msg.obj; - - boolean nowVisible = msg.arg1 != 0; - boolean nowGone = msg.arg2 != 0; - - try { - if (DEBUG_VISIBILITY) Slog.v( - TAG_WM, "Reporting visible in " + wtoken - + " visible=" + nowVisible - + " gone=" + nowGone); - if (nowVisible) { - wtoken.appToken.windowsVisible(); - } else { - wtoken.appToken.windowsGone(); - } - } catch (RemoteException ex) { - } - } break; - case WINDOW_FREEZE_TIMEOUT: { // TODO(multidisplay): Can non-default displays rotate? synchronized (mWindowMap) { diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java new file mode 100644 index 000000000000..8a962e709a24 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java @@ -0,0 +1,42 @@ +/* + * 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 org.junit.Test; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test class for {@link WindowContainerController}. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests + */ +@SmallTest +@Presubmit +@org.junit.runner.RunWith(AndroidJUnit4.class) +public class AppWindowContainerControllerTests extends WindowTestsBase { +// TODO Add tests once TaskWindowContainerController is created. + @Test + public void dummyTest() throws Exception {} +} diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index 07f65bd90021..612919845f92 100644 --- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; import android.app.ActivityManagerInternal; import android.content.Context; @@ -27,7 +26,6 @@ import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.view.IApplicationToken; import com.android.server.LocalServices; @@ -114,7 +112,6 @@ public class UnknownAppVisibilityControllerTest { } private AppWindowToken createAppToken() { - return new AppWindowToken(mWm, mock(IApplicationToken.class), false, - mWm.getDefaultDisplayContentLocked()); + return new AppWindowToken(mWm, null, false, mWm.getDefaultDisplayContentLocked()); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java new file mode 100644 index 000000000000..956735c01019 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java @@ -0,0 +1,84 @@ +/* + * 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 org.junit.Test; +import org.junit.runner.RunWith; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test class for {@link WindowContainerController}. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests + */ +@SmallTest +@Presubmit +@org.junit.runner.RunWith(AndroidJUnit4.class) +public class WindowContainerControllerTests extends WindowTestsBase { + + @Test + public void testCreation() throws Exception { + final WindowContainerController controller = new WindowContainerController(null, sWm); + final WindowContainer container = new WindowContainer(); + + container.setController(controller); + assertEquals(controller, container.getController()); + assertEquals(controller.mContainer, container); + } + + @Test + public void testSetContainer() throws Exception { + final WindowContainerController controller = new WindowContainerController(null, sWm); + final WindowContainer container = new WindowContainer(); + + controller.setContainer(container); + assertEquals(controller.mContainer, container); + + // Assert we can't change the container to another one once set + boolean gotException = false; + try { + controller.setContainer(new WindowContainer()); + } catch (IllegalArgumentException e) { + gotException = true; + } + assertTrue(gotException); + + // Assert that we can set the container to null. + controller.setContainer(null); + assertNull(controller.mContainer); + } + + @Test + public void testRemoveContainer() throws Exception { + final WindowContainerController controller = new WindowContainerController(null, sWm); + final WindowContainer container = new WindowContainer(); + + controller.setContainer(container); + assertEquals(controller.mContainer, container); + + controller.removeContainer(); + assertNull(controller.mContainer); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java index 7277ba42c2da..b57329c5c701 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java @@ -52,7 +52,7 @@ import static org.junit.Assert.assertTrue; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class WindowContainerTests { +public class WindowContainerTests extends WindowTestsBase { @Test public void testCreation() throws Exception { @@ -192,6 +192,44 @@ public class WindowContainerTests { } @Test + public void testRemoveImmediately_WithController() throws Exception { + final WindowContainer container = new WindowContainer(); + final WindowContainerController controller = new WindowContainerController(null, sWm); + + container.setController(controller); + assertEquals(controller, container.getController()); + assertEquals(container, controller.mContainer); + + container.removeImmediately(); + assertNull(container.getController()); + assertNull(controller.mContainer); + } + + @Test + public void testSetController() throws Exception { + final WindowContainerController controller = new WindowContainerController(null, sWm); + final WindowContainer container = new WindowContainer(); + + container.setController(controller); + assertEquals(controller, container.getController()); + assertEquals(container, controller.mContainer); + + // Assert we can't change the controller to another one once set + boolean gotException = false; + try { + container.setController(new WindowContainerController(null, sWm)); + } catch (IllegalArgumentException e) { + gotException = true; + } + assertTrue(gotException); + + // Assert that we can set the controller to null. + container.setController(null); + assertNull(container.getController()); + assertNull(controller.mContainer); + } + + @Test public void testPositionChildAt() throws Exception { final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); final TestWindowContainer root = builder.setLayer(0).build(); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index 398568771cd7..fb3beb3c5161 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.mock; /** * Common base class for window manager unit test classes. */ -public class WindowTestsBase { +class WindowTestsBase { static WindowManagerService sWm = null; private final IWindow mIWindow = new TestIWindow(); private final Session mMockSession = mock(Session.class); @@ -52,17 +52,17 @@ public class WindowTestsBase { private static int sNextTaskId = 0; private static boolean sOneTimeSetupDone = false; - protected static DisplayContent sDisplayContent; - protected static WindowLayersController sLayersController; - protected static WindowState sWallpaperWindow; - protected static WindowState sImeWindow; - protected static WindowState sImeDialogWindow; - protected static WindowState sStatusBarWindow; - protected static WindowState sDockedDividerWindow; - protected static WindowState sNavBarWindow; - protected static WindowState sAppWindow; - protected static WindowState sChildAppWindowAbove; - protected static WindowState sChildAppWindowBelow; + static DisplayContent sDisplayContent; + static WindowLayersController sLayersController; + static WindowState sWallpaperWindow; + static WindowState sImeWindow; + static WindowState sImeDialogWindow; + static WindowState sStatusBarWindow; + static WindowState sDockedDividerWindow; + static WindowState sNavBarWindow; + static WindowState sAppWindow; + static WindowState sChildAppWindowAbove; + static WindowState sChildAppWindowBelow; @Before public void setUp() throws Exception { diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index 28a2cb399cd0..4aeae70ec979 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -43,26 +43,6 @@ public class WindowManagerPermissionTests extends TestCase { @SmallTest public void testMANAGE_APP_TOKENS() { try { - mWm.pauseKeyDispatching(null); - fail("IWindowManager.pauseKeyDispatching did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.resumeKeyDispatching(null); - fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { mWm.setEventDispatching(true); fail("IWindowManager.setEventDispatching did not throw SecurityException as" + " expected"); @@ -93,26 +73,6 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.addAppToken(0, null, 0, 0, false, false, 0, false, false, false, 0, -1); - fail("IWindowManager.addAppToken did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.addAppToTask(null, 0); - fail("IWindowManager.setAppGroupId did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { mWm.updateOrientationFromAppTokens(new Configuration(), null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY); fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as" @@ -124,17 +84,6 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.setAppOrientation(null, 0); - mWm.addWindowToken(null, 0, DEFAULT_DISPLAY); - fail("IWindowManager.setAppOrientation did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { mWm.setFocusedApp(null, false); fail("IWindowManager.setFocusedApp did not throw SecurityException as" + " expected"); @@ -163,56 +112,6 @@ public class WindowManagerPermissionTests extends TestCase { } catch (RemoteException e) { fail("Unexpected remote exception"); } - - try { - mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false); - fail("IWindowManager.setAppStartingWindow did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.setAppVisibility(null, false); - fail("IWindowManager.setAppVisibility did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.startAppFreezingScreen(null, 0); - fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.stopAppFreezingScreen(null, false); - fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { - mWm.removeAppToken(null, DEFAULT_DISPLAY); - fail("IWindowManager.removeAppToken did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } } @SmallTest diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 4b9815d93ac7..71c1117c036c 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -77,14 +77,6 @@ public class IWindowManagerImpl implements IWindowManager { // ---- unused implementation of IWindowManager ---- @Override - public void addAppToken(int addPos, IApplicationToken token, int taskId, - int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int configChanges, - boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, - int targetSdkVersion, int rotationAnimationHint) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override public void addWindowToken(IBinder arg0, int arg1, int arg2) throws RemoteException { // TODO Auto-generated method stub @@ -159,12 +151,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public int getAppOrientation(IApplicationToken arg0) throws RemoteException { - // TODO Auto-generated method stub - return 0; - } - - @Override public int getPendingAppTransition() throws RemoteException { // TODO Auto-generated method stub return 0; @@ -258,12 +244,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void pauseKeyDispatching(IBinder arg0) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException { // TODO Auto-generated method stub @@ -276,24 +256,12 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void removeAppToken(IBinder arg0, int arg1) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override public void removeWindowToken(IBinder arg0, int arg1) throws RemoteException { // TODO Auto-generated method stub } @Override - public void resumeKeyDispatching(IBinder arg0) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver) throws RemoteException { // TODO Auto-generated method stub @@ -301,13 +269,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, - int maxHeight, float frameScale) throws RemoteException { - // TODO Auto-generated method stub - return null; - } - - @Override public void setAnimationScale(int arg0, float arg1) throws RemoteException { // TODO Auto-generated method stub @@ -325,41 +286,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void addAppToTask(IBinder arg0, int arg1) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public boolean setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3, - CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10) - throws RemoteException { - // TODO Auto-generated method stub - return false; - } - - @Override - public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) - throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public void notifyAppStopped(IBinder token) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override public void setEventDispatching(boolean arg0) throws RemoteException { // TODO Auto-generated method stub } @@ -443,11 +369,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override public boolean startViewServer(int arg0) throws RemoteException { // TODO Auto-generated method stub return false; @@ -469,11 +390,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override public boolean stopViewServer() throws RemoteException { // TODO Auto-generated method stub return false; |