Android系统开放App程序监听Home键的权限

来源:互联网 发布:男士头发护理 知乎 编辑:程序博客网 时间:2024/05/29 11:22

项目的安全需要:

要求客户APP在申请了特定ENABLE_HOME权限后,允许监听home键并对HOME键的系统功能进行屏蔽;


修改基于RK平台Android 5.1.1系统


经过对系统代码的分析,按照用户按下HOME键的流程整理如下:

系统服务进程中:

1、framework/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java 

函数:interceptKeyBeforeQueueing  本次并未修改,不展开

函数:interceptKeyBeforeDispatching

        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) {//处理HOME键up(放开)的动作;                mHomePressed = false;//这部分是我加入的如果应用截取了home键,直接退出,主要通过加入的标志mHomeIgnoreflag来判断,后面会做介绍                //add by liaozongping @20161111 for HOME key ignore!                if( mHomeIgnoreflag == true ){                    mHomeIgnoreflag = false;                    return 0;                }                    //added end                cancelPreloadRecentApps();                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 InCallUI at this point,                // and his ONLY options are to answer or reject the call.)                TelecomManager telecomManager = getTelecommService();                if (telecomManager != null && telecomManager.isRinging()) {                    Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");                    return -1;                }                    // 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;                }                    //add by liaozongping @20161111 for HOME key ignore!                mHomeIgnoreflag = false;//此处系统处理home键up的实际操作,也就是退回到桌面的动作                handleShortPressOnHome();                return -1;            }    //这下面处理的是HOME键down(按下)的动作,实际的短按系统没有做什么处理动作            //add by liaozongping @20161111 for HOME key ignore!            mHomeIgnoreflag = false;//跟解说一样,这里是判断,如果是锁屏串口,那么就把按键给锁屏的APP或者是不需要操作的类型,就丢弃            // 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_SCRIM                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {                    // 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();//我的流程中,正常是的短按流程会走到这里,原始是return -1,然后系统就不会将HOME按键传递给APP,这里我们需要传递给APP,使得APP使用onKeyDown函数能够捕获到KEYCODE_HOME按键;                    //add by liaozongping @20161111 for HOME key ignore!                    return 0;                }            } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {                if (!keyguardOn) {                    handleLongPressOnHome();                }            }            //add by liaozongping @20161111 for HOME key ignore!            else {//这里只是保险起见,事实应该没什么用                // give app the key                return 0;            }            //added end            return -1;



经过此文件的修改,在APP中正常的onKeyDown中已经能够捕获到KEYCODE_HOME的按键了!但是无论返回true还是false,APP中依然会退回到桌面;

这里注册一个广播接收器,用于获取KEYCODE_HOME按键down的用户处理状态,如果被APP捕获并处理了,就不再执行up的动作(即handleShortPressOnHome();

   //add by liaozongping @20161111 for HOME key ignore!    HomeIgnoreReceiver mHomeIgnoreReceiver;    private boolean mHomeIgnoreflag;    //added end    /*     *  接收home键屏蔽广播    */    class HomeIgnoreReceiver extends BroadcastReceiver{        public void onReceive(Context context, Intent intent) {            Log.d(TAG, "KeyCode_HOME Ignore!!!");            mHomeIgnoreflag = true;        }    }


在    @Override
    public void init(Context context, IWindowManager windowManager,
            WindowManagerFuncs windowManagerFuncs) 

函数中注册相应的广播接收器(也可以另外找合适的地方进行注册):

        //add by liaozongping @20161111 for HOME key ignore!        IntentFilter homeKeyFilter = new IntentFilter();        homeKeyFilter.addAction("keyevent.ignorehome");        mHomeIgnoreReceiver = new HomeIgnoreReceiver();//这里对于抓取home键的广播进行权限限制,只有具备android.permission.XXXXX.XXX权限的应用能够截取HOME键的操作;        context.registerReceiver( mHomeIgnoreReceiver, homeKeyFilter, "android.permission.XXXXX.XXX", null);        //added end


接下,要对APP的onKeyDown处理结果获取并发送广播,经过查找发现framework中最终调用APP的onKeyDown函数的地方是:

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java

        @Override        public boolean dispatchKeyEvent(KeyEvent event) {            final int keyCode = event.getKeyCode();            final int action = event.getAction();            final boolean isDown = action == KeyEvent.ACTION_DOWN;            if (isDown && (event.getRepeatCount() == 0)) {                // First handle chording of panel key: if a panel key is held                // but not released, try to execute a shortcut in it.                if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {                    boolean handled = dispatchKeyShortcutEvent(event);                    if (handled) {                        return true;                    }                    }                    // If a panel is open, perform a shortcut on it without the                // chorded panel key                if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {                    if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {                        return true;                    }                    }                }                if (!isDestroyed()) {                final Callback cb = getCallback();//没有经过其他处理,并没有销毁的窗口,最终会到这里调用callback,调用到APP重写的onKeyDown,此处handled即为onKeyDown的返回值                final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)                        : super.dispatchKeyEvent(event);                LOGD("keycallback handled=" + handled);                if (handled) {//当APP截取到KeyCODE_HOME按键,返回true后,我们需要通知系统按键服务进程,此次操作被APP捕获了,不要再执行退回到桌面的操作//PS:之所以这里需要使用广播,//1、是因为这里是属于用户APP的进程范围,而KEYCODE_HOME的down和up是独立的event,并且前一个文件中的event处理是在系统按键进程中进行处理,所以只能使用广播//2、客户定义了接口要在onKeyDown中进行捕获,那么只能够将down的捕获情况通过广播传递给按键处理进程,让该进程放弃下一次KEYCODE_HOME的up event的处理                    //add by liaozongping @20161111 for HOME key ignore!                    if(event.getKeyCode() == KeyEvent.KEYCODE_HOME && event.getAction() == KeyEvent.ACTION_DOWN ){                        Intent intent = new Intent();                        intent.setAction("keyevent.ignorehome");                        mContext.sendBroadcast(intent);                    }                        //added end                    return true;                }                }                return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)                    : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);        }    



至此,整个的功能已经完成;

最后,在系统中加入刚才使用的自定义的系统权限:

frameworks/base/core/res/AndroidManifest.xml文件中加入:

2926     <!-- add by liaozongping for app to get HOME key event!-->
2927     <permission android:name="android.permission.XXXXX.XXX"
2928         android:protectionLevel="dangerous" />


附参考链接:http://www.cnblogs.com/android-blogs/p/5684622.html


0 0
原创粉丝点击