Work on issue #4518815: Compatibility mode introduces compatibility regression...

...for Market App iRunner

There were a lot of serious issues with how we updated (or often didn't update)
the display and resource state when switching compatibility mode in conjunction
with restarting and updating application components.  This addresses everything
I could find.

Unfortunately it does *not* fix this particular app.  I am starting to think this
is just an issue in the app.  This change does fix a number of other problems
I could repro, such as switching the compatibility mode of an IME.

Also a few changes here and there to get rid of $#*&^!! debug logs.

Change-Id: Ib15572eac9ec93b4b9966ddcbbc830ce9dec1317
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 4d49c30..ada712d 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -213,7 +213,7 @@
     if (create_cache_path(src_dex, src)) return -1;
     if (create_cache_path(dst_dex, dst)) return -1;
 
-    LOGI("move %s -> %s\n", src_dex, dst_dex);
+    LOGV("move %s -> %s\n", src_dex, dst_dex);
     if (rename(src_dex, dst_dex) < 0) {
         LOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
         return -1;
@@ -229,7 +229,7 @@
     if (!is_valid_apk_path(path)) return -1;
     if (create_cache_path(dex_path, path)) return -1;
 
-    LOGI("unlink %s\n", dex_path);
+    LOGV("unlink %s\n", dex_path);
     if (unlink(dex_path) < 0) {
         LOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
         return -1;
@@ -428,7 +428,7 @@
     }
 
     if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-        LOGD("DexInv: --- END '%s' (success) ---\n", apk_path);
+        LOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
         return 0;
     } else {
         LOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
@@ -495,7 +495,7 @@
         goto fail;
     }
 
-    LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path);
+    LOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
 
     pid_t pid;
     pid = fork();
@@ -563,7 +563,7 @@
         if (path[basepos] == '/') {
             path[basepos] = 0;
             if (lstat(path, statbuf) < 0) {
-                LOGI("Making directory: %s\n", path);
+                LOGV("Making directory: %s\n", path);
                 if (mkdir(path, mode) == 0) {
                     chown(path, uid, gid);
                 } else {
@@ -595,7 +595,7 @@
     if ((statbuf->st_mode&S_IFDIR) == 0) {
         mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
                 dstuid, dstgid, statbuf);
-        LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
+        LOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
         if (rename(srcpath, dstpath) >= 0) {
             if (chown(dstpath, dstuid, dstgid) < 0) {
                 LOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a61147a..6c63c2a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -155,7 +155,9 @@
             = new HashMap<IBinder, Service>();
     AppBindData mBoundApplication;
     Configuration mConfiguration;
+    Configuration mCompatConfiguration;
     Configuration mResConfiguration;
+    CompatibilityInfo mResCompatibilityInfo;
     Application mInitialApplication;
     final ArrayList<Application> mAllApplications
             = new ArrayList<Application>();
@@ -181,8 +183,8 @@
             = new HashMap<String, WeakReference<LoadedApk>>();
     final HashMap<String, WeakReference<LoadedApk>> mResourcePackages
             = new HashMap<String, WeakReference<LoadedApk>>();
-    Display mDisplay = null;
-    DisplayMetrics mDisplayMetrics = null;
+    final HashMap<CompatibilityInfo, DisplayMetrics> mDisplayMetrics
+            = new HashMap<CompatibilityInfo, DisplayMetrics>();
     final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
             = new HashMap<ResourcesKey, WeakReference<Resources> >();
     final ArrayList<ActivityClientRecord> mRelaunchingActivities
@@ -1267,20 +1269,45 @@
         return sPackageManager;
     }
 
-    DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) {
-        if (mDisplayMetrics != null && !forceUpdate) {
-            return mDisplayMetrics;
+    DisplayMetrics getDisplayMetricsLocked(CompatibilityInfo ci, boolean forceUpdate) {
+        DisplayMetrics dm = mDisplayMetrics.get(ci);
+        if (dm != null && !forceUpdate) {
+            return dm;
         }
-        if (mDisplay == null) {
-            WindowManager wm = WindowManagerImpl.getDefault();
-            mDisplay = wm.getDefaultDisplay();
+        if (dm == null) {
+            dm = new DisplayMetrics();
+            mDisplayMetrics.put(ci, dm);
         }
-        DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics();
-        mDisplay.getMetrics(metrics);
+        Display d = WindowManagerImpl.getDefault(ci).getDefaultDisplay();
+        d.getMetrics(dm);
         //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
         //        + metrics.heightPixels + " den=" + metrics.density
         //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
-        return metrics;
+        return dm;
+    }
+
+    static Configuration applyConfigCompat(Configuration config, CompatibilityInfo compat) {
+        if (config == null) {
+            return null;
+        }
+        if (compat != null && !compat.supportsScreen()) {
+            config = new Configuration(config);
+            compat.applyToConfiguration(config);
+        }
+        return config;
+    }
+
+    private final Configuration mMainThreadConfig = new Configuration();
+    Configuration applyConfigCompatMainThread(Configuration config, CompatibilityInfo compat) {
+        if (config == null) {
+            return null;
+        }
+        if (compat != null && !compat.supportsScreen()) {
+            mMainThreadConfig.setTo(config);
+            config = mMainThreadConfig;
+            compat.applyToConfiguration(config);
+        }
+        return config;
     }
 
     /**
@@ -1322,7 +1349,7 @@
         }
 
         //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
-        DisplayMetrics metrics = getDisplayMetricsLocked(false);
+        DisplayMetrics metrics = getDisplayMetricsLocked(compInfo, false);
         r = new Resources(assets, metrics, getConfiguration(), compInfo);
         if (false) {
             Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
@@ -1350,7 +1377,7 @@
      * Creates the top level resources for the given package.
      */
     Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) {
-        return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo);
+        return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo.get());
     }
 
     final Handler getHandler() {
@@ -1517,7 +1544,8 @@
                         CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
                 context.init(info, null, this);
                 context.getResources().updateConfiguration(
-                        getConfiguration(), getDisplayMetricsLocked(false));
+                        getConfiguration(), getDisplayMetricsLocked(
+                                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false));
                 mSystemContext = context;
                 //Slog.i(TAG, "Created system resources " + context.getResources()
                 //        + ": " + context.getResources().getConfiguration());
@@ -1730,7 +1758,7 @@
                 appContext.init(r.packageInfo, r.token, this);
                 appContext.setOuterContext(activity);
                 CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
-                Configuration config = new Configuration(mConfiguration);
+                Configuration config = new Configuration(mCompatConfiguration);
                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                         + r.activityInfo.name + " with config " + config);
                 activity.attach(appContext, this, getInstrumentation(), r.token,
@@ -2763,13 +2791,14 @@
     private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) {
         LoadedApk apk = peekPackageInfo(data.pkg, false);
         if (apk != null) {
-            apk.mCompatibilityInfo = data.info;
+            apk.mCompatibilityInfo.set(data.info);
         }
         apk = peekPackageInfo(data.pkg, true);
         if (apk != null) {
-            apk.mCompatibilityInfo = data.info;
+            apk.mCompatibilityInfo.set(data.info);
         }
         handleConfigurationChanged(mConfiguration, data.info);
+        WindowManagerImpl.getDefault().reportNewConfiguration(mConfiguration);
     }
 
     private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
@@ -3192,20 +3221,22 @@
                 ActivityClientRecord ar = it.next();
                 Activity a = ar.activity;
                 if (a != null) {
+                    Configuration thisConfig = applyConfigCompatMainThread(newConfig,
+                            ar.packageInfo.mCompatibilityInfo.getIfNeeded());
                     if (!ar.activity.mFinished && (allActivities ||
                             (a != null && !ar.paused))) {
                         // If the activity is currently resumed, its configuration
                         // needs to change right now.
                         callbacks.add(a);
-                    } else if (newConfig != null) {
+                    } else if (thisConfig != null) {
                         // Otherwise, we will tell it about the change
                         // the next time it is resumed or shown.  Note that
                         // the activity manager may, before then, decide the
                         // activity needs to be destroyed to handle its new
                         // configuration.
                         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Setting activity "
-                                + ar.activityInfo.name + " newConfig=" + newConfig);
-                        ar.newConfig = newConfig;
+                                + ar.activityInfo.name + " newConfig=" + thisConfig);
+                        ar.newConfig = thisConfig;
                     }
                 }
             }
@@ -3252,7 +3283,6 @@
             // onConfigurationChanged
             int diff = activity.mCurrentConfig.diff(config);
             if (diff != 0) {
-
                 // If this activity doesn't handle any of the config changes
                 // then don't bother calling onConfigurationChanged as we're
                 // going to destroy it.
@@ -3296,7 +3326,15 @@
             return false;
         }
         int changes = mResConfiguration.updateFrom(config);
-        DisplayMetrics dm = getDisplayMetricsLocked(true);
+        DisplayMetrics dm = getDisplayMetricsLocked(compat, true);
+
+        if (compat != null && (mResCompatibilityInfo == null ||
+                !mResCompatibilityInfo.equals(compat))) {
+            mResCompatibilityInfo = compat;
+            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+                    | ActivityInfo.CONFIG_SCREEN_SIZE
+                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        }
 
         // set it for java, this also affects newly created Resources
         if (config.locale != null) {
@@ -3358,13 +3396,14 @@
                 return;
             }
             mConfiguration.updateFrom(config);
-            if (compat != null) {
-                // Can't do this here, because it causes us to report the
-                // comatible config back to the am as the current config
-                // of the activity, and much unhappiness results.
-                //compat.applyToConfiguration(mConfiguration);
+            if (mCompatConfiguration == null) {
+                mCompatConfiguration = new Configuration();
             }
-
+            mCompatConfiguration.setTo(mConfiguration);
+            if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
+                mResCompatibilityInfo.applyToConfiguration(mCompatConfiguration);
+                config = mCompatConfiguration;
+            }
             callbacks = collectComponentCallbacksLocked(false, config);
         }
 
@@ -3385,7 +3424,7 @@
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                 + r.activityInfo.name);
         
-        performConfigurationChanged(r.activity, mConfiguration);
+        performConfigurationChanged(r.activity, mCompatConfiguration);
     }
 
     final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
@@ -3480,6 +3519,7 @@
     private final void handleBindApplication(AppBindData data) {
         mBoundApplication = data;
         mConfiguration = new Configuration(data.config);
+        mCompatConfiguration = new Configuration(data.config);
 
         // send up app name; do this *before* waiting for debugger
         Process.setArgV0(data.processName);
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index b9ac848..10cc9f8 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -37,6 +37,8 @@
  * when first constructing the singleton.</p>
  */
 public class Application extends ContextWrapper implements ComponentCallbacks {
+    /** @hide */
+    public LoadedApk mLoadedApk;
     
     public Application() {
         super(null);
@@ -75,6 +77,6 @@
      */
     /* package */ final void attach(Context context) {
         attachBaseContext(context);
+        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
     }
-
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 73170bb..20dc792 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -425,11 +425,19 @@
 
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
                 public Object getService(ContextImpl ctx) {
-                    CompatibilityInfo ci = ctx.mResources.getCompatibilityInfo();
-                    return WindowManagerImpl.getDefault(ci);
+                    return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
                 }});
     }
 
