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

Commit 7916ac65 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add new command line option to change global screen size.

For example:

adb shell am display-size 1024x600

Change-Id: I5df462acd3323bdaaaefa3126faea7dd8595b726
parent 8f3dbe1c
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
@@ -109,6 +110,8 @@ public class Am {
            runMonitor();
        } else if (op.equals("screen-compat")) {
            runScreenCompat();
        } else if (op.equals("display-size")) {
            runDisplaySize();
        } else {
            throw new IllegalArgumentException("Unknown command: " + op);
        }
@@ -804,6 +807,53 @@ public class Am {
        } while (packageName != null);
    }

    private void runDisplaySize() throws Exception {
        String size = nextArgRequired();
        int m, n;
        if ("reset".equals(size)) {
            m = n = -1;
        } else {
            int div = size.indexOf('x');
            if (div <= 0 || div >= (size.length()-1)) {
                System.err.println("Error: bad size " + size);
                showUsage();
                return;
            }
            String mstr = size.substring(0, div);
            String nstr = size.substring(div+1);
            try {
                m = Integer.parseInt(mstr);
                n = Integer.parseInt(nstr);
            } catch (NumberFormatException e) {
                System.err.println("Error: bad number " + e);
                showUsage();
                return;
            }
        }

        if (m < n) {
            int tmp = m;
            m = n;
            n = tmp;
        }

        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
                Context.WINDOW_SERVICE));
        if (wm == null) {
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't connect to window manager; is the system running?");
        }

        try {
            if (m >= 0 && n >= 0) {
                wm.setForcedDisplaySize(m, n);
            } else {
                wm.clearForcedDisplaySize();
            }
        } catch (RemoteException e) {
       }
    }

    private class IntentReceiver extends IIntentReceiver.Stub {
        private boolean mFinished = false;

@@ -986,6 +1036,8 @@ public class Am {
                "\n" +
                "    control screen compatibility: am screen-compat [on|off] [package]\n" +
                "\n" +
                "    override display size: am display-size [reset|MxN]\n" +
                "\n" +
                "    <INTENT> specifications include these flags:\n" +
                "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                "        [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
+3 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ interface IWindowManager
    void getDisplaySize(out Point size);
    int getMaximumSizeDimension();

    void setForcedDisplaySize(int longDimen, int shortDimen);
    void clearForcedDisplaySize();

    // These can only be called when injecting events to your own window,
    // or by holding the INJECT_EVENTS permission.  These methods may block
    // until pending input events are finished being dispatched even when 'sync' is false.
+139 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.Slog;
import android.view.Surface;
import android.view.SurfaceSession;

/**
 * Four black surfaces put together to make a black frame.
 */
public class BlackFrame {
    class BlackSurface {
        final int left;
        final int top;
        final Surface surface;

        BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
                throws Surface.OutOfResourcesException {
            left = l;
            top = t;
            surface = new Surface(session, 0, "BlackSurface",
                    -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
            surface.setAlpha(1.0f);
            surface.setLayer(layer);
        }

        void setMatrix(Matrix matrix) {
            mTmpMatrix.setTranslate(left, top);
            mTmpMatrix.postConcat(matrix);
            mTmpMatrix.getValues(mTmpFloats);
            surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
                    (int)mTmpFloats[Matrix.MTRANS_Y]);
            surface.setMatrix(
                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
            if (false) {
                Slog.i(WindowManagerService.TAG, "Black Surface @ (" + left + "," + top + "): ("
                        + mTmpFloats[Matrix.MTRANS_X] + ","
                        + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
                        + mTmpFloats[Matrix.MSCALE_X] + ","
                        + mTmpFloats[Matrix.MSCALE_Y] + "]["
                        + mTmpFloats[Matrix.MSKEW_X] + ","
                        + mTmpFloats[Matrix.MSKEW_Y] + "]");
            }
        }

        void clearMatrix() {
            surface.setMatrix(1, 0, 0, 1);
        }
    }

    final Matrix mTmpMatrix = new Matrix();
    final float[] mTmpFloats = new float[9];
    final BlackSurface[] mBlackSurfaces = new BlackSurface[4];

    public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
            int layer) throws Surface.OutOfResourcesException {
        boolean success = false;

        try {
            if (outer.top < inner.top) {
                mBlackSurfaces[0] = new BlackSurface(session, layer,
                        outer.left, outer.top, inner.right, inner.top);
            }
            if (outer.left < inner.left) {
                mBlackSurfaces[1] = new BlackSurface(session, layer,
                        outer.left, inner.top, inner.left, outer.bottom);
            }
            if (outer.bottom > inner.bottom) {
                mBlackSurfaces[2] = new BlackSurface(session, layer,
                        inner.left, inner.bottom, outer.right, outer.bottom);
            }
            if (outer.right > inner.right) {
                mBlackSurfaces[3] = new BlackSurface(session, layer,
                        inner.right, outer.top, outer.right, inner.bottom);
            }
            success = true;
        } finally {
            if (!success) {
                kill();
            }
        }
    }

    public void kill() {
        if (mBlackSurfaces != null) {
            for (int i=0; i<mBlackSurfaces.length; i++) {
                if (mBlackSurfaces[i] != null) {
                    mBlackSurfaces[i].surface.destroy();
                    mBlackSurfaces[i] = null;
                }
            }
        }
    }

    public void hide() {
        if (mBlackSurfaces != null) {
            for (int i=0; i<mBlackSurfaces.length; i++) {
                if (mBlackSurfaces[i] != null) {
                    mBlackSurfaces[i].surface.hide();
                }
            }
        }
    }

    public void setMatrix(Matrix matrix) {
        for (int i=0; i<mBlackSurfaces.length; i++) {
            if (mBlackSurfaces[i] != null) {
                mBlackSurfaces[i].setMatrix(matrix);
            }
        }
    }

    public void clearMatrix() {
        for (int i=0; i<mBlackSurfaces.length; i++) {
            if (mBlackSurfaces[i] != null) {
                mBlackSurfaces[i].clearMatrix();
            }
        }
    }
}
+10 −62
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.server.wm;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -41,46 +40,10 @@ class ScreenRotationAnimation {

    static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;

    class BlackSurface {
        final int left;
        final int top;
        final Surface surface;

        BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
                throws Surface.OutOfResourcesException {
            left = l;
            top = t;
            surface = new Surface(session, 0, "BlackSurface",
                    -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
            surface.setAlpha(1.0f);
            surface.setLayer(FREEZE_LAYER);
        }

        void setMatrix(Matrix matrix) {
            mTmpMatrix.setTranslate(left, top);
            mTmpMatrix.postConcat(matrix);
            mTmpMatrix.getValues(mTmpFloats);
            surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
                    (int)mTmpFloats[Matrix.MTRANS_Y]);
            surface.setMatrix(
                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
            if (false) {
                Slog.i(TAG, "Black Surface @ (" + left + "," + top + "): ("
                        + mTmpFloats[Matrix.MTRANS_X] + ","
                        + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
                        + mTmpFloats[Matrix.MSCALE_X] + ","
                        + mTmpFloats[Matrix.MSCALE_Y] + "]["
                        + mTmpFloats[Matrix.MSKEW_X] + ","
                        + mTmpFloats[Matrix.MSKEW_Y] + "]");
            }
        }
    }

    final Context mContext;
    final Display mDisplay;
    Surface mSurface;
    BlackSurface[] mBlackSurfaces;
    BlackFrame mBlackFrame;
    int mWidth, mHeight;

    int mSnapshotRotation;
@@ -302,14 +265,12 @@ class ScreenRotationAnimation {
                ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
        Surface.openTransaction();

        mBlackSurfaces = new BlackSurface[4];
        try {
            final int w = mDisplayMetrics.widthPixels;
            final int h = mDisplayMetrics.heightPixels;
            mBlackSurfaces[0] = new BlackSurface(session, FREEZE_LAYER, -w, -h, w, h*2);
            mBlackSurfaces[1] = new BlackSurface(session, FREEZE_LAYER, 0, -h, w*2, h);
            mBlackSurfaces[2] = new BlackSurface(session, FREEZE_LAYER, w, 0, w, h*2);
            mBlackSurfaces[3] = new BlackSurface(session, FREEZE_LAYER, -w, h, w*2, h);
            Rect outer = new Rect(-w, -h, w*2, h*2);
            Rect inner = new Rect(0, 0, w, h);
            mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
        } catch (Surface.OutOfResourcesException e) {
            Slog.w(TAG, "Unable to allocate black surface", e);
        } finally {
@@ -326,13 +287,8 @@ class ScreenRotationAnimation {
            mSurface.destroy();
            mSurface = null;
        }
        if (mBlackSurfaces != null) {
            for (int i=0; i<mBlackSurfaces.length; i++) {
                if (mBlackSurfaces[i] != null) {
                    mBlackSurfaces[i].surface.destroy();
                }
            }
            mBlackSurfaces = null;
        if (mBlackFrame != null) {
            mBlackFrame.kill();
        }
        if (mExitAnimation != null) {
            mExitAnimation.cancel();
@@ -383,20 +339,12 @@ class ScreenRotationAnimation {
                mEnterAnimation.cancel();
                mEnterAnimation = null;
                mEnterTransformation.clear();
                if (mBlackSurfaces != null) {
                    for (int i=0; i<mBlackSurfaces.length; i++) {
                        if (mBlackSurfaces[i] != null) {
                            mBlackSurfaces[i].surface.hide();
                        }
                    }
                if (mBlackFrame != null) {
                    mBlackFrame.hide();
                }
            } else {
                if (mBlackSurfaces != null) {
                    for (int i=0; i<mBlackSurfaces.length; i++) {
                        if (mBlackSurfaces[i] != null) {
                            mBlackSurfaces[i].setMatrix(mEnterTransformation.getMatrix());
                        }
                    }
                if (mBlackFrame != null) {
                    mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
                }
            }
        }
+159 −33
Original line number Diff line number Diff line
@@ -190,6 +190,16 @@ public class WindowManagerService extends IWindowManager.Stub
     */
    static final int LAYER_OFFSET_BLUR = 2;

    /**
     * Layer at which to put the rotation freeze snapshot.
     */
    static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1;

    /**
     * Layer at which to put the mask for emulated screen sizes.
     */
    static final int MASK_LAYER = TYPE_LAYER_MULTIPLIER * 200;

    /** The maximum length we will accept for a loaded animation duration:
     * this is 10 seconds.
     */
@@ -383,6 +393,8 @@ public class WindowManagerService extends IWindowManager.Stub
    StrictModeFlash mStrictModeFlash;
    ScreenRotationAnimation mScreenRotationAnimation;

    BlackFrame mBlackFrame;

    int mTransactionSequence = 0;

    final float[] mTmpFloats = new float[9];
@@ -392,6 +404,8 @@ public class WindowManagerService extends IWindowManager.Stub
    boolean mSystemBooted = false;
    int mInitialDisplayWidth = 0;
    int mInitialDisplayHeight = 0;
    int mBaseDisplayWidth = 0;
    int mBaseDisplayHeight = 0;
    int mCurDisplayWidth = 0;
    int mCurDisplayHeight = 0;
    int mRotation = 0;
@@ -3264,6 +3278,18 @@ public class WindowManagerService extends IWindowManager.Stub
        long ident = Binder.clearCallingIdentity();
        
        synchronized(mWindowMap) {
            config = updateOrientationFromAppTokensLocked(currentConfig,
                    freezeThisOneIfNeeded);
        }

        Binder.restoreCallingIdentity(ident);
        return config;
    }

    private Configuration updateOrientationFromAppTokensLocked(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
        Configuration config = null;

        if (updateOrientationFromAppTokensLocked(false)) {
            if (freezeThisOneIfNeeded != null) {
                AppWindowToken wtoken = findAppWindowToken(
@@ -3291,9 +3317,7 @@ public class WindowManagerService extends IWindowManager.Stub
                }
            }
        }
        }
        
        Binder.restoreCallingIdentity(ident);
        return config;
    }

@@ -5042,6 +5066,7 @@ public class WindowManagerService extends IWindowManager.Stub
                } else {
                    Surface.setOrientation(0, rotation, animFlags);
                }
                rebuildBlackFrame(inTransaction);
            }

            for (int i=mWindows.size()-1; i>=0; i--) {
@@ -5484,8 +5509,8 @@ public class WindowManagerService extends IWindowManager.Stub
        // Use the effective "visual" dimensions based on current rotation
        final boolean rotated = (mRotation == Surface.ROTATION_90
                || mRotation == Surface.ROTATION_270);
        final int realdw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
        final int realdh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;

        if (mAltOrientation) {
            mCurDisplayWidth = realdw;
@@ -5922,8 +5947,18 @@ public class WindowManagerService extends IWindowManager.Stub
            }
            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
            mDisplay = wm.getDefaultDisplay();
            mInitialDisplayWidth = mCurDisplayWidth = mDisplay.getRealWidth();
            mInitialDisplayHeight = mCurDisplayHeight = mDisplay.getRealHeight();
            mInitialDisplayWidth = mDisplay.getRealWidth();
            mInitialDisplayHeight = mDisplay.getRealHeight();
            int rot = mDisplay.getRotation();
            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
                // If the screen is currently rotated, we need to swap the
                // initial width and height to get the true natural values.
                int tmp = mInitialDisplayWidth;
                mInitialDisplayWidth = mInitialDisplayHeight;
                mInitialDisplayHeight = tmp;
            }
            mBaseDisplayWidth = mCurDisplayWidth = mInitialDisplayWidth;
            mBaseDisplayHeight = mCurDisplayHeight = mInitialDisplayHeight;
            mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight());
            mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
        }
@@ -6429,8 +6464,88 @@ public class WindowManagerService extends IWindowManager.Stub
    public int getMaximumSizeDimension() {
        synchronized(mWindowMap) {
            // Do this based on the raw screen size, until we are smarter.
            return mInitialDisplayWidth > mInitialDisplayHeight
                    ? mInitialDisplayWidth : mInitialDisplayHeight;
            return mBaseDisplayWidth > mBaseDisplayHeight
                    ? mBaseDisplayWidth : mBaseDisplayHeight;
        }
    }

    public void setForcedDisplaySize(int longDimen, int shortDimen) {
        synchronized(mWindowMap) {
            int width, height;
            if (mInitialDisplayWidth < mInitialDisplayHeight) {
                width = shortDimen < mInitialDisplayWidth
                        ? shortDimen : mInitialDisplayWidth;
                height = longDimen < mInitialDisplayHeight
                        ? longDimen : mInitialDisplayHeight;
            } else {
                width = longDimen < mInitialDisplayWidth
                        ? longDimen : mInitialDisplayWidth;
                height = shortDimen < mInitialDisplayHeight
                        ? shortDimen : mInitialDisplayHeight;
            }
            setForcedDisplaySizeLocked(width, height);
        }
    }

    private void rebuildBlackFrame(boolean inTransaction) {
        if (!inTransaction) {
            if (SHOW_TRANSACTIONS) Slog.i(TAG,
                    ">>> OPEN TRANSACTION rebuildBlackFrame");
            Surface.openTransaction();
        }
        try {
            if (mBlackFrame != null) {
                mBlackFrame.kill();
                mBlackFrame = null;
            }
            if (mBaseDisplayWidth < mInitialDisplayWidth
                    || mBaseDisplayHeight < mInitialDisplayHeight) {
                Rect outer = new Rect(0, 0, mInitialDisplayWidth, mInitialDisplayHeight);
                Rect inner = new Rect(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
                try {
                    mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
                } catch (Surface.OutOfResourcesException e) {
                }
            }
        } finally {
            if (!inTransaction) {
                Surface.closeTransaction();
                if (SHOW_TRANSACTIONS) Slog.i(TAG,
                        "<<< CLOSE TRANSACTION rebuildBlackFrame");
            }
        }
    }

    private void setForcedDisplaySizeLocked(int width, int height) {
        mBaseDisplayWidth = width;
        mBaseDisplayHeight = height;
        mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight);

        mLayoutNeeded = true;

        boolean configChanged = updateOrientationFromAppTokensLocked(false);
        mTempConfiguration.setToDefaults();
        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
        if (computeNewConfigurationLocked(mTempConfiguration)) {
            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
                configChanged = true;
            }
        }

        if (configChanged) {
            mWaitingForConfig = true;
            startFreezingDisplayLocked(false);
            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }

        rebuildBlackFrame(false);

        performLayoutAndPlaceSurfacesLocked();
    }

    public void clearForcedDisplaySize() {
        synchronized(mWindowMap) {
            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
        }
    }

@@ -7983,6 +8098,15 @@ public class WindowManagerService extends IWindowManager.Stub
                }
                mBlurShown = false;
            }

            if (mBlackFrame != null) {
                if (mScreenRotationAnimation != null) {
                    mBlackFrame.setMatrix(
                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
                } else {
                    mBlackFrame.clearMatrix();
                }
            }
        } catch (RuntimeException e) {
            Slog.e(TAG, "Unhandled exception in Window Manager", e);
        }
@@ -8836,7 +8960,9 @@ public class WindowManagerService extends IWindowManager.Stub
            }
            if (mDisplay != null) {
                pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
                        pw.print(mInitialDisplayHeight); pw.print(" cur=");
                        pw.print(mInitialDisplayHeight); pw.print(" base=");
                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
                        pw.print(" cur=");
                        pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
                        pw.print(" real="); pw.print(mDisplay.getRealWidth());
                        pw.print("x"); pw.print(mDisplay.getRealHeight());