Android13屏幕旋转的基本逻辑

2024-05-12 15:52

本文主要是介绍Android13屏幕旋转的基本逻辑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.问题

1.settings put system user_rotation 1是什么意思

答案:设置用户期望的屏幕转向,0代表:Surface.ROTATION_0竖屏;1代表:Surface.ROTATION_90横屏

2.设置user_rotation和GSensor哪个优先级更高,比如user_rotation = 0期待竖屏,但是打开屏幕旋转且处于横屏时,应该是横屏还是竖屏

答案:此时GSensor优先级更高,横屏显示,具体原因看第三个问题

3.systemui中的“自动旋转”按钮影响的是哪个数据和系统的值

Settings.System.ACCELEROMETER_ROTATION和DisplayRotation.userRotationMode:

    /** 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;                                                                                                               /** When not otherwise specified by the activity's screenOrientation, rotation is set by* the user. */public final int USER_ROTATION_LOCKED = 1;USER_ROTATION_FREE :如果应用不指定屏幕方向,sensor传感器决定
USER_ROTATION_LOCKED:如果应用不指定屏幕方向,user决定方向,即user_rotation数据库值。

打开自动旋转时候设置的是Settings.System.ACCELEROMETER_ROTATION值会设置成1,代表,否则设置成0,这个值会直接影响DisplayRotation.userRotationMode的值:

final int userRotationMode = Settings.System.getIntForUser(resolver,Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) !=0? WindowManagerPolicy.USER_ROTATION_FREE: WindowManagerPolicy.USER_ROTATION_LOCKED;也就说如果打开了自动旋转,userRotationMode = USER_ROTATION_FREE,代表通过sensor决定;否则设置
成USER_ROTATION_LOCKED,由user_rotation决定
2.GSensor触发屏幕转向的流程分析

现在我们知道,屏幕方向旋转是通过加速度传感器或者重力传感器来获取,但Sensor上报的原始数据还得通过一系列计算得到最终的旋转角度,这部分逻辑在WindowOrientationListener.AccelSensorJudge类中进行计算转换,当Sensor收到onSensorChanged()回调后,对原始数据进行加工,最终得到屏幕方向旋转角度,并当方向旋转值发生变化时,调用WindowOrientationListener#onProposedRotationChanged()方法发起更新:

        public void onProposedRotationChanged(int rotation) {ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);// Send interaction power boost to improve redraw performance.mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);if (isRotationChoicePossible(mCurrentAppOrientation)) {final boolean isValid = isValidRotationChoice(rotation);sendProposedRotationChangeToStatusBarInternal(rotation, isValid);} else {mService.updateRotation(false /* alwaysSendConfiguration */,false /* forceRelayout */);}}

mService.updateRotation->wms.updateRotationUnchecked->displayContent.updateRotationUnchecked->DisplayRotation.updateRotationUnchecked如下:

