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

相关文章

Python Faker库基本用法详解

《PythonFaker库基本用法详解》Faker是一个非常强大的库,适用于生成各种类型的伪随机数据,可以帮助开发者在测试、数据生成、或其他需要随机数据的场景中提高效率,本文给大家介绍PythonF... 目录安装基本用法主要功能示例代码语言和地区生成多条假数据自定义字段小结Faker 是一个 python

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实战之屏幕录制功能的实现

《Python实战之屏幕录制功能的实现》屏幕录制,即屏幕捕获,是指将计算机屏幕上的活动记录下来,生成视频文件,本文主要为大家介绍了如何使用Python实现这一功能,希望对大家有所帮助... 目录屏幕录制原理图像捕获音频捕获编码压缩输出保存完整的屏幕录制工具高级功能实时预览增加水印多平台支持屏幕录制原理屏幕

SpringBoot整合MybatisPlus的基本应用指南

《SpringBoot整合MybatisPlus的基本应用指南》MyBatis-Plus,简称MP,是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,下面小编就来和大家介绍一下... 目录一、MyBATisPlus简介二、SpringBoot整合MybatisPlus1、创建数据库和

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

《最新SpringSecurity实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)》本章节介绍了如何通过SpringSecurity实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟... 目录前言改造准备开始登录页改造自定义用户名密码登陆成功失败跳转问题自定义登出前后端分离适配方案结语前言

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec