Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 240f8a75 authored by Mitsuru Oshima's avatar Mitsuru Oshima
Browse files

* a best effort fix for apps that uses get/set Matrix API on canvas.

  - scale the matrix
  - but don't scale if the matrix *looks* like obtained from the canvas itself. (typically to set it back to original matrix)

This is best effort change and not perfect (not even close), but works for one game,
and hopes it can handle many other apps that uses set/get Matrix. If you have an alternative idea, please let me know.
parent de08cdc0
Loading
Loading
Loading
Loading
+65 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view;

import android.content.res.CompatibilityInfo.Translator;
import android.graphics.*;
import android.os.Parcelable;
import android.os.Parcel;
@@ -133,8 +134,12 @@ public class Surface implements Parcelable {
    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
@@ -172,23 +177,70 @@ public class Surface implements Parcelable {
     * {@hide}
     */
    public Surface() {
        mCanvas = new Canvas() {
        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 mDisplayMetrics == null ? super.getWidth() : mDisplayMetrics.widthPixels;
            return mCompatibleDisplayMetrics == null ?
                    super.getWidth() : mCompatibleDisplayMetrics.widthPixels;
        }

        @Override
        public int getHeight() {
                return mDisplayMetrics == null ? super.getHeight() : mDisplayMetrics.heightPixels;
            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);
        }
    }
    
    /**
+1 −1
Original line number Diff line number Diff line
@@ -312,7 +312,7 @@ public class SurfaceView extends View {

        Resources res = getContext().getResources();
        if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
            mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics());
            mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
        }
        
        int myWidth = mRequestedWidth;
+2 −1
Original line number Diff line number Diff line
@@ -392,7 +392,8 @@ public final class ViewRoot extends Handler implements ViewParent,
                mTranslator = compatibilityInfo.getTranslator(attrs);

                if (mTranslator != null || !compatibilityInfo.supportsScreen()) {
                    mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics());
                    mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(),
                            mTranslator);
                }

                boolean restore = false;