+    static ContextImpl getImpl(Context context) {
+        Context nextContext;
+        while ((context instanceof ContextWrapper) &&
+                (nextContext=((ContextWrapper)context).getBaseContext()) != null) {
+            context = nextContext;
+        }
+        return (ContextImpl)context;
+    }
+
     // The system service cache for the system services that are
     // cached per-ContextImpl.  Package-scoped to avoid accessor
     // methods.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 6287d33..2549c84 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -38,6 +38,7 @@
 import android.os.StrictMode;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
+import android.view.CompatibilityInfoHolder;
 
 import java.io.File;
 import java.io.IOException;
@@ -64,7 +65,7 @@
  * Local state maintained about a currently loaded .apk.
  * @hide
  */
-final class LoadedApk {
+public final class LoadedApk {
 
     private final ActivityThread mActivityThread;
     private final ApplicationInfo mApplicationInfo;
@@ -78,10 +79,10 @@
     private final ClassLoader mBaseClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
+    public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder();
     Resources mResources;
     private ClassLoader mClassLoader;
     private Application mApplication;
-    CompatibilityInfo mCompatibilityInfo;
 
     private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
         = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
@@ -121,7 +122,7 @@
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
         mIncludeCode = includeCode;
-        mCompatibilityInfo = compatInfo;
+        mCompatibilityInfo.set(compatInfo);
 
         if (mAppDir == null) {
             if (ActivityThread.mSystemContext == null) {
@@ -129,7 +130,7 @@
                     ContextImpl.createSystemContext(mainThread);
                 ActivityThread.mSystemContext.getResources().updateConfiguration(
                          mainThread.getConfiguration(),
-                         mainThread.getDisplayMetricsLocked(false),
+                         mainThread.getDisplayMetricsLocked(compatInfo, false),
                          compatInfo);
                 //Slog.i(TAG, "Created system resources "
                 //        + mSystemContext.getResources() + ": "
@@ -157,7 +158,7 @@
         mIncludeCode = true;
         mClassLoader = systemContext.getClassLoader();
         mResources = systemContext.getResources();
-        mCompatibilityInfo = compatInfo;
+        mCompatibilityInfo.set(compatInfo);
     }
 
     public String getPackageName() {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index b686e54..acf2f2f1 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -456,6 +456,9 @@
             inoutConfig.screenLayout =
                     (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
                     | Configuration.SCREENLAYOUT_SIZE_NORMAL;
+            inoutConfig.screenWidthDp = inoutConfig.compatScreenWidthDp;
+            inoutConfig.screenHeightDp = inoutConfig.compatScreenHeightDp;
+            inoutConfig.smallestScreenWidthDp = inoutConfig.compatSmallestScreenWidthDp;
         }
     }
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6409aac..e2c6483 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -269,6 +269,13 @@
      */
     public int smallestScreenWidthDp;
 
+    /** @hide Hack to get this information from WM to app running in compat mode. */
+    public int compatScreenWidthDp;
+    /** @hide Hack to get this information from WM to app running in compat mode. */
+    public int compatScreenHeightDp;
+    /** @hide Hack to get this information from WM to app running in compat mode. */
+    public int compatSmallestScreenWidthDp;
+
     /**
      * @hide Internal book-keeping.
      */
@@ -309,6 +316,9 @@
         screenWidthDp = o.screenWidthDp;
         screenHeightDp = o.screenHeightDp;
         smallestScreenWidthDp = o.smallestScreenWidthDp;
+        compatScreenWidthDp = o.compatScreenWidthDp;
+        compatScreenHeightDp = o.compatScreenHeightDp;
+        compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
         seq = o.seq;
     }
     
@@ -444,9 +454,9 @@
         orientation = ORIENTATION_UNDEFINED;
         screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
         uiMode = UI_MODE_TYPE_UNDEFINED;
-        screenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
-        screenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
-        smallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+        screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
+        screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
+        smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
         seq = 0;
     }
 
@@ -550,11 +560,18 @@
             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
             screenHeightDp = delta.screenHeightDp;
         }
-        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
-                && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
-            changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             smallestScreenWidthDp = delta.smallestScreenWidthDp;
         }
+        if (delta.compatScreenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
+            compatScreenWidthDp = delta.compatScreenWidthDp;
+        }
+        if (delta.compatScreenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
+            compatScreenHeightDp = delta.compatScreenHeightDp;
+        }
+        if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+            compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
+        }
         
         if (delta.seq != 0) {
             seq = delta.seq;
@@ -739,6 +756,9 @@
         dest.writeInt(screenWidthDp);
         dest.writeInt(screenHeightDp);
         dest.writeInt(smallestScreenWidthDp);
+        dest.writeInt(compatScreenWidthDp);
+        dest.writeInt(compatScreenHeightDp);
+        dest.writeInt(compatSmallestScreenWidthDp);
         dest.writeInt(seq);
     }
 
@@ -763,6 +783,9 @@
         screenWidthDp = source.readInt();
         screenHeightDp = source.readInt();
         smallestScreenWidthDp = source.readInt();
+        compatScreenWidthDp = source.readInt();
+        compatScreenHeightDp = source.readInt();
+        compatSmallestScreenWidthDp = source.readInt();
         seq = source.readInt();
     }
     
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 70bf524..bd8b1a4 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1414,18 +1414,6 @@
             if (compat != null) {
                 mCompatibilityInfo = compat;
             }
-            int configChanges = 0xfffffff;
-            if (config != null) {
-                mTmpConfig.setTo(config);
-                if (mCompatibilityInfo != null) {
-                    mCompatibilityInfo.applyToConfiguration(mTmpConfig);
-                }
-                configChanges = mConfiguration.updateFrom(mTmpConfig);
-                configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
-            }
-            if (mConfiguration.locale == null) {
-                mConfiguration.locale = Locale.getDefault();
-            }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
                 // NOTE: We should re-arrange this code to create a Display
@@ -1441,7 +1429,25 @@
                     mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
                 }
             }
+            if (mCompatibilityInfo != null) {
+                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+            }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
+            int configChanges = 0xfffffff;
+            if (config != null) {
+                mTmpConfig.setTo(config);
+                if (mCompatibilityInfo != null) {
+                    mCompatibilityInfo.applyToConfiguration(mTmpConfig);
+                }
+                if (mTmpConfig.locale == null) {
+                    mTmpConfig.locale = Locale.getDefault();
+                }
+                configChanges = mConfiguration.updateFrom(mTmpConfig);
+                configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+            }
+            if (mConfiguration.locale == null) {
+                mConfiguration.locale = Locale.getDefault();
+            }
 
             String locale = null;
             if (mConfiguration.locale != null) {
@@ -1476,7 +1482,7 @@
                     mConfiguration.screenLayout, mConfiguration.uiMode,
                     Build.VERSION.RESOURCES_SDK_INT);
 
-            if (false) {
+            if (DEBUG_CONFIG) {
                 Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration
                         + " final compat is " + mCompatibilityInfo);
             }
@@ -1558,6 +1564,8 @@
      * @return The resource's current display metrics. 
      */
     public DisplayMetrics getDisplayMetrics() {
+        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
+                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
         return mMetrics;
     }
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 90279d1..155870a 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -75,7 +75,6 @@
             }
         }
         tl = new TextLine();
-        Log.v("TLINE", "new: " + tl);
         return tl;
     }
 
diff --git a/core/java/android/view/CompatibilityInfoHolder.java b/core/java/android/view/CompatibilityInfoHolder.java
new file mode 100644
index 0000000..fc8d684
--- /dev/null
+++ b/core/java/android/view/CompatibilityInfoHolder.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.res.CompatibilityInfo;
+
+/** @hide */
+public class CompatibilityInfoHolder {
+    private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+
+    public void set(CompatibilityInfo compatInfo) {
+        if (compatInfo != null && (compatInfo.isScalingRequired()
+                || !compatInfo.supportsScreen())) {
+            mCompatInfo = compatInfo;
+        } else {
+            mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+        }
+    }
+
+    public CompatibilityInfo get() {
+        return mCompatInfo;
+    }
+
+    public CompatibilityInfo getIfNeeded() {
+        CompatibilityInfo ci = mCompatInfo;
+        if (ci == null || ci  == CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO) {
+            return null;
+        }
+        return ci;
+    }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 8032546..3fa8dfd 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,9 @@
 import android.util.Slog;
 
 public class Display {
+    static final String TAG = "Display";
+    static final boolean DEBUG_COMPAT = false;
+
     /**
      * Specify the default Display
      */
@@ -38,7 +41,7 @@
      * Display gives you access to some information about a particular display
      * connected to the device.
      */
-    Display(int display, CompatibilityInfo compatInfo) {
+    Display(int display, CompatibilityInfoHolder compatInfo) {
         // initalize the statics when this class is first instansiated. This is
         // done here instead of in the static block because Zygote
         synchronized (sStaticInit) {
@@ -47,15 +50,20 @@
                 sInitialized = true;
             }
         }
-        if (compatInfo != null && (compatInfo.isScalingRequired()
-                || !compatInfo.supportsScreen())) {
-            mCompatibilityInfo = compatInfo;
-        } else {
-            mCompatibilityInfo = null;
-        }
+        mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder();
         mDisplay = display;
         init(display);
     }
+
+    /** @hide */
+    public static void setCompatibilityInfo(CompatibilityInfo compatInfo) {
+        if (compatInfo != null && (compatInfo.isScalingRequired()
+                || !compatInfo.supportsScreen())) {
+            sCompatibilityInfo = compatInfo;
+        } else {
+            sCompatibilityInfo = null;
+        }
+    }
     
     /**
      * Returns the index of this display.  This is currently undefined; do
@@ -96,12 +104,13 @@
             IWindowManager wm = getWindowManager();
             if (wm != null) {
                 wm.getDisplaySize(outSize);
-                if (doCompat && mCompatibilityInfo != null) {
+                CompatibilityInfo ci;
+                if (doCompat && (ci=mCompatibilityInfo.getIfNeeded()) != null) {
                     synchronized (mTmpMetrics) {
                         mTmpMetrics.unscaledWidthPixels = outSize.x;
                         mTmpMetrics.unscaledHeightPixels = outSize.y;
                         mTmpMetrics.density = mDensity;
-                        mCompatibilityInfo.applyToDisplayMetrics(mTmpMetrics);
+                        ci.applyToDisplayMetrics(mTmpMetrics);
                         outSize.x = mTmpMetrics.widthPixels;
                         outSize.y = mTmpMetrics.heightPixels;
                     }
@@ -111,6 +120,7 @@
                 // system process before the window manager is up.
                 outSize.y = getRealHeight();
             }
+            if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize);
         } catch (RemoteException e) {
             Slog.w("Display", "Unable to get display size", e);
         }
@@ -236,9 +246,13 @@
         }
         getNonSizeMetrics(outMetrics);
 
-        if (mCompatibilityInfo != null) {
-            mCompatibilityInfo.applyToDisplayMetrics(outMetrics);
+        CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
+        if (ci != null) {
+            ci.applyToDisplayMetrics(outMetrics);
         }
+
+        if (DEBUG_COMPAT) Slog.v(TAG, "Returning DisplayMetrics: " + outMetrics.widthPixels
+                + "x" + outMetrics.heightPixels + " " + outMetrics.density);
     }
 
     /**
@@ -282,7 +296,7 @@
     
     private native void init(int display);
 
-    private final CompatibilityInfo mCompatibilityInfo;
+    private final CompatibilityInfoHolder mCompatibilityInfo;
     private final int   mDisplay;
     // Following fields are initialized from native code
     private int         mPixelFormat;
@@ -299,11 +313,13 @@
     private static boolean sInitialized = false;
     private static IWindowManager sWindowManager;
 
+    private static volatile CompatibilityInfo sCompatibilityInfo;
+
     /**
      * Returns a display object which uses the metric's width/height instead.
      * @hide
      */
-    public static Display createCompatibleDisplay(int displayId, CompatibilityInfo compat) {
+    public static Display createCompatibleDisplay(int displayId, CompatibilityInfoHolder compat) {
         return new Display(displayId, compat);
     }
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 2098955..cdb0339 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -159,6 +159,8 @@
     // so the window should no longer be active.
     boolean mStopped = false;
     
+    boolean mLastInCompatMode = false;
+
     SurfaceHolder.Callback2 mSurfaceHolderCallback;
     BaseSurfaceHolder mSurfaceHolder;
     boolean mIsCreating;
@@ -204,6 +206,8 @@
     boolean mAdded;
     boolean mAddedTouchMode;
 
+    CompatibilityInfoHolder mCompatibilityInfo;
+
     /*package*/ int mAddNesting;
 
     // These are accessed by multiple threads.
@@ -369,8 +373,7 @@
                     enableHardwareAcceleration(attrs);
                 }
 
-                Resources resources = mView.getContext().getResources();
-                CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo();
+                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
                 mTranslator = compatibilityInfo.getTranslator();
 
                 if (mTranslator != null) {
@@ -387,6 +390,7 @@
 
                 if (!compatibilityInfo.supportsScreen()) {
                     attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                    mLastInCompatMode = true;
                 }
 
                 mSoftInputMode = attrs.softInputMode;
@@ -719,6 +723,19 @@
             surfaceChanged = true;
             params = lp;
         }
+        CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+        if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
+            params = lp;
+            fullRedrawNeeded = true;
+            mLayoutRequested = true;
+            if (mLastInCompatMode) {
+                params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                mLastInCompatMode = false;
+            } else {
+                params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                mLastInCompatMode = true;
+            }
+        }
         Rect frame = mWinFrame;
         if (mFirst) {
             fullRedrawNeeded = true;
@@ -1934,6 +1951,13 @@
                 "Applying new config to window "
                 + mWindowAttributes.getTitle()
                 + ": " + config);
+
+        CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
+        if (ci != null) {
+            config = new Configuration(config);
+            ci.applyToConfiguration(config);
+        }
+
         synchronized (sConfigCallbacks) {
             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
                 sConfigCallbacks.get(i).onConfigurationChanged(config);
@@ -1995,6 +2019,7 @@
     public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
     public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
     public final static int DISPATCH_GENERIC_MOTION = 1018;
+    public final static int UPDATE_CONFIGURATION = 1019;
 
     @Override
     public void handleMessage(Message msg) {
@@ -2178,6 +2203,13 @@
         case DISPATCH_SYSTEM_UI_VISIBILITY: {
             handleDispatchSystemUiVisibilityChanged(msg.arg1);
         } break;
+        case UPDATE_CONFIGURATION: {
+            Configuration config = (Configuration)msg.obj;
+            if (config.isOtherSeqNewer(mLastConfiguration)) {
+                config = mLastConfiguration;
+            }
+            updateConfiguration(config, false);
+        } break;
         }
     }
     
@@ -3205,6 +3237,11 @@
         }
     }
 
