是支持屏幕进行旋转的,通过旋转使得屏幕呈现出竖屏或者横屏的布局。有时我们在使用的时候会发现,旋转时会有动画。这是因为,为了使用户在使用转屏旋转过程中提升体验,系统会对屏幕截屏,使用截屏获取的图片进行旋转动画,指导完成旋转,我们所看到的旋转动画其实是,旋转开始时系统所截屏幕所做的动画。
手机是否支持转屏可以在Setting设定,对于Setting中有关是否自动转屏,PhoneWindowManager中的init()函数中创建了SettingsObserver对象,其observe()方法将监听Settings.System.USER_ROTATION的值。如果设置中打开auto-rotation,会触发如下流程。
下面对该流程中涉及到的代码进行分析:
1、AccessibilitySettings类是各手机厂商自己的setting模块中的一个类,该类的命名和方法可能不同,详细代码见下。
2、handleLockScreenRotationPreferenceClick()也是AccessibilitySettings.java的方法。在该方法中调用RotationPolicy类的setRotationLockedForAccessbility(),其实就是用户在settings界面点击auto-Rotation传入对应的值。
3、下面的各类及方法为android中源码。enable为是否允许自动旋转的使能位。
4、在setRotationLock()方法中,根据enable的值,分别执行wms的不允许转屏和允许转屏。
5、freezeRotation()不允许转屏,thawRotation()允许转屏。这里我们分析转屏的流程,因此顺着thawRotation()的流程分析。
6、PhoneWindowManager.java中setUserRotationMode。该方法会在Settings.System中写入值。
7、PhoneWindowManager中的init()函数中创建了SettingsObserver对象,其observe()方法将监
听Settings.System.USER_ROTATION的值,监听到该值后调用onChange。
8、该方法是wms在调用freezeRotation()或thawRotation()后调用的。
9、这里会触发SettingsObserver.onChange(),其中主要调用了updateSettings()和updateRotation()两个函数。其主要的工作是根据需要监听传感器数据,据此判断是否要转屏,如果传感器传回的值改变,则对configuration的各种更新。函数updateSettings()如它的名字主要更新设置信息。如果UserRotation(朝向信息,如Surface.ROTATION_0)和UserRotationMode(USER_ROTATION_FREE vs. USER_ROTATION_LOCKED)有更新,就设置标记updateRotation为true表示接下去需要更新rotation相关信息。
10、如果UserRotationMode的配置有变,由于需要传感器信息的配合,还需调用updateOrientationListenerLp()来设置或取消监听传感器。
11、假设手机设置为自动旋转,那么PhoneWindowManager会通过MyOrientationListener来监听传感器信息。MyOrientationListener是WindowOrientationListener的继承类,WindowOrientationListener的enable()函数中调用SensorManager提供的registerListener()接口来设置Sensor信息的listener。
12、接下来我们重点分析有关传感器部分的流程。
调用SensorManager提供的registerListener()接口设置Sensor信息的listener。
调用SystemSensorManager,registerListenerImpl注册监听器,当Sensor数据有改变的时候将会回调SensorEventListener的onSensorChanged方法。
手机开机后会创建SystemSensorManager的实例,在其构造函数中,主要做了四件事情:
(1)初始化JNI:调用JNI函数nativeClassInit()进行初始化。
(2)初始化Sensor列表:调用JNI函数sensors_module_init,对Sensor模块进行初始化,创建了native层SensorManager的实例。
(3)获取Sensor列表:调用JNI函数sensors_module_get_next_sensor()获取Sensor,并存在sHandleToSensor列表中
(4)构造SensorThread类:构造线程的类函数,并没有启动线程,当有应用注册的时候才会启动线程。
当有应用程序调用registerListenerImpl()方法注册监听的时候,会调用SensorThread.startLoacked()启动线程。线程只会启动一次,并调用enableSensorLocked()接口对指定的sensor使能,并设置采样时间。SensorThreadRunnable实现了Runnable接口,在SensorThread类中被启动。
首先,registerListenerImpl()中创建SensorEventQueue对象(基类为BaseEventQueue),它是传感器事件的队列,记录需要监听哪些传感器信息。同时也负责与SensorService的连接和通信,可以说是SensorEventListener与SensorService间的桥梁。SensorEventListener和SensorEventQueue之间是1:1的关系,它们的映射关系保存在成员mSensorListeners中。如果这里注册的SensorEventListener还没有相应的SensorEventQueue,则新建一个,然后通过addSensor()方法将要关注的传感器进行注册。这个过程中addSensor()调用了enableSensor(),它最终是通过SensorService的enableDisable()方法来完成注册工作的。这样,SensorService就开始监听该Sensor,当底层有传感器数据来时,SensorService主线程中会调用相应SensorEventConnection的sendEvents()将底层传感器传回的数据发给对应的Client。前面初始化SensorEventQueue时会创建Receiver,它是一个Looper的回调对象,在Client端收到从SensorService来的数据后被回调。当有数据收到时Receiver的handleEvent()被调用,继而通过JNI调用到SystemSensorManager::dispatchSensorEvent()。接着就调到了WindowOrientationListener的onSensorChanged()函数。该函数将计算是否需要转屏。如果需要转屏,将计算结果传给MyOrientationListener的onProposedRotationChanged()。
13、回到PhoneWindowManager的updateSettings()流程。最后如果检测到UserRotation或UserRotationMode有更新,会调用updateRotation(),继而调用WMS的updateRotation()保证当前的屏幕方向是一致的。
如果手机现在转了屏幕,期望转屏事件发生。如前面所说,onProposedRotationChanged()被调用,其中调用updateRotation()函数,随之的updateRotationUncheckedLocked()就是真正执行转屏的地方了。当然除了上面这条种情况会进行转屏,还有其它情况可能会触发转屏,比如应用请求转屏。例如需要横屏的游戏(通过updateOrientationFromAppTokensLocked()方法)。updateRotation()中主要是执行两个函数:updateRotationUncheckedLocked()和sendNewConfiguration()。前者执行转屏动作,包含转屏动画等。后者使AMS获取当前新的configuration,并且广播该事件给所有相应的listener。