AI 147976: Compatibility mode support. Part 2.
  * Introduced ApplicationScale (may not be good name. CompatibilityScale? CanvasScale? Pls let me know if you have better idea)
  * Changes to RootView / SurfaceView
  - Makes the app believe it's running in the supported density/resolution.
  - Makes the window manager believe it's running at the right density/resolution.
  * Added methods to Rect/Event for scaling up/down.
  Known issues:
  * certain kind of images (such as nine patch for buttons) seesm to be loaded not by app, thus does not take the scale into account,
  which, in turn, is causing layout issue.
  * ZoomButton in MapView is rendered in wrong place
  * Transparent region on Surface is not correct
  * Specifying different densities in one process is not working.
  BUG=1770627

Automated import of CL 147976
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 18ee9ae..0b03626 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -128,6 +128,9 @@
     int mHeight;
     Rect mDirty; // will be a graphics.Region soon
     boolean mIsAnimating;
+    // TODO: change these to scaler class.
+    float mAppScale;
+    float mAppScaleInverted; // = 1.0f / mAppScale
 
     final View.AttachInfo mAttachInfo;
 
@@ -384,10 +387,12 @@
             View panelParentView) {
         synchronized (this) {
             if (mView == null) {
+                mView = view;
+                mAppScale = mView.getContext().getApplicationScale();
+                mAppScaleInverted = 1.0f / mAppScale;
                 mWindowAttributes.copyFrom(attrs);
                 mSoftInputMode = attrs.softInputMode;
                 mWindowAttributesChanged = true;
-                mView = view;
                 mAttachInfo.mRootView = view;
                 if (panelParentView != null) {
                     mAttachInfo.mPanelParentWindowToken
@@ -400,7 +405,7 @@
                 // manager, to make sure we do the relayout before receiving
                 // any other events from the system.
                 requestLayout();
-                
+
                 try {
                     res = sWindowSession.add(mWindow, attrs,
                             getHostVisibility(), mAttachInfo.mContentInsets);
@@ -411,6 +416,7 @@
                     unscheduleTraversals();
                     throw new RuntimeException("Adding window failed", e);
                 }
+                mAttachInfo.mContentInsets.scale(mAppScaleInverted);
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
                 if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
@@ -472,6 +478,8 @@
         synchronized (this) {
             int oldSoftInputMode = mWindowAttributes.softInputMode;
             mWindowAttributes.copyFrom(attrs);
+            mWindowAttributes.scale(mAppScale);
+
             if (newView) {
                 mSoftInputMode = attrs.softInputMode;
                 requestLayout();
@@ -521,9 +529,14 @@
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
         if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
-        if (mCurScrollY != 0) {
+        if (mCurScrollY != 0 || mAppScale != 1.0f) {
             mTempRect.set(dirty);
-            mTempRect.offset(0, -mCurScrollY);
+            if (mCurScrollY != 0) {
+               mTempRect.offset(0, -mCurScrollY);
+            }
+            if (mAppScale != 1.0f) {
+                mTempRect.scale(mAppScale);
+            }
             dirty = mTempRect;
         }
         mDirty.union(dirty);
@@ -613,8 +626,8 @@
             mLayoutRequested = true;
 
             Display d = new Display(0);
-            desiredWindowWidth = d.getWidth();
-            desiredWindowHeight = d.getHeight();
+            desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
+            desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
 
             // For the very first time, tell the view hierarchy that it
             // is attached to the window.  Note that at this point the surface
@@ -683,8 +696,8 @@
                     windowResizesToFitContent = true;
 
                     Display d = new Display(0);
-                    desiredWindowWidth = d.getWidth();
-                    desiredWindowHeight = d.getHeight();
+                    desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
+                    desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
                 }
             }
 
@@ -792,10 +805,12 @@
                         params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                     }
                 }
-                relayoutResult = sWindowSession.relayout(
-                    mWindow, params, host.mMeasuredWidth, host.mMeasuredHeight,
-                    viewVisibility, insetsPending, frame,
-                    mPendingContentInsets, mPendingVisibleInsets, mSurface);
+                if (DEBUG_LAYOUT) {
+                    Log.i(TAG, "host=w:" + host.mMeasuredWidth + ", h:" +
+                            host.mMeasuredHeight + ", params=" + params);
+                }
+                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
+
                 if (params != null) {
                     params.flags = fl;
                 }
@@ -862,7 +877,7 @@
             mHeight = frame.height();
 
             if (initialized) {
-                mGlCanvas.setViewport(mWidth, mHeight);
+                mGlCanvas.setViewport((int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
             }
 
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -944,6 +959,11 @@
                         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 ?
                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                     mPreviousTransparentRegion.set(mTransparentRegion);
                     // reconfigure window manager
@@ -974,6 +994,9 @@
             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 (insetsPending || !mLastGivenInsets.equals(insets)) {
                 mLastGivenInsets.set(insets);
@@ -1113,7 +1136,7 @@
         
         int yoff;
         final boolean scrolling = mScroller != null
-                && mScroller.computeScrollOffset(); 
+                && mScroller.computeScrollOffset();
         if (scrolling) {
             yoff = mScroller.getCurrY();
         } else {
@@ -1135,10 +1158,19 @@
                     mGL.glEnable(GL_SCISSOR_TEST);
 
                     mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
-                    canvas.translate(0, -yoff);
                     mView.mPrivateFlags |= View.DRAWN;
-                    mView.draw(canvas);
-                    canvas.translate(0, yoff);
+
+                    float scale = mAppScale;
+                    int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                    try {
+                        canvas.translate(0, -yoff);
+                        if (scale != 1.0f) {
+                            canvas.scale(scale, scale);
+                        }
+                        mView.draw(canvas);
+                    } finally {
+                        canvas.restoreToCount(saveCount);
+                    }
 
                     mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                     checkEglErrors();
@@ -1160,7 +1192,7 @@
         }
 
         if (fullRedrawNeeded)
-            dirty.union(0, 0, mWidth, mHeight);
+            dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
 
         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
             Log.v("ViewRoot", "Draw " + mView + "/"
@@ -1212,10 +1244,24 @@
                 dirty.setEmpty();
                 mIsAnimating = false;
                 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
-                canvas.translate(0, -yoff);
-                mView.mPrivateFlags |= View.DRAWN;                    
-                mView.draw(canvas);
-                canvas.translate(0, yoff);
+                mView.mPrivateFlags |= View.DRAWN;
+
+                float scale = mAppScale;
+                Context cxt = mView.getContext();
+                if (DEBUG_DRAW) {
+                    Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + ", appScale=" + mAppScale);
+                }
+                int saveCount =  canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                try {
+                    canvas.translate(0, -yoff);
+                    if (scale != 1.0f) {
+                        // re-scale this
+                        canvas.scale(scale, scale);
+                    }
+                    mView.draw(canvas);
+                } finally {
+                    canvas.restoreToCount(saveCount);
+                }
 
                 if (SHOW_FPS) {
                     int now = (int)SystemClock.elapsedRealtime();
@@ -1508,6 +1554,9 @@
             } else {
                 didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
             }
+            if (event != null) {
+                event.scale(mAppScaleInverted);
+            }
 
             try {
                 boolean handled;
@@ -1628,7 +1677,8 @@
                         if (mGlWanted && !mUseGL) {
                             initializeGL();
                             if (mGlCanvas != null) {
-                                mGlCanvas.setViewport(mWidth, mHeight);
+                                mGlCanvas.setViewport((int) (mWidth * mAppScale),
+                                        (int) (mHeight * mAppScale));
                             }
                         }
                     }
@@ -1828,6 +1878,9 @@
         } else {
             didFinish = false;
         }
+        if (event != null) {
+            event.scale(mAppScaleInverted);
+        }
 
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
@@ -2254,6 +2307,20 @@
         return mAudioManager;
     }
 
+    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
+            boolean insetsPending) throws RemoteException {
+        int relayoutResult = sWindowSession.relayout(
+                mWindow, params,
+                (int) (mView.mMeasuredWidth * mAppScale),
+                (int) (mView.mMeasuredHeight * mAppScale),
+                viewVisibility, insetsPending, mWinFrame,
+                mPendingContentInsets, mPendingVisibleInsets, mSurface);
+        mPendingContentInsets.scale(mAppScaleInverted);
+        mPendingVisibleInsets.scale(mAppScaleInverted);
+        mWinFrame.scale(mAppScaleInverted);
+        return relayoutResult;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -2322,12 +2389,8 @@
                     // to the window manager to make sure it has the correct
                     // animation info.
                     try {
-                        if ((sWindowSession.relayout(
-                                    mWindow, mWindowAttributes,
-                                    mView.mMeasuredWidth, mView.mMeasuredHeight,
-                                    viewVisibility, false, mWinFrame, mPendingContentInsets,
-                                    mPendingVisibleInsets, mSurface)
-                                &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+                        if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
+                                & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                             sWindowSession.finishDrawing(mWindow);
                         }
                     } catch (RemoteException e) {
@@ -2361,8 +2424,11 @@
                 + " visibleInsets=" + visibleInsets.toShortString()
                 + " reportDraw=" + reportDraw);
         Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
-        msg.arg1 = w;
-        msg.arg2 = h;
+
+        coveredInsets.scale(mAppScaleInverted);
+        visibleInsets.scale(mAppScaleInverted);
+        msg.arg1 = (int) (w * mAppScaleInverted);
+        msg.arg2 = (int) (h * mAppScaleInverted);
         msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
         sendMessage(msg);
     }
@@ -2493,7 +2559,7 @@
                     sWindowSession.finishKey(mWindow);
                  } catch (RemoteException e) {
                  }
-            } else if (mIsPointer) {
+           } else if (mIsPointer) {
                 boolean didFinish;
                 MotionEvent event = mMotionEvent;
                 if (event == null) {