我们在一开始初始化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函数进行解析这个类:它会调用WindowManagerService的InputMonitor实例来调用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);
}
这些拦截的操作来看,都用到了WindowManagerService的mPolicy这个实例:
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并传入参数:
我们在dispatchOnce的dispatchOnceInnerLocked之后都会调用我们前面设置的Intercept操作,然后就会处理mCommandQueue的中函数。然后决定是否drop某些操作.