Android4.1 关于Rotation相关的Configuration整体分析

2024-01-02 08:08

本文主要是介绍Android4.1 关于Rotation相关的Configuration整体分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于Rotation方面在Android中有点会涉及到。

1. 在Settings->Display中有“Auto-rotate screen” 选项,当enable或者disable的时候都会影响到系统的Rotation

2. 当旋转手机的时候,系统会做怎么的操作去通知Activity要旋转界面了。

3. 当新启一个应用需要强制横屏或者竖屏的时候,系统是怎么去判断的。


1. 当我们enable或者disable “Auto-rotate screen”的时候,系统会做什么

1.  RotationPolicy.setRotationLockForAccessibility()

     1. 当用户enable或者disable “Auto-rotate screen”的时候,会调用RotationPolicy.setRotationLockForAccessibility(), 而在这个函数里面如果是enable就调用wm.freezeRotation(Suface.ROTATION_0);   // goto 1.1

      2. 否则就调用wm.thawRotation().

    public static void setRotationLockForAccessibility(Context context, final boolean enabled) {Settings.System.putIntForUser(context.getContentResolver(),Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0,UserHandle.USER_CURRENT);AsyncTask.execute(new Runnable() {@Overridepublic void run() {try {IWindowManager wm = WindowManagerGlobal.getWindowManagerService();if (enabled) {wm.freezeRotation(Surface.ROTATION_0);} else {wm.thawRotation();}} catch (RemoteException exc) {Log.w(TAG, "Unable to save auto-rotate setting");}}});}

1.1 WindowManagerService.freezeRotation()

      1. mPolicy.setUserRotationMode 通过PhoneWindowManager.setUserRotationMode()去设置Settings.System相关的数据库值,在PhoneWindowManager中会有一个Observe去监听Settings.System的数值变化,如果有变动就去调用SettingsObserver.onChange()   //goto 1.1.1

       2. updateRotationUnchecked(false, false);   // goto  1.1.2

    public void freezeRotation(int rotation) {... ...if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,rotation == -1 ? mRotation : rotation);updateRotationUnchecked(false, false);}

1.1.1 SettingsObserver.onChange()

    1. updateSettings();  跟新系统相关的设置  //goto 1.1.1.1

    2. updateRotation(false);  

        @Override public void onChange(boolean selfChange) {updateSettings();updateRotation(false);}


