In Android 8.0, users could toggle between auto-rotate and portrait rotation modes using a Quicksettings tile or Display settings. In Android 9, we updated portrait rotation mode to eliminate unintentional rotations by pinning the current screen rotation even if the device position changes. Users can trigger rotation manually when needed by pressing a new button in the navigation bar. We renamed the portrait mode to rotation lock and it activates when auto-rotate is off. There are no changes to auto-rotate mode.
When the device is in rotation lock mode, users can lock their screen to any
rotation supported by the top, visible Activity (given current system
constraints). If the top Activity can be rendered in multiple rotations in
auto-rotate mode, the same options should be available in rotation locked mode,
with some exceptions based on the Activity's screenOrientation
setting.
Rotation lock mode works by showing a button in the navbar on device rotation
changes. To accomplish this, the device's orientation sensor must remain active
even when auto-rotate is off. Tapping this button effectively sets user rotation
preference (Settings.System.USER_ROTATION
). WindowManager uses this
preference, along with other details about the top Activity and system status,
to change the system's rotation. WindowManager continues to use user rotation
preference when deciding what rotation to render the system in when moving to
another Activity.
User rotation preference should be maintained when moving between Activities. However, because most phone users only want to be in landscape for a short, temporary period of time, we added natural orientation bias. User rotation preference is reset to the device's natural orientation whenever the system rotation changes to the device's natural orientation. For most phones, the device's natural orientation is portrait (0º). Resetting user rotation preference often happens when using a portrait-only app, locking the phone or returning to launcher workspace.
Rotation interactions for users haven't changed much in the last decade. Users may find this feature hard to discover given their prior history with rotation and button positioning in the navigation bar. For this reason, we've added an introduction mode to the rotate button that highlights it when it appears. Intro mode behavior only happens for the first few button interactions after which introduction mode is disabled.
Source
Support for rotation suggestions has been added to Android 9. Most changes are contained within the following files.
services/.../server/policy/PhoneWindowManager.java
:- Hooks consuming the output of
WindowOrientationListener
(MyOrientationListener
, responsible for monitoring sensors to determine if the device has been rotated) - Keeps the
WindowOrientationListener
active even when auto-rotate is disabled (seeneedSensorRunningLp()
) - Computes the system rotation given user rotation preference, top
Activity
screenOrientation
settings and system status (seerotationForOrientationLw()
) - Determine if the top Activity can rotate to a given rotation (see
isRotationChoicePossible()
)
- Hooks consuming the output of
SystemUI/.../statusbar/phone/NavigationBarFragment
:- Determines if the navbar button should be shown on rotation
suggestion callbacks from
PhoneWindowManager
(seeonRotationProposal()
) - Handles when to hide the rotate navbar button (see calls to
setRotateSuggestionButtonState(false)
) - Handles button timeouts, including the special case when the navbar is hidden (commonly in full screen)
- Resets user preference on return to the device's natural
orientation (
mRotationWatcher
) - Picks the appropriate style for the navbar button animation,
applied in
NavigationBarView
(seeonRotationProposal()
) - Adds introduction mode logic, including specialized animation
(see references to
Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED
) - Implements the disable2 rotation flag (see
disable()
)
- Determines if the navbar button should be shown on rotation
suggestion callbacks from
SystemUI/.../statusbar/phone/NavigationBarView.java
:- Styles button icon animation to match pending rotation (see
updateRotateSuggestionButtonStyle()
) - Handles button visibility changes (see
setRotateButtonVisibility()
), including logic to hide the rotate button if certain Accessibility services are active (accounting for the right-most navbar button stack ranking)
- Styles button icon animation to match pending rotation (see
SystemUI/res/layout/menu_ime.xml
:- Includes a new
KeyButtonView
for the rotate button, stacked above the menu and IME/keyboard chooser but below the Accessibility button
- Includes a new
SystemUI/res/drawable/ic_sysbar_rotate_button.xml
:- Complex
AnimatedVectorDrawable
used to animate the rotate navbar button - Styling (in
SystemUI/res/values/styles.xml
) is used to set the start and end angles of rotation so the same drawable can be used to animate various starting and ending rotations - Icon tinting is set via
TintedKeyButtonDrawable
- Complex
Implementation
Android 9 includes all necessary changes to get rotation suggestions working for devices that use software navigation keys (back, home, etc).
Device manufacturers who create devices with hardware navigation keys that wish to implement this feature will need to design and implement their own System UI affordance or disable the feature. It is recommended that any introduced surface be easy to use when the device is held at 90º or 180º to the current system rotation and is rapidly accessible. For these reasons, the use of notifications (as is done for the IME/keyboard picker) is not recommended.
The hardware requirements to use this feature are the same as the requirements to use auto-rotate.
It is necessary for implementation consistency that user rotation preference
(Settings.System.USER_ROTATION
) is reset to the device's natural
rotation when the system changes to the device's natural rotation for any reason
when auto-rotate is off. The provided implementation does this (see
NavigationBarFragment.mRotationWatcher
).
There is a new flag in StatusBarManager.disable2
to temporarily
prevent rotation suggestions from appearing. See
StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS
. This flag must be
respected in all implementations as it's used by critical system apps, including
Setup Wizard. The provided implementation supports this (see
NavigationBarFragment.disable()
).
We strongly recommend enabling the feature and following the AOSP implementation, if possible. We aim to keep the rotation experience similar between devices, mirroring the uniformity in experience on most phones today between auto-rotate and portrait lock.
Customization
As rotation suggestions appear only in rotation locked mode (auto-rotate off),
it is possible to choose if the feature is default on for new installs by
choosing to have auto-rotate off by default. See
def_accelerometer_rotation
in
SettingsProvider/res/values/defaults.xml
to make default changes.
Users can easily change if auto-rotate is active or not (regardless of default) via the rotate tile in Quicksettings or Display settings.
Validation
For testing, the feature can be turned off and on by altering a gating
Settings.Secure
value. This accomplished easiest by running the
following command from a privileged adb instance:
adb shell settings put secure show_rotation_suggestions <x>
Set x to 0
for off and 1
for on.
For testing, introduction mode can be reset by altering the associated
Settings.Secure
value. This accomplished easiest by running the
following command from a privileged adb instance:
adb shell settings put secure num_rotation_suggestions_accepted 0