resolution support fix/improvement
    * adding compatibility menu
    * backup gravity
    * set expanable=true if the screen size is hvga * density.
    * added "supports any density" mode. I'll add sdk check later.
    * disallow to catch orientation change event if the app is not expandable. This
      was causing layout problem under non-expandable mode. I discussed this with Mike C
      and we agreed to do this approach for now. We'll revisit if this causes problem to
      a lot of applications.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f3dfc5a..f10dd53 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -145,6 +145,13 @@
     public static final int FLAG_ALLOW_BACKUP = 1<<10;
     
     /**
+     * Indicates that the application supports any densities;
+     * {@hide}
+     */
+    public static final int ANY_DENSITY = -1;
+    private static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
+
+    /**
      * Flags associated with the application.  Any combination of
      * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
@@ -369,4 +376,14 @@
         }
         return null;
     }
+
+    /**
+     * Disable compatibility mode
+     * 
+     * @hide
+     */
+    public void disableCompatibilityMode() {
+        expandable = true;
+        supportsDensities = ANY_DENSITIES_ARRAY;
+    }
 }
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 19379fb..836de39 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -51,10 +51,17 @@
     public final float mApplicationInvertedScale;
     
     /**
-     * 
      * A boolean flag to indicates that the application can expand over the original size.
+     * The flag is set to true if
+     * 1) Application declares its expandable in manifest file using <expandable /> or
+     * 2) The screen size is same as (320 x 480) * density. 
      */
-    public final boolean mExpandable;
+    public boolean mExpandable;
+
+    /**
+     * A expandable flag in the configuration.
+     */
+    public final boolean mConfiguredExpandable;
     
     /**
      * A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
@@ -62,13 +69,16 @@
     public final boolean mScalingRequired;
 
     public CompatibilityInfo(ApplicationInfo appInfo) {
-        // A temp workaround to fix rotation issue.
-        // mExpandable = appInfo.expandable;
-        mExpandable = true;
+        mExpandable = mConfiguredExpandable = appInfo.expandable;
+        
         float packageDensityScale = -1.0f;
         if (appInfo.supportsDensities != null) {
             int minDiff = Integer.MAX_VALUE;
             for (int density : appInfo.supportsDensities) {
+                if (density == ApplicationInfo.ANY_DENSITY) { 
+                    packageDensityScale = 1.0f;
+                    break;
+                }
                 int tmpDiff = Math.abs(DisplayMetrics.DEVICE_DENSITY - density);
                 if (tmpDiff == 0) {
                     packageDensityScale = 1.0f;
@@ -92,7 +102,7 @@
 
     private CompatibilityInfo() {
         mApplicationScale = mApplicationInvertedScale = 1.0f;
-        mExpandable = true;
+        mExpandable = mConfiguredExpandable = true;
         mScalingRequired = false;
     }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 976b618..2f63820 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -88,7 +88,7 @@
     PluralRules mPluralRule;
     
     private final CompatibilityInfo mCompatibilityInfo;
-    
+
     private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
         @Override
         public void put(int k, Object o) {
@@ -1255,7 +1255,7 @@
 
         return array;
     }
-    
+
     /**
      * Store the newly updated configuration.
      */
@@ -1268,7 +1268,7 @@
             }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
-                mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration);
+                mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration.orientation);
             }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 52cec22..c2da593 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1025,6 +1025,14 @@
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
         /**
+         * If 0, the compatibility mode is off for all applications.
+         * If 1, older applications run under compatibility mode.
+         * TODO: remove this settings before code freeze (bug/1907571)
+         * @hide
+         */
+        public static final String COMPATIBILITY_MODE = "compatibility_mode";
+
+        /**
          * The screen backlight brightness between 0 and 255.
          */
         public static final String SCREEN_BRIGHTNESS = "screen_brightness";
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 987be2b..245148d 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -103,10 +103,10 @@
     }
 
     /**
-     * Update the display metrics based on the compatibility info and configuration.
+     * Update the display metrics based on the compatibility info and orientation
      * {@hide}
      */
