Android强制系统横屏的原理和实现
一、Android屏幕相关的知识
Android横竖屏设置
Android设置横竖屏的入口多种多样,如下:
1、Activity窗口:应用Mainfest中配置screenOrientation参数、Activity中调用setRequestedOrientation(),这是通过设置Activity的screenOrientation属性
2、系统栏屏幕自动旋转:使用systemui包中的RotationLockTile类的handleClick()方法设置的
3、非Activity窗口:指定WindowManager.LayoutParams.screenOrientation属性
注:屏幕旋转会触发onConfigurationChanged(),如果Activity不设置忽略屏幕方向改变,Activity生命周期会重走,可以按项目需求做相应操作
虽然设置的入口多种多样,中间经过流程也各不相同,但最终的都是调用了PhoneWindowManager的rotationForOrientationLw(int orientation, int lastRotation)的方法(到这一步,已经是最终的切换了,前面还有一些步骤),具体源码就不在贴出,其实大家可以想到,如果修改framework源码,在这里就可实现强制横屏了
Android的屏幕绘制简介
关于android绘制原理比较复杂,特别是具体到View层面,大致就是通过ViewRootImpl与WMS通信(Bind通信),完成performTraversals -> performMeasure() -> performLayout() -> performDraw()流程,最终通过canvs在surface上绘制,生成FrameBuffer去显示,具体细节与本文主题关系不大,暂不深入。时序图如下:
这里我们主要说下view、window、surface、surfaceFlinger的关系:
View:android 视图组成的基本控件
Window:屏幕上的某块显示区域,用来承载 View(PhoneWinow就是window的实现类),主要用来提供添加,移除,渲染的能力(继承ViewManager),事件响应,如Toast,状态栏,Activity界面,Dialog,包括锁屏界面(这个有点特殊),window是Z-order的,即window在Z轴是有层级关系的
Surface:对应一块屏幕缓冲区,每个 window 对应一个 Surface
SurfaceFlinger:管理surface,Android 的一个服务进程,负责管理 Surface
WindowManagerService(WMS):Android 框架层的一个服务进程,用来管理 Window
下面三张图可以帮助大家了解下:
Window的层级
通过上面知识,大家了解到window是有层级的,在系统中,WindowManager中使用WindowManager.LayoutParams的type字段来存储window的层级,由于window本身存在父子关系,具体层级关系如下:
窗口层级(type) |
层级值 |
Application windows(应用窗口) |
1~99 |
Sub-windows(子窗口) |
1000~1999 |
System windows(系统窗口) |
2000~2999 |
注意:从表面上看系统窗口 > 子窗口 > 应用窗口,从数值上来说是正确的,但是如果说 Window Layer的层级关系(大部分情况都是按照层级关系),这个说法就是错误的,举个很简单的例子,壁纸层 属于系统窗口管理,但是Window Layer的层级关系 却是最底端;WindowType 的值划分是为了更好的管理Window的类别、权限、依赖关系,和实际的Window Layer层级并没有关系。
从层级到Z-order(android定义的z轴界面层级,有1-33,33级)android有一套对应关系,具体在WindowManagerPolicy的getWindowLayerFromTypeLw()方法中,源码就不贴出了,部分对应和z轴定义如下截图
最终在Framework中计算方式:Layer = Z-Order * 10000 + 1000,即SurfaceFlinger中的混合顺序,我们可以通过adb shell dumpsys SurfaceFlinger来看下层级,下面截图是我在强制横屏demo下场景下截的图(如果window没有长宽,是不会在SurfaceFlinger中显示)
横竖屏设置选项
这里我们介绍下横竖屏的设置选项。默认是unspecified,即由系统决定
注意:虽然Android只提供了几种旋转角度,但其实framework可以设置任意角度
二、强制横屏实现
通过前面知识介绍,我们知道了几种设置横竖屏的方法,这里使用添加高layer的window并设置横竖屏
申请在其他应用上层显示权限
1.判断权限
2.申请权限
添加window并进行横竖屏设置
由于window本身并不是一个真正view,仅仅是个载体,我们需要添加一个长宽均0的view,代码如下:
1.创建布局
2.添加window
这里有个小技巧,我们使用service去实现,并且stopself(),这样状态栏不会有notification。
可能大家会疑惑,为什么我只是使用WindowManger.addview(),并没有创建新的window,其实使用WindowManager 的addview方法,系统会自动创建一个window,可以通过 Android Studio的layout inspector工具查看页面
三、原理介绍
屏幕方向的确定的过程
从上到下遍历窗口堆栈,在可见的窗口中确定一个基准screenOrientation
1、非Activity窗口的screenOrientation如果不是(SCREEN_ORIENTATION_UNSPECIFIED、SCREEN_ORIENTATION_BEHIND)两个值,则结束遍历
2、一旦遍历到一个Activity窗口,接下来仅在Activity窗口中遍历,不再关心非Activity窗口总结来讲就是根据窗口的优先级高低来确定屏幕旋转方向,这也是我们方案的基本原理
转屏的准备
大家可能考虑到,系统检测到要改变屏幕方向,接下来屏幕上能看到的所有窗口都要以新的尺寸来重新绘制,由于各个窗口的重绘不可能在同一时刻完成,也不可能同时刷新,如果我们什么都不做,在屏幕上将会看到各种闪烁。这个应该怎么办?
系统解决方案:
1、截屏保存屏幕状态 (WindowManagerService.screenRotationAnimation())
2、用第一步的截屏生成一个非常高层级的,完全不透明的Layer,让用户在视觉上一直停留在竖屏状态,由于是完全不透明,所以在它下方的所有内容完全不可见,那么就尽情地绘制吧(WindowManagerService .updateRotationUncheckedLocked())
3、方向改变前哪些窗口可见,就必须等待那些窗口绘制完成,这个很好理解
4、截屏Layer为整体,施加旋转并淡出的动画,重绘的所有横屏界面为另一个整体,也施加一个旋转动画,这样当动画结束时看到的就是重绘后的横屏界面。还有一点需要注意,转屏过程中系统会禁用所有其它动画,避免动画的叠加。
(WMS.startAnimation()->
WMS.performSurfacePlacementInner->
WindowAnimator.animateLocked()->
WindowStateAnimator.computeShownFrameLocked())
过程演示图如下:
Android强制系统横屏的原理和实现相关推荐
- Android 强制设置横屏或竖屏 设置全屏
Android 强制设置横屏或竖屏 设置全屏 全屏 在Activity的onCreate方法中的setContentView(myview)调用之前添加下面代码 requestWindowFeatur ...
- android 屏幕录制方案,ShareREC for Android全系统录屏原理解析
本文是Mob开发者平台技术副总监余勋杰基于MediaProjection实现Android全系统录屏功能的原理解析,包括了结合MediaRecorder和MediaCodec两套方案. 文 / 余勋杰 ...
- android设置系统横屏方案
效果如下: 实现方案: 1.ChangeOrientationService.java /*** @描述 强制旋转屏幕服务* @作者 tll* @时间 2018/1/5*/public class C ...
- Android强制设置横屏或竖屏
全屏 在Activity的onCreate方法中的setContentView(myview)调用之前添加下面代码 requestWindowFeature(Window.FEATURE_NO_TIT ...
- android 强制设置横屏 判断是横屏还是竖屏
判断activity 是横屏还是竖屏 方法 1: //根据设备配置信息 Configuration cf= this.getResources().getConfiguration(); //获取设 ...
- Android 强制设置横屏或竖屏
在AndroidManifest.xml的activity节点中设置 横屏: 更改为 android:screenOrientation="landscape" 竖屏:更改为 an ...
- Android 系统(57)---深入理解Android输入系统
<深入理解Android 卷III>第五章 深入理解Android输入系统 <深入理解Android 卷III>即将发布,作者是张大伟.此书填补了深入理解Android Fra ...
- 深入Android系统(十二)Android图形显示系统-2-SurfaceFlinger与图像输出
最近有些忙,切实体验了一把拖更的羞耻感 ( *︾▽︾) 本文和上一篇深入Android系统(十二)Android图形显示系统-1-显示原理与Surface关系比较密切,撸完前篇更易理解本文啦 (๑‾ ...
- Android Q 强制黑暗模式(ForceDark) | 原理 实践
搜狐技术产品(sohu-tech) | 来源 Hi,大家好,这里是承香墨影! Android Q 版本增加了 ForceDark 功能,可以快速实现应用的黑暗模式.本文主要讲述了 Android Q ...
- android 版本更新原理,Android系统Recovery工作原理之使用update.zip升级过程分析(二)...
Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的解决 在上一篇末尾提到的生成差分包时出现的问题,现已解决,由于最近比较忙,相 ...
最新文章
- 3种常见的linux版本,查看linux版本的三种常用方法
- PHP+MySql获取自动增长字段的新添加记录ID值
- git rebase教程
- linux小白-基础命令-ls
- 现代c++之列表初始化/统一初始化
- 在Eclipse中有效使用JUnit
- Eigen(1)配置VS2015
- 一步步学习SPD2010--第九章节--使用可重用工作流和工作流表单(1)--创建和使用可重用工作流...
- 特斯拉开始发布其汽车的开源Linux软件代码
- iOS 蓝牙扫描枪功能
- 【三角】和差角公式的证明与积化和差和差化积公式的推导
- 构建新型现代化智慧博物馆之物联网环境监控方案
- 5G 技术特性、频段、架构、部署极5G 手机
- KP700 comfort 精致面板与西门子1200CPU进行时钟同步
- 多元回归分析(multiple regression)及其应用
- Esp8266进阶之路14 esp8266的 FreeRtos系统学习的正确姿势,环境配置环境、烧录。(附带demo)
- Mysql数据库SaaS多租户实现方案
- 工作中常用的Linux命令(持续更新)
- linux查看gc日志,将GC日志输出到文件
- 学Python基础面向对象看这一篇文章就够了【全网首推】