diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-09-20 15:08:29 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-09-21 19:26:15 -0700 |
commit | 01a98ddbdfbaf1f0d2bc602537e6e314364902a3 (patch) | |
tree | ce904db3ee0772e0e2a35882a6cf86c7b9fcd84e | |
parent | 04ef5b8dd7262ee90b56df9c992f103695d0a21c (diff) | |
download | frameworks_base-01a98ddbdfbaf1f0d2bc602537e6e314364902a3.zip frameworks_base-01a98ddbdfbaf1f0d2bc602537e6e314364902a3.tar.gz frameworks_base-01a98ddbdfbaf1f0d2bc602537e6e314364902a3.tar.bz2 |
Handle orientation changes more systematically.
Bug: 4981385
Simplify the orientation changing code path in the
WindowManager. Instead of the policy calling setRotation()
when the sensor determined orientation changes, it calls
updateRotation(), which figures everything out. For the most
part, the rotation actually passed to setRotation() was
more or less ignored and just added confusion, particularly
when handling deferred orientation changes.
Ensure that 180 degree rotations are disallowed even when
the application specifies SCREEN_ORIENTATION_SENSOR_*.
These rotations are only enabled when docked upside-down for
some reason or when the application specifies
SCREEN_ORIENTATION_FULL_SENSOR.
Ensure that special modes like HDMI connected, lid switch,
dock and rotation lock all cause the sensor to be ignored
even when the application asks for sensor-based orientation
changes. The sensor is not relevant in these modes because
some external factor (or the user) is determining the
preferred rotation.
Currently, applications can still override the preferred
rotation even when there are special modes in play that
might say otherwise. We could tweak this so that some
special modes trump application choices completely
(resulting in a letter-boxed application, perhaps).
I tested this sort of tweak (not included in the patch)
and it seems to work fine, including transitions between
applications with varying orientation.
Delete dead code related to animFlags.
Handle pausing/resuming orientation changes more precisely.
Ensure that a deferred orientation change is performed when
a drag completes, even if endDragLw() is not called because the
drag was aborted before the drop happened. We pause
the orientation change in register() and resume in unregister()
because those methods appear to always be called as needed.
Change-Id: If0a31de3d057251e581fdee64819f2b19e676e9a
12 files changed, 341 insertions, 387 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 335c66b..55c821d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -163,15 +163,13 @@ interface IWindowManager // These can only be called with the SET_ORIENTATION permission. /** - * Change the current screen rotation, constants as per - * {@link android.view.Surface}. - * @param rotation the intended rotation. + * Update the current screen rotation based on the current state of + * the world. * @param alwaysSendConfiguration Flag to force a new configuration to * be evaluated. This can be used when there are other parameters in * configuration that are changing. - * @param animFlags Animation flags as per {@link android.view.Surface}. */ - void setRotation(int rotation, boolean alwaysSendConfiguration, int animFlags); + void updateRotation(boolean alwaysSendConfiguration); /** * Retrieve the current screen orientation, constants as per diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 3880bc4..64d3d31 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -207,9 +207,6 @@ public class Surface implements Parcelable { /** Enable dithering when compositing this surface @hide */ public static final int SURFACE_DITHER = 0x04; - - /** Disable the orientation animation @hide */ - public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001; // The mSurfaceControl will only be present for Surfaces used by the window // server or system processes. When this class is parceled we defer to the @@ -393,7 +390,7 @@ public class Surface implements Parcelable { * set the orientation of the given display. * @param display * @param orientation - * @param flags + * @param flags Currently unused, set to 0. * @hide */ public static native void setOrientation(int display, int orientation, int flags); diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index c07faf6..1dbb083 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -375,12 +375,6 @@ public interface WindowManagerPolicy { /** Screen turned off because of proximity sensor */ public final int OFF_BECAUSE_OF_PROX_SENSOR = 4; - /** - * Magic constant to {@link IWindowManager#setRotation} to not actually - * modify the rotation. - */ - public final int USE_LAST_ROTATION = -1000; - /** When not otherwise specified by the activity's screenOrientation, rotation should be * determined by the system (that is, using sensors). */ public final int USER_ROTATION_FREE = 0; @@ -856,22 +850,30 @@ public interface WindowManagerPolicy { public boolean inKeyguardRestrictedKeyInputMode(); /** - * Given an orientation constant - * ({@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE - * ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE} or - * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT - * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}), return a surface - * rotation. + * Given an orientation constant, returns the appropriate surface rotation, + * taking into account sensors, docking mode, rotation lock, and other factors. + * + * @param orientation An orientation constant, such as + * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param lastRotation The most recently used rotation. + * @return The surface rotation to use. */ - public int rotationForOrientationLw(int orientation, int lastRotation, - boolean displayEnabled); - + public int rotationForOrientationLw(int orientation, int lastRotation); + /** - * Return the currently locked screen rotation, if any. Return - * Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or - * Surface.ROTATION_270 if locked; return -1 if not locked. + * Given an orientation constant and a rotation, returns true if the rotation + * has compatible metrics to the requested orientation. For example, if + * the application requested landscape and got seascape, then the rotation + * has compatible metrics; if the application requested portrait and got landscape, + * then the rotation has incompatible metrics; if the application did not specify + * a preference, then anything goes. + * + * @param orientation An orientation constant, such as + * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param rotation The rotation to check. + * @return True if the rotation is compatible with the requested orientation. */ - public int getLockedRotationLw(); + public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation); /** * Called when the system is mostly done booting to determine whether diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java index 76b47ca..726bf4a 100755 --- a/core/java/android/view/WindowOrientationListener.java +++ b/core/java/android/view/WindowOrientationListener.java @@ -118,14 +118,13 @@ public abstract class WindowOrientationListener { /** * Gets the current orientation. - * @param lastRotation - * @return + * @return The current rotation, or -1 if unknown. */ - public int getCurrentRotation(int lastRotation) { + public int getCurrentRotation() { if (mEnabled) { - return mSensorEventListener.getCurrentRotation(lastRotation); + return mSensorEventListener.getCurrentRotation(); } - return lastRotation; + return -1; } /** @@ -342,8 +341,8 @@ public abstract class WindowOrientationListener { mOrientationListener = orientationListener; } - public int getCurrentRotation(int lastRotation) { - return mRotation != ROTATION_UNKNOWN ? mRotation : lastRotation; + public int getCurrentRotation() { + return mRotation; // may be -1, if unknown } @Override diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index 6b31ca4..e0f4cf9 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -88,11 +88,6 @@ public: eElectronBeamAnimationOff = 0x10 }; - // flags for setOrientation - enum { - eOrientationAnimationDisable = 0x00000001 - }; - /* create connection with surface flinger, requires * ACCESS_SURFACE_FLINGER permission */ @@ -112,7 +107,8 @@ public: virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0; virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags) = 0; - /* Set display orientation. requires ACCESS_SURFACE_FLINGER permission */ + /* Set display orientation. requires ACCESS_SURFACE_FLINGER permission + * No flags are currently defined. Set flags to 0. */ virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags) = 0; /* signal that we're done booting. diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index c8c0041..a2d983f 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -385,9 +385,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mPortraitRotation = 0; // default portrait rotation int mUpsideDownRotation = 0; // "other" portrait rotation - // Nothing to see here, move along... - int mFancyRotationAnimation; - // What we do when the user long presses on home private int mLongPressOnHomeBehavior = -1; @@ -439,12 +436,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onChange(boolean selfChange) { updateSettings(); - try { - mWindowManager.setRotation(USE_LAST_ROTATION, false, - mFancyRotationAnimation); - } catch (RemoteException e) { - // Ignore - } + updateRotation(false); } } @@ -457,45 +449,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onOrientationChanged(int rotation) { // Send updates based on orientation value if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation); - try { - mWindowManager.setRotation(rotation, false, - mFancyRotationAnimation); - } catch (RemoteException e) { - // Ignore - - } - } + updateRotation(false); + } } MyOrientationListener mOrientationListener; - boolean useSensorForOrientationLp(int appOrientation) { - // The app says use the sensor. - if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) { - return true; - } - // The user preference says we can rotate, and the app is willing to rotate. - if (mAccelerometerDefault != 0 && - (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { - return true; - } - // We're in a dock that has a rotation affinity, and the app is willing to rotate. - if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) - || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) { - // Note we override the nosensor flag here. - if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { - return true; - } - } - // Else, don't use the sensor. - return false; - } - /* * We always let the sensor be switched on by default except when * the user has explicitly disabled sensor based rotation or when the @@ -826,8 +784,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mIncallPowerBehavior = Settings.Secure.getInt(resolver, Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT); - mFancyRotationAnimation = Settings.System.getInt(resolver, - "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); @@ -882,7 +838,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateScreenSaverTimeoutLocked(); } if (updateRotation) { - updateRotation(0); + updateRotation(true); } if (addView != null) { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( @@ -1025,8 +981,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); - - mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN); + updateKeyboardVisibility(); if (config.keyboard == Configuration.KEYBOARD_NOKEYS) { config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; @@ -2295,8 +2250,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { // lid changed state mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED; + updateKeyboardVisibility(); + boolean awakeNow = mKeyguardMediator.doLidChangeTq(lidOpen); - updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateRotation(true); if (awakeNow) { // If the lid is opening and we don't have to keep the // keyguard up, then we can turn on the screen @@ -2325,7 +2282,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void setHdmiPlugged(boolean plugged) { if (mHdmiPlugged != plugged) { mHdmiPlugged = plugged; - updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateRotation(true); Intent intent = new Intent(ACTION_HDMI_PLUGGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged); @@ -2802,7 +2759,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } } - updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateRotation(true); updateOrientationListenerLp(); } }; @@ -2914,10 +2871,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - - public int rotationForOrientationLw(int orientation, int lastRotation, - boolean displayEnabled) { + @Override + public int rotationForOrientationLw(int orientation, int lastRotation) { if (false) { Slog.v(TAG, "rotationForOrientationLw(orient=" + orientation + ", last=" + lastRotation @@ -2928,128 +2884,129 @@ public class PhoneWindowManager implements WindowManagerPolicy { } synchronized (mLock) { + int sensorRotation = mOrientationListener.getCurrentRotation(); // may be -1 + + int preferredRotation = -1; + if (mHdmiPlugged) { + // Ignore sensor when plugged into HDMI. + preferredRotation = mLandscapeRotation; + } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) { + // Ignore sensor when lid switch is open and rotation is forced. + preferredRotation = mLidOpenRotation; + } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR + && ((mCarDockEnablesAccelerometer && sensorRotation >= 0) + || mCarDockRotation >= 0)) { + // Ignore sensor when in car dock unless explicitly enabled. + // This case can override the behavior of NOSENSOR, and can also + // enable 180 degree rotation while docked. + preferredRotation = mCarDockEnablesAccelerometer && sensorRotation >= 0 + ? sensorRotation : mCarDockRotation; + } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK + && ((mDeskDockEnablesAccelerometer && sensorRotation >= 0) + || mDeskDockRotation >= 0)) { + // Ignore sensor when in desk dock unless explicitly enabled. + // This case can override the behavior of NOSENSOR, and can also + // enable 180 degree rotation while docked. + preferredRotation = mDeskDockEnablesAccelerometer && sensorRotation >= 0 + ? sensorRotation : mDeskDockRotation; + } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { + // Ignore sensor when user locked rotation. + preferredRotation = mUserRotation; + } else if ((mAccelerometerDefault != 0 + && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER + || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) + || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR + || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR + || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE + || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) { + // Otherwise, use sensor only if requested by the application or enabled + // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR. + if (sensorRotation != Surface.ROTATION_180 + || mAllowAllRotations + || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) { + preferredRotation = sensorRotation; + } else { + preferredRotation = lastRotation; + } + } + + // TODO: Sometimes, we might want to override the application-requested + // orientation, such as when HDMI is plugged in or when docked. + // We can do that by modifying the appropriate cases above to return + // the preferred orientation directly instead of continuing on down here. + switch (orientation) { case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - //always return portrait if orientation set to portrait + // Always return portrait if orientation set to portrait. return mPortraitRotation; + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - //always return landscape if orientation set to landscape + // Always return landscape if orientation set to landscape. return mLandscapeRotation; + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: - //always return portrait if orientation set to portrait + // Always return portrait if orientation set to portrait. return mUpsideDownRotation; + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: - //always return seascape if orientation set to reverse landscape + // Always return seascape if orientation set to reverse landscape. return mSeascapeRotation; + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: - //return either landscape rotation based on the sensor - return getCurrentLandscapeRotation(lastRotation); - case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: - return getCurrentPortraitRotation(lastRotation); - } + // Return either landscape rotation. + if (isLandscapeOrSeascape(preferredRotation)) { + return preferredRotation; + } + if (isLandscapeOrSeascape(lastRotation)) { + return lastRotation; + } + return mLandscapeRotation; - // case for nosensor meaning ignore sensor and consider only lid - // or orientation sensor disabled - //or case.unspecified - if (mHdmiPlugged) { - return mLandscapeRotation; - } else if (mLidOpen == LID_OPEN) { - return mLidOpenRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { - return mCarDockRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { - return mDeskDockRotation; - } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { - return mUserRotation; - } else { - if (useSensorForOrientationLp(orientation)) { - // Disable 180 degree rotation unless allowed by default for the device - // or explicitly requested by the application. - int rotation = mOrientationListener.getCurrentRotation(lastRotation); - if (rotation == Surface.ROTATION_180 - && !mAllowAllRotations - && orientation != ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) { + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: + // Return either portrait rotation. + if (isAnyPortrait(preferredRotation)) { + return preferredRotation; + } + if (isAnyPortrait(lastRotation)) { return lastRotation; } - return rotation; - } - return Surface.ROTATION_0; - } - } - } + return mPortraitRotation; - public int getLockedRotationLw() { - synchronized (mLock) { - if (false) { - // Not yet working. - if (mHdmiPlugged) { + default: + // For USER, UNSPECIFIED and NOSENSOR, just return the preferred + // orientation we already calculated. + if (preferredRotation >= 0) { + return preferredRotation; + } return Surface.ROTATION_0; - } else if (mLidOpen == LID_OPEN) { - return mLidOpenRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { - return mCarDockRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { - return mDeskDockRotation; - } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { - return mUserRotation; - } } - return -1; } } - private int getCurrentLandscapeRotation(int lastRotation) { - // if the user has locked rotation, we ignore the sensor - if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { - if (isLandscapeOrSeascape(mUserRotation)) { - return mUserRotation; - } else { - // it seems odd to obey the sensor at all if rotation lock is enabled - return mLandscapeRotation; - } - } + @Override + public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation) { + switch (orientation) { + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: + return isAnyPortrait(rotation); + + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: + return isLandscapeOrSeascape(rotation); - int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); - if (isLandscapeOrSeascape(sensorRotation)) { - return sensorRotation; - } - // try to preserve the old rotation if it was landscape - if (isLandscapeOrSeascape(lastRotation)) { - return lastRotation; + default: + return true; } - // default to one of the primary landscape rotation - return mLandscapeRotation; - } - - private boolean isLandscapeOrSeascape(int sensorRotation) { - return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation; } - private int getCurrentPortraitRotation(int lastRotation) { - // if the user has locked rotation, we ignore the sensor - if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { - if (isAnyPortrait(mUserRotation)) { - return mUserRotation; - } else { - // it seems odd to obey the sensor at all if rotation lock is enabled - return mPortraitRotation; - } - } - - int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); - if (isAnyPortrait(sensorRotation)) { - return sensorRotation; - } - // try to preserve the old rotation if it was portrait - if (isAnyPortrait(lastRotation)) { - return lastRotation; - } - // default to one of the primary portrait rotations - return mPortraitRotation; + private boolean isLandscapeOrSeascape(int rotation) { + return rotation == mLandscapeRotation || rotation == mSeascapeRotation; } - private boolean isAnyPortrait(int sensorRotation) { - return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation; + private boolean isAnyPortrait(int rotation) { + return rotation == mPortraitRotation || rotation == mUpsideDownRotation; } @@ -3298,26 +3255,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableScreenAfterBoot() { readLidState(); - updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateKeyboardVisibility(); + + updateRotation(true); } - void updateRotation(int animFlags) { + private void updateKeyboardVisibility() { mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN); - int rotation = Surface.ROTATION_0; - if (mHdmiPlugged) { - rotation = Surface.ROTATION_0; - } else if (mLidOpen == LID_OPEN) { - rotation = mLidOpenRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { - rotation = mCarDockRotation; - } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { - rotation = mDeskDockRotation; - } - //if lid is closed orientation will be portrait + } + + void updateRotation(boolean alwaysSendConfiguration) { try { //set orientation on WindowManager - mWindowManager.setRotation(rotation, true, - mFancyRotationAnimation | animFlags); + mWindowManager.updateRotation(alwaysSendConfiguration); } catch (RemoteException e) { // Ignore } diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java index dd440bf..f2e7485 100644 --- a/services/java/com/android/server/wm/DragState.java +++ b/services/java/com/android/server/wm/DragState.java @@ -125,6 +125,12 @@ class DragState { mDragWindowHandle.frameTop = 0; mDragWindowHandle.frameRight = mService.mCurDisplayWidth; mDragWindowHandle.frameBottom = mService.mCurDisplayHeight; + + // Pause rotations before a drag. + if (WindowManagerService.DEBUG_ORIENTATION) { + Slog.d(WindowManagerService.TAG, "Pausing rotation during drag"); + } + mService.pauseRotationLocked(); } } @@ -142,6 +148,12 @@ class DragState { mDragWindowHandle = null; mDragApplicationHandle = null; + + // Resume rotations after a drag. + if (WindowManagerService.DEBUG_ORIENTATION) { + Slog.d(WindowManagerService.TAG, "Resuming rotation after drag"); + } + mService.resumeRotationLocked(); } } @@ -257,13 +269,6 @@ class DragState { // free our resources and drop all the object references mService.mDragState.reset(); mService.mDragState = null; - - if (WindowManagerService.DEBUG_ORIENTATION) Slog.d(WindowManagerService.TAG, "Performing post-drag rotation"); - boolean changed = mService.setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); - if (changed) { - mService.mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); - } } void notifyMoveLw(float x, float y) { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index ff75cfd..02b246a 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -427,14 +427,11 @@ public class WindowManagerService extends IWindowManager.Stub int mAppDisplayWidth = 0; int mAppDisplayHeight = 0; int mRotation = 0; - int mRequestedRotation = 0; int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mAltOrientation = false; - int mLastRotationFlags; ArrayList<IRotationWatcher> mRotationWatchers = new ArrayList<IRotationWatcher>(); - int mDeferredRotation; - int mDeferredRotationAnimFlags; + int mDeferredRotationPauseCount; boolean mLayoutNeeded = true; boolean mAnimationPending = false; @@ -3414,9 +3411,7 @@ public class WindowManagerService extends IWindowManager.Stub //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); - if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION, - mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE, - inTransaction)) { + if (updateRotationUncheckedLocked(inTransaction)) { changed = true; } } @@ -4823,8 +4818,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.enableScreenAfterBoot(); // Make sure the last requested orientation has been applied. - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, - mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateRotationUnchecked(false); } public void showBootMessage(final CharSequence msg, final boolean always) { @@ -5043,6 +5037,10 @@ public class WindowManagerService extends IWindowManager.Stub return bm; } + /** + * Freeze rotation changes. (Enable "rotation lock".) + * Persists across reboots. + */ public void freezeRotation() { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "freezeRotation()")) { @@ -5052,9 +5050,13 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation); mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation); - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); + updateRotationUnchecked(false); } + /** + * Thaw rotation changes. (Disable "rotation lock".) + * Persists across reboots. + */ public void thawRotation() { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "thawRotation()")) { @@ -5064,30 +5066,56 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); + updateRotationUnchecked(false); } - public void setRotation(int rotation, - boolean alwaysSendConfiguration, int animFlags) { - if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, - "setRotation()")) { - throw new SecurityException("Requires SET_ORIENTATION permission"); - } + /** + * Recalculate the current rotation. + * + * Called by the window manager policy whenever the state of the system changes + * such that the current rotation might need to be updated, such as when the + * device is docked or rotated into a new posture. + */ + public void updateRotation(boolean alwaysSendConfiguration) { + updateRotationUnchecked(alwaysSendConfiguration); + } - setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags); + /** + * Temporarily pauses rotation changes until resumed. + * + * This can be used to prevent rotation changes from occurring while the user is + * performing certain operations, such as drag and drop. + * + * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}. + */ + void pauseRotationLocked() { + mDeferredRotationPauseCount += 1; + } + + /** + * Resumes normal rotation changes after being paused. + */ + void resumeRotationLocked() { + if (mDeferredRotationPauseCount > 0) { + mDeferredRotationPauseCount -= 1; + if (mDeferredRotationPauseCount == 0) { + boolean changed = updateRotationUncheckedLocked(false); + if (changed) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + } + } + } } - public void setRotationUnchecked(int rotation, - boolean alwaysSendConfiguration, int animFlags) { - if(DEBUG_ORIENTATION) Slog.v(TAG, - "setRotationUnchecked(rotation=" + rotation + - " alwaysSendConfiguration=" + alwaysSendConfiguration + - " animFlags=" + animFlags); + public void updateRotationUnchecked( + boolean alwaysSendConfiguration) { + if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked(" + + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); long origId = Binder.clearCallingIdentity(); boolean changed; synchronized(mWindowMap) { - changed = setRotationUncheckedLocked(rotation, animFlags, false); + changed = updateRotationUncheckedLocked(false); } if (changed || alwaysSendConfiguration) { @@ -5098,152 +5126,113 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * Apply a new rotation to the screen, respecting the requests of - * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply - * re-evaluate the desired rotation. - * - * Returns null if the rotation has been changed. In this case YOU - * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN. + * Updates the current rotation. + * + * Returns true if the rotation has been changed. In this case YOU + * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. */ - public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) { - if (mDragState != null - || (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating())) { - // Potential rotation during a drag or while waiting for a previous orientation - // change to finish (rotation animation will be dismissed). - // Don't do the rotation now, but make a note to perform the rotation later. - if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation."); - if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) { - mDeferredRotation = rotation; - mDeferredRotationAnimFlags = animFlags; - } + public boolean updateRotationUncheckedLocked(boolean inTransaction) { + if (mDeferredRotationPauseCount > 0) { + // Rotation updates have been paused temporarily. Defer the update until + // updates have been resumed. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused."); return false; } - boolean changed; - if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { - if (mDeferredRotation != WindowManagerPolicy.USE_LAST_ROTATION) { - rotation = mDeferredRotation; - mRequestedRotation = rotation; - mLastRotationFlags = mDeferredRotationAnimFlags; - } - rotation = mRequestedRotation; - } else { - mRequestedRotation = rotation; - mLastRotationFlags = animFlags; - } - mDeferredRotation = WindowManagerPolicy.USE_LAST_ROTATION; - if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation); - rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, - mRotation, mDisplayEnabled); - if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation); - - int desiredRotation = rotation; - int lockedRotation = mPolicy.getLockedRotationLw(); - if (lockedRotation >= 0 && rotation != lockedRotation) { - // We are locked in a rotation but something is requesting - // a different rotation... we will either keep the locked - // rotation if it results in the same orientation, or have to - // switch into an emulated orientation mode. - - // First, we know that our rotation is actually going to be - // the locked rotation. - rotation = lockedRotation; - - // Now the difference between the desired and lockedRotation - // may mean that the orientation is different... if that is - // not the case, we can just make the desired rotation be the - // same as the new locked rotation. - switch (lockedRotation) { - case Surface.ROTATION_0: - if (rotation == Surface.ROTATION_180) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_90: - if (rotation == Surface.ROTATION_270) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_180: - if (rotation == Surface.ROTATION_0) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_270: - if (rotation == Surface.ROTATION_90) { - desiredRotation = lockedRotation; - } - break; - } + if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) { + // Rotation updates cannot be performed while the previous rotation change + // animation is still in progress. Skip this update. We will try updating + // again after the animation is finished and the display is unfrozen. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress."); + return false; } - changed = mDisplayEnabled && mRotation != rotation; - if (mAltOrientation != (rotation != desiredRotation)) { - changed = true; - mAltOrientation = rotation != desiredRotation; + if (!mDisplayEnabled) { + // No point choosing a rotation if the display is not enabled. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled."); + return false; } - if (changed) { - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Rotation changed to " + rotation - + " from " + mRotation - + " (forceApp=" + mForcedAppOrientation - + ", req=" + mRequestedRotation + ")"); - mRotation = rotation; - mWindowsFreezingScreen = true; - mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); - mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), - 2000); - mWaitingForConfig = true; - mLayoutNeeded = true; - startFreezingDisplayLocked(inTransaction); - //Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); - mInputManager.setDisplayOrientation(0, rotation); - if (mDisplayEnabled) { - // NOTE: We disable the rotation in the emulator because - // it doesn't support hardware OpenGL emulation yet. - if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null - && mScreenRotationAnimation.hasScreenshot()) { - Surface.freezeDisplay(0); - if (!inTransaction) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION setRotationUnchecked"); - Surface.openTransaction(); - } - try { - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.setRotation(rotation); - } - } finally { - if (!inTransaction) { - Surface.closeTransaction(); - if (SHOW_TRANSACTIONS) Slog.i(TAG, - "<<< CLOSE TRANSACTION setRotationUnchecked"); - } - } - Surface.setOrientation(0, rotation, animFlags); - Surface.unfreezeDisplay(0); - } else { - Surface.setOrientation(0, rotation, animFlags); - } - rebuildBlackFrame(inTransaction); - } + // TODO: Implement forced rotation changes. + // Set mAltOrientation to indicate that the application is receiving + // an orientation that has different metrics than it expected. + // eg. Portrait instead of Landscape. - for (int i=mWindows.size()-1; i>=0; i--) { - WindowState w = mWindows.get(i); - if (w.mSurface != null) { - w.mOrientationChanging = true; - } + int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation); + boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( + mForcedAppOrientation, rotation); + + if (DEBUG_ORIENTATION) { + Slog.v(TAG, "Application requested orientation " + + mForcedAppOrientation + ", got rotation " + rotation + + " which has " + (altOrientation ? "incompatible" : "compatible") + + " metrics"); + } + + if (mRotation == rotation && mAltOrientation == altOrientation) { + // No change. + return false; + } + + if (DEBUG_ORIENTATION) { + Slog.v(TAG, + "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") + + " from " + mRotation + (mAltOrientation ? " (alt)" : "") + + ", forceApp=" + mForcedAppOrientation); + } + + mRotation = rotation; + mAltOrientation = altOrientation; + + mWindowsFreezingScreen = true; + mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); + mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); + mWaitingForConfig = true; + mLayoutNeeded = true; + startFreezingDisplayLocked(inTransaction); + mInputManager.setDisplayOrientation(0, rotation); + + // NOTE: We disable the rotation in the emulator because + // it doesn't support hardware OpenGL emulation yet. + if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null + && mScreenRotationAnimation.hasScreenshot()) { + Surface.freezeDisplay(0); + if (!inTransaction) { + if (SHOW_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION setRotationUnchecked"); + Surface.openTransaction(); } - for (int i=mRotationWatchers.size()-1; i>=0; i--) { - try { - mRotationWatchers.get(i).onRotationChanged(rotation); - } catch (RemoteException e) { + try { + if (mScreenRotationAnimation != null) { + mScreenRotationAnimation.setRotation(rotation); + } + } finally { + if (!inTransaction) { + Surface.closeTransaction(); + if (SHOW_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION setRotationUnchecked"); } } - } //end if changed + Surface.setOrientation(0, rotation); + Surface.unfreezeDisplay(0); + } else { + Surface.setOrientation(0, rotation); + } + rebuildBlackFrame(inTransaction); - return changed; + for (int i=mWindows.size()-1; i>=0; i--) { + WindowState w = mWindows.get(i); + if (w.mSurface != null) { + w.mOrientationChanging = true; + } + } + for (int i=mRotationWatchers.size()-1; i>=0; i--) { + try { + mRotationWatchers.get(i).onRotationChanged(rotation); + } catch (RemoteException e) { + } + } + return true; } public int getRotation() { @@ -8601,8 +8590,7 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); - boolean changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); + boolean changed = updateRotationUncheckedLocked(false); if (changed) { mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } else { @@ -9029,8 +9017,7 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); - configChanged |= setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); + configChanged |= updateRotationUncheckedLocked(false); } if (configChanged) { @@ -9403,12 +9390,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); pw.print(" mRotation="); pw.print(mRotation); - pw.print(" mRequestedRotation="); pw.print(mRequestedRotation); pw.print(" mAltOrientation="); pw.println(mAltOrientation); pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation); pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); - pw.print(" mDeferredRotation="); pw.print(mDeferredRotation); - pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags); + pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount); pw.print(" mAnimationPending="); pw.print(mAnimationPending); pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0ef03bb..09097ee 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -566,7 +566,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const int dpy = 0; const int orientation = mCurrentState.orientation; - const uint32_t type = mCurrentState.orientationType; + // Currently unused: const uint32_t flags = mCurrentState.orientationFlags; GraphicPlane& plane(graphicPlane(dpy)); plane.setOrientation(orientation); @@ -1299,7 +1299,7 @@ int SurfaceFlinger::setOrientation(DisplayID dpy, Mutex::Autolock _l(mStateLock); if (mCurrentState.orientation != orientation) { if (uint32_t(orientation)<=eOrientation270 || orientation==42) { - mCurrentState.orientationType = flags; + mCurrentState.orientationFlags = flags; mCurrentState.orientation = orientation; setTransactionFlags(eTransactionNeeded); mTransactionCV.wait(mStateLock); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d7f005f..43191b7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -245,7 +245,7 @@ private: } LayerVector layersSortedByZ; uint8_t orientation; - uint8_t orientationType; + uint8_t orientationFlags; uint8_t freezeDisplay; }; diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index f015378..5df018e 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -412,9 +412,31 @@ public class WindowManagerPermissionTests extends TestCase { @SmallTest public void testSET_ORIENTATION() { try { - mWm.setRotation(0, true, 0); + mWm.updateRotation(true); mWm.getSwitchState(0); - fail("IWindowManager.setRotation did not throw SecurityException as" + fail("IWindowManager.updateRotation did not throw SecurityException as" + + " expected"); + } catch (SecurityException e) { + // expected + } catch (RemoteException e) { + fail("Unexpected remote exception"); + } + + try { + mWm.freezeRotation(); + mWm.getSwitchState(0); + fail("IWindowManager.freezeRotation did not throw SecurityException as" + + " expected"); + } catch (SecurityException e) { + // expected + } catch (RemoteException e) { + fail("Unexpected remote exception"); + } + + try { + mWm.thawRotation(); + mWm.getSwitchState(0); + fail("IWindowManager.thawRotation did not throw SecurityException as" + " expected"); } catch (SecurityException e) { // expected diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java index 3d1fa7a..940b290 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java @@ -396,7 +396,7 @@ public class BridgeWindowManager implements IWindowManager { } - public void setRotation(int arg0, boolean arg1, int arg2) throws RemoteException { + public void updateRotation(boolean arg0) throws RemoteException { // TODO Auto-generated method stub } |