-    public void updateMetrics(CompatibilityInfo compatibilityInfo, Configuration configuration) {
+    public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation) {
         if (compatibilityInfo.mScalingRequired) {
             float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
             density *= invertedRatio;
@@ -116,31 +116,42 @@
             widthPixels *= invertedRatio;
             heightPixels *= invertedRatio;
         }
-        if (!compatibilityInfo.mExpandable) {
+        if (!compatibilityInfo.mConfiguredExpandable) {
             // Note: this assume that configuration is updated before calling
             // updateMetrics method.
             int defaultWidth;
             int defaultHeight;
-            switch (configuration.orientation) {
+            switch (orientation) {
                 case Configuration.ORIENTATION_LANDSCAPE: {
                     defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
                     defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
                     break;
                 }
-                case Configuration.ORIENTATION_UNDEFINED:
                 case Configuration.ORIENTATION_PORTRAIT:
                 case Configuration.ORIENTATION_SQUARE:
                 default: {
                     defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
                     defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
+                    break;
+                }
+                case Configuration.ORIENTATION_UNDEFINED: {
+                    // don't change
+                    return;
                 }
             }
-            // adjust the size only when the device's screen is bigger.
-            if (defaultWidth < widthPixels) {
-                widthPixels = defaultWidth;
-            }
-            if (defaultHeight < heightPixels) {
-                heightPixels = defaultHeight;
+            
+            if (defaultWidth == widthPixels && defaultHeight == heightPixels) {
+                // the screen size is same as expected size. make it expandable
+                compatibilityInfo.mExpandable = true;
+            } else {
+                compatibilityInfo.mExpandable = false;
+                // adjust the size only when the device's screen is bigger.
+                if (defaultWidth < widthPixels) {
+                    widthPixels = defaultWidth;
+                }
+                if (defaultHeight < heightPixels) {
+                    heightPixels = defaultHeight;
+                }
             }
         }
     }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index d8bab56..ee8229d 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -129,7 +129,6 @@
     boolean mIsAnimating;
     
     private CompatibilityInfo mCompatibilityInfo;
-    private int[] mWindowLayoutParamsBackup = null;
 
     final View.AttachInfo mAttachInfo;
 
@@ -388,10 +387,11 @@
             if (mView == null) {
                 mView = view;
                 mWindowAttributes.copyFrom(attrs);
-                mCompatibilityInfo =
-                        mView.getContext().getResources().getCompatibilityInfo();
-                if (mCompatibilityInfo.mScalingRequired) {
-                    mWindowLayoutParamsBackup = new int[4];
+                mCompatibilityInfo = mView.getContext().getResources().getCompatibilityInfo();
+                boolean restore = false;
+                if (mCompatibilityInfo.mScalingRequired || !mCompatibilityInfo.mExpandable) {
+                    restore = true;
+                    mWindowAttributes.backup();
                 }
                 if (!mCompatibilityInfo.mExpandable) {
                     adjustWindowAttributesForCompatibleMode(mWindowAttributes);
@@ -420,6 +420,11 @@
                     unscheduleTraversals();
                     throw new RuntimeException("Adding window failed", e);
                 }
+
+                if (restore) {
+                    mWindowAttributes.restore();
+                }
+
                 if (mCompatibilityInfo.mScalingRequired) {
                     mAttachInfo.mContentInsets.scale(
                             mCompatibilityInfo.mApplicationInvertedScale);
@@ -1921,9 +1926,6 @@
         } else {
             didFinish = false;
         }
-        if (event != null && mCompatibilityInfo.mScalingRequired) {
-            event.scale(mCompatibilityInfo.mApplicationInvertedScale);
-        }
 
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
@@ -2355,13 +2357,15 @@
         boolean restore = false;
         float appScale = mCompatibilityInfo.mApplicationScale;
         boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
-        
         if (params != null && !mCompatibilityInfo.mExpandable) {
+            restore = true;
+            params.backup();
             adjustWindowAttributesForCompatibleMode(params);
         }
         if (params != null && scalingRequired) {
+            if (!restore) params.backup();
             restore = true;
-            params.scale(appScale, mWindowLayoutParamsBackup);
+            params.scale(appScale);
         }
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
@@ -2370,7 +2374,7 @@
                 viewVisibility, insetsPending, mWinFrame,
                 mPendingContentInsets, mPendingVisibleInsets, mSurface);
         if (restore) {
-            params.restore(mWindowLayoutParamsBackup);
+            params.restore();
         }
         if (scalingRequired) {
             float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
@@ -2396,12 +2400,15 @@
             if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
                 attrs.width = metrics.widthPixels;
                 attrs.gravity |= Gravity.CENTER_HORIZONTAL;
+                mWindowAttributesChanged = attrs == mWindowAttributes;
             }
             if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
                 attrs.height = metrics.heightPixels;
+                attrs.gravity |= Gravity.TOP;
+                mWindowAttributesChanged = attrs == mWindowAttributes;
             }
             if (DEBUG_LAYOUT) {
-                Log.d(TAG, "Attributes fixed for compatibility : " + attrs);
+                Log.d(TAG, "Adjusted Attributes for compatibility : " + attrs);
             }
         }
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ec2069c..e1c4687 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -818,6 +818,9 @@
         public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
         public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
     
+        // internal buffer to backup/restore parameters under compatibility mode.
+        private int[] mCompatibilityParamsBackup = null;
+        
         public final int copyFrom(LayoutParams o) {
             int changes = 0;
     
@@ -975,37 +978,47 @@
 
         /**
          * Scale the layout params' coordinates and size.
-         * Returns the original info as a backup so that the caller can
-         * restore the layout params;
          */
-        void scale(float scale, int[] backup) {
-            if (scale != 1.0f) {
-                backup[0] = x;
-                backup[1] = y;
-                x *= scale;
-                y *= scale;
-                if (width > 0) {
-                    backup[2] = width;
-                    width *= scale;
-                }
-                if (height > 0) {
-                    backup[3] = height;
-                    height *= scale;
-                }
+        void scale(float scale) {
+            x *= scale;
+            y *= scale;
+            if (width > 0) {
+                width *= scale;
+            }
+            if (height > 0) {
+                height *= scale;
             }
         }
 
         /**
-         * Restore the layout params' coordinates and size.
+         * Backup the layout parameters used in compatibility mode.
+         * @see LayoutParams#restore()
          */
-        void restore(int[] backup) {
-            x = backup[0];
-            y = backup[1];
-            if (width > 0) {
-                width = backup[2];
+        void backup() {
+            int[] backup = mCompatibilityParamsBackup;
+            if (backup == null) {
+                // we backup 5 elements, x, y, width, height and gravity.
+                backup = mCompatibilityParamsBackup = new int[5];
             }
-            if (height > 0) {
+            backup[0] = x;
+            backup[1] = y;
+            backup[2] = width;
+            backup[3] = height;
+            backup[4] = gravity;
+        }
+
+        /**
+         * Restore the layout params' coordinates, size and gravity
+         * @see LayoutParams#backup()
+         */
+        void restore() {
+            int[] backup = mCompatibilityParamsBackup;
+            if (backup != null) {
+                x = backup[0];
+                y = backup[1];
+                width = backup[2];
                 height = backup[3];
+                gravity = backup[4];
             }
         }