经典好文推荐,通过阅读本文,您将收获以下知识点:
一、Android 按键修改
二、PhoneWindowManager 简介
三、如何打开 或者 关闭 Navigation Bar
四、如何长按Home 键启动Google Now
五、如何长按实体Menu键进入多窗口模式
六、如何点击 Menu键进入调出最近任务列表
七、如何让 App 拿到Power key 值
八、如何修Activity启动背景窗口
九、WindowManagerPolicy 简介
十、参考文献
在Android 中会有以下5个按键(Back、Home、Menu、Power、Volume)与用户进行交互,Framework层中实现按键功能,因此,从手机系统定制的角度,可以满足客户的客制化要求。本文主要从Framework层浅析这些客制化需求的实现。
Back、Home、Menu、Power、Volume 按键图
以MTK 平台为例,按键客制化的代码主要存放在以下类中
PhoneWindowManager
PhoneWindowManager代码路径如下:
alps\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
alps\frameworks\base\core\java\android\view\WindowManagerPolicy.java
PhoneWindowManager 类实现接口如下:
java.lang.Object
↳ android.view.WindowManagerPolicy.java
↳ com.android.server.policy.PhoneWindowManager.java
PhoneWindowManager 类实现关系
PhoneWindowManager主要用于实现各种实体或虚拟按键处理,如需特殊处理按键,请修改源码。
虚拟导航栏
如何打开 或者 关闭 Navigation Bar 的解决方法如下:
搜索关键字config_showNavigationBar, 查看 config_showNavigationBar 值true 表示显示,false 表示不显示
<!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
autodetected from the Configuration. -->
<bool name="config_showNavigationBar">true</bool>
参考路径如下:alps\frameworks\base\core\res\res\values\config.xml
查询关键字 qemu.hw.mainkeys,并查看值,1表示关闭0.表示开启 。
# temporary enables NAV bar (soft keys)
qemu.hw.mainkeys=1
不同项目文件存放地址不一样,可以使用以下命令查找
终端下查找文件方法
find 路径 -name "文件名.java"
或者直接查找文件中的字符串
find 路径 -type f -name "文件名" | xargs grep "文件中的字符串"如果上面两个修改都不生效(搜索关键字config_showNavigationBar、qemu.hw.mainkeys),请在PhoneWindowManager 查看setInitialDisplaySize方法中mHasNavigationBar 的值是否被写死,true表示会显示、false表示不显示导航栏。
底部导航卡显示代码控制
Google Now APK请自行安装APK
长按Home键启动Google Now,实现方法参考launchAssistLongPressAction 功能实现。
PhoneWindowManager 长按Home 建启动Google Now
自己实现常按Home 键吊起Google Now方法,供在按键分发处理事件时候调用。
自己实现常按Home 键吊起Google Now 方法
在按键分发处理之前调用自定义长按Home键的方法
自定义长按Home 键的方法
在phoneWindowManager.java 的interceptKeyBeforeQueueing 方法中修改
修改方法如下:
双击Home 键调出最近任务列表
Android N上支持Multi-Window,通过recent key进入多窗口,对于没有打开虚拟导航栏,只有实体menu按键的手机,可以考虑向SystemUI发送广播的形式,进入Android 分屏多任务模式。
解决方案如下:
PhoneStatusBar 是SystemUI模块的代码,参考路径如下:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
自定义广播实现可以参考系统mDemoReceiver 的实现方法
动态注册广播方法如下:
自定义广播注册
自定义接收广播后,onReceive处理事件实现分屏方法如下:
自定义接收广播处理
在 PhoneWindowManager的interceptKeyBeforeDispatching方法中发送广播
interceptKeyBeforeDispatching 发送广播
再Destory方法中记得一定要注销广播
mContext.unregisterReceiver(mDemoReceiver);
mContext.unregisterReceiver(mAppLongSwitchReceiver);
如果想调出最近任务列表,需要拦截menu的事件,在PhoneWindowManager的interceptKeyBeforeDispatching 中处理即可
menu 键调出最近任务列表
如果想长按Menu调出可以使用以下方法
长按menu 键调出任务列表
一般情况下App是拿不到Power的Key值,但通过以下方法可以实现。
在PhoneWindowManager 中修改interceptKeyBeforeQueueing方法实现让特定的APP拿到Power key 值
power key 启动App
Power 键启动Activity 的方法
当用户从主菜单进入其他应用程序例如时钟、联系人、文件管理等时,可能会出现屏幕闪一下黑屏、白屏等问题,这种现象在当前手机主题(Theme)是浅色(例如白色)的情况下比较明显。
此所谓的闪"黑屏",其实是应用程序的启动窗口。
启动窗口出现的条件如下:
仅在要启动的Activity在新的Task或者新的Process时,才可能显示启动窗口
启动窗口先于Activity窗口显示,当Activity窗口的内容准备好之后,启动窗口就会被移除掉,show出真正的activity 窗口
启动窗口和普通的Activity window类似,只是没有画任何内容,默认是一个黑色背景的窗口
正是由于启动窗口默认是黑色背景的,所以在当前的手机主题为浅色调的时候,就比较容易因为颜色的深浅对比而产生一种视觉上的闪动感。
解决方法如下:
在 ActivityStack.java中将SHOW_APP_STARTING_PREVIEW设置为false既可
在 PhoneWindowManager中的addStartingWindow方法中添加自定义样式或者背景等
修改启动窗口样式
PhoneWindowManager 实现 的接口类如下:
alps\frameworks\base\core\java\android\view\WindowManagerPolicy.java
WindowManagerPolicy 接口实现
WindowManagerPolicy 是一个接口类,主要对外提供一些接口。
常用接口如下:
WindowState 接口
WindowMangerFuncs接口
Screen On 接口
Keyguard 接口