/*** Update rotation with an option to force the update. This updates the container's perception* of rotation and, depending on the top activities, will freeze the screen or start seamless* rotation. The display itself gets rotated in {@link DisplayContent#applyRotationLocked}* during {@link DisplayContent#sendNewConfiguration}.** @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating*                    orientation because we're waiting for some rotation to finish or display*                    to unfreeze, which results in configuration of the previously visible*                    activity being applied to a newly visible one. Forcing the rotation*                    update allows to workaround this issue.* @return {@code true} if the rotation has been changed. In this case YOU MUST CALL*         {@link DisplayContent#sendNewConfiguration} TO COMPLETE THE ROTATION AND UNFREEZE*         THE SCREEN.*/boolean updateRotationUnchecked(boolean forceUpdate) {final int displayId = mDisplayContent.getDisplayId();if (!forceUpdate) {if (mDeferredRotationPauseCount > 0) {// Rotation updates have been paused temporarily. Defer the update until updates// have been resumed.ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused.");return false;}final ScreenRotationAnimation screenRotationAnimation =mDisplayContent.getRotationAnimation();if (screenRotationAnimation != null && screenRotationAnimation.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.ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress.");return false;}if (mService.mDisplayFrozen) {// Even if the screen rotation animation has finished (e.g. isAnimating returns// false), there is still some time where we haven't yet unfrozen the display. We// also need to abort rotation here.ProtoLog.v(WM_DEBUG_ORIENTATION,"Deferring rotation, still finishing previous rotation");return false;}if (mDisplayContent.mFixedRotationTransitionListener.shouldDeferRotation()) {// Makes sure that after the transition is finished, updateOrientation() can see// the difference from the latest orientation source.mLastOrientation = SCREEN_ORIENTATION_UNSET;// During the recents animation, the closing app might still be considered on top.// In order to ignore its requested orientation to avoid a sensor led rotation (e.g// user rotating the device while the recents animation is running), we ignore// rotation update while the animation is running.return false;}}if (!mService.mDisplayEnabled) {// No point choosing a rotation if the display is not enabled.ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled.");return false;}//当前(未更新)的屏幕转向final int oldRotation = mRotation;//最近一次应用请求的转向final int lastOrientation = mLastOrientation;//根据给定的显示方向确定一个屏幕方向final int rotation = rotationForOrientation(lastOrientation, oldRotation);ProtoLog.v(WM_DEBUG_ORIENTATION,"Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and "+ "oldRotation=%s (%d)",Surface.rotationToString(rotation), rotation,displayId,ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,Surface.rotationToString(oldRotation), oldRotation);ProtoLog.v(WM_DEBUG_ORIENTATION,"Display id=%d selected orientation %s (%d), got rotation %s (%d)", displayId,ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,Surface.rotationToString(rotation), rotation);if (oldRotation == rotation) {// No change.return false;}// Preemptively cancel the running recents animation -- SysUI can't currently handle this// case properly since the signals it receives all happen post-change. We do this earlier// in the rotation flow, since DisplayContent.updateDisplayOverrideConfigurationLocked seems// to happen too late.final RecentsAnimationController recentsAnimationController =mService.getRecentsAnimationController();if (recentsAnimationController != null) {recentsAnimationController.cancelAnimationForDisplayChange();}ProtoLog.v(WM_DEBUG_ORIENTATION,"Display id=%d rotation changed to %d from %d, lastOrientation=%d",displayId, rotation, oldRotation, lastOrientation);if (deltaRotation(oldRotation, rotation) != Surface.ROTATION_180) {mDisplayContent.mWaitingForConfig = true;}mRotation = rotation;mDisplayContent.setLayoutNeeded();if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {final boolean wasCollecting = mDisplayContent.mTransitionController.isCollecting();final TransitionRequestInfo.DisplayChange change = wasCollecting ? null: new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(),oldRotation, mRotation);mDisplayContent.requestChangeTransitionIfNeeded(ActivityInfo.CONFIG_WINDOW_CONFIGURATION, change);if (wasCollecting) {// Use remote-rotation infra since the transition has already been requested// TODO(shell-transitions): Remove this once lifecycle management can cover all//                          rotation cases.startRemoteRotation(oldRotation, mRotation);}return true;}mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) {// The screen rotation animation uses a screenshot to freeze the screen while windows// resize underneath. When we are rotating seamlessly, we allow the elements to// transition to their rotated state independently and without a freeze required.prepareSeamlessRotation();} else {prepareNormalRotationAnimation();}// Give a remote handler (system ui) some time to reposition things.startRemoteRotation(oldRotation, mRotation);return true;}

其中特别重要的函数时rotationForOrientation,根据当下屏幕方向和应用请求的方向,决定最终的屏幕显示方向,看下其实现方式:

int rotationForOrientation(@ScreenOrientation int orientation,@Surface.Rotation int lastRotation) {ProtoLog.v(WM_DEBUG_ORIENTATION,"rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",ActivityInfo.screenOrientationToString(orientation), orientation,Surface.rotationToString(lastRotation), lastRotation,Surface.rotationToString(mUserRotation), mUserRotation,mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED? "USER_ROTATION_LOCKED" : "");//用户锁定了方向,直接返回user_rotation数据设置的用户期待的值if (isFixedToUserRotation()) {return mUserRotation;}//获取Sensor检测到的屏幕方向值int sensorRotation = mOrientationListener != null? mOrientationListener.getProposedRotation() // may be -1: -1;mLastSensorRotation = sensorRotation;if (sensorRotation < 0) {sensorRotation = lastRotation;}final int lidState = mDisplayPolicy.getLidState();final int dockMode = mDisplayPolicy.getDockMode();final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();final boolean carDockEnablesAccelerometer =mDisplayPolicy.isCarDockEnablesAccelerometer();final boolean deskDockEnablesAccelerometer =mDisplayPolicy.isDeskDockEnablesAccelerometer();final int preferredRotation;if (!isDefaultDisplay) {// For secondary displays we ignore things like displays sensors, docking mode and// rotation lock, and always prefer user rotation.preferredRotation = mUserRotation;} else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {// Ignore sensor when lid switch is open and rotation is forced.preferredRotation = mLidOpenRotation;} else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR&& (carDockEnablesAccelerometer || 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 = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;} else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK|| dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK|| dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)&& (deskDockEnablesAccelerometer || 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 = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;} else if (hdmiPlugged && mDemoHdmiRotationLock) {// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.// Note that the dock orientation overrides the HDMI orientation.preferredRotation = mDemoHdmiRotation;} else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED&& mUndockedHdmiRotation >= 0) {// Ignore sensor when plugged into HDMI and an undocked orientation has// been specified in the configuration (only for legacy devices without// full multi-display support).// Note that the dock orientation overrides the HDMI orientation.preferredRotation = mUndockedHdmiRotation;} else if (mDemoRotationLock) {// Ignore sensor when demo rotation lock is enabled.// Note that the dock orientation and HDMI rotation lock override this.preferredRotation = mDemoRotation;} else if (mDisplayPolicy.isPersistentVrModeEnabled()) {// While in VR, apps always prefer a portrait rotation. This does not change// any apps that explicitly set landscape, but does cause sensors be ignored,// and ignored any orientation lock that the user has set (this conditional// should remain above the ORIENTATION_LOCKED conditional below).preferredRotation = mPortraitRotation;} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {// Application just wants to remain locked in the last rotation.preferredRotation = lastRotation;} else if (!mSupportAutoRotation) {// If we don't support auto-rotation then bail out here and ignore// the sensor and any rotation lock settings.preferredRotation = -1;} else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))|| 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|| getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {preferredRotation = sensorRotation;} else {preferredRotation = lastRotation;}} else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED&& orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR&& orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE&& orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT&& orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE&& orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {// Apply rotation lock. Does not apply to NOSENSOR or specific rotations.// The idea is that the user rotation expresses a weak preference for the direction// of gravity and as NOSENSOR is never affected by gravity, then neither should// NOSENSOR be affected by rotation lock (although it will be affected by docks).// Also avoid setting user rotation when app has preference over one particular rotation// to avoid leaving the rotation to the reverse of it which has the compatible// orientation, but isn't what app wants, when the user rotation is the reverse of the// preferred rotation.preferredRotation = mUserRotation;} else {// No overriding preference.// We will do exactly what the application asked us to do.preferredRotation = -1;}switch (orientation) {case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:// Return portrait unless overridden.if (isAnyPortrait(preferredRotation)) {return preferredRotation;}return mPortraitRotation;case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:// Return landscape unless overridden.if (isLandscapeOrSeascape(preferredRotation)) {return preferredRotation;}return mLandscapeRotation;case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:// Return reverse portrait unless overridden.if (isAnyPortrait(preferredRotation)) {return preferredRotation;}return mUpsideDownRotation;case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:// Return seascape unless overridden.if (isLandscapeOrSeascape(preferredRotation)) {return preferredRotation;}return mSeascapeRotation;case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:// Return either landscape rotation.if (isLandscapeOrSeascape(preferredRotation)) {return preferredRotation;}if (isLandscapeOrSeascape(lastRotation)) {return lastRotation;}return mLandscapeRotation;case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:// Return either portrait rotation.if (isAnyPortrait(preferredRotation)) {return preferredRotation;}if (isAnyPortrait(lastRotation)) {return lastRotation;}return mPortraitRotation;default:// For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,// just return the preferred orientation we already calculated.if (preferredRotation >= 0) {return preferredRotation;}return Surface.ROTATION_0;}}

参考文章:

安卓开发之屏幕旋转_安卓开发 屏幕旋转逻辑-CSDN博客

https://juejin.cn/post/6958440883276496927

https://juejin.cn/post/6982153383880687624

这篇关于Android13屏幕旋转的基本逻辑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/983061

相关文章

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2187 凸包or旋转qia壳法

题意: 给n(50000)个点,求这些点与点之间距离最大的距离。 解析: 先求凸包然后暴力。 或者旋转卡壳大法。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <s

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

C 语言的基本数据类型

C 语言的基本数据类型 注:本文面向 C 语言初学者,如果你是熟手,那就不用看了。 有人问我,char、short、int、long、float、double 等这些关键字到底是什么意思,如果说他们是数据类型的话,那么为啥有这么多数据类型呢? 如果写了一句: int a; 那么执行的时候在内存中会有什么变化呢? 橡皮泥大家都玩过吧,一般你买橡皮泥的时候,店家会赠送一些模板。 上

Android13_SystemUI下拉框新增音量控制条

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Android13_SystemUI下拉框新增音量控制条 一、必备知识二、源码分析对比1.brightness模块分析对比2.statusbar/phone 对应模块对比对比初始化类声明对比构造方法 三、源码修改四、相关资源 一、必备知识 在Android12 版本上面已经完成了功能的实现,目前是在And

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

Java基础回顾系列-第一天-基本语法

基本语法 Java基础回顾系列-第一天-基本语法基础常识人机交互方式常用的DOS命令什么是计算机语言(编程语言) Java语言简介Java程序运行机制Java虚拟机(Java Virtual Machine)垃圾收集机制(Garbage Collection) Java语言的特点面向对象健壮性跨平台性 编写第一个Java程序什么是JDK, JRE下载及安装 JDK配置环境变量 pathHe

逻辑表达式,最小项

目录 得到此图的逻辑电路 1.画出它的真值表 2.根据真值表写出逻辑式 3.画逻辑图 逻辑函数的表示 逻辑表达式 最小项 定义 基本性质 最小项编号 最小项表达式   得到此图的逻辑电路 1.画出它的真值表 这是同或的逻辑式。 2.根据真值表写出逻辑式   3.画逻辑图   有两种画法,1是根据运算优先级非>与>或得到,第二种是采