1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Android 手机按键客制化详解

Android 手机按键客制化详解

时间:2019-05-14 10:40:16

相关推荐

Android 手机按键客制化详解

在Android 中会有以下5个按键(Back、Home、Menu、Power、Volume)与用户进行交互,Framework 层中实现按键功能,因此,从手机系统定制的角度,可以满足客户的客制化要求。本文主要从Framework层浅析这些客制化需求的实现。

Back、Home、Menu、Power、Volume 按键图

Android 按键修改相关的类PhoneWindowManager 简介如何打开 或者 关闭 Navigation Bar如何长按Home 键启动Google Now如何长按实体Menu键进入多窗口模式如何点击 Menu键进入调出最近任务列表如何让App拿到Power key 值如何修Activity启动是的窗口(app启动白屏,黑屏问题)WindowManagerPolicy 简介

欢迎关注微信公众号:程序员Android

公众号ID:ProgramAndroid

获取更多信息

微信公众号:ProgramAndroid

我们不是牛逼的程序员,我们只是程序开发中的垫脚石。

我们不发送红包,我们只是红包的搬运工。

1. Android 按键修改相关的类

以MTK 平台为例,按键客制化的代码主要存放在以下类中

PhoneWindowManager

PhoneWindowManager 代码路径如下:

\alps\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

WindowManagerPolicy

PhoneWindowManager 实现 的接口类WindowManagerPolicy 代码路径如下:

alps\frameworks\base\core\java\android\view\WindowManagerPolicy.java

2. PhoneWindowManager 简介

PhoneWindowManager 类实现接口如下:

java.lang.Object↳ android.view.WindowManagerPolicy.java↳ com.android.server.policy.PhoneWindowManager.java

PhoneWindowManager 类实现关系

PhoneWindowManager主要用于实现各种实体或虚拟按键处理,如需特殊处理按键,请修改源码。

3. 如何打开 或者 关闭 Navigation Bar

虚拟导航栏

解决方法:

修改config.xml 文件中

搜索关键字 config_showNavigationBar , 查看 config_showNavigationBar 值

true 表示显示,false 表示不显示

<!-- Whether a software navigation bar should be shown. NOTE: in the future this may beautodetected from the Configuration. --><bool name="config_showNavigationBar">true</bool>

参考路径如下:

alps\frameworks\base\core\res\res\values\config.xml

修改 system.prop 文件

查询关键字 qemu.hw.mainkeys ,并查看值,0 表示关闭 1.表示开启 。

# temporary enables NAV bar (soft keys)qemu.hw.mainkeys=1

不同项目文件存放地址不一样,可以使用以下命令查找

终端下查找文件方法

find 路径 -name "文件名.java"

或者直接查找文件中的字符串

find 路径 -type f -name "文件名" | xargs grep "文件中的字符串"

修改PhoneWindowManager代码

如果上面两个修改都不生效(搜索关键字config_showNavigationBar、qemu.hw.mainkeys),请在PhoneWindowManager 查看setInitialDisplaySize方法中mHasNavigationBar 的值是否被写死,true表示会显示、false 表示不显示导航栏。

