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.
diff --git a/api/current.xml b/api/current.xml
index 6b277f3..c0a76f8 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -173008,6 +173008,19 @@
  visibility="public"
 >
 </method>
+<method name="dispatchConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
 <method name="dispatchDisplayHint"
  return="void"
  abstract="false"
@@ -174699,6 +174712,19 @@
  visibility="public"
 >
 </method>
+<method name="onConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
 <method name="onCreateContextMenu"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 56e44c8..13cc3ba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1392,7 +1392,7 @@
             r.startsNotResumed = notResumed;
             r.createdConfig = config;
 
-            synchronized (mRelaunchingActivities) {
+            synchronized (mPackages) {
                 mRelaunchingActivities.add(r);
             }
 
@@ -1523,8 +1523,11 @@
         }
 
         public void scheduleConfigurationChanged(Configuration config) {
-            synchronized (mRelaunchingActivities) {
-                mPendingConfiguration = config;
+            synchronized (mPackages) {
+                if (mPendingConfiguration == null ||
+                        mPendingConfiguration.isOtherSeqNewer(config)) {
+                    mPendingConfiguration = config;
+                }
             }
             queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
         }
@@ -2060,6 +2063,7 @@
             = new HashMap<IBinder, Service>();
     AppBindData mBoundApplication;
     Configuration mConfiguration;
+    Configuration mResConfiguration;
     Application mInitialApplication;
     final ArrayList<Application> mAllApplications
             = new ArrayList<Application>();
@@ -2073,14 +2077,6 @@
     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<ActivityRecord> mRelaunchingActivities
-            = new ArrayList<ActivityRecord>();
-    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 @@
     DisplayMetrics mDisplayMetrics = null;
     HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
         = new HashMap<ResourcesKey, WeakReference<Resources> >();
+    final ArrayList<ActivityRecord> mRelaunchingActivities
+            = new ArrayList<ActivityRecord>();
+        Configuration mPendingConfiguration = null;
 
     // The lock of mProviderMap protects the following variables.
     final HashMap<String, ProviderRecord> mProviderMap
@@ -3555,7 +3554,7 @@
         // 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 @@
             // 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 @@
         }
     }
 
-    final void handleConfigurationChanged(Configuration config) {
+    final void applyConfigurationToResourcesLocked(Configuration config) {
+        if (mResConfiguration == null) {
+            mResConfiguration = new Configuration();
+        }
+        if (!mResConfiguration.isOtherSeqNewer(config)) {
+            return;
+        }
+        mResConfiguration.updateFrom(config);
+        DisplayMetrics dm = getDisplayMetricsLocked(true);
 
-        synchronized (mRelaunchingActivities) {
-            if (mPendingConfiguration != null) {
-                config = mPendingConfiguration;
-                mPendingConfiguration = null;
-            }
+        // set it for java, this also affects newly created Resources
+        if (config.locale != null) {
+            Locale.setDefault(config.locale);
         }
 
-        ArrayList<ComponentCallbacks> callbacks
-                = new ArrayList<ComponentCallbacks>();
+        Resources.updateSystemConfiguration(config, dm);
 
-        if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
-                + config);
+        ContextImpl.ApplicationPackageManager.configurationChanged();
+        //Log.i(TAG, "Configuration changed in " + currentPackageName());
         
-        synchronized(mPackages) {
+        Iterator<WeakReference<Resources>> it =
+            mActiveResources.values().iterator();
+        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
+        //    mActiveResources.entrySet().iterator();
+        while (it.hasNext()) {
+            WeakReference<Resources> 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) {
+
+        ArrayList<ComponentCallbacks> callbacks = null;
+
+        synchronized (mPackages) {
+            if (mPendingConfiguration != null) {
+                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
+                    config = mPendingConfiguration;
+                }
+                mPendingConfiguration = null;
+            }
+
+            if (config == null) {
+                return;
+            }
+            
+            if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
+                    + config);
+        
+            applyConfigurationToResourcesLocked(config);
+            
             if (mConfiguration == null) {
                 mConfiguration = new Configuration();
             }
+            if (!mConfiguration.isOtherSeqNewer(config)) {
+                return;
+            }
             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<WeakReference<Resources>> it =
-                    mActiveResources.values().iterator();
-                //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
-                //    mActiveResources.entrySet().iterator();
-                while (it.hasNext()) {
-                    WeakReference<Resources> 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();
-                    }
-                }
-            }
 
             callbacks = collectComponentCallbacksLocked(false, config);
         }
 
