From e36d6e277e49475076b7872d36ea6a5c5b996e9d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 17 Feb 2010 19:46:25 -0800 Subject: [PATCH] Work on issue #2263557: PMF3000 showing hybrid of portrait and landscape modes This is a bunch of reworking of how configuration changes are handled: - When orientation is changing (for whatever reason), the window manager no longer tries to pre-emptively compute a new configuration. Instead, it just determines change is happening and tells the window manager. - The activity manager is now responsible for giving the window manager the final configuration it is using. This is both so it knows whem the activity manager is done with its configuration updates, and so the window manager can use the "real" configuration. - When an orientation or other configuration change is happening, freeze the screen and keep it frozen until the activity manager has given us the final configuration. - The window manager can now send new configurations to its clients during its layout pass, as part of a resize, if it has determined that it has changed. This allows for a new View.onConfigurationChanged() API for any view to easily find out when the configuration has changed. - ViewRoot now also works with the activity thread to make sure the process's current resources are updated to the new configuration when it receives one from a window. This ensures that at the time onConfigurationChanged() and other view callbacks are happening, the correct configuration is in force. - There is now a sequence number associated with Configuration, which ActivityThread uses to avoid using stale configurations. This is needed now that it can receive configurations asynchronously from both the window manager and activity manager. - The hack for keeping the locale has been removed, and underlying problem fixed by having Configuration initialize its locale to "unknown" instead of a valid default value. --- api/current.xml | 26 ++ core/java/android/app/ActivityThread.java | 153 +++++--- core/java/android/content/res/Configuration.java | 48 ++- core/java/android/content/res/Resources.java | 4 + .../service/wallpaper/WallpaperService.java | 3 +- core/java/android/view/IWindow.aidl | 3 +- core/java/android/view/IWindowManager.aidl | 9 +- core/java/android/view/SurfaceView.java | 3 +- core/java/android/view/View.java | 27 ++ core/java/android/view/ViewGroup.java | 14 + core/java/android/view/ViewRoot.java | 51 ++- .../com/android/internal/view/BaseIWindow.java | 3 +- .../com/android/server/WindowManagerService.java | 395 ++++++++++++--------- .../android/server/am/ActivityManagerService.java | 31 +- .../src/com/android/layoutlib/bridge/Bridge.java | 3 +- 15 files changed, 516 insertions(+), 257 deletions(-) diff --git a/api/current.xml b/api/current.xml index 6b277f39d438..c0a76f872c66 100644 --- a/api/current.xml +++ b/api/current.xml @@ -173008,6 +173008,19 @@ visibility="public" > + + + + + + + + (); AppBindData mBoundApplication; Configuration mConfiguration; + Configuration mResConfiguration; Application mInitialApplication; final ArrayList mAllApplications = new ArrayList(); @@ -2073,14 +2077,6 @@ public final class ActivityThread { boolean mSystemThread = false; boolean mJitEnabled = false; - /** - * Activities that are enqueued to be relaunched. This list is accessed - * by multiple threads, so you must synchronize on it when accessing it. - */ - final ArrayList mRelaunchingActivities - = new ArrayList(); - Configuration mPendingConfiguration = null; - // These can be accessed by multiple threads; mPackages is the lock. // XXX For now we keep around information about all packages we have // seen, not removing entries from this map. @@ -2092,6 +2088,9 @@ public final class ActivityThread { DisplayMetrics mDisplayMetrics = null; HashMap > mActiveResources = new HashMap >(); + final ArrayList mRelaunchingActivities + = new ArrayList(); + Configuration mPendingConfiguration = null; // The lock of mProviderMap protects the following variables. final HashMap mProviderMap @@ -3555,7 +3554,7 @@ public final class ActivityThread { // First: make sure we have the most recent configuration and most // recent version of the activity, or skip it if some previous call // had taken a more recent version. - synchronized (mRelaunchingActivities) { + synchronized (mPackages) { int N = mRelaunchingActivities.size(); IBinder token = tmp.token; tmp = null; @@ -3585,8 +3584,12 @@ public final class ActivityThread { // assume that is really what we want regardless of what we // may have pending. if (mConfiguration == null - || mConfiguration.diff(tmp.createdConfig) != 0) { - changedConfig = tmp.createdConfig; + || (tmp.createdConfig.isOtherSeqNewer(mConfiguration) + && mConfiguration.diff(tmp.createdConfig) != 0)) { + if (changedConfig == null + || tmp.createdConfig.isOtherSeqNewer(changedConfig)) { + changedConfig = tmp.createdConfig; + } } } @@ -3761,62 +3764,81 @@ public final class ActivityThread { } } + final void applyConfigurationToResourcesLocked(Configuration config) { + if (mResConfiguration == null) { + mResConfiguration = new Configuration(); + } + if (!mResConfiguration.isOtherSeqNewer(config)) { + return; + } + mResConfiguration.updateFrom(config); + DisplayMetrics dm = getDisplayMetricsLocked(true); + + // set it for java, this also affects newly created Resources + if (config.locale != null) { + Locale.setDefault(config.locale); + } + + Resources.updateSystemConfiguration(config, dm); + + ContextImpl.ApplicationPackageManager.configurationChanged(); + //Log.i(TAG, "Configuration changed in " + currentPackageName()); + + Iterator> it = + mActiveResources.values().iterator(); + //Iterator>> it = + // mActiveResources.entrySet().iterator(); + while (it.hasNext()) { + WeakReference v = it.next(); + Resources r = v.get(); + if (r != null) { + r.updateConfiguration(config, dm); + //Log.i(TAG, "Updated app resources " + v.getKey() + // + " " + r + ": " + r.getConfiguration()); + } else { + //Log.i(TAG, "Removing old resources " + v.getKey()); + it.remove(); + } + } + } + final void handleConfigurationChanged(Configuration config) { - synchronized (mRelaunchingActivities) { + ArrayList callbacks = null; + + synchronized (mPackages) { if (mPendingConfiguration != null) { - config = mPendingConfiguration; + if (!mPendingConfiguration.isOtherSeqNewer(config)) { + config = mPendingConfiguration; + } mPendingConfiguration = null; } - } - - ArrayList callbacks - = new ArrayList(); - if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: " - + config); + if (config == null) { + return; + } + + if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: " + + config); - synchronized(mPackages) { + applyConfigurationToResourcesLocked(config); + if (mConfiguration == null) { mConfiguration = new Configuration(); } - mConfiguration.updateFrom(config); - DisplayMetrics dm = getDisplayMetricsLocked(true); - - // set it for java, this also affects newly created Resources - if (config.locale != null) { - Locale.setDefault(config.locale); - } - - Resources.updateSystemConfiguration(config, dm); - - ContextImpl.ApplicationPackageManager.configurationChanged(); - //Log.i(TAG, "Configuration changed in " + currentPackageName()); - { - Iterator> it = - mActiveResources.values().iterator(); - //Iterator>> it = - // mActiveResources.entrySet().iterator(); - while (it.hasNext()) { - WeakReference v = it.next(); - Resources r = v.get(); - if (r != null) { - r.updateConfiguration(config, dm); - //Log.i(TAG, "Updated app resources " + v.getKey() - // + " " + r + ": " + r.getConfiguration()); - } else { - //Log.i(TAG, "Removing old resources " + v.getKey()); - it.remove(); - } - } + if (!mConfiguration.isOtherSeqNewer(config)) { + return; } + mConfiguration.updateFrom(config); callbacks = collectComponentCallbacksLocked(false, config); } - final int N = callbacks.size(); - for (int i=0; i callbacks = new ArrayList(); - synchronized(mPackages) { + synchronized (mPackages) { callbacks = collectComponentCallbacksLocked(true, null); } @@ -4348,6 +4370,25 @@ public final class ActivityThread { "Unable to instantiate Application():" + e.toString(), e); } } + + ViewRoot.addConfigCallback(new ComponentCallbacks() { + public void onConfigurationChanged(Configuration newConfig) { + synchronized (mPackages) { + if (mPendingConfiguration == null || + mPendingConfiguration.isOtherSeqNewer(newConfig)) { + mPendingConfiguration = newConfig; + + // We need to apply this change to the resources + // immediately, because upon returning the view + // hierarchy will be informed about it. + applyConfigurationToResourcesLocked(newConfig); + } + } + queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig); + } + public void onLowMemory() { + } + }); } private final void detach() diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index aa5f12826dd4..6490b65c947e 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -193,6 +193,11 @@ public final class Configuration implements Parcelable, Comparable>> OPEN TRANSACTION"); Surface.openTransaction(); @@ -2203,7 +2205,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { - WindowState w = windowForClientLocked(session, client); + WindowState w = windowForClientLocked(session, client, false); if (w != null) { w.mGivenInsetsPending = false; w.mGivenContentInsets.set(contentInsets); @@ -2221,7 +2223,7 @@ public class WindowManagerService extends IWindowManager.Stub public void getWindowDisplayFrame(Session session, IWindow client, Rect outDisplayFrame) { synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win == null) { outDisplayFrame.setEmpty(); return; @@ -2291,11 +2293,11 @@ public class WindowManagerService extends IWindowManager.Stub Surface outSurface) { boolean displayed = false; boolean inTouchMode; - Configuration newConfig = null; + boolean configChanged; long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } @@ -2507,7 +2509,7 @@ public class WindowManagerService extends IWindowManager.Stub if (assignLayers) { assignLayersLocked(); } - newConfig = updateOrientationFromAppTokensLocked(null, null); + configChanged = updateOrientationFromAppTokensLocked(); performLayoutAndPlaceSurfacesLocked(); if (displayed && win.mIsWallpaper) { updateWallpaperOffsetLocked(win, mDisplay.getWidth(), @@ -2533,7 +2535,7 @@ public class WindowManagerService extends IWindowManager.Stub inTouchMode = mInTouchMode; } - if (newConfig != null) { + if (configChanged) { sendNewConfiguration(); } @@ -2546,7 +2548,7 @@ public class WindowManagerService extends IWindowManager.Stub public void finishDrawingWindow(Session session, IWindow client) { final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); + WindowState win = windowForClientLocked(session, client, false); if (win != null && win.finishDrawingLocked()) { if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { adjustWallpaperWindowsLocked(); @@ -2988,62 +2990,62 @@ public class WindowManagerService extends IWindowManager.Stub } public int getOrientationFromAppTokensLocked() { - int pos = mAppTokens.size() - 1; - int curGroup = 0; - int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - boolean findingBehind = false; - boolean haveGroup = false; - boolean lastFullscreen = false; - while (pos >= 0) { - AppWindowToken wtoken = mAppTokens.get(pos); - pos--; - // if we're about to tear down this window and not seek for - // the behind activity, don't use it for orientation - if (!findingBehind - && (!wtoken.hidden && wtoken.hiddenRequested)) { + int pos = mAppTokens.size() - 1; + int curGroup = 0; + int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + boolean findingBehind = false; + boolean haveGroup = false; + boolean lastFullscreen = false; + while (pos >= 0) { + AppWindowToken wtoken = mAppTokens.get(pos); + pos--; + // if we're about to tear down this window and not seek for + // the behind activity, don't use it for orientation + if (!findingBehind + && (!wtoken.hidden && wtoken.hiddenRequested)) { + continue; + } + + if (!haveGroup) { + // We ignore any hidden applications on the top. + if (wtoken.hiddenRequested || wtoken.willBeHidden) { continue; } - - if (!haveGroup) { - // We ignore any hidden applications on the top. - if (wtoken.hiddenRequested || wtoken.willBeHidden) { - continue; - } - haveGroup = true; - curGroup = wtoken.groupId; - lastOrientation = wtoken.requestedOrientation; - } else if (curGroup != wtoken.groupId) { - // If we have hit a new application group, and the bottom - // of the previous group didn't explicitly say to use - // the orientation behind it, and the last app was - // full screen, then we'll stick with the - // user's orientation. - if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND - && lastFullscreen) { - return lastOrientation; - } - } - int or = wtoken.requestedOrientation; - // If this application is fullscreen, and didn't explicitly say - // to use the orientation behind it, then just take whatever - // orientation it has and ignores whatever is under it. - lastFullscreen = wtoken.appFullscreen; - if (lastFullscreen - && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { - return or; - } - // If this application has requested an explicit orientation, - // then use it. - if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || - or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || - or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_USER) { - return or; - } - findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); - } - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + haveGroup = true; + curGroup = wtoken.groupId; + lastOrientation = wtoken.requestedOrientation; + } else if (curGroup != wtoken.groupId) { + // If we have hit a new application group, and the bottom + // of the previous group didn't explicitly say to use + // the orientation behind it, and the last app was + // full screen, then we'll stick with the + // user's orientation. + if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND + && lastFullscreen) { + return lastOrientation; + } + } + int or = wtoken.requestedOrientation; + // If this application is fullscreen, and didn't explicitly say + // to use the orientation behind it, then just take whatever + // orientation it has and ignores whatever is under it. + lastFullscreen = wtoken.appFullscreen; + if (lastFullscreen + && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { + return or; + } + // If this application has requested an explicit orientation, + // then use it. + if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || + or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || + or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || + or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || + or == ActivityInfo.SCREEN_ORIENTATION_USER) { + return or; + } + findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); + } + return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } public Configuration updateOrientationFromAppTokens( @@ -3053,81 +3055,75 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - Configuration config; + Configuration config = null; long ident = Binder.clearCallingIdentity(); - config = updateOrientationFromAppTokensUnchecked(currentConfig, - freezeThisOneIfNeeded); - Binder.restoreCallingIdentity(ident); - return config; - } - - Configuration updateOrientationFromAppTokensUnchecked( - Configuration currentConfig, IBinder freezeThisOneIfNeeded) { - Configuration config; + synchronized(mWindowMap) { - config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded); - if (config != null) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); + if (updateOrientationFromAppTokensLocked()) { + if (freezeThisOneIfNeeded != null) { + AppWindowToken wtoken = findAppWindowToken( + freezeThisOneIfNeeded); + if (wtoken != null) { + startAppFreezingScreenLocked(wtoken, + ActivityInfo.CONFIG_ORIENTATION); + } + } + config = computeNewConfigurationLocked(); + + } else if (currentConfig != null) { + // No obvious action we need to take, but if our current + // state mismatches the activity maanager's, update it + mTempConfiguration.setToDefaults(); + if (computeNewConfigurationLocked(mTempConfiguration)) { + if (currentConfig.diff(mTempConfiguration) != 0) { + mWaitingForConfig = true; + mLayoutNeeded = true; + startFreezingDisplayLocked(); + config = new Configuration(mTempConfiguration); + } + } } } + + Binder.restoreCallingIdentity(ident); 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(). + * * 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) */ - Configuration updateOrientationFromAppTokensLocked( - Configuration appConfig, IBinder freezeThisOneIfNeeded) { + boolean updateOrientationFromAppTokensLocked() { boolean changed = false; long ident = Binder.clearCallingIdentity(); try { int req = computeForcedAppOrientationLocked(); if (req != mForcedAppOrientation) { - changed = true; mForcedAppOrientation = req; //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); - } - - if (changed) { - changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, - mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)); - if (changed) { - if (freezeThisOneIfNeeded != null) { - AppWindowToken wtoken = findAppWindowToken( - freezeThisOneIfNeeded); - if (wtoken != null) { - startAppFreezingScreenLocked(wtoken, - ActivityInfo.CONFIG_ORIENTATION); - } - } - return computeNewConfigurationLocked(); + if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION, + mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)) { + changed = true; } } - // No obvious action we need to take, but if our current - // state mismatches the activity maanager's, update it - if (appConfig != null) { - mTempConfiguration.setToDefaults(); - if (computeNewConfigurationLocked(mTempConfiguration)) { - if (appConfig.diff(mTempConfiguration) != 0) { - return new Configuration(mTempConfiguration); - } - } - } + return changed; } finally { Binder.restoreCallingIdentity(ident); } - - return null; } int computeForcedAppOrientationLocked() { @@ -3138,6 +3134,19 @@ public class WindowManagerService extends IWindowManager.Stub return req; } + public void setNewConfiguration(Configuration config) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "setNewConfiguration()")) { + throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); + } + + synchronized(mWindowMap) { + mCurConfiguration = new Configuration(config); + mWaitingForConfig = false; + performLayoutAndPlaceSurfacesLocked(); + } + } + public void setAppOrientation(IApplicationToken token, int requestedOrientation) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "setAppOrientation()")) { @@ -3648,9 +3657,7 @@ public class WindowManagerService extends IWindowManager.Stub mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); } - if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) { - stopFreezingDisplayLocked(); - } + stopFreezingDisplayLocked(); } } } @@ -4403,20 +4410,21 @@ public class WindowManagerService extends IWindowManager.Stub changed = setRotationUncheckedLocked(rotation, animFlags); } - if (changed) { - sendNewConfiguration(); - synchronized(mWindowMap) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } else if (alwaysSendConfiguration) { - //update configuration ignoring orientation change + if (changed || alwaysSendConfiguration) { sendNewConfiguration(); } Binder.restoreCallingIdentity(origId); } + /** + * Apply a new rotation to the screen, respecting the requests of + * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply + * re-evaluate the desired rotation. + * + * Returns null if the rotation has been changed. In this case YOU + * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN. + */ public boolean setRotationUncheckedLocked(int rotation, int animFlags) { boolean changed; if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { @@ -4442,6 +4450,8 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); + mWaitingForConfig = true; + mLayoutNeeded = true; startFreezingDisplayLocked(); Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); mQueue.setOrientation(rotation); @@ -6707,7 +6717,8 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); try { return mPolicy.performHapticFeedbackLw( - windowForClientLocked(this, window), effectId, always); + windowForClientLocked(this, window, true), + effectId, always); } finally { Binder.restoreCallingIdentity(ident); } @@ -6718,7 +6729,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { long ident = Binder.clearCallingIdentity(); try { - setWindowWallpaperPositionLocked(windowForClientLocked(this, window), + setWindowWallpaperPositionLocked( + windowForClientLocked(this, window, true), x, y, xStep, yStep); } finally { Binder.restoreCallingIdentity(ident); @@ -6736,7 +6748,7 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); try { return sendWindowWallpaperCommandLocked( - windowForClientLocked(this, window), + windowForClientLocked(this, window, true), action, x, y, z, extras, sync); } finally { Binder.restoreCallingIdentity(ident); @@ -6852,6 +6864,10 @@ public class WindowManagerService extends IWindowManager.Stub WindowState mNextOutsideTouch; + int mLayoutSeq = -1; + + Configuration mConfiguration = null; + // Actual frame shown on-screen (may be modified by animation) final Rect mShownFrame = new Rect(); final Rect mLastShownFrame = new Rect(); @@ -7980,7 +7996,7 @@ public class WindowManagerService extends IWindowManager.Stub public void binderDied() { try { synchronized(mWindowMap) { - WindowState win = windowForClientLocked(mSession, mClient); + WindowState win = windowForClientLocked(mSession, mClient, false); Log.i(TAG, "WIN DEATH: " + win); if (win != null) { removeWindowLocked(mSession, win); @@ -8056,8 +8072,6 @@ public class WindowManagerService extends IWindowManager.Stub } void dump(PrintWriter pw, String prefix) { - StringBuilder sb = new StringBuilder(64); - pw.print(prefix); pw.print("mSession="); pw.print(mSession); pw.print(" mClient="); pw.println(mClient.asBinder()); pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs); @@ -8105,7 +8119,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled); } pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); - pw.print(" h="); pw.println(mRequestedHeight); + pw.print(" h="); pw.print(mRequestedHeight); + pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); if (mXOffset != 0 || mYOffset != 0) { pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); pw.print(" y="); pw.println(mYOffset); @@ -8119,6 +8134,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets); pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending); } + pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); pw.print(prefix); pw.print("mShownFrame="); mShownFrame.printShortString(pw); pw.print(" last="); mLastShownFrame.printShortString(pw); @@ -8693,7 +8709,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int FORCE_GC = 15; public static final int ENABLE_SCREEN = 16; public static final int APP_FREEZE_TIMEOUT = 17; - public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18; + public static final int SEND_NEW_CONFIGURATION = 18; private Session mLastReportedHold; @@ -9019,10 +9035,9 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case COMPUTE_AND_SEND_NEW_CONFIGURATION: { - if (updateOrientationFromAppTokensUnchecked(null, null) != null) { - sendNewConfiguration(); - } + case SEND_NEW_CONFIGURATION: { + removeMessages(SEND_NEW_CONFIGURATION); + sendNewConfiguration(); break; } @@ -9064,23 +9079,33 @@ public class WindowManagerService extends IWindowManager.Stub // Internals // ------------------------------------------------------------- - final WindowState windowForClientLocked(Session session, IWindow client) { - return windowForClientLocked(session, client.asBinder()); + final WindowState windowForClientLocked(Session session, IWindow client, + boolean throwOnError) { + return windowForClientLocked(session, client.asBinder(), throwOnError); } - final WindowState windowForClientLocked(Session session, IBinder client) { + final WindowState windowForClientLocked(Session session, IBinder client, + boolean throwOnError) { WindowState win = mWindowMap.get(client); if (localLOGV) Log.v( TAG, "Looking up client " + client + ": " + win); if (win == null) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " does not exist", ex); + RuntimeException ex = new IllegalArgumentException( + "Requested window " + client + " does not exist"); + if (throwOnError) { + throw ex; + } + Log.w(TAG, "Failed looking up window", ex); return null; } if (session != null && win.mSession != session) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " is in session " + - win.mSession + ", not " + session, ex); + RuntimeException ex = new IllegalArgumentException( + "Requested window " + client + " is in session " + + win.mSession + ", not " + session); + if (throwOnError) { + throw ex; + } + Log.w(TAG, "Failed looking up window", ex); return null; } @@ -9183,6 +9208,13 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mWaitingForConfig) { + // Our configuration has changed (most likely rotation), but we + // don't yet have the complete configuration to report to + // applications. Don't do any window layout until we have it. + return; + } + boolean recoveringMemory = false; if (mForceRemoves != null) { recoveringMemory = true; @@ -9249,6 +9281,10 @@ public class WindowManagerService extends IWindowManager.Stub while (mLayoutNeeded) { mPolicy.beginLayoutLw(dw, dh); + int seq = mLayoutSeq+1; + if (seq < 0) seq = 0; + mLayoutSeq = seq; + // First perform layout of any root windows (not attached // to another window). int topAttached = -1; @@ -9266,7 +9302,7 @@ public class WindowManagerService extends IWindowManager.Stub || win.mAttachedHidden || win.mExiting || win.mDestroying; - if (win.mLayoutAttached) { + if (!win.mLayoutAttached) { if (DEBUG_LAYOUT) Log.v(TAG, "First pass " + win + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame + " mLayoutAttached=" + win.mLayoutAttached); @@ -9286,6 +9322,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!gone || !win.mHaveFrame) { if (!win.mLayoutAttached) { mPolicy.layoutWindowLw(win, win.mAttrs, null); + win.mLayoutSeq = seq; if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame=" + win.mFrame + " mContainingFrame=" + win.mContainingFrame + " mDisplayFrame=" @@ -9316,6 +9353,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) || !win.mHaveFrame) { mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); + win.mLayoutSeq = seq; if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame=" + win.mFrame + " mContainingFrame=" + win.mContainingFrame + " mDisplayFrame=" @@ -9336,11 +9374,8 @@ public class WindowManagerService extends IWindowManager.Stub Log.w(TAG, "Layout repeat aborted after too many iterations"); mLayoutNeeded = false; if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { - Configuration newConfig = updateOrientationFromAppTokensLocked( - null, null); - if (newConfig != null) { - mLayoutNeeded = true; - mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION); + if (updateOrientationFromAppTokensLocked()) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } else { @@ -9349,10 +9384,8 @@ public class WindowManagerService extends IWindowManager.Stub repeats++; if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Log.v(TAG, "Computing new config from layout"); - Configuration newConfig = updateOrientationFromAppTokensLocked( - null, null); - if (newConfig != null) { - mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION); + if (updateOrientationFromAppTokensLocked()) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } @@ -9996,14 +10029,22 @@ public class WindowManagerService extends IWindowManager.Stub } } } - if (!w.mAppFreezing) { + if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { w.mContentInsetsChanged = !w.mLastContentInsets.equals(w.mContentInsets); w.mVisibleInsetsChanged = !w.mLastVisibleInsets.equals(w.mVisibleInsets); + boolean configChanged = + w.mConfiguration != mCurConfiguration + && (w.mConfiguration == null + || mCurConfiguration.diff(w.mConfiguration) != 0); + if (localLOGV) Log.v(TAG, "Resizing " + w + + ": configChanged=" + configChanged + + " last=" + w.mLastFrame + " frame=" + w.mFrame); if (!w.mLastFrame.equals(w.mFrame) || w.mContentInsetsChanged - || w.mVisibleInsetsChanged) { + || w.mVisibleInsetsChanged + || configChanged) { w.mLastFrame.set(w.mFrame); w.mLastContentInsets.set(w.mContentInsets); w.mLastVisibleInsets.set(w.mVisibleInsets); @@ -10014,7 +10055,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Log.v(TAG, "Resizing while display frozen: " + w); w.mOrientationChanging = true; - if (mWindowsFreezingScreen) { + if (!mWindowsFreezingScreen) { mWindowsFreezingScreen = true; // XXX should probably keep timeout from // when we first froze the display. @@ -10327,9 +10368,7 @@ public class WindowManagerService extends IWindowManager.Stub mWindowsFreezingScreen = false; mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); } - if (mAppsFreezingScreen == 0) { - stopFreezingDisplayLocked(); - } + stopFreezingDisplayLocked(); } i = mResizingWindows.size(); @@ -10340,9 +10379,20 @@ public class WindowManagerService extends IWindowManager.Stub try { if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to " + win + ": " + win.mFrame); + boolean configChanged = + win.mConfiguration != mCurConfiguration + && (win.mConfiguration == null + || mCurConfiguration.diff(win.mConfiguration) != 0); + win.mConfiguration = mCurConfiguration; + if (DEBUG_ORIENTATION && configChanged) { + Log.i(TAG, "Sending new config to window " + win + ": " + + win.mFrame.width() + "x" + win.mFrame.height() + + " / " + win.mConfiguration); + } win.mClient.resized(win.mFrame.width(), win.mFrame.height(), win.mLastContentInsets, - win.mLastVisibleInsets, win.mDrawPending); + win.mLastVisibleInsets, win.mDrawPending, + configChanged ? win.mConfiguration : null); win.mContentInsetsChanged = false; win.mVisibleInsetsChanged = false; } catch (RemoteException e) { @@ -10732,6 +10782,10 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) { + return; + } + mDisplayFrozen = false; mH.removeMessages(H.APP_FREEZE_TIMEOUT); if (PROFILE_ORIENTATION) { @@ -10921,7 +10975,9 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); } - pw.print(" mInTouchMode="); pw.println(mInTouchMode); + pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration); + pw.print(" mInTouchMode="); pw.print(mInTouchMode); + pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); pw.print(" mSystemBooted="); pw.print(mSystemBooted); pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); @@ -10939,7 +10995,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); - pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen); + pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); + pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); pw.print(" mRotation="); pw.print(mRotation); pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation); pw.print(", mRequestedRotation="); pw.println(mRequestedRotation); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 47a58cf03880..45c3f0057d31 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -766,6 +766,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Configuration mConfiguration = new Configuration(); /** + * Current sequencing integer of the configuration, for skipping old + * configurations. + */ + int mConfigurationSeq = 0; + + /** * Hardware-reported OpenGLES version. */ final int GL_ES_VERSION; @@ -2662,20 +2668,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mConfiguration, next.mayFreezeScreenLocked(next.app) ? next : null); if (config != null) { - /* - * Explicitly restore the locale to the one from the - * old configuration, since the one that comes back from - * the window manager has the default (boot) locale. - * - * It looks like previously the locale picker only worked - * by coincidence: usually it would do its setting of - * the locale after the activity transition, so it didn't - * matter that this lost it. With the synchronized - * block now keeping them from happening at the same time, - * this one always would happen second and undo what the - * locale picker had just done. - */ - config.locale = mConfiguration.locale; next.frozenBeforeDestroy = true; } updated = updateConfigurationLocked(config, next); @@ -8347,7 +8339,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mAlwaysFinishActivities = alwaysFinishActivities; // This happens before any activities are started, so we can // change mConfiguration in-place. + mConfiguration.locale = Locale.getDefault(); mConfiguration.updateFrom(configuration); + mConfigurationSeq = mConfiguration.seq = 1; if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration); } } @@ -13090,6 +13084,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen values.userSetLocale); } + mConfigurationSeq++; + if (mConfigurationSeq <= 0) { + mConfigurationSeq = 1; + } + newConfig.seq = mConfigurationSeq; mConfiguration = newConfig; Log.i(TAG, "Config changed: " + newConfig); @@ -13146,6 +13145,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + if (values != null && mWindowManager != null) { + mWindowManager.setNewConfiguration(mConfiguration); + } + return kept; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 990498f98915..41d9f9dde5a1 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -30,6 +30,7 @@ import com.android.ninepatch.NinePatch; import com.android.tools.layoutlib.create.MethodAdapter; import com.android.tools.layoutlib.create.OverrideMethod; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; @@ -1133,7 +1134,7 @@ public final class Bridge implements ILayoutBridge { } @SuppressWarnings("unused") - public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4) + public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5) throws RemoteException { // pass for now. } -- 2.11.0