@Overridepublic void setInitialDisplaySize(Display display, int width, int height, int density) {...// mHasNavigationBar 值控制是否显示虚拟导航栏mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);...}

4. 如何长按Home 键启动Google Now

预制 Google Now APK

请自行安装APK

修改 PhoneWindowManager 代码

长按Home键启动Google Now ,实现方法参考launchAssistLongPressAction 功能实现。

private void launchAssistAction(String hint, int deviceId) {sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);if (!isUserSetupComplete()) {// Disable opening assist window during setupreturn;}Bundle args = null;if (deviceId > Integer.MIN_VALUE) {args = new Bundle();args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId);}if ((mContext.getResources().getConfiguration().uiMode& Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {// On TV, use legacy handling until assistants are implemented in the proper way.((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)).launchLegacyAssist(hint, UserHandle.myUserId(), args);} else {if (hint != null) {if (args == null) {args = new Bundle();}args.putBoolean(hint, true);}StatusBarManagerInternal statusbar = getStatusBarManagerInternal();if (statusbar != null) {statusbar.startAssist(args);}}}

自己实现常按Home 键吊起Google Now 方法,供在按键分发处理事件时候调用。

private void launchAssistLongPressAction() {performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);// launch the search activityIntent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);try {// TODO: This only stops the factory-installed search manager.// Need to formalize an API to handle othersSearchManager searchManager = getSearchManager();if (searchManager != null) {searchManager.stopSearch();}startActivityAsUser(intent, UserHandle.CURRENT);} catch (ActivityNotFoundException e) {Slog.w(TAG, "No activity to handle assist long press action.", e);}}private SearchManager getSearchManager() {if (mSearchManager == null) {mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);}return mSearchManager;}private void startActivityAsUser(Intent intent, UserHandle handle) {if (isUserSetupComplete()) {mContext.startActivityAsUser(intent, handle);} else {Slog.i(TAG, "Not starting activity because user setup is in progress: " + intent);}}

在按键事件分发之前处理

在按键分发处理之前调用自定义长按Home 键的方法

@Overridepublic long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {...} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {if (down) {if (repeatCount == 0) {mAssistKeyLongPressed = false;} else if (repeatCount == 1) {mAssistKeyLongPressed = true;if (!keyguardOn) {launchAssistLongPressAction();}}...}

注意 双击Home 键调出最近任务列表请用以下方法

双击Home 键调出最近任务列表

在 phoneWindowManager.java 的 interceptKeyBeforeQueueing 方法中修改

修改方法如下:

int result = 0; // 原为 int result, 请加入初始值.// 请在类中补充 boolean homeDownDoubleClick = false; 的定义// 请在类中补充 long lastHomeDownTime=0; 的定义// 请在类中补充 long lastHomeUpTime=0; 的定义// 检测原理: 检测上一次按下的 home key 与本次按下的 home key 时间间隔是否 < 500ms// if yes, 则认为是双击 home keyif (keyCode == KeyEvent.KEYCODE_HOME) {if (down) {// this is home downif (((event.getEventTime() - lastHomeDownTime) < 500)) {homeDownDoubleClick = true;} else {homeDownDoubleClick = false;}lastHomeDownTime = event.getEventTime();} else {// then home up comesLog.d(TAG, "homeDownDoubleClick=" + homeDownDoubleClick+ ",lastHomeDownTime=" + lastHomeDownTime+ ",lastHomeUpTime=" + lastHomeUpTime+ ",this home up=" + event.getEventTime());if (homeDownDoubleClick&& ((event.getEventTime() - lastHomeUpTime) < 500)) {Log.d(TAG, "double click on home detected");try {IStatusBarService statusbar = getStatusBarService();if (statusbar != null) {// 调出最近任务列表statusbar.preloadRecentApps();statusbar.toggleRecentApps();}} catch (RemoteException e) {Slog.e(TAG,"RemoteException when preloading recent apps",e);mStatusBarService = null;}result |= ACTION_WAKE_UP;return result;}lastHomeUpTime = event.getEventTime();}}

5. 如何长按实体Menu键进入多窗口模式

Android N上支持Multi-Window,通过recent key 进入多窗口,对于没有打开虚拟导航栏,只有实体menu按键的手机,可以考虑向SystemUI发送广播的形式,进入Android 分屏多任务模式。

解决方案如下:

PhoneStatusBar 里注册广播

PhoneStatusBar 是SystemUI模块的代码,参考路径如下:

alps/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

自定义广播实现可以参考系统mDemoReceiver 的实现方法

动态注册广播方法如下:

context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,android.Manifest.permission.DUMP, null);context.registerReceiverAsUser(mAppLongSwitchReceiver, UserHandle.ALL, new IntentFilter("广播的Action"),android.Manifest.permission.DUMP, null);

自定义接收广播后,onReceive处理事件实现分屏方法如下:

private BroadcastReceiver mAppLongSwitchReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {if (DEBUG) Log.v(TAG, "onReceive: " + intent);toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);}};

PhoneWindowManager 中发送广播

在 PhoneWindowManager 的interceptKeyBeforeDispatching方法中发送广播

@Overridepublic long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {...if (!keyguardOn) {if (down && repeatCount == 1){Intent intent = new Intent("com.app_long_switch");mContext.sendBroadcast(intent);return -1;}if (down && repeatCount == 0) {preloadRecentApps();} else if (!down) {toggleRecentApps();}}...}

destory 方法注销广播

再destory 方法中记得一定要注销广播

