* Moved supports-density tag under manifest
* Refactored Compatibility code
  * Added CompatibilityInfo class
  * Removed getApplicationScale from Context
  * Added Resources#getCompatibilityInfo so that RootView can get the compatibility info w/o going through Context
* Expandable support
  * Added expandable tag under manifest
  * Old application w/o expandable is given the default screen size  ([320, 480] x density).
  * The non-expandable window is centered.
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 7cd65e2..d8bab56 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -30,6 +30,7 @@
 import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
 import android.util.Config;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.EventLog;
 import android.util.SparseArray;
@@ -40,6 +41,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
 import android.content.pm.PackageManager;
+import android.content.res.CompatibilityInfo;
 import android.content.Context;
 import android.app.ActivityManagerNative;
 import android.Manifest;
@@ -125,9 +127,8 @@
     int mHeight;
     Rect mDirty; // will be a graphics.Region soon
     boolean mIsAnimating;
-    // TODO: change these to scalar class.
-    private float mAppScale;
-    private float mAppScaleInverted; // = 1.0f / mAppScale
+    
+    private CompatibilityInfo mCompatibilityInfo;
     private int[] mWindowLayoutParamsBackup = null;
 
     final View.AttachInfo mAttachInfo;
@@ -386,12 +387,15 @@
         synchronized (this) {
             if (mView == null) {
                 mView = view;
-                mAppScale = mView.getContext().getApplicationScale();
-                if (mAppScale != 1.0f) {
+                mWindowAttributes.copyFrom(attrs);
+                mCompatibilityInfo =
+                        mView.getContext().getResources().getCompatibilityInfo();
+                if (mCompatibilityInfo.mScalingRequired) {
                     mWindowLayoutParamsBackup = new int[4];
                 }
-                mAppScaleInverted = 1.0f / mAppScale;
-                mWindowAttributes.copyFrom(attrs);
+                if (!mCompatibilityInfo.mExpandable) {
+                    adjustWindowAttributesForCompatibleMode(mWindowAttributes);
+                }
                 mSoftInputMode = attrs.softInputMode;
                 mWindowAttributesChanged = true;
                 mAttachInfo.mRootView = view;
@@ -406,9 +410,8 @@
                 // manager, to make sure we do the relayout before receiving
                 // any other events from the system.
                 requestLayout();
-
                 try {
-                    res = sWindowSession.add(mWindow, attrs,
+                    res = sWindowSession.add(mWindow, mWindowAttributes,
                             getHostVisibility(), mAttachInfo.mContentInsets);
                 } catch (RemoteException e) {
                     mAdded = false;
@@ -417,7 +420,10 @@
                     unscheduleTraversals();
                     throw new RuntimeException("Adding window failed", e);
                 }
-                mAttachInfo.mContentInsets.scale(mAppScaleInverted);
+                if (mCompatibilityInfo.mScalingRequired) {
+                    mAttachInfo.mContentInsets.scale(
+                            mCompatibilityInfo.mApplicationInvertedScale);
+                }
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
                 if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
@@ -529,13 +535,13 @@
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
         if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
-        if (mCurScrollY != 0 || mAppScale != 1.0f) {
+        if (mCurScrollY != 0 || mCompatibilityInfo.mScalingRequired) {
             mTempRect.set(dirty);
             if (mCurScrollY != 0) {
                mTempRect.offset(0, -mCurScrollY);
             }
-            if (mAppScale != 1.0f) {
-                mTempRect.scale(mAppScale);
+            if (mCompatibilityInfo.mScalingRequired) {
+                mTempRect.scale(mCompatibilityInfo.mApplicationScale);
             }
             dirty = mTempRect;
         }
@@ -615,6 +621,8 @@
         boolean viewVisibilityChanged = mViewVisibility != viewVisibility
                 || mNewSurfaceNeeded;
 
+        float appScale = mCompatibilityInfo.mApplicationScale;
+
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
             mWindowAttributesChanged = false;
@@ -625,9 +633,10 @@
             fullRedrawNeeded = true;
             mLayoutRequested = true;
 
-            Display d = new Display(0);
-            desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
-            desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
+            DisplayMetrics packageMetrics = 
+                mView.getContext().getResources().getDisplayMetrics();
+            desiredWindowWidth = packageMetrics.widthPixels;
+            desiredWindowHeight = packageMetrics.heightPixels;
 
             // For the very first time, tell the view hierarchy that it
             // is attached to the window.  Note that at this point the surface
@@ -696,9 +705,10 @@
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowResizesToFitContent = true;
 
-                    Display d = new Display(0);
-                    desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
-                    desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
+                    DisplayMetrics packageMetrics = 
+                        mView.getContext().getResources().getDisplayMetrics();
+                    desiredWindowWidth = packageMetrics.widthPixels;
+                    desiredWindowHeight = packageMetrics.heightPixels;
                 }
             }
 
@@ -878,7 +888,7 @@
             mHeight = frame.height();
 
             if (initialized) {
-                mGlCanvas.setViewport((int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
+                mGlCanvas.setViewport((int) (mWidth * appScale), (int) (mHeight * appScale));
             }
 
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -968,11 +978,7 @@
                         mTmpLocation[1] + host.mBottom - host.mTop);
 
                 host.gatherTransparentRegion(mTransparentRegion);
-
-                // TODO: scale the region, like:
-                // Region uses native methods. We probabl should have ScalableRegion class.
-
-                // Region does not have equals method ?
+                mTransparentRegion.scale(appScale);                
                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                     mPreviousTransparentRegion.set(mTransparentRegion);
                     // reconfigure window manager
@@ -983,7 +989,6 @@
                 }
             }
 
-
             if (DBG) {
                 System.out.println("======================================");
                 System.out.println("performTraversals -- after setFrame");
@@ -1003,10 +1008,11 @@
             givenContent.left = givenContent.top = givenContent.right
                     = givenContent.bottom = givenVisible.left = givenVisible.top
                     = givenVisible.right = givenVisible.bottom = 0;
-            insets.contentInsets.scale(mAppScale);
-            insets.visibleInsets.scale(mAppScale);
-
             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
+            if (mCompatibilityInfo.mScalingRequired) {
+                insets.contentInsets.scale(appScale);
+                insets.visibleInsets.scale(appScale);
+            }
             if (insetsPending || !mLastGivenInsets.equals(insets)) {
                 mLastGivenInsets.set(insets);
                 try {
@@ -1154,6 +1160,8 @@
             mCurScrollY = yoff;
             fullRedrawNeeded = true;
         }
+        float appScale = mCompatibilityInfo.mApplicationScale;
+        boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
 
         Rect dirty = mDirty;
         if (mUseGL) {
@@ -1169,12 +1177,11 @@
                     mAttachInfo.mIgnoreDirtyState = true;
                     mView.mPrivateFlags |= View.DRAWN;
 
-                    float scale = mAppScale;
                     int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                     try {
                         canvas.translate(0, -yoff);
-                        if (scale != 1.0f) {
-                            canvas.scale(scale, scale);
+                        if (scalingRequired) {
+                            canvas.scale(appScale, appScale);
                         }
                         mView.draw(canvas);
                         if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -1206,8 +1213,8 @@
         }
 
         if (fullRedrawNeeded) {
-            mAttachInfo.mIgnoreDirtyState = true;            
-            dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
+            mAttachInfo.mIgnoreDirtyState = true;
+            dirty.union(0, 0, (int) (mWidth * appScale), (int) (mHeight * appScale));
         }
 
         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
@@ -1215,7 +1222,8 @@
                     + mWindowAttributes.getTitle()
                     + ": dirty={" + dirty.left + "," + dirty.top
                     + "," + dirty.right + "," + dirty.bottom + "} surface="
-                    + surface + " surface.isValid()=" + surface.isValid());
+                    + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
+                    appScale + ", width=" + mWidth + ", height=" + mHeight);
         }
 
         Canvas canvas;
@@ -1272,18 +1280,16 @@
                 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
                 mView.mPrivateFlags |= View.DRAWN;
 
-                float scale = mAppScale;
                 if (DEBUG_DRAW) {
                     Context cxt = mView.getContext();
                     Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
-                            ", appScale=" + mAppScale);
+                            ", metrics=" + mView.getContext().getResources().getDisplayMetrics());
                 }
-                int saveCount =  canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                 try {
                     canvas.translate(0, -yoff);
-                    if (scale != 1.0f) {
-                        // re-scale this
-                        canvas.scale(scale, scale);
+                    if (scalingRequired) {
+                        canvas.scale(appScale, appScale);
                     }
                     mView.draw(canvas);
                 } finally {
@@ -1586,8 +1592,8 @@
             } else {
                 didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
             }
-            if (event != null) {
-                event.scale(mAppScaleInverted);
+            if (event != null && mCompatibilityInfo.mScalingRequired) {
+                event.scale(mCompatibilityInfo.mApplicationInvertedScale);
             }
 
             try {
@@ -1709,8 +1715,9 @@
                         if (mGlWanted && !mUseGL) {
                             initializeGL();
                             if (mGlCanvas != null) {
-                                mGlCanvas.setViewport((int) (mWidth * mAppScale),
-                                        (int) (mHeight * mAppScale));
+                                float appScale = mCompatibilityInfo.mApplicationScale;
+                                mGlCanvas.setViewport(
+                                        (int) (mWidth * appScale), (int) (mHeight * appScale));
                             }
                         }
                     }
@@ -1914,8 +1921,8 @@
         } else {
             didFinish = false;
         }
-        if (event != null) {
-            event.scale(mAppScaleInverted);
+        if (event != null && mCompatibilityInfo.mScalingRequired) {
+            event.scale(mCompatibilityInfo.mApplicationInvertedScale);
         }
 
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
@@ -2345,27 +2352,59 @@
 
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
-
         boolean restore = false;
-        if (params != null && mAppScale != 1.0f) {
+        float appScale = mCompatibilityInfo.mApplicationScale;
+        boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
+        
+        if (params != null && !mCompatibilityInfo.mExpandable) {
+            adjustWindowAttributesForCompatibleMode(params);
+        }
+        if (params != null && scalingRequired) {
             restore = true;
-            params.scale(mAppScale, mWindowLayoutParamsBackup);
+            params.scale(appScale, mWindowLayoutParamsBackup);
         }
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
-                (int) (mView.mMeasuredWidth * mAppScale),
-                (int) (mView.mMeasuredHeight * mAppScale),
+                (int) (mView.mMeasuredWidth * appScale),
+                (int) (mView.mMeasuredHeight * appScale),
                 viewVisibility, insetsPending, mWinFrame,
                 mPendingContentInsets, mPendingVisibleInsets, mSurface);
         if (restore) {
             params.restore(mWindowLayoutParamsBackup);
         }
-
-        mPendingContentInsets.scale(mAppScaleInverted);
-        mPendingVisibleInsets.scale(mAppScaleInverted);
-        mWinFrame.scale(mAppScaleInverted);
+        if (scalingRequired) {
+            float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
+            mPendingContentInsets.scale(invertedScale);
+            mPendingVisibleInsets.scale(invertedScale);
+            mWinFrame.scale(invertedScale);
+        }
         return relayoutResult;
     }
+    
+    /**
+     * Adjust the window's layout parameter for compatibility mode. It replaces FILL_PARENT
+     * with the default window size, and centers if the window wanted to fill
+     * horizontally.
+     * 
+     * @param attrs the window's layout params to adjust
+     */
+    private void adjustWindowAttributesForCompatibleMode(WindowManager.LayoutParams attrs) {
+        // fix app windows only
+        if (attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+            DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
+            // TODO: improve gravity logic
+            if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
+                attrs.width = metrics.widthPixels;
+                attrs.gravity |= Gravity.CENTER_HORIZONTAL;
+            }
+            if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
+                attrs.height = metrics.heightPixels;
+            }
+            if (DEBUG_LAYOUT) {
+                Log.d(TAG, "Attributes fixed for compatibility : " + attrs);
+            }
+        }
+    }
 
     /**
      * {@inheritDoc}
@@ -2470,11 +2509,16 @@
                 + " visibleInsets=" + visibleInsets.toShortString()
                 + " reportDraw=" + reportDraw);
         Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
-
-        coveredInsets.scale(mAppScaleInverted);
-        visibleInsets.scale(mAppScaleInverted);
-        msg.arg1 = (int) (w * mAppScaleInverted);
-        msg.arg2 = (int) (h * mAppScaleInverted);
+        if (mCompatibilityInfo.mScalingRequired) {
+            float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
+            coveredInsets.scale(invertedScale);
+            visibleInsets.scale(invertedScale);
+            msg.arg1 = (int) (w * invertedScale);
+            msg.arg2 = (int) (h * invertedScale);
+        } else {
+            msg.arg1 = w;
+            msg.arg2 = h;
+        }
         msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
         sendMessage(msg);
     }