当前位置: 代码迷 >> Android >> android4.0 frameworks障蔽key、touch等事件,不派发到app的方法
  详细解决方案

android4.0 frameworks障蔽key、touch等事件,不派发到app的方法

热度:71   发布时间:2016-05-01 14:59:53.0
android4.0 frameworks屏蔽key、touch等事件,不派发到app的方法


我们在一开始初始化InputManager.java中的InputManager实例的时候,会有如下得操作:

InputManager.java

InputManager的构造函数中:

//初始化Callbacks函数

this.mCallbacks = new Callbacks();

//然后在调用native方法的时候会将Callbacks函数放在C++中的InputDispatcher线程以便回调

nativeInit(mContext, mCallbacks, looper.getQueue());

private final class Callbacks {

        public long notifyANR(InputApplicationHandle inputApplicationHandle,

                InputWindowHandle inputWindowHandle) {

            return mWindowManagerService.mInputMonitor.notifyANR(

                    inputApplicationHandle, inputWindowHandle);

        }

        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn){

            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(

                    event, policyFlags, isScreenOn);

        }

        public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {

            return mWindowManagerService.mInputMonitor

.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);

        }

        public long interceptKeyBeforeDispatching(InputWindowHandle focus,

                KeyEvent event, int policyFlags) {

            return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(

                    focus, event, policyFlags);

        }

……

}

interceptKeyBeforDispatching函数进行解析这个类:它会调用WindowManagerServiceInputMonitor实例来调用interceptKeyBeforeDispatching的方法:mInputMonitor就是InputMonitor的实例。

InputMonitor.java

public long interceptKeyBeforeDispatching(

InputWindowHandle focus, KeyEvent event, int policyFlags) {

   

WindowState windowState = focus != null ? (WindowState) focus.windowState : null;

        

return mService.mPolicy

.interceptKeyBeforeDispatching(windowState, event, policyFlags);

}

    public int interceptKeyBeforeQueueing(

            KeyEvent event, int policyFlags, boolean isScreenOn) {

        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);

}

    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {

        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);

    }

这些拦截的操作来看,都用到了WindowManagerServicemPolicy这个实例:

WindowManagerService.java

final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();

这里创建了WindowManagerPolicy的实例,那么为什么要用到makeNewWindowManager呢?

我们一步步分析:

PolicyManager.java

    public static WindowManagerPolicy makeNewWindowManager() {

        return sPolicy.makeNewWindowManager();

    }

这个sPolicy是这样定义和初始化的:

    private static final IPolicy sPolicy;

//根据路径/com/android/internal/policy/impl/policy找到这个类,也就是Policy

            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);

//根据这个类来实例化Policy

            sPolicy = (IPolicy)policyClass.newInstance();

再看看Policy.java中类的声明:

public class Policy implements IPolicy

原来如此,是一个远程的类。所以在PolicyManager中可以通过spolicy这个Policy的实例来创建这个

PhoneWindowManager

//Policy.java中创建PhoneWindowManager(继承自WindowManagerPolicy)

    public WindowManagerPolicy makeNewWindowManager() {

        return new PhoneWindowManager();

    }

这个时候我们就理解了:其实不仅仅是HardKey的处理,只要是我们想拦截的一切消息,都可以在PhoneWindowManager中进行处理,不往上面再报了。

那么,这个回调方法何时调用?

InputDispatcher.cpp

    nsecs_t delay = 

mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,

             &event, entry->policyFlags);

    if (delay < 0) {

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;

    } else if (!delay) {

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;

    } else {

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;

        entry->interceptKeyWakeupTime = now() + delay;

    }

    entry->release();

根据上面的代码,我们知道,要是在delay < 0,那么就是不做处理,我们只需要在PhoneWindowManager中对需要在framework中处理的key做出处理,然后返回-1,就可以实现不往上派发了。

这里分析一下如何调用上面方法禁止向app上报一些key event

我们在InputReader中读取到Event之后将Event封装放在一个队列中。调用notify操作,在这里我们唤醒

DispatcherThread这个线程,接着是dispatchOnce,然后是dispatchOnceInnerLocked,最后是dispatchKeyLocked函数,就是这里,我们将需要Intercept的操作进行封装成CommandEntry,调用postCommandLocked放到CommandEntry队列中,dispatchOnce下一步就开始运行这些命令。详见下面的分析:

先看看postCommandLocked函数,

typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);

InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {

//Command封装到CommandEntry结构体中

    CommandEntry* commandEntry = new CommandEntry(command);

//添加到mCommandQueue

    mCommandQueue.enqueueAtTail(commandEntry);

    return commandEntry;

}

总之一句话,这里只是将Command传入到CommandEntry,然后等待后面的调用。我们有一个疑问,这里并没有参数传入到doInterceptKeyBeforeDispatchingLockedInterruptible,它的形参如何传进来的?

void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(

        CommandEntry* commandEntry) {

    KeyEntry* entry = commandEntry->keyEntry;

    KeyEvent event;

    initializeKeyEvent(&event, entry);

    mLock.unlock();

//回调PhoneWindowManager的函数进行相关的处理

    nsecs_t delay = 

mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,

            &event, entry->policyFlags);

    mLock.lock();

/** 

*这里根据PhoneWindowManager中的回调函数处理结构决定interceptKeyResult

*/

    if (delay < 0) {

//skip

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;

    } else if (!delay) {

//continue

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;

    } else {

//delay

        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;

        entry->interceptKeyWakeupTime = now() + delay;

    }

    entry->release();

}

我们来回答如何调用doInterceptKeyBeforeDispatchingLockedInterruptible并传入参数:

我们在dispatchOncedispatchOnceInnerLocked之后都会调用我们前面设置的Intercept操作,然后就会处理mCommandQueue的中函数。然后决定是否drop某些操作.