mContext.unregisterReceiver(mDemoReceiver);mContext.unregisterReceiver(mAppLongSwitchReceiver);

6. 如何点击 Menu键进入调出最近任务列表

如果想调出最近任务列表,需要拦截menu的事件,在PhoneWindowManager的interceptKeyBeforeDispatching 中处理即可

else if (keyCode == KeyEvent.KEYCODE_MENU) {// Hijack modified menu keys for debugging featuresfinal int chordBug = KeyEvent.META_SHIFT_ON;this.toggleRecentApps();return -1;

如果想长按Menu 调出可以使用以下方法

else if (keyCode == KeyEvent.KEYCODE_MENU) {// Hijack modified menu keys for debugging featuresfinal int chordBug = KeyEvent.META_SHIFT_ON;if(KeyEvent.ACTION_UP == event.getAction()&&event.getEventTime()-event.getDownTime()>500){//long pressthis.toggleRecentApps();return -1;}

7. 如何让 App 拿到Power key 值

一般情况下App 是拿不到Power的Key值,但通过以下方法可以实现。

修改PhoneWindowManager 文件实现

在PhoneWindowManager 中修改interceptKeyBeforeQueueing 方法实现让特定的APP拿到Power key 值

/** {@inheritDoc} */@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {...case KeyEvent.KEYCODE_POWER: {//com.example.adc为要处理power key的包名if(win != null && win.getAttrs() !=null&&win.getOwningPackage().equals("com.example.adc")){return 1;// return 1事件就传给app处理}}... }

如果只想让某个app的某个Activity 处理

/** {@inheritDoc} */@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {...case KeyEvent.KEYCODE_POWER: {// 如果只想让power键让某个Activity处理,将以上的if条件改为:if(win != null && win.getAttrs() != null&&win.getAttrs().getTitle().equals("xxx.xxx.xxx.xxxActivity")){return 1;// return 1 就会传给 xxx.xxx.xxx.xxxActivity处理}}... }

8. 如何修Activity启动是的窗口(app启动白屏,黑屏问题)

当用户从主菜单进入其他应用程序例如时钟、联系人、文件管理等时,可能会出现屏幕闪一下黑屏、白屏等问题,这种现象在当前手机主题(Theme)是浅色(例如白色)的情况下比较明显。

此所谓的闪"黑屏",其实是应用程序的启动窗口。

启动窗口出现的条件如下:

仅在要启动的Activity在新的Task或者新的Process时,才可能显示启动窗口

启动窗口先于Activity窗口显示,当Activity窗口的内容准备好之后,启动窗口就会被移除掉,show出真正的activity 窗口

启动窗口和普通的Activity window类似,只是没有画任何内容,默认是一个黑色背景的窗口

正是由于启动窗口默认是黑色背景的,所以在当前的手机主题为浅色调的时候,就比较容易因为颜色的深浅对比而产生一种视觉上的闪动感。

解决方法如下:

1.去掉启动窗口

在 ActivityStack.java中将SHOW_APP_STARTING_PREVIEW 设置为false 既可

修改启动窗口样式

在 PhoneWindowManager中的addStartingWindow 方法中添加自定义样式或者背景等

/** {@inheritDoc} */@Overridepublic View addStartingWindow(IBinder appToken, String packageName, int theme,CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,int icon, int logo, int windowFlags, Configuration overrideConfig) {...//添加自定义背景View.setBackgroundColor(...); ...}

9. WindowManagerPolicy 简介

PhoneWindowManager 实现 的接口类如下:

alps\frameworks\base\core\java\android\view\WindowManagerPolicy.java

WindowManagerPolicy 接口实现

WindowManagerPolicy 是一个接口类,主要对外提供一些接口。

常用接口如下:

WindowState 接口

WindowMangerFuncs接口

Screen On 接口

Keyguard 接口

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

如有侵权,请联系小编,小编对此深感抱歉,届时小编会删除文章,立即停止侵权行为,请您多多包涵。

既然都看到这里,领两个红包在走吧!

以下两个红包每天都可以领取

1.支付宝搜索522398497,或扫码支付宝红包海报。

支付宝扫一扫,每天领取大红包

2.微信红包,微信扫一扫即可领取红包

微信扫一扫,每天领取微信红包

小礼物走一走,来简书关注我

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。