1.1.2  WindowManagerService.updateRotationUnchecked()

      这是freezeRotation里面做的第二个动作,为什么要把它写在前面,因为在debug的时候,发现这个函数中会调用policy中函数请求mLock的锁,然后block住1.1.1.1 PhoneWindowManager.updateSettings()。

     1. updateRotationUncheckedLocked(false);   如果返回的是false,就去直接执行performLayoutAndPlaceSurfacesLocked 去进行后续的刷新工作 // goto 1.1.2.1

     2. 如果满足相应的条件, performLayoutAndPlaceSurfacesLocked()  //

     3. 如果Configuration有变化或者明确要求sendConfiguration,就调用sendNewConfiguration(); 让AMS去updateConfiguration。 //这时候还不会执行

    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {long origId = Binder.clearCallingIdentity();boolean changed;synchronized(mWindowMap) {changed = updateRotationUncheckedLocked(false);  // goto 1.1.2.1if (!changed || forceRelayout) {getDefaultDisplayContentLocked().layoutNeeded = true;performLayoutAndPlaceSurfacesLocked();  //后续分析}}if (changed || alwaysSendConfiguration) {sendNewConfiguration();}}


1.1.2.1 WindowManagerService.updateRotationUncheckedLocked()

      1. mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);   // 返回0  goto 1.1.2.1.1

      2.  mPolicy.rotationHasCompatibleMetricsLw 

      3. 如果roataion 和altOrientataion都没有发生变化就直接返回 false.  (这种情况是在portrait模式下enable rotation),如果是landscape模式下就应该往下走了。

      4. computeScreenConfigurationLocked(null); // Update application display metrics. 跟新屏幕相关的信息。

    public boolean updateRotationUncheckedLocked(boolean inTransaction) {... ...int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(mForcedAppOrientation, rotation);if (mRotation == rotation && mAltOrientation == altOrientation) {// No change.return false;}mRotation = rotation;mAltOrientation = altOrientation;mPolicy.setRotationLw(mRotation);mWindowsFreezingScreen = true;mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),WINDOW_FREEZE_TIMEOUT_DURATION);mWaitingForConfig = true;getDefaultDisplayContentLocked().layoutNeeded = true;startFreezingDisplayLocked(inTransaction, 0, 0);// startFreezingDisplayLocked can reset the ScreenRotationAnimation.screenRotationAnimation =mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);// We need to update our screen size information to match the new// rotation.  Note that this is redundant with the later call to// sendNewConfiguration() that must be called after this function// returns...  however we need to do the screen size part of that// before then so we have the correct size to use when initializing// the rotation animation for the new rotation.computeScreenConfigurationLocked(null);final DisplayContent displayContent = getDefaultDisplayContentLocked();final DisplayInfo displayInfo = displayContent.getDisplayInfo();if (!inTransaction) {if (SHOW_TRANSACTIONS) {Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");}Surface.openTransaction();}try {// NOTE: We disable the rotation in the emulator because//       it doesn't support hardware OpenGL emulation yet.if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null&& screenRotationAnimation.hasScreenshot()) {if (screenRotationAnimation.setRotationInTransaction(rotation, mFxSession,MAX_ANIMATION_DURATION, mTransitionAnimationScale,displayInfo.logicalWidth, displayInfo.logicalHeight)) {updateLayoutToAnimationLocked();}}mDisplayManagerService.performTraversalInTransactionFromWindowManager();} finally {if (!inTransaction) {Surface.closeTransaction();if (SHOW_LIGHT_TRANSACTIONS) {Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");}}}final WindowList windows = displayContent.getWindowList();for (int i = windows.size() - 1; i >= 0; i--) {WindowState w = windows.get(i);if (w.mHasSurface) {if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);w.mOrientationChanging = true;mInnerFields.mOrientationChangeComplete = false;}}for (int i=mRotationWatchers.size()-1; i>=0; i--) {try {mRotationWatchers.get(i).onRotationChanged(rotation);} catch (RemoteException e) {}}scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);return true;}

1.1.2.1.1 PhoneWindowManager.rotationForOrientationLw()

       这个函数的主要作用是返回跟Orientation相关的rotation,如果没有固定的设置,系统会返回一个默认的Rotation值。

       1.  先去调用mOrientationListener.getProposeRotation()去获取Sensor认为的合适的rotation值,通常是-1,我debug的时候返回的就是。mOrientationListener 为MyOrientationListener对象

       2. 由于此时mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 所以把preferredRotation = mUserRotation; 然后跟据对应的orientation选择对应的Rotation返回,我们这个case是走到default里面把preferredRotation返回回去。

    public int rotationForOrientationLw(int orientation, int lastRotation) {synchronized (mLock) {int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1if (sensorRotation < 0) {sensorRotation = lastRotation;}final int preferredRotation;if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {.... ...} else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED&& orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {// Apply rotation lock.  Does not apply to NOSENSOR.// 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).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:// Return either landscape rotation.if (isLandscapeOrSeascape(preferredRotation)) {return preferredRotation;}if (isLandscapeOrSeascape(lastRotation)) {return lastRotation;}return mLandscapeRotation;case ActivityInfo.SCREEN_ORIENTATION_SENSOR_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;}}}


1.1.1.1 PhoneWindowManager.updateSettings()

   当 1.1.2的lock释放之后,也就是 PhoneWindowManager.rotationForOrientationLw()执行完,updateSettings会等到mLock锁.

   由于userRotation和userRotationMode都发生了变化,所以会先后执行

     1. updateOrientationListenerLp();  // goto 1.1.1.1.1

      2. updateRotation(true);  //这个操作跟1.1.1.2是一样的,只不过这次需要去sendConfiguration了。

    public void updateSettings() {ContentResolver resolver = mContext.getContentResolver();boolean updateRotation = false;synchronized (mLock) {... ...// Configure rotation lock.int userRotation = Settings.System.getIntForUser(resolver,Settings.System.USER_ROTATION, Surface.ROTATION_0,UserHandle.USER_CURRENT);if (mUserRotation != userRotation) {mUserRotation = userRotation;updateRotation = true;}int userRotationMode = Settings.System.getIntForUser(resolver,Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?WindowManagerPolicy.USER_ROTATION_FREE :WindowManagerPolicy.USER_ROTATION_LOCKED;if (mUserRotationMode != userRotationMode) {mUserRotationMode = userRotationMode;updateRotation = true;updateOrientationListenerLp();}}if (updateRotation) {updateRotation(true);}}

1.1.1.1.1 PhoneWindowManager.updateOrientationListenerLp();

  这是函数很简单,由于我们把Rotation打开了,所以就去enable mOrientationListener (MyOrientationListener),作为Sensor变化的一个listener的回调函数。

    void updateOrientationListenerLp() {if (!mOrientationListener.canDetectOrientation()) {// If sensor is turned off or nonexistent for some reasonreturn;}//Could have been invoked due to screen turning on or off or//change of the currently visible window's orientationif (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+", current orientation="+mCurrentAppOrientation+", SensorEnabled="+mOrientationSensorEnabled);boolean disable = true;if (mScreenOnEarly) {if (needSensorRunningLp()) {disable = false;//enable listener if not already enabledif (!mOrientationSensorEnabled) {mOrientationListener.enable();if(localLOGV) Log.v(TAG, "Enabling listeners");mOrientationSensorEnabled = true;}} } //check if sensors need to be disabledif (disable && mOrientationSensorEnabled) {mOrientationListener.disable();if(localLOGV) Log.v(TAG, "Disabling listeners");mOrientationSensorEnabled = false;}

1.1.1.1 PhoneWindowManager.sendNewConfiguration()

 调用AMS去updateconfigurattion,后续分析

    void sendNewConfiguration() {try {mActivityManager.updateConfiguration(null);} catch (RemoteException e) {}}



这篇关于Android4.1 关于Rotation相关的Configuration整体分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3