设备平放,屏幕朝正上方。以下四个常量分别代表:
private static final int ROTATION_0 = 0;//初始情况。这个时候设备是横屏还是竖屏与硬件设备安装时默认的显示方向有关。
private static final int ROTATION_90 = 1;//设置屏幕方向自动旋转后,右侧翻起侧立时,屏幕会旋转到这个方向。
private static final int ROTATION_270 = 2;//设置屏幕方向自动旋转后,左侧翻起度侧立时,屏幕会旋转到这个方向。
private static final int ROTATION_180 = 3;//设置屏幕方向自动旋转后,屏幕底部侧立时,屏幕会旋转到这个方向。
再看两个数组:
private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {{{60, 165}, {165, 195}, {195, 300}},{{0, 30}, {165, 195}, {195, 315}, {315, 360}},{{0, 45}, {45, 165}, {165, 195}, {330, 360}},{{0, 45}, {45, 135}, {225, 315}, {315, 360}},};private static final int[][] ROTATE_TO_WITH_180 = new int[][] {{ROTATION_90, ROTATION_180, ROTATION_270},{ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},{ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},{ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},};
当前屏幕旋转方向为ROTATION_0时,取int[][] threshold=THRESHOLDS_WITH_180[0];
当前屏幕旋转方向为ROTATION_90时,取int[][] threshold=THRESHOLDS_WITH_180[1];
当前屏幕旋转方向为ROTATION_270时,取int[][] threshold=THRESHOLDS_WITH_180[2];
当前屏幕旋转方向为ROTATION_180时,取int[][] threshold=THRESHOLDS_WITH_180[3];
其中,threshold中的每一个元素由两个值构成,用来表示一个范围。
WindowOrientationListener会注册一个Accelerator类型的SensorEventListener,当有新的SensorEvent产生时,调用filterOrientation产生一个int orientation值。这个值会在threshold的各个元素表示的范围中匹配,看会落在哪个范围。假设当前屏幕方向为ROTATION_0,那么threshold={{60, 165}, {165, 195}, {195, 300}},假设这个时候把屏幕左侧翻起90度。filterOrientation计算出的orientation值落在了第三个元素范围内,那么去ROTATE_TO_WITH_180中寻找与它对应的值,发现是ROTATION_270,那么就把当前屏幕旋转方向改变为270度。threshold的取值就变成了THRESHOLDS_WITH_180[2]。当把屏幕再次放平时,filterOrientation计算出的orientation值会落在第一个元素表示的范围内。去ROTATE_TO_WITH_180中寻找与它对应的值,发现是ROTATION_0,那么当前屏幕旋转方向被改变为0度。
还有一个变量比较重要,mAllow180Rotation,这个变量设置为false时,就不使用THRESHOLDS_WITH_180和ROTATE_TO_WITH_180这一对数组来做上面这些变的了,就使用THRESHOLDS和ROTATE_TO。
其实,我研究了半天也没有搞清filterOrientation的算法以及THRESHOLDS_WITH_180和THRESHOLDS这两个数组里面的每个数字代表的具体意义。最后只搞清了上面的这个流程,还有ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_180这四个角度分别代表哪四个方向。但这足以应付我们要做的事情了。
比如,我想让屏幕最多只旋转90度和180度,不让它有旋转270度的机会。那就把ROTATE_TO_WITH_180里面的ROTATION_270全部变成90度。这样,应该旋转到270度时,就会旋转到90度了。如果不想让屏幕旋转,把所有值都改成ROTATION_0就可以了。
再深入挖掘一下这个话题
参考一下我前面写的这篇文章(/a345017062/article/details/6592527)可以知道,PhonwWindowManager是唯一实现WindowOrientationListener接口的类,它管理着整个设备界面的显示。当PhonwWindowManager通过WindowOrientationListener知道屏幕方向发生旋转时,会告诉WindowManagerService:
mWindowManager.setRotation(rotation, false, mFancyRotationAnimation);
而WindowManagerService得到这个通知后,会做两个比较重要的事情:
1、Surface.setOrientation(0, rotation, animFlags);
2、mRotationWatchers.get(i).onRotationChanged(rotation);
我们知道,每个Activity都有一个View树,每个View树都是绘画在一个Surface上面的。通过上面这两步,先把Surface给旋转了,再告诉Activity重新绘制View树,就完了整个屏幕的旋转。