diff options
5 files changed, 363 insertions, 95 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 8a9144c..38cacdd 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -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" + diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0be02a6..adafb59 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -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. diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java new file mode 100644 index 0000000..f9f5758 --- /dev/null +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -0,0 +1,139 @@ +/* + * 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(); + } + } + } +} diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index fbf1ec3..bb01633 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -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()); } } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 992ab3b..6103b0f 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -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,36 +3278,46 @@ public class WindowManagerService extends IWindowManager.Stub long ident = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - if (updateOrientationFromAppTokensLocked(false)) { - if (freezeThisOneIfNeeded != null) { - AppWindowToken wtoken = findAppWindowToken( - freezeThisOneIfNeeded); - if (wtoken != null) { - startAppFreezingScreenLocked(wtoken, - ActivityInfo.CONFIG_ORIENTATION); - } - } - config = computeNewConfigurationLocked(); - - } else if (currentConfig != null) { - // No obvious action we need to take, but if our current - // state mismatches the activity manager's, update it, - // disregarding font scale, which should remain set to - // the value of the previous configuration. - mTempConfiguration.setToDefaults(); - mTempConfiguration.fontScale = currentConfig.fontScale; - if (computeNewConfigurationLocked(mTempConfiguration)) { - if (currentConfig.diff(mTempConfiguration) != 0) { - mWaitingForConfig = true; - mLayoutNeeded = true; - startFreezingDisplayLocked(false); - config = new Configuration(mTempConfiguration); - } + 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( + freezeThisOneIfNeeded); + if (wtoken != null) { + startAppFreezingScreenLocked(wtoken, + ActivityInfo.CONFIG_ORIENTATION); + } + } + config = computeNewConfigurationLocked(); + + } else if (currentConfig != null) { + // No obvious action we need to take, but if our current + // state mismatches the activity manager's, update it, + // disregarding font scale, which should remain set to + // the value of the previous configuration. + mTempConfiguration.setToDefaults(); + mTempConfiguration.fontScale = currentConfig.fontScale; + if (computeNewConfigurationLocked(mTempConfiguration)) { + if (currentConfig.diff(mTempConfiguration) != 0) { + mWaitingForConfig = true; + mLayoutNeeded = true; + startFreezingDisplayLocked(false); + config = new Configuration(mTempConfiguration); } } } - 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()); |