-        final int N = callbacks.size();
-        for (int i=0; i<N; i++) {
-            performConfigurationChanged(callbacks.get(i), config);
+        if (callbacks != null) {
+            final int N = callbacks.size();
+            for (int i=0; i<N; i++) {
+                performConfigurationChanged(callbacks.get(i), config);
+            }
         }
     }
 
@@ -3856,7 +3878,7 @@
         ArrayList<ComponentCallbacks> callbacks
                 = new ArrayList<ComponentCallbacks>();
 
-        synchronized(mPackages) {
+        synchronized (mPackages) {
             callbacks = collectComponentCallbacksLocked(true, null);
         }
 
@@ -4348,6 +4370,25 @@
                         "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 aa5f128..6490b65 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -193,6 +193,11 @@
     public int uiMode;
 
     /**
+     * @hide Internal book-keeping.
+     */
+    public int seq;
+    
+    /**
      * Construct an invalid Configuration.  You must call {@link #setToDefaults}
      * for this object to be valid.  {@more}
      */
@@ -220,6 +225,7 @@
         orientation = o.orientation;
         screenLayout = o.screenLayout;
         uiMode = o.uiMode;
+        seq = o.seq;
     }
 
     public String toString() {
@@ -250,6 +256,10 @@
         sb.append(screenLayout);
         sb.append(" uiMode=");
         sb.append(uiMode);
+        if (seq != 0) {
+            sb.append(" seq=");
+            sb.append(seq);
+        }
         sb.append('}');
         return sb.toString();
     }
@@ -260,7 +270,7 @@
     public void setToDefaults() {
         fontScale = 1;
         mcc = mnc = 0;
-        locale = Locale.getDefault();
+        locale = null;
         userSetLocale = false;
         touchscreen = TOUCHSCREEN_UNDEFINED;
         keyboard = KEYBOARD_UNDEFINED;
@@ -271,6 +281,7 @@
         orientation = ORIENTATION_UNDEFINED;
         screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
         uiMode = UI_MODE_TYPE_NORMAL;
+        seq = 0;
     }
 
     /** {@hide} */
@@ -357,6 +368,10 @@
             uiMode = delta.uiMode;
         }
         
+        if (delta.seq != 0) {
+            seq = delta.seq;
+        }
+        
         return changed;
     }
 
@@ -456,6 +471,35 @@
     }
     
     /**
+     * @hide Return true if the sequence of 'other' is better than this.  Assumes
+     * that 'this' is your current sequence and 'other' is a new one you have
+     * received some how and want to compare with what you have.
+     */
+    public boolean isOtherSeqNewer(Configuration other) {
+        if (other == null) {
+            // Sanity check.
+            return false;
+        }
+        if (other.seq == 0) {
+            // If the other sequence is not specified, then we must assume
+            // it is newer since we don't know any better.
+            return true;
+        }
+        if (seq == 0) {
+            // If this sequence is not specified, then we also consider the
+            // other is better.  Yes we have a preference for other.  Sue us.
+            return true;
+        }
+        int diff = other.seq - seq;
+        if (diff > 0x10000) {
+            // If there has been a sufficiently large jump, assume the
+            // sequence has wrapped around.
+            return false;
+        }
+        return diff > 0;
+    }
+    
+    /**
      * Parcelable methods
      */
     public int describeContents() {
@@ -488,6 +532,7 @@
         dest.writeInt(orientation);
         dest.writeInt(screenLayout);
         dest.writeInt(uiMode);
+        dest.writeInt(seq);
     }
 
     public static final Parcelable.Creator<Configuration> CREATOR
@@ -522,6 +567,7 @@
         orientation = source.readInt();
         screenLayout = source.readInt();
         uiMode = source.readInt();
+        seq = source.readInt();
     }
 
     public int compareTo(Configuration that) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ae8e297..a5e39d4 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
+import java.util.Locale;
 
 /**
  * Class for accessing an application's resources.  This sits on top of the
@@ -1259,6 +1260,9 @@
             if (config != null) {
                 configChanges = mConfiguration.updateFrom(config);
             }
+            if (mConfiguration.locale == null) {
+                mConfiguration.locale = Locale.getDefault();
+            }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
                 mMetrics.updateMetrics(mCompatibilityInfo,
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index eb48a0c..52de64c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -226,7 +227,7 @@
             
             @Override
             public void resized(int w, int h, Rect coveredInsets,
-                    Rect visibleInsets, boolean reportDraw) {
+                    Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0);
                 mCaller.sendMessage(msg);
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 71302cb..3b09808 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -44,7 +45,7 @@
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
     void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
-            boolean reportDraw);
+            boolean reportDraw, in Configuration newConfig);
     void dispatchKey(in KeyEvent event);
     void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
     void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0ebe360..9b7b2f4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -64,8 +64,6 @@
     void addAppToken(int addPos, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen);
     void setAppGroupId(IBinder token, int groupId);
-    Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
@@ -85,6 +83,13 @@
     void moveAppTokensToTop(in List<IBinder> tokens);
     void moveAppTokensToBottom(in List<IBinder> tokens);
 
+    // Re-evaluate the current orientation from the caller's state.
+    // 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);
+    void setNewConfiguration(in Configuration config);
+    
     // these require DISABLE_KEYGUARD permission
     void disableKeyguard(IBinder token, String tag);
     void reenableKeyguard(IBinder token);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ca5e1de..d7f2539 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -19,6 +19,7 @@
 import com.android.internal.view.BaseIWindow;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
@@ -504,7 +505,7 @@
         }
 
         public void resized(int w, int h, Rect coveredInsets,
-                Rect visibleInsets, boolean reportDraw) {
+                Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
                 if (localLOGV) Log.v(
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bc49439..2eb633f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20,6 +20,7 @@
 import com.android.internal.view.menu.MenuBuilder;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -3933,6 +3934,32 @@
     }
 
     /**
+     * Dispatch a notification about a resource configuration change down
+     * the view hierarchy.
+     * ViewGroups should override to route to their children.
+     *
+     * @param newConfig The new resource configuration.
+     *
+     * @see #onConfigurationChanged
+     */
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        onConfigurationChanged(newConfig);
+    }
+
+    /**
+     * Called when the current configuration of the resources being used
+     * by the application have changed.  You can use this to decide when
+     * to reload resources that can changed based on orientation and other
+     * configuration characterstics.  You only need to use this if you are
+     * not relying on the normal {@link android.app.Activity} mechanism of
+     * recreating the activity instance upon a configuration change.
+     *
+     * @param newConfig The new resource configuration.
+     */
+    protected void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    /**
      * Private function to aggregate all per-view attributes in to the view
      * root.
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2ed623d..0663215 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -722,6 +723,19 @@
     /**
      * {@inheritDoc}
      */
+    @Override
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        super.dispatchConfigurationChanged(newConfig);
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < count; i++) {
+            children[i].dispatchConfigurationChanged(newConfig);
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
     public void recomputeViewAttributes(View child) {
         ViewParent parent = mParent;
         if (parent != null) parent.recomputeViewAttributes(this);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 07b2d1c..264b8c9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -41,7 +41,9 @@
 import android.widget.Scroller;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.app.ActivityManagerNative;
 import android.Manifest;
@@ -101,6 +103,9 @@
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
     static boolean sFirstDrawComplete = false;
     
+    static final ArrayList<ComponentCallbacks> sConfigCallbacks
+            = new ArrayList<ComponentCallbacks>();
+    
     private static int sDrawTime;
 
     long mLastTrackballTime = 0;
@@ -171,6 +176,12 @@
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
 
+    class ResizedInfo {
+        Rect coveredInsets;
+        Rect visibleInsets;
+        Configuration newConfig;
+    }
+    
     boolean mScrollMayChange;
     int mSoftInputMode;
     View mLastScrolledFocus;
@@ -265,6 +276,12 @@
         }
     }
     