+    public void requestUpdateConfiguration(Configuration config) {
+        Message msg = obtainMessage(UPDATE_CONFIGURATION, config);
+        sendMessage(msg);
+    }
+
     private void destroyHardwareRenderer() {
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroy(true);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5236a9e..e07085c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.app.Application;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -25,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Slog;
 import android.view.accessibility.AccessibilityEvent;
 
 /**
@@ -463,11 +465,16 @@
         mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
     }
 
+    static CompatibilityInfoHolder getCompatInfo(Context context) {
+        Application app = (Application)context.getApplicationContext();
+        return app != null ? app.mLoadedApk.mCompatibilityInfo : new CompatibilityInfoHolder();
+    }
+
     private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
         private final boolean mHardwareAccelerated;
 
         LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
-            super(wm, mContext.getResources().getCompatibilityInfo());
+            super(wm, getCompatInfo(mContext));
             mHardwareAccelerated = hardwareAccelerated;
         }
 
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 9cae75c..a853c15 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -19,11 +19,13 @@
 import java.util.HashMap;
 
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.util.AndroidRuntimeException;
 import android.util.Config;
 import android.util.Log;
+import android.util.Slog;
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
@@ -88,29 +90,32 @@
             = new HashMap<CompatibilityInfo, WindowManager>();
 
     static class CompatModeWrapper implements WindowManager {
-        private final WindowManager mWindowManager;
+        private final WindowManagerImpl mWindowManager;
         private final Display mDefaultDisplay;
+        private final CompatibilityInfoHolder mCompatibilityInfo;
 
-        CompatModeWrapper(WindowManager wm, CompatibilityInfo ci) {
-            mWindowManager = wm;
+        CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
+            mWindowManager = wm instanceof CompatModeWrapper
+                    ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
 
             // Use the original display if there is no compatibility mode
             // to apply, or the underlying window manager is already a
             // compatibility mode wrapper.  (We assume that if it is a
             // wrapper, it is applying the same compatibility mode.)
-            if (ci == null || wm instanceof CompatModeWrapper
-                    || (!ci.isScalingRequired() && ci.supportsScreen())) {
+            if (ci == null) {
                 mDefaultDisplay = mWindowManager.getDefaultDisplay();
             } else {
                 //mDefaultDisplay = mWindowManager.getDefaultDisplay();
                 mDefaultDisplay = Display.createCompatibleDisplay(
                         mWindowManager.getDefaultDisplay().getDisplayId(), ci);
             }
+
+            mCompatibilityInfo = ci;
         }
 
         @Override
         public void addView(View view, android.view.ViewGroup.LayoutParams params) {
-            mWindowManager.addView(view, params);
+            mWindowManager.addView(view, params, mCompatibilityInfo);
         }
 
         @Override
@@ -146,8 +151,9 @@
     }
 
     public static WindowManager getDefault(CompatibilityInfo compatInfo) {
-        if (compatInfo == null || (!compatInfo.isScalingRequired()
-                && compatInfo.supportsScreen())) {
+        CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
+        cih.set(compatInfo);
+        if (cih.getIfNeeded() == null) {
             return sWindowManager;
         }
 
@@ -159,35 +165,40 @@
             // having to make wrappers.
             WindowManager wm = sCompatWindowManagers.get(compatInfo);
             if (wm == null) {
-                wm = new CompatModeWrapper(sWindowManager, compatInfo);
+                wm = new CompatModeWrapper(sWindowManager, cih);
                 sCompatWindowManagers.put(compatInfo, wm);
             }
             return wm;
         }
     }
+
+    public static WindowManager getDefault(CompatibilityInfoHolder compatInfo) {
+        return new CompatModeWrapper(sWindowManager, compatInfo);
+    }
     
     public boolean isHardwareAccelerated() {
         return false;
     }
     
-    public void addView(View view)
-    {
+    public void addView(View view) {
         addView(view, new WindowManager.LayoutParams(
             WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE));
     }
 
-    public void addView(View view, ViewGroup.LayoutParams params)
-    {
-        addView(view, params, false);
+    public void addView(View view, ViewGroup.LayoutParams params) {
+        addView(view, params, null, false);
     }
     
-    public void addViewNesting(View view, ViewGroup.LayoutParams params)
-    {
-        addView(view, params, false);
+    public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
+        addView(view, params, cih, false);
     }
     
-    private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
-    {
+    public void addViewNesting(View view, ViewGroup.LayoutParams params) {
+        addView(view, params, null, false);
+    }
+
+    private void addView(View view, ViewGroup.LayoutParams params,
+            CompatibilityInfoHolder cih, boolean nest) {
         if (Config.LOGV) Log.v("WindowManager", "addView view=" + view);
 
         if (!(params instanceof WindowManager.LayoutParams)) {
@@ -237,6 +248,11 @@
             
             root = new ViewRoot(view.getContext());
             root.mAddNesting = 1;
+            if (cih == null) {
+                root.mCompatibilityInfo = new CompatibilityInfoHolder();
+            } else {
+                root.mCompatibilityInfo = cih;
+            }
 
             view.setLayoutParams(wparams);
             
@@ -402,6 +418,17 @@
         }
     }
     
+    public void reportNewConfiguration(Configuration config) {
+        synchronized (this) {
+            int count = mViews.length;
+            config = new Configuration(config);
+            for (int i=0; i<count; i++) {
+                ViewRoot root = mRoots[i];
+                root.requestUpdateConfiguration(config);
+            }
+        }
+    }
+
     public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
         ViewParent vp = view.getParent();
         while (vp != null && !(vp instanceof ViewRoot)) {
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp
index 5a162cc..00498bd 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/utils/StreamingZipInflater.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_NDEBUG 1
+//#define LOG_NDEBUG 0
 #define LOG_TAG "szipinf"
 #include <utils/Log.h>
 
@@ -77,7 +77,7 @@
 }
 
 void StreamingZipInflater::initInflateState() {
-    LOGD("Initializing inflate state");
+    LOGV("Initializing inflate state");
 
     memset(&mInflateState, 0, sizeof(mInflateState));
     mInflateState.zalloc = Z_NULL;
@@ -152,13 +152,13 @@
             mInflateState.avail_out = mOutBufSize;
 
             /*
-            LOGD("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
+            LOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
                     mInflateState.avail_in, mInflateState.avail_out,
                     mInflateState.next_in, mInflateState.next_out);
             */
             int result = Z_OK;
             if (mStreamNeedsInit) {
-                LOGD("Initializing zlib to inflate");
+                LOGV("Initializing zlib to inflate");
                 result = inflateInit2(&mInflateState, -MAX_WBITS);
                 mStreamNeedsInit = false;
             }
@@ -192,7 +192,7 @@
         size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
         if (toRead > 0) {
             ssize_t didRead = ::read(mFd, mInBuf, toRead);
-            //LOGD("Reading input chunk, size %08x didread %08x", toRead, didRead);
+            //LOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
             if (didRead < 0) {
                 // TODO: error
                 LOGE("Error reading asset data");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8d8ff96..13205e8 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -860,7 +860,7 @@
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
             lp.format = PixelFormat.TRANSLUCENT;
             lp.setTitle("PointerLocation");
-            WindowManagerImpl wm = (WindowManagerImpl)
+            WindowManager wm = (WindowManager)
                     mContext.getSystemService(Context.WINDOW_SERVICE);
             wm.addView(addView, lp);
             
@@ -883,7 +883,7 @@
                 mPointerLocationInputChannel = null;
             }
             
-            WindowManagerImpl wm = (WindowManagerImpl)
+            WindowManager wm = (WindowManager)
                     mContext.getSystemService(Context.WINDOW_SERVICE);
             wm.removeView(removeView);
         }
@@ -1174,8 +1174,7 @@
                     com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
             params.setTitle("Starting " + packageName);
 
-            WindowManagerImpl wm = (WindowManagerImpl)
-                    context.getSystemService(Context.WINDOW_SERVICE);
+            WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
             View view = win.getDecorView();
 
             if (win.isFloating()) {
@@ -1220,7 +1219,7 @@
             TAG, "Removing starting window for " + appToken + ": " + window);
 
         if (window != null) {
-            WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE);
+            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
             wm.removeView(window);
         }
     }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 6acc32f..6e88490 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -84,7 +84,7 @@
 
 public class WifiService extends IWifiManager.Stub {
     private static final String TAG = "WifiService";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private final WifiStateMachine mWifiStateMachine;
 
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index f9f5758..d8fd7fe 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -38,6 +38,9 @@
             top = t;
             surface = new Surface(session, 0, "BlackSurface",
                     -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  BLACK " + surface + ": CREATE layer=" + layer);
             surface.setAlpha(1.0f);
             surface.setLayer(layer);
         }
@@ -104,6 +107,10 @@
         if (mBlackSurfaces != null) {
             for (int i=0; i<mBlackSurfaces.length; i++) {
                 if (mBlackSurfaces[i] != null) {
+                    if (WindowManagerService.SHOW_TRANSACTIONS ||
+                            WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(
+                                    WindowManagerService.TAG,
+                                    "  BLACK " + mBlackSurfaces[i].surface + ": DESTROY");
                     mBlackSurfaces[i].surface.destroy();
                     mBlackSurfaces[i] = null;
                 }
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index a266d70..a3293e8 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -41,8 +41,9 @@
 
     DimAnimator (SurfaceSession session) {
         if (mDimSurface == null) {
-            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
-                    + mDimSurface + ": CREATE");
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  DIM " + mDimSurface + ": CREATE");
             try {
                 mDimSurface = new Surface(session, 0,
                         "DimAnimator",
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index 220c7fb..d7bb8b3 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -32,8 +32,9 @@
 
     DimSurface(SurfaceSession session) {
         if (mDimSurface == null) {
-            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
-                    + mDimSurface + ": CREATE");
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  DIM " + mDimSurface + ": CREATE");
             try {
                 mDimSurface = new Surface(session, 0,
                         "DimSurface",
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index b01ddd3..8470918 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -102,6 +102,10 @@
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
             }
 
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  FREEZE " + mSurface + ": CREATE");
+
             setRotation(display.getRotation());
 
             if (mSurface != null) {
@@ -284,6 +288,9 @@
 
     public void kill() {
         if (mSurface != null) {
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  FREEZE " + mSurface + ": DESTROY");
             mSurface.destroy();
             mSurface = null;
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 9291182..7b09cc6 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -160,6 +161,7 @@
     static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_DRAG = false;
+    static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
 
@@ -463,6 +465,9 @@
 
     Display mDisplay;
 
+    final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+    final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
+
     H mH = new H();
 
     WindowState mCurrentFocus = null;
@@ -2489,6 +2494,8 @@
 
             if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs);
 
+            win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
+
             if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
                 win.mAlpha = attrs.alpha;
             }
@@ -5052,7 +5059,7 @@
             mWaitingForConfig = true;
             mLayoutNeeded = true;
             startFreezingDisplayLocked(inTransaction);
-            Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
+            //Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
             mInputManager.setDisplayOrientation(0, rotation);
             if (mDisplayEnabled) {
                 // NOTE: We disable the rotation in the emulator because
@@ -5522,6 +5529,26 @@
         return curSize;
     }
 
+    private int computeSmallestWidth(boolean rotated, int dw, int dh, float density) {
+        // We need to determine the smallest width that will occur under normal
+        // operation.  To this, start with the base screen size and compute the
+        // width under the different possible rotations.  We need to un-rotate
+        // the current screen dimensions before doing this.
+        int unrotDw, unrotDh;
+        if (rotated) {
+            unrotDw = dh;
+            unrotDh = dw;
+        } else {
+            unrotDw = dw;
+            unrotDh = dh;
+        }
+        int sw = reduceConfigWidthSize(unrotDw, Surface.ROTATION_0, density, unrotDw);
+        sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh);
+        sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw);
+        sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh);
+        return sw;
+    }
+
     boolean computeNewConfigurationLocked(Configuration config) {
         if (mDisplay == null) {
             return false;
@@ -5567,7 +5594,7 @@
         }
         config.orientation = orientation;
 
-        DisplayMetrics dm = new DisplayMetrics();
+        DisplayMetrics dm = mDisplayMetrics;
         mDisplay.getRealMetrics(dm);
 
         // Override display width and height with what we are computing,
@@ -5577,10 +5604,17 @@
         dm.heightPixels = dm.unscaledHeightPixels = mAppDisplayHeight
                 = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
 
-        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, null);
+        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
+                mCompatDisplayMetrics);
 
         config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density);
         config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density);
+        config.smallestScreenWidthDp = computeSmallestWidth(rotated, dw, dh, dm.density);
+
+        config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
+        config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
+        config.compatSmallestScreenWidthDp = (int)(config.smallestScreenWidthDp
+                / mCompatibleScreenScale);
 
         // We need to determine the smallest width that will occur under normal
         // operation.  To this, start with the base screen size and compute the
@@ -8446,7 +8480,8 @@
                 // surface and ask the app to request another one.
                 Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
                 if (surface != null) {
-                    if (SHOW_TRANSACTIONS) logSurface(win, "RECOVER DESTROY", null);
+                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(win,
+                            "RECOVER DESTROY", null);
                     surface.destroy();
                     win.mSurfaceShown = false;
                     win.mSurface = null;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 144341b..587685e 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -54,6 +54,10 @@
  * A window in the window manager.
  */
 final class WindowState implements WindowManagerPolicy.WindowState {
+    static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
+    static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
+    static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC;
+
     final WindowManagerService mService;
     final Session mSession;
     final IWindow mClient;
@@ -71,7 +75,7 @@
     final boolean mIsImWindow;
     final boolean mIsWallpaper;
     final boolean mIsFloatingLayer;
-    final boolean mEnforceSizeCompat;
+    boolean mEnforceSizeCompat;
     int mViewVisibility;
     boolean mPolicyVisibility = true;
     boolean mPolicyVisibilityAfterAnim = true;
@@ -600,7 +604,7 @@
             if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 flags |= Surface.SECURE;
             }
-            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(
+            if (DEBUG_VISIBILITY) Slog.v(
                 WindowManagerService.TAG, "Creating surface in session "
                 + mSession.mSurfaceSession + " window " + this
                 + " w=" + mCompatFrame.width()
@@ -639,7 +643,8 @@
                         mSession.mSurfaceSession, mSession.mPid,
                         mAttrs.getTitle().toString(),
                         0, w, h, format, flags);
-                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  CREATE SURFACE "
+                if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                        "  CREATE SURFACE "
                         + mSurface + " IN SESSION "
                         + mSession.mSurfaceSession
                         + ": pid=" + mSession.mPid + " format="
@@ -659,7 +664,7 @@
                 WindowManagerService.TAG, "Got surface: " + mSurface
                 + ", set left=" + mFrame.left + " top=" + mFrame.top
                 + ", animLayer=" + mAnimLayer);
-            if (WindowManagerService.SHOW_TRANSACTIONS) {
+            if (SHOW_TRANSACTIONS) {
                 Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
                 WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left
                         + "," + mFrame.top + ") (" +
@@ -677,7 +682,7 @@
                     mSurfaceShown = false;
                     mSurface.hide();
                     if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
-                        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null);
+                        if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null);
                         mSurface.setFlags(Surface.SURFACE_DITHER,
                                 Surface.SURFACE_DITHER);
                     }
@@ -688,7 +693,7 @@
                 mLastHidden = true;
             } finally {
                 Surface.closeTransaction();
-                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION createSurfaceLocked");
+                if (SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "<<< CLOSE TRANSACTION createSurfaceLocked");
             }
             if (WindowManagerService.localLOGV) Slog.v(
                     WindowManagerService.TAG, "Created surface " + this);
@@ -725,7 +730,7 @@
             }
 
             try {
-                if (WindowManagerService.DEBUG_VISIBILITY) {
+                if (DEBUG_VISIBILITY) {
                     RuntimeException e = null;
                     if (!WindowManagerService.HIDE_STACK_CRAWLS) {
                         e = new RuntimeException();
@@ -734,13 +739,13 @@
                     Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface "
                             + mSurface + ", session " + mSession, e);
                 }
-                if (WindowManagerService.SHOW_TRANSACTIONS) {
+                if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
                     RuntimeException e = null;
                     if (!WindowManagerService.HIDE_STACK_CRAWLS) {
                         e = new RuntimeException();
                         e.fillInStackTrace();
                     }
-                    if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DESTROY", e);
+                    WindowManagerService.logSurface(this, "DESTROY", e);
                 }
                 mSurface.destroy();
             } catch (RuntimeException e) {
@@ -756,7 +761,7 @@
 
     boolean finishDrawingLocked() {
         if (mDrawPending) {
-            if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v(
+            if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v(
                 WindowManagerService.TAG, "finishDrawingLocked: " + mSurface);
             mCommitDrawPending = true;
             mDrawPending = false;
@@ -783,7 +788,7 @@
 
     // This must be called while inside a transaction.
     boolean performShowLocked() {
-        if (WindowManagerService.DEBUG_VISIBILITY) {
+        if (DEBUG_VISIBILITY) {
             RuntimeException e = null;
             if (!WindowManagerService.HIDE_STACK_CRAWLS) {
                 e = new RuntimeException();
@@ -794,9 +799,9 @@
                     + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
         }
         if (mReadyToShow && isReadyForDisplay()) {
-            if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this,
+            if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this,
                     "SHOW (performShowLocked)", null);
-            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this
+            if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this
                     + " during animation: policyVis=" + mPolicyVisibility
                     + " attHidden=" + mAttachedHidden
                     + " tok.hiddenRequested="
@@ -958,7 +963,7 @@
         mHasTransformation = false;
         mHasLocalTransformation = false;
         if (mPolicyVisibility != mPolicyVisibilityAfterAnim) {
-            if (WindowManagerService.DEBUG_VISIBILITY) {
+            if (DEBUG_VISIBILITY) {
                 Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": "
                         + mPolicyVisibilityAfterAnim);
             }
@@ -1020,7 +1025,7 @@
         if (mSurface != null) {
             mService.mDestroySurface.add(this);
             mDestroying = true;
-            if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null);
+            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null);
             mSurfaceShown = false;
             try {
                 mSurface.hide();
@@ -1414,9 +1419,9 @@
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             return false;
         }
-        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this);
+        if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this);
         if (doAnimation) {
-            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility="
+            if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility="
                     + mPolicyVisibility + " mAnimation=" + mAnimation);
             if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) {
                 doAnimation = false;
@@ -1462,7 +1467,7 @@
         if (doAnimation) {
             mPolicyVisibilityAfterAnim = false;
         } else {
-            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this);
+            if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this);
             mPolicyVisibilityAfterAnim = false;
             mPolicyVisibility = false;
             // Window is no longer visible -- make sure if we were waiting