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

项目的安全需要:

要求客户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



经过此文件的修改,在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    
2927     2928         android:protectionLevel="dangerous" />


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


你可能感兴趣的:(android平台开发)