+    public static void addConfigCallback(ComponentCallbacks callback) {
+        synchronized (sConfigCallbacks) {
+            sConfigCallbacks.add(callback);
+        }
+    }
+    
     // FIXME for perf testing only
     private boolean mProfile = false;
 
@@ -1782,23 +1799,33 @@
             handleGetNewSurface();
             break;
         case RESIZED:
-            Rect coveredInsets = ((Rect[])msg.obj)[0];
-            Rect visibleInsets = ((Rect[])msg.obj)[1];
+            ResizedInfo ri = (ResizedInfo)msg.obj;
 
             if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
-                    && mPendingContentInsets.equals(coveredInsets)
-                    && mPendingVisibleInsets.equals(visibleInsets)) {
+                    && mPendingContentInsets.equals(ri.coveredInsets)
+                    && mPendingVisibleInsets.equals(ri.visibleInsets)) {
                 break;
             }
             // fall through...
         case RESIZED_REPORT:
             if (mAdded) {
+                Configuration config = ((ResizedInfo)msg.obj).newConfig;
+                if (config != null) {
+                    synchronized (sConfigCallbacks) {
+                        for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
+                            sConfigCallbacks.get(i).onConfigurationChanged(config);
+                        }
+                    }
+                    if (mView != null) {
+                        mView.dispatchConfigurationChanged(config);
+                    }
+                }
                 mWinFrame.left = 0;
                 mWinFrame.right = msg.arg1;
                 mWinFrame.top = 0;
                 mWinFrame.bottom = msg.arg2;
-                mPendingContentInsets.set(((Rect[])msg.obj)[0]);
-                mPendingVisibleInsets.set(((Rect[])msg.obj)[1]);
+                mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
+                mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
                 if (msg.what == RESIZED_REPORT) {
                     mReportNextDraw = true;
                 }
@@ -2587,7 +2614,7 @@
     }
 
     public void dispatchResized(int w, int h, Rect coveredInsets,
-            Rect visibleInsets, boolean reportDraw) {
+            Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
                 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
@@ -2601,7 +2628,11 @@
         }
         msg.arg1 = w;
         msg.arg2 = h;
-        msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
+        ResizedInfo ri = new ResizedInfo();
+        ri.coveredInsets = new Rect(coveredInsets);
+        ri.visibleInsets = new Rect(visibleInsets);
+        ri.newConfig = newConfig;
+        msg.obj = ri;
         sendMessage(msg);
     }
 
@@ -2802,11 +2833,11 @@
         }
 
         public void resized(int w, int h, Rect coveredInsets,
-                Rect visibleInsets, boolean reportDraw) {
+                Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
                 viewRoot.dispatchResized(w, h, coveredInsets,
-                        visibleInsets, reportDraw);
+                        visibleInsets, reportDraw, newConfig);
             }
         }
 
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 15dcbd6..22c6e79 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -1,5 +1,6 @@
 package com.android.internal.view;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -17,7 +18,7 @@
     }
     
     public void resized(int w, int h, Rect coveredInsets,
-            Rect visibleInsets, boolean reportDraw) {
+            Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7fcf900..a481036e 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -373,10 +373,15 @@
     boolean mLayoutNeeded = true;
     boolean mAnimationPending = false;
     boolean mDisplayFrozen = false;
+    boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
     long mFreezeGcPending = 0;
     int mAppsFreezingScreen = 0;
 
+    int mLayoutSeq = 0;
+    
+    Configuration mCurConfiguration = new Configuration();
+    
     // This is held as long as we have the screen frozen, to give us time to
     // perform a rotation animation when turning off shows the lock screen which
     // changes the orientation.
@@ -1828,7 +1833,7 @@
             }
 
             if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
-                attachedWindow = windowForClientLocked(null, attrs.token);
+                attachedWindow = windowForClientLocked(null, attrs.token, false);
                 if (attachedWindow == null) {
                     Log.w(TAG, "Attempted to add window with token that is not a window: "
                           + attrs.token + ".  Aborting.");
@@ -1988,6 +1993,10 @@
             if (localLOGV) Log.v(
                 TAG, "New client " + client.asBinder()
                 + ": window=" + win);
+            
+            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {
+                reportNewConfig = true;
+            }
         }
 
         // sendNewConfiguration() checks caller permissions so we must call it with
@@ -1997,14 +2006,6 @@
         final long origId = Binder.clearCallingIdentity();
         if (reportNewConfig) {
             sendNewConfiguration();
-        } else {
-            // Update Orientation after adding a window, only if the window needs to be
-            // displayed right away
-            if (win.isVisibleOrAdding()) {
-                if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
-                    sendNewConfiguration();
-                }
-            }
         }
         Binder.restoreCallingIdentity(origId);
 
@@ -2013,7 +2014,7 @@
 
     public void removeWindow(Session session, IWindow client) {
         synchronized(mWindowMap) {
-            WindowState win = windowForClientLocked(session, client);
+            WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
                 return;
             }
@@ -2081,8 +2082,9 @@
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && computeForcedAppOrientationLocked()
-                != mForcedAppOrientation) {
-            mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
+                != mForcedAppOrientation
+                && updateOrientationFromAppTokensLocked()) {
+            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
         Binder.restoreCallingIdentity(origId);
@@ -2177,7 +2179,7 @@
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
-                WindowState w = windowForClientLocked(session, client);
+                WindowState w = windowForClientLocked(session, client, false);
                 if ((w != null) && (w.mSurface != null)) {
                     if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
                     Surface.openTransaction();
@@ -2203,7 +2205,7 @@
         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 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 @@
             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 @@
             if (assignLayers) {
                 assignLayersLocked();
             }
-            newConfig = updateOrientationFromAppTokensLocked(null, null);
+            configChanged = updateOrientationFromAppTokensLocked();
             performLayoutAndPlaceSurfacesLocked();
             if (displayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
@@ -2533,7 +2535,7 @@
             inTouchMode = mInTouchMode;
         }
 
-        if (newConfig != null) {
+        if (configChanged) {
             sendNewConfiguration();
         }
 
@@ -2546,7 +2548,7 @@
     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 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;
-                    }
+                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;
+            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 @@
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
 
-        Configuration config;
+        Configuration config = null;
         long ident = Binder.clearCallingIdentity();
-        config = updateOrientationFromAppTokensUnchecked(currentConfig,
-                freezeThisOneIfNeeded);
+        
+        synchronized(mWindowMap) {
+            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;
     }
 
-    Configuration updateOrientationFromAppTokensUnchecked(
-            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
-        Configuration config;
-        synchronized(mWindowMap) {
-            config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
-            if (config != null) {
-                mLayoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
-            }
-        }
-        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 @@
         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 @@
                     mLayoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
                 }
-                if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
-                    stopFreezingDisplayLocked();
-                }
+                stopFreezingDisplayLocked();
             }
         }
     }
@@ -4403,20 +4410,21 @@
             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 @@
             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 @@
                 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 @@
             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 @@
                 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 @@
 
         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 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 @@
         }
 
         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 @@
                 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 @@
                 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 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 @@
                     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 @@
     // 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 @@
             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 @@
         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 @@
                         || 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 @@
                 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 @@
                     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 @@
                 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 @@
                 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 @@
                             }
                         }
                     }
-                    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 @@
                                 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 @@
                 mWindowsFreezingScreen = false;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
-            if (mAppsFreezingScreen == 0) {
-                stopFreezingDisplayLocked();
-            }
+            stopFreezingDisplayLocked();
         }
 
         i = mResizingWindows.size();
@@ -10340,9 +10379,20 @@
                 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 @@
             return;
         }
 
+        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
+            return;
+        }
+        
         mDisplayFrozen = false;
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         if (PROFILE_ORIENTATION) {
@@ -10921,7 +10975,9 @@
                 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 @@
                     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 47a58cf..45c3f00 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -766,6 +766,12 @@
     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 @@
                         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 @@
             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 @@
                                      values.userSetLocale);
                 }
 
+                mConfigurationSeq++;
+                if (mConfigurationSeq <= 0) {
+                    mConfigurationSeq = 1;
+                }
+                newConfig.seq = mConfigurationSeq;
                 mConfiguration = newConfig;
                 Log.i(TAG, "Config changed: " + newConfig);
                 
@@ -13146,6 +13145,10 @@
             }
         }
         
+        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 990498f..41d9f9d 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.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 @@
         }
 
         @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.
         }