在 Android 8.0 中,用户可以使用“快捷设置”图块或“显示”设置在自动旋转模式和纵向旋转模式之间切换。在 Android 9 中,我们更新了纵向旋转模式,通过固定当前屏幕旋转来消除意外旋转,即使设备位置发生变化也是如此。用户可以在需要时通过按导航栏中的新按钮手动触发旋转。我们将纵向模式重命名为旋转锁定,当自动旋转关闭时,它会激活。自动旋转模式没有任何变化。
当设备处于旋转锁定模式时,用户可以将屏幕锁定为顶部可见 Activity 支持的任何旋转方向(在当前系统约束条件下)。如果顶部 Activity 可以在自动旋转模式下以多个旋转方向呈现,则相同的选项也应该在旋转锁定模式下可用,但基于 Activity 的 screenOrientation
设置的一些例外情况除外。
旋转锁定模式的工作原理是在设备旋转更改时在导航栏中显示一个按钮。为了实现这一点,即使自动旋转关闭,设备的取向传感器也必须保持活动状态。点按此按钮实际上会设置用户旋转偏好设置 (Settings.System.USER_ROTATION
)。WindowManager 使用此偏好设置,以及有关顶部 Activity 和系统状态的其他详细信息,来更改系统的旋转方向。当移动到另一个 Activity 时,WindowManager 会继续使用用户旋转偏好设置来决定以什么旋转方向呈现系统。

在 Activity 之间移动时,应保持用户旋转偏好设置。但是,由于大多数手机用户只希望在短时间内临时处于横向模式,因此我们添加了自然方向偏差。每当系统旋转方向更改为设备的自然方向时,用户旋转偏好设置都会重置为设备的自然方向。对于大多数手机,设备的自然方向为纵向 (0º)。当使用仅限纵向模式的应用、锁定手机或返回启动器工作区时,通常会发生重置用户旋转偏好设置的情况。
在过去十年中,用户的旋转互动方式变化不大。鉴于用户之前使用旋转的习惯以及导航栏中按钮的位置,他们可能会发现此功能难以发现。因此,我们为旋转按钮添加了介绍模式,以便在按钮出现时突出显示它。介绍模式行为仅在最初几次按钮互动时发生,之后介绍模式将被禁用。
来源
Android 9 中添加了对旋转建议的支持。大多数更改都包含在以下文件中。
services/.../server/policy/PhoneWindowManager.java
:- 使用
WindowOrientationListener
输出的 Hook (MyOrientationListener
,负责监控传感器以确定设备是否已旋转) - 即使在自动旋转被禁用时,也保持
WindowOrientationListener
处于活动状态(请参阅needSensorRunningLp()
) - 根据用户旋转偏好设置、顶部 Activity
screenOrientation
设置和系统状态计算系统旋转方向(请参阅rotationForOrientationLw()
) - 确定顶部 Activity 是否可以旋转到给定的旋转方向(请参阅
isRotationChoicePossible()
)
- 使用
SystemUI/.../statusbar/phone/NavigationBarFragment
:- 确定是否应在来自
PhoneWindowManager
的旋转建议回调中显示导航栏按钮(请参阅onRotationProposal()
) - 处理何时隐藏旋转导航栏按钮(请参阅对
setRotateSuggestionButtonState(false)
的调用) - 处理按钮超时,包括导航栏隐藏时的特殊情况(通常在全屏模式下)
- 在返回设备的自然方向时重置用户偏好设置 (
mRotationWatcher
) - 为导航栏按钮动画选择合适的样式,在
NavigationBarView
中应用(请参阅onRotationProposal()
) - 添加介绍模式逻辑,包括专门的动画(请参阅对
Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED
的引用) - 实现 disable2 旋转标志(请参阅
disable()
)
- 确定是否应在来自
SystemUI/.../statusbar/phone/NavigationBarView.java
:- 设置按钮图标动画的样式以匹配待处理的旋转方向(请参阅
updateRotateSuggestionButtonStyle()
) - 处理按钮可见性更改(请参阅
setRotateButtonVisibility()
),包括在某些辅助功能服务处于活动状态时隐藏旋转按钮的逻辑(考虑最右侧导航栏按钮的堆叠排名)
- 设置按钮图标动画的样式以匹配待处理的旋转方向(请参阅
SystemUI/res/layout/menu_ime.xml
:- 包括一个新的
KeyButtonView
用于旋转按钮,堆叠在菜单和 IME/键盘选择器之上,但在辅助功能按钮之下
- 包括一个新的
SystemUI/res/drawable/ic_sysbar_rotate_button.xml
:- 用于动画旋转导航栏按钮的复杂
AnimatedVectorDrawable
- 样式(在
SystemUI/res/values/styles.xml
中)用于设置旋转的起始角度和结束角度,以便可以使用相同的可绘制对象来动画各种起始和结束旋转 - 图标着色通过
TintedKeyButtonDrawable
设置
- 用于动画旋转导航栏按钮的复杂
实现
Android 9 包含使旋转建议在使用软件导航键(返回、主屏幕等)的设备上工作所需的所有更改。
希望实现此功能的硬件导航键设备制造商将需要设计和实现自己的系统 UI 辅助功能或禁用该功能。建议任何引入的表面在设备以相对于当前系统旋转方向 90º 或 180º 角度握持时易于使用,并且可以快速访问。由于这些原因,不建议使用通知(如 IME/键盘选择器所做的那样)。
使用此功能的硬件要求与使用自动旋转的要求相同。
为了实现实施一致性,当系统由于任何原因在自动旋转关闭时更改为设备的自然旋转方向时,用户旋转偏好设置 (Settings.System.USER_ROTATION
) 必须重置为设备的自然旋转方向。提供的实现确实如此(请参阅 NavigationBarFragment.mRotationWatcher
)。
在 StatusBarManager.disable2
中有一个新标志,用于临时阻止旋转建议出现。请参阅 StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS
。此标志必须在所有实现中得到遵守,因为它被关键系统应用(包括设置向导)使用。提供的实现支持此标志(请参阅 NavigationBarFragment.disable()
)。
如果可能,我们强烈建议启用该功能并遵循 AOSP 实现。我们的目标是保持设备之间的旋转体验相似,从而在当今大多数手机上自动旋转和纵向锁定之间的体验保持一致。
自定义
由于旋转建议仅在旋转锁定模式下(自动旋转关闭)出现,因此可以通过选择默认关闭自动旋转来选择是否默认启用该功能以用于新安装。请参阅 SettingsProvider/res/values/defaults.xml
中的 def_accelerometer_rotation
以进行默认更改。
用户可以轻松更改自动旋转是否处于活动状态(无论默认设置如何),方法是通过“快捷设置”或“显示”设置中的旋转图块进行更改。
验证
为了进行测试,可以通过更改门控 Settings.Secure
值来关闭和打开该功能。最简单的方法是从特权 adb 实例运行以下命令
adb shell settings put secure show_rotation_suggestions <x>
将 x 设置为 0
表示关闭,设置为 1
表示开启。
为了进行测试,可以通过更改关联的 Settings.Secure
值来重置介绍模式。最简单的方法是从特权 adb 实例运行以下命令
adb shell settings put secure num_rotation_suggestions_accepted 0