Android4.3 屏蔽HOME按键返回桌面详解(源码环境下)
首先声明我是做系统开发的(高通平台),所以下面介绍的方法并不适合应用开发者。
最经有个需求要屏蔽HOME按键返回桌面并且实现自己的功能,发现以前的方式报错用不了,上网搜索了一下,发现都是抄来抄去基本是无用的。网上的方法不外乎这几种:
第一, 大家最常用的重写onAttachedToWindow()方法,然后在HOME点击事件KeyEvent.KEYCODE_HOME中做自己想做的事情,但是这个方法google处于安全考虑在android2.3.3之后就不支持了。
第二, 抓取系统log日志,判断有没有打印“Android.intent.category.HOME”信息来获得是否按下了HOME按键, 这样做就算代码知道是按下HOME键,那怎么阻止返回桌面呢? 这只能是截获HOME按键,并不能屏蔽它返回桌面的功能。
第三, 修改framework源码,在PhoneWindowManager中处理HOME按键的地方发送一个消息,然后在上层应用中捕获这个消息,这和上面是一样的,只能截获HOME按键,并不能阻止返回桌面的动作。
第四, 在setContentView之前getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED, FLAG_HOMEKEY_DISPATCHED); 这个FLAG_HOMEKEY_DISPATCHED其实是个标志位,是个常量,值为0x80000000, 这个方法确实可以,但仅限于MTK(联发科)平台的系统,因为MTK自己实现了一套机制来规避HOME按键,而其它的平台,如高通、博通、展迅的代码中是没有加这个属性的,所以也不行。
还有极少数思路很极端的方式,看上去都觉得很繁琐,根本没耐心细看。
现在介绍我的思路,首先还是复写onAttachedToWindow()方法,具体代码是在activity中加入这一段:
@Override
public void onAttachedToWindow() {
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
super.onAttachedToWindow();
}
结果当然是一进入这个activity就报错,logcat查看错误信息,报的错误是"Window type can not be changed after the window is added.",发现是WindowManagerService.java中报的错,源码位置frameworks/base/services/java/com/android/server/wm/WindowManagerService.java,具体代码段是relayoutWindow方法中判断窗口类型的时候报错:
if (attrs != null) {
if (win.mAttrs.type != attrs.type) {
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
flagChanges = win.mAttrs.flags ^= attrs.flags;
attrChanges = win.mAttrs.copyFrom(attrs);
if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
| WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
win.mLayoutNeeded = true;
}
}
刚才说了,google可能是出于安全原因不能让你把窗口类型设为WindowManager.LayoutParams.TYPE_KEYGUARD了, 设置了就报错,要屏蔽这个错误只需要把if (win.mAttrs.type != attrs.type) {
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
注释掉就行了,再次运行就不会报错了,但是按HOME键还是返回桌面。继续看分发HOME按键事件的代码,源码位置frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java中的if (keyCode == KeyEvent.KEYCODE_HOME) {...}中,这里就是处理上层用户按下HOME键的代码,在里面会看到// If a system window has focus, then it doesn't make sense
// right now to interact with applications.
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
// the "app" is keyguard, so give it the key
return 0;
}
final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
for (int i=0; i<typeCount; i++) {
if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
// don't do anything, but also don't pass it to the app
return -1;
}
}
}
这一段代码,意思就是如果设置了窗口类型为 WindowManager.LayoutParams.TYPE_KEYGUARD(值为2004) 或者WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,那就return 0,交给用户自己处理,不返回桌面,否则返回-1,返回桌面。通过打log发现代码确实是return 0,但还是返回桌面,后来才发现还有方法在返回桌面:/**
* A home key -> launch home action was detected. Take the appropriate action
* given the situation with the keyguard.
*/
void launchHomeFromHotKey() {
if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
// don't launch home if keyguard showing
} else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
// before launching home
mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
public void onKeyguardExitResult(boolean success) {
if (success) {
try {
ActivityManagerNative.getDefault().stopAppSwitches();
} catch (RemoteException e) {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
startDockOrHome();
}
}
});
} else {
// no keyguard stuff to worry about, just launch home!
try {
ActivityManagerNative.getDefault().stopAppSwitches();
} catch (RemoteException e) {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
startDockOrHome();
}
}
不知道高通怎么改的,就算return 0也会执行这个方法,也会返回桌面,因为这个方法在判断窗口类型前面调用,现在要做的就简单了,只需要加个判断,就可以屏蔽返回HOME了:
boolean isGoHome = true;
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
isGoHome = false;
}
}
// Go home!
if (isGoHome) {
launchHomeFromHotKey();
}
整个HOME按键的代码段:
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
if (!down) {
cancelPreloadRecentApps();
mHomePressed = false;
if (mHomeConsumed) {
mHomeConsumed = false;
return -1;
}
if (canceled) {
Log.i(TAG, "Ignoring HOME; event canceled.");
return -1;
}
// If an incoming call is ringing, HOME is totally disabled.
// (The user is already on the InCallScreen at this point,
// and his ONLY options are to answer or reject the call.)
try {
ITelephony telephonyService = getTelephonyService();
if (telephonyService != null && telephonyService.isRinging()) {
Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
return -1;
}
} catch (RemoteException ex) {
Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
}
// Delay handling home if a double-tap is possible.
if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
mHomeDoubleTapPending = true;
mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
ViewConfiguration.getDoubleTapTimeout());
return -1;
}
boolean isGoHome = true;
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
isGoHome = false;
}
}
// Go home!
if (isGoHome) {
launchHomeFromHotKey();
}
return -1;
}
// If a system window has focus, then it doesn't make sense
// right now to interact with applications.
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
// the "app" is keyguard, so give it the key
return 0;
}
final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
for (int i=0; i<typeCount; i++) {
if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
// don't do anything, but also don't pass it to the app
return -1;
}
}
}
// Remember that home is pressed and handle special actions.
if (repeatCount == 0) {
mHomePressed = true;
if (mHomeDoubleTapPending) {
mHomeDoubleTapPending = false;
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
handleDoubleTapOnHome();
} else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI
|| mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
preloadRecentApps();
}
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
if (!keyguardOn) {
handleLongPressOnHome();
}
}
return -1;
}
至此就可以屏蔽HOME按键了,在需在上层应用中复写onAttachedToWindow()方法即可,然后
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_HOME:
// 想实现的功能
break;
}
return true;
}
至此分析完毕,如果要屏蔽HOME键返回桌面不修改源码是不行的,至少上面介绍的那些方法是不行的(MTK除外),所以有这个需求的童鞋找方法的时候就不要浪费时间去看那些抄来抄去的帖子了。
Android4.3 屏蔽HOME按键返回桌面详解(源码环境下)的更多相关文章
- ArrayList详解-源码分析
ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ...
- LinkedList详解-源码分析
LinkedList详解-源码分析 LinkedList是List接口的第二个具体的实现类,第一个是ArrayList,前面一篇文章已经总结过了,下面我们来结合源码,学习LinkedList. 基于双 ...
- Java开源生鲜电商平台-盈利模式详解(源码可下载)
Java开源生鲜电商平台-盈利模式详解(源码可下载) 该平台提供一个联合买家与卖家的一个平台.(类似淘宝购物,这里指的是食材的购买.) 平台有以下的盈利模式:(类似的平台有美菜网,食材网等) 1. 订 ...
- Shiro的Filter机制详解---源码分析
Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...
- Shiro的Filter机制详解---源码分析(转)
Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...
- Python-Flask框架之——图书管理系统 , 附详解源码和效果图 !
该图书管理系统要实现的功能: 1. 可以通过添加窗口添加书籍或作者, 如果要添加的作者和书籍已存在于书架上, 则给出相应的提示. 2. 如果要添加的作者存在, 而要添加的书籍书架上没有, 则将该书籍添 ...
- udhcp详解源码(序)
最近负责接入模块,包括dhcp.ipoe和pppoe等等.所以需要对dhcp和ppp这几个app的源代码进行一些分析.网上有比较好的文章,参考并补充自己的分析. 这篇udhcp详解是基于busybox ...
- RecyclerView实现瀑布流效果(图文详解+源码奉送)
最近有时间研究了一下RecyclerView,果然功能强大啊,能实现的效果还是比较多的,那么今天给大家介绍一个用RecyclerView实现的瀑布流效果. 先来一张效果图: 看看怎么实现吧: 整体工程 ...
- Java和Ibatis调用存储过程并取得返回值详解
Java和Ibatis调用存储过程并取得返回值详解 2011-07-19 17:33 jiandanfeng2 CSDN博客 字号:T | T 本文主要介绍了Java和Ibatis调用存储过程的方法, ...
随机推荐
- servlet之cookie实现
三个servlet的实现: package app02c;import java.io.IOException;import java.io.PrintWriter;import javax.serv ...
- [HNOI2009]无归岛
Description Neverland是个神奇的地方,它由一些岛屿环形排列组成,每个岛上都生活着之中与众不同的物种.但是这些物种都有一个共同的生活习性:对于同一个岛上的任意两个生物,他们有且仅有一 ...
- 计蒜客NOIP2017提高组模拟赛(三)day2-直线的交点
传送门 简单几何+逆序对 发现当两条直线甲乙与平板的交点在上面甲在较左的位置,那么下面甲在较右的位置就可以相交 然后把上面的位置排下序,下面离散化+树状数组即可 #include<cstdio& ...
- hdu3966 点权模板-树链部分
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- bzoj1934
1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 2406 Solved: 1498[Submit][ ...
- 文本分类学习 (五) 机器学习SVM的前奏-特征提取(卡方检验续集)
前言: 上一篇比较详细的介绍了卡方检验和卡方分布.这篇我们就实际操刀,找到一些训练集,正所谓纸上得来终觉浅,绝知此事要躬行.然而我在躬行的时候,发现了卡方检验对于文本分类来说应该把公式再变形一般,那样 ...
- 修改表单元素中placeholder属性样式、清除IE浏览器中input元素的清除图标和眼睛图标
一.修改input元素placeholder属性样式 在做项目的时候,一般表单元素的placeholder属性样式都是使用浏览器默认的,但有时候为了追求设计上的美感需要修表单元素的placeholde ...
- Python中的条件和循环语句
条件和循环语句 1. 条件语句 if单用 格式:if 条件表达式 例如:if 5 > 3: print('True') >>> 'True' #当条件满足时才会执行上述操作. ...
- 指尖大冒险H5小游戏
前些天看了一篇很赞的文章,又因为想学习phaser,所以有了这个案例,在线预览可以点下方链接. 本案例中,核心原理是按文章中所提到的内容制作,整体遵循"大道至简"的原则开发,其实是 ...
- npm ERR! Windows_NT 10.0.10586
安装vue脚手架时候一直失败,如图: npm cache clean 管理员下安装: 快捷键 win +x , 按A进入: