am e0ef973b: Merge change 8323 into donut

Merge commit 'e0ef973b1358585d039989ee5572e16751078aaf'

* commit 'e0ef973b1358585d039989ee5572e16751078aaf':
  * a best effort fix for apps that uses get/set Matrix API on canvas.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e6bbf9f5..9178131 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.*;
 import android.os.Parcelable;
 import android.os.Parcel;
@@ -135,8 +136,12 @@
     private Canvas mCanvas;
 
     // The display metrics used to provide the pseudo canvas size for applications
-    // running in compatibility mode. This is set to null for regular mode.
-    private DisplayMetrics mDisplayMetrics;
+    // running in compatibility mode. This is set to null for non compatibility mode.
+    private DisplayMetrics mCompatibleDisplayMetrics;
+
+    // A matrix to scale the matrix set by application. This is set to null for
+    // non compatibility mode.
+    private Matrix mCompatibleMatrix;
 
     /**
      * Exception thrown when a surface couldn't be created or resized
@@ -174,23 +179,70 @@
      * {@hide}
      */
     public Surface() {
-        mCanvas = new Canvas() {
-            @Override
-            public int getWidth() {
-                return mDisplayMetrics == null ? super.getWidth() : mDisplayMetrics.widthPixels;
-            }
-            @Override
-            public int getHeight() {
-                return mDisplayMetrics == null ? super.getHeight() : mDisplayMetrics.heightPixels;
-            }
-        };
+        mCanvas = new CompatibleCanvas();
     }
 
     /**
+     * A Canvas class that can handle the compatibility mode. This does two things differently.
+     * <ul>
+     *  <li> Returns the width and height of the target metrics, rather than native.
+     *  For example, the canvas returns 320x480 even if an app is running in WVGA high density.
+     *  <li> Scales the matrix in setMatrix by the application scale, except if the matrix looks
+     *  like obtained from getMatrix. This is a hack to handle the case that an application
+     *  uses getMatrix to keep the original matrix, set matrix of its own, then set the original
+     *  matrix back. There is no perfect solution that works for all cases, and there are a lot of
+     *  cases that this model dose not work, but we hope this works for many apps.
+     * </ul>
+     */
+    private class CompatibleCanvas extends Canvas {
+        // A temp matrix to remember what an application obtained via {@link getMatrix}
+        private Matrix mOrigMatrix = null;
+
+        @Override
+        public int getWidth() {
+            return mCompatibleDisplayMetrics == null ?
+                    super.getWidth() : mCompatibleDisplayMetrics.widthPixels;
+        }
+
+        @Override
+        public int getHeight() {
+            return mCompatibleDisplayMetrics == null ?
+                    super.getHeight() : mCompatibleDisplayMetrics.heightPixels;
+        }
+
+        @Override
+        public void setMatrix(Matrix matrix) {
+            if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
+                // don't scale the matrix if it's not compatibility mode, or
+                // the matrix was obtained from getMatrix.
+                super.setMatrix(matrix);
+            } else {
+                Matrix m = new Matrix(mCompatibleMatrix);
+                m.preConcat(matrix);
+                super.setMatrix(m);
+            }
+        }
+
+        @Override
+        public void getMatrix(Matrix m) {
+            super.getMatrix(m);
+            if (mOrigMatrix == null) {
+                mOrigMatrix = new Matrix(); 
+            }
+            mOrigMatrix.set(m);
+        }
+    };
+
+    /**
      * Sets the display metrics used to provide canva's width/height in comaptibility mode.
      */
-    void setCompatibleDisplayMetrics(DisplayMetrics metrics) {
-        mDisplayMetrics = metrics;
+    void setCompatibleDisplayMetrics(DisplayMetrics metrics, Translator translator) {
+        mCompatibleDisplayMetrics = metrics;
+        if (translator != null) {
+            float appScale = translator.applicationScale;
+            mCompatibleMatrix = new Matrix();
+            mCompatibleMatrix.setScale(appScale, appScale);
+        }
     }
     
     /**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a854535..ae5968e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -313,7 +313,7 @@
 
         Resources res = getContext().getResources();
         if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
-            mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics());
+            mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
         }
         
         int myWidth = mRequestedWidth;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 242690b..7429a89 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -399,7 +399,8 @@
                 mTranslator = compatibilityInfo.getTranslator(attrs);
 
                 if (mTranslator != null || !compatibilityInfo.supportsScreen()) {
-                    mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics());
+                    mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(),
+                            mTranslator);
                 }
 
                 boolean restore = false;