diff options
18 files changed, 448 insertions, 214 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 4de5b421cefc..4df13251f8ed 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1235,6 +1235,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final Configuration config = Configuration.CREATOR.createFromParcel(data); + final int displayId = data.readInt(); + final boolean updated = updateDisplayOverrideConfiguration(config, displayId); + reply.writeNoException(); + reply.writeInt(updated ? 1 : 0); + return true; + } + case SET_REQUESTED_ORIENTATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -4608,8 +4618,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return res; } - public boolean updateConfiguration(Configuration values) throws RemoteException - { + public boolean updateConfiguration(Configuration values) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4621,6 +4630,20 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return updated; } + public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + values.writeToParcel(data, 0); + data.writeInt(displayId); + mRemote.transact(UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION, data, reply, 0); + reply.readException(); + boolean updated = reply.readInt() == 1; + data.recycle(); + reply.recycle(); + return updated; + } public void setRequestedOrientation(IBinder token, int requestedOrientation) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 1253e6935cf4..5edd03f438f4 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -274,12 +274,24 @@ public interface IActivityManager extends IInterface { /** * Updates global configuration and applies changes to the entire system. - * @param values Update values for global configuration. + * @param values Update values for global configuration. If null is passed it will request the + * Window Manager to compute new config for the default display. * @throws RemoteException * @return Returns true if the configuration was updated. */ public boolean updateConfiguration(Configuration values) throws RemoteException; + /** + * Updates override configuration applied to specific display. + * @param values Update values for display configuration. If null is passed it will request the + * Window Manager to compute new config for the specified display. + * @param displayId Id of the display to apply the config to. + * @throws RemoteException + * @return Returns true if the configuration was updated. + */ + public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) + throws RemoteException; + public void setRequestedOrientation(IBinder token, int requestedOrientation) throws RemoteException; public int getRequestedOrientation(IBinder token) throws RemoteException; @@ -1103,4 +1115,5 @@ public interface IActivityManager extends IInterface { int REQUEST_ACTIVITY_RELAUNCH = IBinder.FIRST_CALL_TRANSACTION+400; int GET_DEFAULT_PICTURE_IN_PICTURE_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 401; int GET_PICTURE_IN_PICTURE_MOVEMENT_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 402; + int UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 403; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 717b67511855..791704183635 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -191,10 +191,10 @@ interface IWindowManager // If there is a change, the new Configuration is returned and the // caller must call setNewConfiguration() sometime later. Configuration updateOrientationFromAppTokens(in Configuration currentConfig, - IBinder freezeThisOneIfNeeded); - // Notify window manager of the new configuration. Returns an array of stack ids that's - // affected by the update, ActivityManager should resize these stacks. - int[] setNewConfiguration(in Configuration config); + IBinder freezeThisOneIfNeeded, int displayId); + // Notify window manager of the new display override configuration. Returns an array of stack + // ids that were affected by the update, ActivityManager should resize these stacks. + int[] setNewDisplayOverrideConfiguration(in Configuration overrideConfig, int displayId); // Retrieves the new bounds after the configuration update evaluated by window manager. Rect getBoundsForNewConfiguration(int stackId); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9a638a2e4a7f..2211e5e816dd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -219,7 +219,6 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import android.util.Xml; -import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -256,6 +255,7 @@ import dalvik.system.VMRuntime; import libcore.io.IoUtils; import libcore.util.EmptyArray; +import static android.Manifest.permission.CHANGE_CONFIGURATION; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; @@ -279,6 +279,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; +import static android.os.Build.VERSION_CODES.N; import static android.os.Process.PROC_CHAR; import static android.os.Process.PROC_OUT_LONG; import static android.os.Process.PROC_PARENS; @@ -293,6 +294,7 @@ import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; import static android.provider.Settings.System.FONT_SCALE; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static android.view.Display.DEFAULT_DISPLAY; + import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; @@ -1130,10 +1132,11 @@ public final class ActivityManagerService extends ActivityManagerNative private int mConfigurationSeq; /** - * Temp object used when global configuration is updated. It is also sent to outer world - * instead of {@link #getGlobalConfiguration} because we don't trust anyone... + * Temp object used when global and/or display override configuration is updated. It is also + * sent to outer world instead of {@link #getGlobalConfiguration} because we don't trust + * anyone... */ - private Configuration mTempGlobalConfig = new Configuration(); + private Configuration mTempConfig = new Configuration(); private final UpdateConfigurationResult mTmpUpdateConfigurationResult = new UpdateConfigurationResult(); @@ -2717,14 +2720,14 @@ public final class ActivityManagerService extends ActivityManagerNative mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations")); - mTempGlobalConfig.setToDefaults(); - mTempGlobalConfig.setLocales(LocaleList.getDefault()); - mConfigurationSeq = mTempGlobalConfig.seq = 1; + mTempConfig.setToDefaults(); + mTempConfig.setLocales(LocaleList.getDefault()); + mConfigurationSeq = mTempConfig.seq = 1; mProcessCpuTracker.init(); mStackSupervisor = new ActivityStackSupervisor(this); - mStackSupervisor.onConfigurationChanged(mTempGlobalConfig); + mStackSupervisor.onConfigurationChanged(mTempConfig); mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mActivityStarter = new ActivityStarter(this, mStackSupervisor); @@ -4762,23 +4765,12 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return; } - TaskRecord task = r.task; - if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) { - // Fixed screen orientation isn't supported when activities aren't in full screen - // mode. - return; - } final long origId = Binder.clearCallingIdentity(); - mWindowManager.setAppOrientation(r.appToken, requestedOrientation); - Configuration config = mWindowManager.updateOrientationFromAppTokens( - getGlobalConfiguration(), r.mayFreezeScreenLocked(r.app) ? r.appToken : null); - if (config != null) { - r.frozenBeforeDestroy = true; - if (!updateConfigurationLocked(config, r, false)) { - mStackSupervisor.resumeFocusedStackTopActivityLocked(); - } + try { + r.setRequestedOrientation(requestedOrientation); + } finally { + Binder.restoreCallingIdentity(origId); } - Binder.restoreCallingIdentity(origId); } } @@ -14877,6 +14869,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (dumpPackage == null) { pw.println(" mGlobalConfiguration: " + getGlobalConfiguration()); + mStackSupervisor.dumpDisplayConfigs(pw, " "); } if (dumpAll) { pw.println(" mConfigWillChange: " + getFocusedStack().mConfigWillChange); @@ -18939,8 +18932,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void updatePersistentConfiguration(Configuration values) { - enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, - "updatePersistentConfiguration()"); + enforceCallingPermission(CHANGE_CONFIGURATION, "updatePersistentConfiguration()"); enforceWriteSettingsPermission("updatePersistentConfiguration()"); if (values == null) { throw new NullPointerException("Configuration must not be null"); @@ -18965,12 +18957,16 @@ public final class ActivityManagerService extends ActivityManagerNative private void updateFontScaleIfNeeded(@UserIdInt int userId) { final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(), FONT_SCALE, 1.0f, userId); - if (getGlobalConfiguration().fontScale != scaleFactor) { - final Configuration configuration = mWindowManager.computeNewConfiguration(); - configuration.fontScale = scaleFactor; - synchronized (this) { - updatePersistentConfigurationLocked(configuration, userId); + + synchronized (this) { + if (getGlobalConfiguration().fontScale == scaleFactor) { + return; } + + final Configuration configuration + = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY); + configuration.fontScale = scaleFactor; + updatePersistentConfigurationLocked(configuration, userId); } } @@ -18995,21 +18991,20 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public boolean updateConfiguration(Configuration values) { - enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, - "updateConfiguration()"); + enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()"); synchronized(this) { if (values == null && mWindowManager != null) { // sentinel: fetch the current configuration from the window manager - values = mWindowManager.computeNewConfiguration(); + values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY); } if (mWindowManager != null) { + // Update OOM levels based on display size. mProcessList.applyDisplaySize(mWindowManager); } final long origId = Binder.clearCallingIdentity(); - try { if (values != null) { Settings.System.clearConfiguration(values); @@ -19096,8 +19091,8 @@ public final class ActivityManagerService extends ActivityManagerNative /** Update default (global) configuration and notify listeners about changes. */ private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale, boolean persistent, int userId, boolean deferResume) { - mTempGlobalConfig.setTo(getGlobalConfiguration()); - final int changes = mTempGlobalConfig.updateFrom(values); + mTempConfig.setTo(getGlobalConfiguration()); + final int changes = mTempConfig.updateFrom(values); if (changes == 0) { return 0; } @@ -19124,33 +19119,33 @@ public final class ActivityManagerService extends ActivityManagerNative } mConfigurationSeq = Math.max(++mConfigurationSeq, 1); - mTempGlobalConfig.seq = mConfigurationSeq; + mTempConfig.seq = mConfigurationSeq; // Update stored global config and notify everyone about the change. - mStackSupervisor.onConfigurationChanged(mTempGlobalConfig); + mStackSupervisor.onConfigurationChanged(mTempConfig); - Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempGlobalConfig); + Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig); // TODO(multi-display): Update UsageEvents#Event to include displayId. - mUsageStatsService.reportConfigurationChange(mTempGlobalConfig, + mUsageStatsService.reportConfigurationChange(mTempConfig, mUserController.getCurrentUserIdLocked()); // TODO: If our config changes, should we auto dismiss any currently showing dialogs? - mShowDialogs = shouldShowDialogs(mTempGlobalConfig, mInVrMode); + mShowDialogs = shouldShowDialogs(mTempConfig, mInVrMode); AttributeCache ac = AttributeCache.instance(); if (ac != null) { - ac.updateConfiguration(mTempGlobalConfig); + ac.updateConfiguration(mTempConfig); } // Make sure all resources in our process are updated right now, so that anyone who is going // to retrieve resource values after we return will be sure to get the new ones. This is // especially important during boot, where the first config change needs to guarantee all // resources have that config before following boot code is executed. - mSystemThread.applyConfigurationToResources(mTempGlobalConfig); + mSystemThread.applyConfigurationToResources(mTempConfig); // We need another copy of global config because we're scheduling some calls instead of // running them in place. We need to be sure that object we send will be handled unchanged. - final Configuration configCopy = new Configuration(mTempGlobalConfig); + final Configuration configCopy = new Configuration(mTempConfig); if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) { Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG); msg.obj = configCopy; @@ -19158,16 +19153,6 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.sendMessage(msg); } - // TODO(multi-display): Clear also on secondary display density change? - final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0; - if (isDensityChange) { - // Reset the unsupported display size dialog. - mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG); - - killAllBackgroundProcessesExcept(Build.VERSION_CODES.N, - ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - } - for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord app = mLruProcesses.get(i); try { @@ -19197,13 +19182,116 @@ public final class ActivityManagerService extends ActivityManagerNative UserHandle.USER_ALL); } + // Override configuration of the default display duplicates global config, so we need to + // update it also. This will also notify WindowManager about changes. + performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume, + DEFAULT_DISPLAY); + + return changes; + } + + @Override + public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) { + enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()"); + + synchronized (this) { + if (values == null && mWindowManager != null) { + // sentinel: fetch the current configuration from the window manager + values = mWindowManager.computeNewConfiguration(displayId); + } + + if (mWindowManager != null) { + // Update OOM levels based on display size. + mProcessList.applyDisplaySize(mWindowManager); + } + + final long origId = Binder.clearCallingIdentity(); + try { + if (values != null) { + Settings.System.clearConfiguration(values); + } + updateDisplayOverrideConfigurationLocked(values, null /* starting */, + false /* deferResume */, displayId, mTmpUpdateConfigurationResult); + return mTmpUpdateConfigurationResult.changes != 0; + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting, + boolean deferResume, int displayId) { + return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */, + displayId, null /* result */); + } + + /** + * Updates override configuration specific for the selected display. If no config is provided, + * new one will be computed in WM based on current display info. + */ + private boolean updateDisplayOverrideConfigurationLocked(Configuration values, + ActivityRecord starting, boolean deferResume, int displayId, + UpdateConfigurationResult result) { + int changes = 0; + boolean kept = true; + + if (mWindowManager != null) { + mWindowManager.deferSurfaceLayout(); + } + try { + if (values != null) { + if (displayId == DEFAULT_DISPLAY) { + // Override configuration of the default display duplicates global config, so + // we're calling global config update instead for default display. It will also + // apply the correct override config. + changes = updateGlobalConfiguration(values, false /* initLocale */, + false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume); + } else { + changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId); + } + } + + kept = ensureConfigAndVisibilityAfterUpdate(starting, changes); + } finally { + if (mWindowManager != null) { + mWindowManager.continueSurfaceLayout(); + } + } + + if (result != null) { + result.changes = changes; + result.activityRelaunched = !kept; + } + return kept; + } + + private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume, + int displayId) { + mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId)); + final int changes = mTempConfig.updateFrom(values); + if (changes == 0) { + return 0; + } + + Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " " + mTempConfig + + " for displayId=" + displayId); + mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId); + + final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0; + if (isDensityChange) { + // Reset the unsupported display size dialog. + mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG); + + killAllBackgroundProcessesExcept(N, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + } + // Update the configuration with WM first and check if any of the stacks need to be resized // due to the configuration change. If so, resize the stacks now and do any relaunches if // necessary. This way we don't need to relaunch again afterwards in // ensureActivityConfigurationLocked(). if (mWindowManager != null) { final int[] resizedStacks = - mWindowManager.setNewConfiguration(mTempGlobalConfig); + mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId); if (resizedStacks != null) { for (int stackId : resizedStacks) { resizeStackWithBoundsFromWindowManager(stackId, deferResume); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index b7618a1be408..abe4f30ae1e4 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1646,6 +1646,17 @@ final class ActivityRecord { return null; } + /** + * @return display id to which this record is attached, -1 if not attached. + */ + int getDisplayId() { + final ActivityStack stack = getStack(); + if (stack == null) { + return -1; + } + return stack.mDisplayId; + } + final boolean isDestroyable() { if (finishing || app == null || state == ActivityState.DESTROYING || state == ActivityState.DESTROYED) { @@ -1704,6 +1715,26 @@ final class ActivityRecord { } } + 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); + if (config != null) { + frozenBeforeDestroy = true; + if (!service.updateDisplayOverrideConfigurationLocked(config, this, + false /* deferResume */, displayId)) { + mStackSupervisor.resumeFocusedStackTopActivityLocked(); + } + } + } + // TODO: now used only in one place to address race-condition. Remove when that will be fixed. void setLastReportedConfiguration(@NonNull Configuration config) { mLastReportedConfiguration.setTo(config); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 55066fdad8ec..22d8078dac7e 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2285,13 +2285,14 @@ final class ActivityStack extends ConfigurationContainer { // the screen based on the new activity order. boolean notUpdated = true; if (mStackSupervisor.isFocusedStack(this)) { - Configuration config = mWindowManager.updateOrientationFromAppTokens( - mService.getGlobalConfiguration(), - next.mayFreezeScreenLocked(next.app) ? next.appToken : null); + final Configuration config = mWindowManager.updateOrientationFromAppTokens( + mStackSupervisor.getDisplayOverrideConfiguration(mDisplayId), + next.mayFreezeScreenLocked(next.app) ? next.appToken : null, mDisplayId); if (config != null) { next.frozenBeforeDestroy = true; } - notUpdated = !mService.updateConfigurationLocked(config, next, false); + notUpdated = !mService.updateDisplayOverrideConfigurationLocked(config, next, + false /* deferResume */, mDisplayId); } if (notUpdated) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index a111230c3546..ca36908e0eaa 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -419,7 +419,7 @@ public final class ActivityStackSupervisor extends ConfigurationContainer } @Override - protected ConfigurationContainer getChildAt(int index) { + protected ActivityDisplay getChildAt(int index) { return mActivityDisplays.valueAt(index); } @@ -428,6 +428,24 @@ public final class ActivityStackSupervisor extends ConfigurationContainer return null; } + Configuration getDisplayOverrideConfiguration(int displayId) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException("No display found with id: " + displayId); + } + + return activityDisplay.getOverrideConfiguration(); + } + + void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException("No display found with id: " + displayId); + } + + activityDisplay.onOverrideConfigurationChanged(overrideConfiguration); + } + static class FindTaskResult { ActivityRecord r; boolean matchedByRootAffinity; @@ -1190,20 +1208,20 @@ public final class ActivityStackSupervisor extends ConfigurationContainer r.startLaunchTickingLocked(); } - // Have the window manager re-evaluate the orientation of - // the screen based on the new activity order. Note that - // as a result of this, it can call back into the activity - // manager with a new orientation. We don't care about that, - // because the activity is not currently running so we are - // just restarting it anyway. + // Have the window manager re-evaluate the orientation of the screen based on the new + // activity order. Note that as a result of this, it can call back into the activity + // manager with a new orientation. We don't care about that, because the activity is not + // currently running so we are just restarting it anyway. if (checkConfig) { - Configuration config = mWindowManager.updateOrientationFromAppTokens( - mService.getGlobalConfiguration(), - r.mayFreezeScreenLocked(app) ? r.appToken : null); + final int displayId = r.getDisplayId(); + final Configuration config = mWindowManager.updateOrientationFromAppTokens( + getDisplayOverrideConfiguration(displayId), + r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId); // Deferring resume here because we're going to launch new activity shortly. // We don't want to perform a redundant launch of the same record while ensuring // configurations and trying to resume top activity of focused stack. - mService.updateConfigurationLocked(config, r, false, true /* deferResume */); + mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */, + displayId); } r.app = app; @@ -3156,6 +3174,20 @@ public final class ActivityStackSupervisor extends ConfigurationContainer } /** + * Dump all connected displays' configurations. + * @param prefix Prefix to apply to each line of the dump. + */ + void dumpDisplayConfigs(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println("Display override configurations:"); + final int displayCount = mActivityDisplays.size(); + for (int i = 0; i < displayCount; i++) { + final ActivityDisplay activityDisplay = mActivityDisplays.valueAt(i); + pw.print(prefix); pw.print(" "); pw.print(activityDisplay.mDisplayId); pw.print(": "); + pw.println(activityDisplay.getOverrideConfiguration()); + } + } + + /** * Dumps the activities matching the given {@param name} in the either the focused stack * or all visible stacks if {@param dumpVisibleStacks} is true. */ diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 56eaa83383c5..d46b53538643 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -949,7 +949,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.updateFocusedWindowLocked( UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/); - mService.getDefaultDisplayContentLocked().setLayoutNeeded(); + getDisplayContent().setLayoutNeeded(); mService.mWindowPlacerLocked.performSurfacePlacement(); Binder.restoreCallingIdentity(origId); return true; diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 8b5f62e51d21..f75f224d7123 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -371,6 +371,7 @@ public class DockedStackDividerController implements DimLayerUser { } void notifyDockedStackExistsChanged(boolean exists) { + // TODO(multi-display): Perform all actions only for current display. final int size = mDockedStackListeners.beginBroadcast(); for (int i = 0; i < size; ++i) { final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 065a3dca05ff..6a06ef3d9a18 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; @@ -384,7 +385,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { /* Notifies that the input device configuration has changed. */ @Override public void notifyConfigurationChanged() { - mService.sendNewConfiguration(); + // TODO(multi-display): Notify proper displays that are associated with this input device. + mService.sendNewConfiguration(DEFAULT_DISPLAY); synchronized (mInputDevicesReadyMonitor) { if (!mInputDevicesReady) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 24a0d1aff996..90e27ea3f6e0 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -236,7 +236,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { mService.configureDisplayPolicyLocked(dc); // TODO(multi-display): Create an input channel for each display with touch capability. - if (displayId == Display.DEFAULT_DISPLAY) { + if (displayId == DEFAULT_DISPLAY) { dc.mTapDetector = new TaskTapPointerEventListener( mService, dc); mService.registerPointerEventListener(dc.mTapDetector); @@ -274,8 +274,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { mService.mStackIdToStack.put(stackId, stack); if (stackId == DOCKED_STACK_ID) { - mService.getDefaultDisplayContentLocked().mDividerControllerLocked - .notifyDockedStackExistsChanged(true); + dc.mDividerControllerLocked.notifyDockedStackExistsChanged(true); } } @@ -569,8 +568,33 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { } } - /** Set new config and return array of ids of stacks that were changed during update. */ - int[] setGlobalConfigurationIfNeeded(Configuration newConfiguration) { + /** + * Set new display override config and return array of ids of stacks that were changed during + * update. If called for the default display, global configuration will also be updated. + */ + int[] setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration, int displayId) { + final DisplayContent displayContent = getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("Display not found for id: " + displayId); + } + + final Configuration currentConfig = displayContent.getOverrideConfiguration(); + final boolean configChanged = currentConfig.diff(newConfiguration) != 0; + if (!configChanged) { + return null; + } + displayContent.onOverrideConfigurationChanged(currentConfig); + + if (displayId == DEFAULT_DISPLAY) { + // Override configuration of the default display duplicates global config. In this case + // we also want to update the global config. + return setGlobalConfigurationIfNeeded(newConfiguration); + } else { + return updateStackBoundsAfterConfigChange(displayId); + } + } + + private int[] setGlobalConfigurationIfNeeded(Configuration newConfiguration) { final boolean configChanged = getConfiguration().diff(newConfiguration) != 0; if (!configChanged) { return null; @@ -603,6 +627,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList); } + /** Same as {@link #updateStackBoundsAfterConfigChange()} but only for a specific display. */ + private int[] updateStackBoundsAfterConfigChange(int displayId) { + mChangedStackList.clear(); + + final DisplayContent dc = getDisplayContent(displayId); + dc.updateStackBoundsAfterConfigChange(mChangedStackList); + + return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList); + } + private void prepareFreezingTaskBounds() { for (int i = mChildren.size() - 1; i >= 0; i--) { mChildren.get(i).prepareFreezingTaskBounds(); @@ -1145,8 +1179,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { if (mUpdateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); - if (mService.updateRotationUncheckedLocked(false)) { - mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION); + // TODO(multi-display): Update rotation for different displays separately. + final int displayId = defaultDisplay.getDisplayId(); + if (mService.updateRotationUncheckedLocked(false, displayId)) { + mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } else { mUpdateRotation = false; } @@ -1231,7 +1267,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { final int displayId = dc.getDisplayId(); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; - final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + final boolean isDefaultDisplay = (displayId == DEFAULT_DISPLAY); final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked; // Reset for each display. @@ -1259,9 +1295,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { if (isDefaultDisplay && (dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); - if (mService.updateOrientationFromAppTokensLocked(true)) { + if (mService.updateOrientationFromAppTokensLocked(true, displayId)) { dc.setLayoutNeeded(); - mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION); + mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 19c9b7d0fcf6..7f543f9e4a96 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -327,8 +327,9 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU * the adjusted bounds's top. */ void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) { - final Configuration overrideConfig = getOverrideConfiguration(); - if (!isResizeable() || Configuration.EMPTY.equals(overrideConfig)) { + // Task override config might be empty, while display or stack override config isn't, so + // we have to check merged override config here. + if (!isResizeable() || Configuration.EMPTY.equals(getMergedOverrideConfiguration())) { return; } @@ -340,7 +341,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top); } setTempInsetBounds(tempInsetBounds); - resizeLocked(mTmpRect2, overrideConfig, false /* forced */); + resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */); } /** Return true if the current bound can get outputted to the rest of the system as-is. */ diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 9effb8dc6c0a..5402f0ae7ff3 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -448,8 +448,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye // Calculate the current position. final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); - final int dividerSize = mService.getDefaultDisplayContentLocked() - .getDockedDividerController().getContentWidth(); + final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth(); final int dockSide = getDockSide(outBounds); final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, dockSide, dividerSize); @@ -783,13 +782,14 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mAnimationBackgroundSurface.destroySurface(); mAnimationBackgroundSurface = null; } + final DockedStackDividerController dividerController = + mDisplayContent.mDividerControllerLocked; mDisplayContent = null; mService.mWindowPlacerLocked.requestTraversal(); if (mStackId == DOCKED_STACK_ID) { - mService.getDefaultDisplayContentLocked().mDividerControllerLocked - .notifyDockedStackExistsChanged(false); + dividerController.notifyDockedStackExistsChanged(false); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 40001b22beb0..e6c951254635 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1413,7 +1413,7 @@ public class WindowManagerService extends IWindowManager.Stub win.applyAdjustForImeIfNeeded(); if (type == TYPE_DOCK_DIVIDER) { - getDefaultDisplayContentLocked().getDockedDividerController().setWindow(win); + mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win); } final WindowStateAnimator winAnimator = win.mWinAnimator; @@ -1480,13 +1480,13 @@ public class WindowManagerService extends IWindowManager.Stub if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client " + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5)); - if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { + if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false, displayId)) { reportNewConfig = true; } } if (reportNewConfig) { - sendNewConfiguration(); + sendNewConfiguration(displayId); } Binder.restoreCallingIdentity(origId); @@ -1881,11 +1881,13 @@ public class WindowManagerService extends IWindowManager.Stub == PackageManager.PERMISSION_GRANTED; long origId = Binder.clearCallingIdentity(); + final int displayId; synchronized(mWindowMap) { WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } + displayId = win.getDisplayId(); WindowStateAnimator winAnimator = win.mWinAnimator; if (viewVisibility != View.GONE) { @@ -2066,16 +2068,16 @@ public class WindowManagerService extends IWindowManager.Stub } if (wallpaperMayMove) { - getDefaultDisplayContentLocked().pendingLayoutChanges |= + win.getDisplayContent().pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; - configChanged = updateOrientationFromAppTokensLocked(false); + configChanged = updateOrientationFromAppTokensLocked(false, displayId); mWindowPlacerLocked.performSurfacePlacement(); if (toBeDisplayed && win.mIsWallpaper) { - DisplayInfo displayInfo = getDefaultDisplayInfoLocked(); + DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo(); dc.mWallpaperController.updateWallpaperOffset( win, displayInfo.logicalWidth, displayInfo.logicalHeight, false); } @@ -2121,7 +2123,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (configChanged) { - sendNewConfiguration(); + sendNewConfiguration(displayId); } Binder.restoreCallingIdentity(origId); return result; @@ -2156,9 +2158,8 @@ public class WindowManagerService extends IWindowManager.Stub } win.destroyOrSaveSurface(); } - //TODO (multidisplay): Magnification is supported only for the default - if (mAccessibilityController != null - && win.getDisplayId() == DEFAULT_DISPLAY) { + // TODO(multidisplay): Magnification is supported only for the default display. + if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) { mAccessibilityController.onWindowTransitionLocked(win, transit); } return focusMayChange; @@ -2278,7 +2279,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void finishDrawingWindow(Session session, IWindow client) { + void finishDrawingWindow(Session session, IWindow client) { final long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { @@ -2287,7 +2288,7 @@ public class WindowManagerService extends IWindowManager.Stub + (win != null ? win.mWinAnimator.drawStateToString() : "null")); if (win != null && win.mWinAnimator.finishDrawingLocked()) { if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { - getDefaultDisplayContentLocked().pendingLayoutChanges |= + win.getDisplayContent().pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } win.setDisplayLayoutNeeded(); @@ -2530,32 +2531,34 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public Configuration updateOrientationFromAppTokens( - Configuration currentConfig, IBinder freezeThisOneIfNeeded) { + public Configuration updateOrientationFromAppTokens(Configuration currentConfig, + IBinder freezeThisOneIfNeeded, int displayId) { if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - Configuration config = null; - long ident = Binder.clearCallingIdentity(); - - synchronized(mWindowMap) { - config = updateOrientationFromAppTokensLocked(currentConfig, - freezeThisOneIfNeeded); + final Configuration config; + final long ident = Binder.clearCallingIdentity(); + try { + synchronized(mWindowMap) { + config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded, + displayId); + } + } finally { + Binder.restoreCallingIdentity(ident); } - Binder.restoreCallingIdentity(ident); return config; } - private Configuration updateOrientationFromAppTokensLocked( - Configuration currentConfig, IBinder freezeThisOneIfNeeded) { + private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig, + IBinder freezeThisOneIfNeeded, int displayId) { if (!mDisplayReady) { return null; } Configuration config = null; - if (updateOrientationFromAppTokensLocked(false)) { + if (updateOrientationFromAppTokensLocked(false, displayId)) { // If we changed the orientation but mOrientationChangeComplete is already true, // we used seamless rotation, and we don't need to freeze the screen. if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) { @@ -2564,7 +2567,7 @@ public class WindowManagerService extends IWindowManager.Stub atoken.startFreezingScreen(); } } - config = computeNewConfigurationLocked(); + config = computeNewConfigurationLocked(displayId); } else if (currentConfig != null) { // No obvious action we need to take, but if our current state mismatches the activity @@ -2574,10 +2577,10 @@ public class WindowManagerService extends IWindowManager.Stub // to keep override configs clear of non-empty values (e.g. fontSize). mTempConfiguration.unset(); mTempConfiguration.updateFrom(currentConfig); - computeScreenConfigurationLocked(mTempConfiguration); + computeScreenConfigurationLocked(mTempConfiguration, displayId); if (currentConfig.diff(mTempConfiguration) != 0) { mWaitingForConfig = true; - final DisplayContent displayContent = getDefaultDisplayContentLocked(); + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); displayContent.setLayoutNeeded(); int anim[] = new int[2]; if (displayContent.isDimming()) { @@ -2593,31 +2596,28 @@ public class WindowManagerService extends IWindowManager.Stub return config; } - /* - * Determine the new desired orientation of the display, returning - * a non-null new Configuration if it has changed from the current - * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL - * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE - * SCREEN. This will typically be done for you if you call - * sendNewConfiguration(). + /** + * Determine the new desired orientation of the display, returning a non-null new Configuration + * if it has changed from the current orientation. IF TRUE IS RETURNED SOMEONE MUST CALL + * {@link #setNewDisplayOverrideConfiguration(Configuration, int)} TO TELL THE WINDOW MANAGER IT + * CAN UNFREEZE THE SCREEN. This will typically be done for you if you call + * {@link #sendNewConfiguration(int)}. * - * The orientation is computed from non-application windows first. If none of - * the non-application windows specify orientation, the orientation is computed from - * application tokens. - * @see android.view.IWindowManager#updateOrientationFromAppTokens( - * android.os.IBinder) + * The orientation is computed from non-application windows first. If none of the + * non-application windows specify orientation, the orientation is computed from application + * tokens. + * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int) */ - boolean updateOrientationFromAppTokensLocked(boolean inTransaction) { + boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) { long ident = Binder.clearCallingIdentity(); try { - // TODO: multi-display - int req = getDefaultDisplayContentLocked().getOrientation(); + final int req = mRoot.getDisplayContent(displayId).getOrientation(); if (req != mLastOrientation) { mLastOrientation = req; //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); - if (updateRotationUncheckedLocked(inTransaction)) { + if (updateRotationUncheckedLocked(inTransaction, displayId)) { // changed return true; } @@ -2643,8 +2643,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public int[] setNewConfiguration(Configuration config) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewConfiguration()")) { + public int[] setNewDisplayOverrideConfiguration(Configuration overrideConfig, int displayId) { + if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewDisplayOverrideConfiguration()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } @@ -2653,7 +2653,7 @@ public class WindowManagerService extends IWindowManager.Stub mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } - return mRoot.setGlobalConfigurationIfNeeded(config); + return mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, displayId); } } @@ -4436,8 +4436,9 @@ public class WindowManagerService extends IWindowManager.Stub } try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); - return screenshotApplicationsInner(null, DEFAULT_DISPLAY, -1, -1, true, 1f, - Bitmap.Config.ARGB_8888, true); + return screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, + -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */, + Bitmap.Config.ARGB_8888, true /* wallpaperOnly */); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @@ -4455,15 +4456,13 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } - FgThread.getHandler().post(new Runnable() { - @Override - public void run() { - Bitmap bm = screenshotApplicationsInner(null, DEFAULT_DISPLAY, -1, -1, - true, 1f, Bitmap.Config.ARGB_8888, false); - try { - receiver.send(bm); - } catch (RemoteException e) { - } + FgThread.getHandler().post(() -> { + Bitmap bm = screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, + -1 /* width */, -1 /* height */, true /* includeFullDisplay */, + 1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */); + try { + receiver.send(bm); + } catch (RemoteException e) { } }); @@ -4864,16 +4863,17 @@ public class WindowManagerService extends IWindowManager.Stub if (mDeferredRotationPauseCount > 0) { mDeferredRotationPauseCount -= 1; if (mDeferredRotationPauseCount == 0) { - boolean changed = updateRotationUncheckedLocked(false); + // TODO(multi-display): Update rotation for different displays separately. + final int displayId = DEFAULT_DISPLAY; + final boolean changed = updateRotationUncheckedLocked(false, displayId); if (changed) { - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } } } } - private void updateRotationUnchecked(boolean alwaysSendConfiguration, - boolean forceRelayout) { + private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:" + " alwaysSendConfiguration=" + alwaysSendConfiguration + " forceRelayout=" + forceRelayout); @@ -4882,8 +4882,10 @@ public class WindowManagerService extends IWindowManager.Stub try { final boolean rotationChanged; + // TODO(multi-display): Update rotation for different displays separately. + int displayId = DEFAULT_DISPLAY; synchronized (mWindowMap) { - rotationChanged = updateRotationUncheckedLocked(false); + rotationChanged = updateRotationUncheckedLocked(false, displayId); if (!rotationChanged || forceRelayout) { getDefaultDisplayContentLocked().setLayoutNeeded(); mWindowPlacerLocked.performSurfacePlacement(); @@ -4891,22 +4893,20 @@ public class WindowManagerService extends IWindowManager.Stub } if (rotationChanged || alwaysSendConfiguration) { - sendNewConfiguration(); + sendNewConfiguration(displayId); } } finally { Binder.restoreCallingIdentity(origId); } } - - // TODO(multidisplay): Rotate any display? /** - * Updates the current rotation. + * Updates the current rotation of the specified display. * - * Returns true if the rotation has been changed. In this case YOU - * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. + * Returns true if the rotation has been changed. In this case YOU MUST CALL + * {@link #sendNewConfiguration(int)} TO UNFREEZE THE SCREEN. */ - boolean updateRotationUncheckedLocked(boolean inTransaction) { + boolean updateRotationUncheckedLocked(boolean inTransaction, int displayId) { if (mDeferredRotationPauseCount > 0) { // Rotation updates have been paused temporarily. Defer the update until // updates have been resumed. @@ -4915,7 +4915,7 @@ public class WindowManagerService extends IWindowManager.Stub } ScreenRotationAnimation screenRotationAnimation = - mAnimator.getScreenRotationAnimationLocked(DEFAULT_DISPLAY); + mAnimator.getScreenRotationAnimationLocked(displayId); if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { // Rotation updates cannot be performed while the previous rotation change // animation is still in progress. Skip this update. We will try updating @@ -4937,7 +4937,7 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - final DisplayContent displayContent = getDefaultDisplayContentLocked(); + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); final WindowList windows = displayContent.getWindowList(); final int oldRotation = mRotation; @@ -5017,7 +5017,7 @@ public class WindowManagerService extends IWindowManager.Stub startFreezingDisplayLocked(inTransaction, anim[0], anim[1]); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. screenRotationAnimation = - mAnimator.getScreenRotationAnimationLocked(DEFAULT_DISPLAY); + mAnimator.getScreenRotationAnimationLocked(displayId); } else { // The screen rotation animation uses a screenshot to freeze the screen // while windows resize underneath. @@ -5035,7 +5035,7 @@ public class WindowManagerService extends IWindowManager.Stub // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). // By updating the Display info here it will be available to // computeScreenConfigurationLocked later. - updateDisplayAndOrientationLocked(mRoot.getConfiguration().uiMode); + updateDisplayAndOrientationLocked(displayContent.getConfiguration().uiMode, displayId); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (!inTransaction) { @@ -5568,13 +5568,14 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * Instruct the Activity Manager to fetch new configurations, update global configuration - * and broadcast changes to config-changed listeners if appropriate. + * Instruct the Activity Manager to fetch and update the current display's configuration and + * broadcast them to config-changed listeners if appropriate. * NOTE: Can't be called with the window manager lock held since it call into activity manager. */ - void sendNewConfiguration() { + void sendNewConfiguration(int displayId) { try { - final boolean configUpdated = mActivityManager.updateConfiguration(null); + final boolean configUpdated = mActivityManager.updateDisplayOverrideConfiguration( + null /* values */, displayId); if (!configUpdated) { // Something changed (E.g. device rotation), but no configuration update is needed. // E.g. changing device rotation by 180 degrees. Go ahead and perform surface @@ -5584,7 +5585,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mWaitingForConfig) { mWaitingForConfig = false; mLastFinishedFreezeSource = "config-unchanged"; - getDefaultDisplayContentLocked().setLayoutNeeded(); + mRoot.getDisplayContent(displayId).setLayoutNeeded(); mWindowPlacerLocked.performSurfacePlacement(); } } @@ -5593,18 +5594,18 @@ public class WindowManagerService extends IWindowManager.Stub } } - public Configuration computeNewConfiguration() { + public Configuration computeNewConfiguration(int displayId) { synchronized (mWindowMap) { - return computeNewConfigurationLocked(); + return computeNewConfigurationLocked(displayId); } } - private Configuration computeNewConfigurationLocked() { + private Configuration computeNewConfigurationLocked(int displayId) { if (!mDisplayReady) { return null; } - Configuration config = new Configuration(); - computeScreenConfigurationLocked(config); + final Configuration config = new Configuration(); + computeScreenConfigurationLocked(config, displayId); return config; } @@ -5713,9 +5714,8 @@ public class WindowManagerService extends IWindowManager.Stub } /** Do not call if mDisplayReady == false */ - DisplayInfo updateDisplayAndOrientationLocked(int uiMode) { - // TODO(multidisplay): For now, apply Configuration to main screen only. - final DisplayContent displayContent = getDefaultDisplayContentLocked(); + private DisplayInfo updateDisplayAndOrientationLocked(int uiMode, int displayId) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); // Use the effective "visual" dimensions based on current rotation final boolean rotated = (mRotation == Surface.ROTATION_90 @@ -5776,9 +5776,8 @@ public class WindowManagerService extends IWindowManager.Stub } /** Do not call if mDisplayReady == false */ - void computeScreenConfigurationLocked(Configuration config) { - final DisplayInfo displayInfo = updateDisplayAndOrientationLocked( - config.uiMode); + private void computeScreenConfigurationLocked(Configuration config, int displayId) { + final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(config.uiMode, displayId); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; @@ -6417,11 +6416,9 @@ public class WindowManagerService extends IWindowManager.Stub View view = null; try { - final Configuration overrideConfig = - wtoken != null ? wtoken.getMergedOverrideConfiguration() : null; view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme, sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, - sd.windowFlags, overrideConfig); + sd.windowFlags, wtoken.getMergedOverrideConfiguration()); } catch (Exception e) { Slog.w(TAG_WM, "Exception when adding starting window", e); } @@ -6668,8 +6665,9 @@ public class WindowManagerService extends IWindowManager.Stub } case SEND_NEW_CONFIGURATION: { - removeMessages(SEND_NEW_CONFIGURATION); - sendNewConfiguration(); + removeMessages(SEND_NEW_CONFIGURATION, msg.obj); + final int displayId = (Integer) msg.obj; + sendNewConfiguration(displayId); break; } @@ -7317,16 +7315,19 @@ public class WindowManagerService extends IWindowManager.Stub configureDisplayPolicyLocked(displayContent); displayContent.setLayoutNeeded(); - boolean configChanged = updateOrientationFromAppTokensLocked(false); - final Configuration globalConfig = mRoot.getConfiguration(); - mTempConfiguration.setTo(globalConfig); - computeScreenConfigurationLocked(mTempConfiguration); - configChanged |= globalConfig.diff(mTempConfiguration) != 0; + final int displayId = displayContent.getDisplayId(); + boolean configChanged = updateOrientationFromAppTokensLocked(false /* inTransaction */, + displayId); + final Configuration currentDisplayConfig = displayContent.getConfiguration(); + mTempConfiguration.setTo(currentDisplayConfig); + computeScreenConfigurationLocked(mTempConfiguration, displayId); + configChanged |= currentDisplayConfig.diff(mTempConfiguration) != 0; if (configChanged) { mWaitingForConfig = true; - startFreezingDisplayLocked(false, 0, 0); - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + startFreezingDisplayLocked(false /* inTransaction */, 0 /* exitAnim */, + 0 /* enterAnim */); + mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } mWindowPlacerLocked.performSurfacePlacement(); @@ -7744,7 +7745,7 @@ public class WindowManagerService extends IWindowManager.Stub // to avoid inconsistent states. However, something interesting // could have actually changed during that time so re-evaluate it // now to catch that. - configChanged = updateOrientationFromAppTokensLocked(false); + configChanged = updateOrientationFromAppTokensLocked(false, displayId); // A little kludge: a lot could have happened while the // display was frozen, so now that we are coming back we @@ -7758,11 +7759,11 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation"); - configChanged |= updateRotationUncheckedLocked(false); + configChanged |= updateRotationUncheckedLocked(false, displayId); } if (configChanged) { - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } } @@ -8887,8 +8888,9 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) { Slog.i(TAG, "Performing post-rotate rotation after seamless rotation"); } - if (updateRotationUncheckedLocked(false)) { - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + final int displayId = w.getDisplayId(); + if (updateRotationUncheckedLocked(false, displayId)) { + mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f80e08543e65..a7b46111379b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -38,7 +38,6 @@ import android.os.WorkSource; import android.util.DisplayMetrics; import android.util.Slog; import android.util.TimeUtils; -import android.view.Display; import android.view.DisplayInfo; import android.view.Gravity; import android.view.IApplicationToken; @@ -1670,7 +1669,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP //TODO (multidisplay): Accessibility supported only for the default display. if (mService.mAccessibilityController != null - && getDisplayContent().getDisplayId() == Display.DEFAULT_DISPLAY) { + && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) { mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(); } @@ -1831,6 +1830,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Visibility of the removed window. Will be used later to update orientation later on. boolean wasVisible = false; + final int displayId = getDisplayId(); + // First, see if we need to run an animation. If we do, we have to hold off on removing the // window until the animation is done. If the display is frozen, just remove immediately, // since the animation wouldn't be seen. @@ -1891,8 +1892,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mAnimatingExit = true; } //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mAccessibilityController != null - && getDisplayId() == Display.DEFAULT_DISPLAY) { + if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) { mService.mAccessibilityController.onWindowTransitionLocked(this, transit); } } @@ -1922,8 +1922,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP removeImmediately(); // Removing a visible window will effect the computed orientation // So just update orientation if needed. - if (wasVisible && mService.updateOrientationFromAppTokensLocked(false)) { - mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION); + if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) { + mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); Binder.restoreCallingIdentity(origId); @@ -3037,8 +3037,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } //TODO (multidisplay): Accessibility supported only for the default display. - if (mService.mAccessibilityController != null - && getDisplayId() == Display.DEFAULT_DISPLAY) { + if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) { mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 85b0d967283e..62947eb9110e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -118,6 +118,8 @@ import java.util.Locale; import java.util.Timer; import java.util.TimerTask; +import static android.view.Display.DEFAULT_DISPLAY; + public final class SystemServer { private static final String TAG = "SystemServer"; @@ -1403,7 +1405,7 @@ public final class SystemServer { // Update the configuration for this context by hand, because we're going // to start using it before the config change done in wm.systemReady() will // propagate to it. - Configuration config = wm.computeNewConfiguration(); + final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY); DisplayMetrics metrics = new DisplayMetrics(); WindowManager w = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); w.getDefaultDisplay().getMetrics(metrics); 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 84243445428a..f737b247a7f5 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -25,6 +25,7 @@ import android.view.IWindowManager; import junit.framework.TestCase; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.view.Display.DEFAULT_DISPLAY; /** * TODO: Remove this. This is only a placeholder, need to implement this. @@ -113,7 +114,8 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.updateOrientationFromAppTokens(new Configuration(), null); + mWm.updateOrientationFromAppTokens(new Configuration(), + null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY); fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as" + " expected"); } catch (SecurityException e) { diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 09ab65700c46..6b4db42324e9 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -413,7 +413,8 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public int[] setNewConfiguration(Configuration arg0) throws RemoteException { + public int[] setNewDisplayOverrideConfiguration(Configuration arg0, int displayId) + throws RemoteException { // TODO Auto-generated method stub return null; } @@ -487,7 +488,7 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1) + public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1, int arg2) throws RemoteException { // TODO Auto-generated method stub return null; |