Android之Input子系统事件分发流程
Android创建窗口机制,请看如下转载:
http://blog.csdn.net/sfdev/article/details/9130527
一、Android4.2系统服务侧――与View关系
1.服务端channel注册过程
frameworks/base/core/java/android/view/ViewRootImpl.java
[cpp] view plaincopy
publicvoidsetView(Viewview,WindowManager.LayoutParamsattrs,ViewpanelParentView){
mInputChannel=newInputChannel();//创建InputChannel
res=mWindowSession.addToDisplay(mWindow,mSeq,mWindowAttributes,
getHostVisibility(),mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,mInputChannel);//创建与上述InputChannel对应的通道至服务端
/*
mWindowSession=WindowManagerGlobal.getWindowSession(context.getMainLooper());
frameworks/base/core/java/android/view/WindowManagerGlobal.java
publicstaticIWindowSessiongetWindowSession(LoopermainLooper){
IWindowManagerwindowManager=getWindowManagerService();
sWindowSession=windowManager.openSession(
imm.getClient(),imm.getInputContext());
returnsWindowSession;
}
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
publicIWindowSessionopenSession(IInputMethodClientclient,
IInputContextinputContext){
if(client==null)thrownewIllegalArgumentException("nullclient");
if(inputContext==null)thrownewIllegalArgumentException("nullinputContext");
Sessionsession=newSession(this,client,inputContext);
returnsession;
}
*/
mInputEventReceiver=newWindowInputEventReceiver(mInputChannel,
Looper.myLooper());//将本通道注册进InputEventReceiver
}
frameworks/base/services/java/com/android/server/wm/Session.java
[cpp] view plaincopy
publicintaddToDisplay(IWindowwindow,intseq,WindowManager.LayoutParamsattrs,
intviewVisibility,intdisplayId,RectoutContentInsets,
InputChanneloutInputChannel){
returnmService.addWindow(this,window,seq,attrs,viewVisibility,displayId,
outContentInsets,outInputChannel);
}
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
[cpp] view plaincopy
publicintaddWindow(Sessionsession,IWindowclient,intseq,
WindowManager.LayoutParamsattrs,intviewVisibility,intdisplayId,
RectoutContentInsets,InputChanneloutInputChannel){
//以下包括了管道的创建(用于WMS与应用程序View通信)等
Stringname=win.makeInputChannelName();
InputChannel[]inputChannels=InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
//以下便是注册至server端过程
//finalInputManagerServicemInputManager;
mInputManager.registerInputChannel(win.mInputChannel,win.mInputWindowHandle);
}
frameworks/base/service/java/com/android/server/input/InputManagerService.java
[cpp] view plaincopy
publicvoidregisterInputChannel(InputChannelinputChannel,
InputWindowHandleinputWindowHandle){
nativeRegisterInputChannel(mPtr,inputChannel,inputWindowHandle,false);
}
privatestaticnativevoidnativeRegisterInputChannel(intptr,InputChannelinputChannel,
InputWindowHandleinputWindowHandle,booleanmonitor);
frameworks/base/service/jni/com_android_server_input_InputManagerService.cpp
[cpp] view plaincopy
staticvoidnativeRegisterInputChannel(JNIEnv*env,jclassclazz,
jintptr,jobjectinputChannelObj,jobjectinputWindowHandleObj,jbooleanmonitor){
NativeInputManager*im=reinterpret_cast<NativeInputManager*>(ptr);
status_tstatus=im->registerInputChannel(
env,inputChannel,inputWindowHandle,monitor);
}
status_tNativeInputManager::registerInputChannel(JNIEnv*env,
constsp<InputChannel>&inputChannel,
constsp<InputWindowHandle>&inputWindowHandle,boolmonitor){
returnmInputManager->getDispatcher()->registerInputChannel(
inputChannel,inputWindowHandle,monitor);
//mInputManager=newInputManager(eventHub,this,this);
/*
frameworks/base/services/input/InputManager.cpp
sp<InputDispatcherInterface>InputManager::getDispatcher(){
returnmDispatcher;
}
mDispatcher=newInputDispatcher(dispatcherPolicy);
*/
}
frameworks/base/services/input/InputDispatcher.cpp
[cpp] view plaincopy
status_tInputDispatcher::registerInputChannel(constsp<InputChannel>&inputChannel,
constsp<InputWindowHandle>&inputWindowHandle,boolmonitor){
intfd=inputChannel->getFd();
mConnectionsByFd.add(fd,connection);
//该fd监听对应的处理函数为handleReceiveCallback
mLooper->addFd(fd,0,ALOOPER_EVENT_INPUT,handleReceiveCallback,this);
}
2.服务端上报过程
2.1.InputReaderThread线程从驱动读取数据并处理,如实现鼠标右键上报back键即在此处完成、以下代码将会看到
frameworks/base/services/input/InputReader.cpp
[cpp] view plaincopy
boolInputReaderThread::threadLoop(){
mReader->loopOnce();
returntrue;
}
voidInputReader::loopOnce(){
size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);
/*
frameworks/base/services/input/EventHub.cpp
size_tEventHub::getEvents(inttimeoutMillis,RawEvent*buffer,size_tbufferSize){
int32_treadSize=read(device->fd,readBuffer,
sizeof(structinput_event)*capacity);//从驱动读取事件
}
*/
processEventsLocked(mEventBuffer,count);
}
voidInputReader::processEventsLocked(constRawEvent*rawEvents,size_tcount){
processEventsForDeviceLocked(deviceId,rawEvent,batchSize);
}
voidInputReader::processEventsForDeviceLocked(int32_tdeviceId,
constRawEvent*rawEvents,size_tcount){
device->process(rawEvents,count);
}
voidInputDevice::process(constRawEvent*rawEvents,size_tcount){
//该设备的所有mapper进行处理;注意:这里使用了多态
for(size_ti=0;i<numMappers;i++){
InputMapper*mapper=mMappers[i];
mapper->process(rawEvent);
}
}
//以下就是各个mapper
//CursorInput鼠标设备
voidCursorInputMapper::process(constRawEvent*rawEvent){
mCursorButtonAccumulator.process(rawEvent);
mCursorMotionAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
if(rawEvent->type==EV_SYN&&rawEvent->code==SYN_REPORT){
sync(rawEvent->when);
}
}
//CursorButtonAccumulator::process(constRawEvent*rawEvent)
//CursorMotionAccumulator::process(constRawEvent*rawEvent)
//CursorScrollAccumulator::process(constRawEvent*rawEvent)
voidCursorInputMapper::sync(nsecs_twhen){
int32_tcurrentButtonState=mCursorButtonAccumulator.getButtonState();
/*
uint32_tCursorButtonAccumulator::getButtonState()const{
if(mBtnRight){
//Changedbytankformouseleftbuttontoback
result|=AMOTION_EVENT_BUTTON_BACK;
//result|=AMOTION_EVENT_BUTTON_SECONDARY;
}
if(mBtnMiddle){
//changebytank@tcl.comformousemiddlebuttontomenu
result|=AMOTION_EVENT_BUTTON_MENU;
//result|=AMOTION_EVENT_BUTTON_TERTIARY;
}
}
*/
getListener()->notifyMotion(&args);
synthesizeButtonKeys(getContext(),AKEY_EVENT_ACTION_UP,when,getDeviceId(),mSource,
policyFlags,lastButtonState,currentButtonState);
/*
staticvoidsynthesizeButtonKeys(InputReaderContext*context,int32_taction,
nsecs_twhen,int32_tdeviceId,uint32_tsource,
uint32_tpolicyFlags,int32_tlastButtonState,int32_tcurrentButtonState){
synthesizeButtonKey(context,action,when,deviceId,source,policyFlags,
lastButtonState,currentButtonState,
AMOTION_EVENT_BUTTON_BACK,AKEYCODE_BACK);
synthesizeButtonKey(context,action,when,deviceId,source,policyFlags,
lastButtonState,currentButtonState,
AMOTION_EVENT_BUTTON_FORWARD,AKEYCODE_FORWARD);
//addbytankmousekeyeventmiddle->menu.
synthesizeButtonKey(context,action,when,deviceId,source,policyFlags,
lastButtonState,currentButtonState,
AMOTION_EVENT_BUTTON_MENU,AKEYCODE_MENU);
//endtank
}
staticvoidsynthesizeButtonKey(InputReaderContext*context,int32_taction,
nsecs_twhen,int32_tdeviceId,uint32_tsource,
uint32_tpolicyFlags,int32_tlastButtonState,int32_tcurrentButtonState,
int32_tbuttonState,int32_tkeyCode){
if((action==AKEY_EVENT_ACTION_DOWN&&!(lastButtonState&buttonState)
&&(currentButtonState&buttonState))
||(action==AKEY_EVENT_ACTION_UP
&&(lastButtonState&buttonState)
&&!(currentButtonState&buttonState))){
context->getListener()->notifyKey(&args);
}
}
*/
}
//TouchInput触摸板设备
voidSingleTouchInputMapper::process(constRawEvent*rawEvent)
TouchInputMapper::process(rawEvent);
mSingleTouchMotionAccumulator.process(rawEvent);
}
//SingleTouchMotionAccumulator::process(constRawEvent*rawEvent)
voidMultiTouchInputMapper::process(constRawEvent*rawEvent){
TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
}
//MultiTouchMotionAccumulator::process(constRawEvent*rawEvent)
voidTouchInputMapper::process(constRawEvent*rawEvent){
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if(rawEvent->type==EV_SYN&&rawEvent->code==SYN_REPORT){
sync(rawEvent->when);
}
}
//TouchButtonAccumulator::process(constRawEvent*rawEvent)
voidTouchInputMapper::sync(nsecs_twhen){
dispatchTouches(when,policyFlags);
}
voidTouchInputMapper::dispatchTouches(nsecs_twhen,uint32_tpolicyFlags){
dispatchMotion(when,policyFlags,mSource,
AMOTION_EVENT_ACTION_MOVE,0,metaState,buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
currentIdBits,-1,
mOrientedXPrecision,mOrientedYPrecision,mDownTime);
}
voidTouchInputMapper::dispatchMotion(nsecs_twhen,uint32_tpolicyFlags,uint32_tsource,
int32_taction,int32_tflags,int32_tmetaState,int32_tbuttonState,int32_tedgeFlags,
constPointerProperties*properties,constPointerCoords*coords,
constuint32_t*idToIndex,BitSet32idBits,
int32_tchangedId,floatxPrecision,floatyPrecision,nsecs_tdownTime){
getListener()->notifyMotion(&args);
}
//SwitchInput设备
voidSwitchInputMapper::process(constRawEvent*rawEvent){
sync(rawEvent->when);
}
voidSwitchInputMapper::sync(nsecs_twhen){
getListener()->notifySwitch(&args);
}
//JoystickInput游戏手柄设备
voidJoystickInputMapper::process(constRawEvent*rawEvent){
sync(rawEvent->when,false/*force*/);
}
voidJoystickInputMapper::sync(nsecs_twhen,boolforce){
getListener()->notifyMotion(&args);
}
//KeyboardInput按键设备
voidKeyboardInputMapper::process(constRawEvent*rawEvent){
processKey(rawEvent->when,rawEvent->value!=0,keyCode,scanCode,flags);
}
voidKeyboardInputMapper::processKey(nsecs_twhen,booldown,int32_tkeyCode,
int32_tscanCode,uint32_tpolicyFlags){
getListener()->notifyKey(&args);
}
2.2.InputReaderThread线程对系统层按键做处理(比较重要的是POWER键,最终在PhoneWindowManager中的 interceptKeyBeforeQueueing和interceptMotionBeforeQueueingWhenScreenOff)后分 发给InputDispatcherThread线程,以下分析将看到之前一个鼠标操作过程中无法待机的问题解决
以下几种情况都会唤醒InputDispatcherThread线程,即调用mLooper->wake()唤醒正在awoken()中的InputReaderThread线程:
frameworks/base/services/input/InputDispatcher.cpp
[cpp] view plaincopy
//有新输入设备注册等
voidInputDispatcher::notifyConfigurationChanged(constNotifyConfigurationChangedArgs*args){
ConfigurationChangedEntry*newEntry=newConfigurationChangedEntry(args->eventTime);
needWake=enqueueInboundEventLocked(newEntry);
if(needWake){
mLooper->wake();
}
}
//分发按键事件
voidInputDispatcher::notifyKey(constNotifyKeyArgs*args){
//说明:PhoneWindowManager.java中policyFlags位决定系统按键(如HOME等是否需要由系统处理)
mPolicy->interceptKeyBeforeQueueing(&event,policyFlags);
//以下分析将看到,该调用实际是在PhoneWindowManager.java中实现
/*
frameworks/base/services/input/InputManager.cpp
InputManager::InputManager(
constsp<EventHubInterface>&eventHub,
constsp<InputReaderPolicyInterface>&readerPolicy,
constsp<InputDispatcherPolicyInterface>&dispatcherPolicy){
mDispatcher=newInputDispatcher(dispatcherPolicy);
mReader=newInputReader(eventHub,readerPolicy,mDispatcher);
}
frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobjectcontextObj,
jobjectserviceObj,constsp<Looper>&looper):
mLooper(looper){
mInputManager=newInputManager(eventHub,this,this);
}
voidNativeInputManager::interceptKeyBeforeQueueing(constKeyEvent*keyEvent,
uint32_t&policyFlags){
wmActions=env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj,policyFlags,isScreenOn);
//如下函数中将有待机和开机的处理
handleInterceptActions(wmActions,when,policyFlags);
}
frameworks/base/service/java/com/android/server/input/InputManagerService.java
privateintinterceptKeyBeforeQueueing(KeyEventevent,intpolicyFlags,booleanisScreenOn){
returnmWindowManagerCallbacks.interceptKeyBeforeQueueing(
event,policyFlags,isScreenOn);
}
frameworks/base/service/java/com/android/server/SystemServer.java
inputManager=newInputManagerService(context,wmHandler);
wm=WindowManagerService.main(context,power,display,inputManager,
uiHandler,wmHandler,
factoryTest!=SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot,onlyCore);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
publicInputMonitorgetInputMonitor(){
returnmInputMonitor;
}
frameworks/base/service/java/com/android/server/wm/InputMonitor.java
publicintinterceptKeyBeforeQueueing(
KeyEventevent,intpolicyFlags,booleanisScreenOn){
returnmService.mPolicy.interceptKeyBeforeQueueing(event,policyFlags,isScreenOn);
}
publicInputMonitor(WindowManagerServiceservice){
mService=service;
}
frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
finalWindowManagerPolicymPolicy=PolicyManager.makeNewWindowManager();
frameworks/base/core/java/com/android/internal/policy/PolicyManager.java
publicstaticWindowManagerPolicymakeNewWindowManager(){
returnsPolicy.makeNewWindowManager();
}
privatestaticfinalStringPOLICY_IMPL_CLASS_NAME=
"com.android.internal.policy.impl.Policy";
ClasspolicyClass=Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy=(IPolicy)policyClass.newInstance();
frameworks/base/core/java/com/android/internal/policy/Policy.java
packagecom.android.internal.policy.impl;
publicclassPolicyimplementsIPolicy{
publicWindowManagerPolicymakeNewWindowManager(){
returnnewPhoneWindowManager();
}
}
frameworks/base/core/java/com/android/internal/policy/PhoneWindowManager.java
publicintinterceptKeyBeforeQueueing(KeyEventevent,intpolicyFlags,booleanisScreenOn){
caseKeyEvent.KEYCODE_POWER:{
result=(result&~ACTION_WAKE_UP)|ACTION_GO_TO_SLEEP;
}
}
*/
KeyEntry*newEntry=newKeyEntry(args->eventTime,
args->deviceId,args->source,policyFlags,
args->action,flags,args->keyCode,args->scanCode,
metaState,repeatCount,args->downTime);
needWake=enqueueInboundEventLocked(newEntry);
if(needWake){
mLooper->wake();
}
}
//分发Motion事件
voidInputDispatcher::notifyMotion(constNotifyMotionArgs*args){
mPolicy->interceptMotionBeforeQueueing(args->eventTime,/*byref*/policyFlags);
/*
如上分析,不再累赘;该接口是:
frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
voidNativeInputManager::interceptMotionBeforeQueueing(nsecs_twhen,uint32_t&policyFlags){
jintwmActions=env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
policyFlags);
handleInterceptActions(wmActions,when,policyFlags);
}
如上interceptMotionBeforeQueueingWhenScreenOff在PhoneWindowManager中实现;分析同上,不再累赘:
frameworks/base/core/java/com/android/internal/policy/PhoneWindowManager.java
publicintinterceptMotionBeforeQueueingWhenScreenOff(intpolicyFlags){
//result|=ACTION_WAKE_UP;
//addbytank
result=result&(~ACTION_WAKE_UP);
//endtank
returnresult;
}
看看handleInterceptActions函数:
voidNativeInputManager::handleInterceptActions(jintwmActions,nsecs_twhen,
uint32_t&policyFlags){
//接上边PhoneWindowManager中interceptKeyBeforeQueueing对于power键的返回值可知,系统将待机
if(wmActions&WM_ACTION_GO_TO_SLEEP){
#ifDEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions:Goingtosleep.");
#endif
android_server_PowerManagerService_goToSleep(when);
}
//以下说明PhoneWindowManager中interceptMotionBeforeQueueingWhenScreenOff返回值WM_ACTION_WAKE_UP将会导致唤醒
//当然,是可是收到motion事件的前提下
if(wmActions&WM_ACTION_WAKE_UP){
#ifDEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions:Wakingup.");
#endif
android_server_PowerManagerService_wakeUp(when);
}
//以下是可以上报给系统的
if(wmActions&WM_ACTION_PASS_TO_USER){
policyFlags|=POLICY_FLAG_PASS_TO_USER;
}
}
*/
MotionEntry*newEntry=newMotionEntry(args->eventTime,
args->deviceId,args->source,policyFlags,
args->action,args->flags,args->metaState,args->buttonState,
args->edgeFlags,args->xPrecision,args->yPrecision,args->downTime,
args->displayId,
args->pointerCount,args->pointerProperties,args->pointerCoords);
needWake=enqueueInboundEventLocked(newEntry);
if(needWake){
mLooper->wake();
}
}
//设备重置
voidInputDispatcher::notifyDeviceReset(constNotifyDeviceResetArgs*args){
DeviceResetEntry*newEntry=newDeviceResetEntry(args->eventTime,args->deviceId);
needWake=enqueueInboundEventLocked(newEntry);
if(needWake){
mLooper->wake();
}
}
//C层的按键注入接口
int32_tInputDispatcher::injectInputEvent(constInputEvent*event,
int32_tinjectorPid,int32_tinjectorUid,int32_tsyncMode,int32_ttimeoutMillis,
uint32_tpolicyFlags){
needWake|=enqueueInboundEventLocked(entry);
if(needWake){
mLooper->wake();
}
}
//setInputWindows
//setFocusedApplication
//setInputDispatchMode
//setInputFilterEnabled
//transferTouchFocus
//registerInputChannel
//unregisterInputChannel
//monitor
2.3.InputDispatcherThread线程处理,根据PhoneWindowManager中的interceptKeyBeforeDispatching决定是否丢弃按键
InputDispatcherThread线程被唤醒
[cpp] view plaincopy
boolInputDispatcherThread::threadLoop(){
mDispatcher->dispatchOnce();
returntrue;
}
voidInputDispatcher::dispatchOnce(){
dispatchOnceInnerLocked(&nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime){
if(!mPolicy->isKeyRepeatEnabled()){
resetKeyRepeatLocked();
}
switch(mPendingEvent->type){
caseEventEntry::TYPE_CONFIGURATION_CHANGED:{
done=dispatchConfigurationChangedLocked(currentTime,typedEntry);
}
caseEventEntry::TYPE_DEVICE_RESET:{
done=dispatchDeviceResetLocked(currentTime,typedEntry);
}
caseEventEntry::TYPE_KEY:{
done=dispatchKeyLocked(currentTime,typedEntry,&dropReason,nextWakeupTime);
}
caseEventEntry::TYPE_MOTION:{
done=dispatchMotionLocked(currentTime,typedEntry,
&dropReason,nextWakeupTime);
}
}
dropInboundEventLocked(mPendingEvent,dropReason);//丢弃的事件!!!!
}
boolInputDispatcher::dispatchKeyLocked(nsecs_tcurrentTime,KeyEntry*entry,
DropReason*dropReason,nsecs_t*nextWakeupTime){
CommandEntry*commandEntry=postCommandLocked(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
/*
voidInputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry*commandEntry){
//说明:PhoneWindowManager.java中可以截断事件而不上报,即返回-1、将被丢弃
nsecs_tdelay=mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event,entry->policyFlags);
if(delay<0){
entry->interceptKeyResult=KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
}elseif(!delay){
entry->interceptKeyResult=KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}else{
entry->interceptKeyResult=KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
entry->interceptKeyWakeupTime=now()+delay;
}
}
*/
elseif(entry->interceptKeyResult==KeyEntry::INTERCEPT_KEY_RESULT_SKIP){
if(*dropReason==DROP_REASON_NOT_DROPPED){
*dropReason=DROP_REASON_POLICY;//dropReason是因为策略丢弃
}
}
if(*dropReason!=DROP_REASON_NOT_DROPPED){
setInjectionResultLocked(entry,*dropReason==DROP_REASON_POLICY
?INPUT_EVENT_INJECTION_SUCCEEDED:INPUT_EVENT_INJECTION_FAILED);
returntrue;
}
dispatchEventLocked(currentTime,entry,inputTargets);
}
boolInputDispatcher::dispatchMotionLocked(
nsecs_tcurrentTime,MotionEntry*entry,DropReason*dropReason,nsecs_t*nextWakeupTime){
dispatchEventLocked(currentTime,entry,inputTargets);
}
2.4.InputDispatcherThread线程分发给应用程序进程
在这里解决了up事件上报两次的问题!!!!!!
frameworks/base/services/input/InputDispatcher.cpp
[cpp] view plaincopy
voidInputDispatcher::dispatchEventLocked(nsecs_tcurrentTime,
EventEntry*eventEntry,constVector<InputTarget>&inputTargets){
pokeUserActivityLocked(eventEntry);//和Activity相关,后边三中有设备删除的分析;基本同下
ssize_tconnectionIndex=getConnectionIndexLocked(inputTarget.inputChannel);
sp<Connection>connection=mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime,connection,eventEntry,&inputTarget);
}
voidInputDispatcher::prepareDispatchCycleLocked(nsecs_tcurrentTime,
constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget){
enqueueDispatchEntriesLocked(currentTime,connection,eventEntry,inputTarget);
}
voidInputDispatcher::enqueueDispatchEntriesLocked(nsecs_tcurrentTime,
constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget){
enqueueDispatchEntryLocked(connection,eventEntry,inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);//将按键注入队列
/*
voidInputDispatcher::enqueueDispatchEntryLocked(
constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget,
int32_tdispatchMode){
DispatchEntry*dispatchEntry=newDispatchEntry(eventEntry,//incrementsref
inputTargetFlags,inputTarget->xOffset,inputTarget->yOffset,
inputTarget->scaleFactor);
if(!connection->inputState.trackKey(keyEntry,
dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags)||(dispatchEntry->resolvedFlags==0x28)){
//addbytankai0x28
deletedispatchEntry;
return;
}
}
*/
//dropInboundEventLocked
//synthesizeCancelationEventsForAllConnectionsLocked->
//synthesizeCancelationEventsForConnectionLocked->
/*
voidInputDispatcher::synthesizeCancelationEventsForConnectionLocked(
constsp<Connection>&connection,constCancelationOptions&options){
Vector<EventEntry*>cancelationEvents;
connection->inputState.synthesizeCancelationEvents(currentTime,
cancelationEvents,options);
//关键在这里,mKeyMementos;在enqueueDispatchEntryLocked时调用trackKey由addKeyMemento注入!!!!!!
if(!cancelationEvents.isEmpty()){
enqueueDispatchEntryLocked(connection,cancelationEventEntry,//incrementsref
&target,InputTarget::FLAG_DISPATCH_AS_IS);
}
}
*/
//enqueueDispatchEntriesLocked,注入了0x28标志的按键
startDispatchCycleLocked(currentTime,connection);
}
voidInputDispatcher::startDispatchCycleLocked(nsecs_tcurrentTime,
constsp<Connection>&connection){
switch(eventEntry->type){
caseEventEntry::TYPE_KEY:{
status=connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId,keyEntry->source,
dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags,
keyEntry->keyCode,keyEntry->scanCode,
keyEntry->metaState,keyEntry->repeatCount,keyEntry->downTime,
keyEntry->eventTime);
}
caseEventEntry::TYPE_MOTION:{
status=connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId,motionEntry->source,
dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags,
motionEntry->edgeFlags,motionEntry->metaState,motionEntry->buttonState,
xOffset,yOffset,
motionEntry->xPrecision,motionEntry->yPrecision,
motionEntry->downTime,motionEntry->eventTime,
motionEntry->pointerCount,motionEntry->pointerProperties,
usingCoords);
}
}
}
frameworks/base/libs/androidfw/InputTransport.cpp
[cpp] view plaincopy
status_tInputPublisher::publishKeyEvent(
uint32_tseq,
int32_tdeviceId,
int32_tsource,
int32_taction,
int32_tflags,
int32_tkeyCode,
int32_tscanCode,
int32_tmetaState,
int32_trepeatCount,
nsecs_tdownTime,
nsecs_teventTime){
returnmChannel->sendMessage(&msg);
}
status_tInputChannel::sendMessage(constInputMessage*msg){
do{
nWrite=::send(mFd,msg,msgLength,MSG_DONTWAIT|MSG_NOSIGNAL);
}while(nWrite==-1&&errno==EINTR);
}
二、Android4.2系统应用程序侧――与View关系
InputManagerService也就是InputDispatcher与应用程序通信是靠looper。
说明:
InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等。
InputDispatcher获得按键事件后,根据当前设备的状况来优先消化事件(该过程交由PhoneWindowManager.java来处理);最后,剩余事件分发给ViewRoot;ViewRoot再分发给IME输入法或View、Activity。
1.应用程序View中channel注册过程
frameworks/base/core/java/android/view/ViewRootImpl.java
[cpp] view plaincopy
publicvoidsetView(Viewview,WindowManager.LayoutParamsattrs,ViewpanelParentView){
mInputChannel=newInputChannel();//创建InputChannel
res=mWindowSession.addToDisplay(mWindow,mSeq,mWindowAttributes,
getHostVisibility(),mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,mInputChannel);//创建与上述InputChannel对应的通道至服务端
mInputEventReceiver=newWindowInputEventReceiver(mInputChannel,
Looper.myLooper());//将本通道注册进InputEventReceiver
}
finalclassWindowInputEventReceiverextendsInputEventReceiver{
publicWindowInputEventReceiver(InputChannelinputChannel,Looperlooper){
super(inputChannel,looper);
}
@Override
publicvoidonInputEvent(InputEventevent){
enqueueInputEvent(event,this,0,true);
}
}
frameworks/base/core/java/android/view/InputEventReceiver.java
[cpp] view plaincopy
publicInputEventReceiver(InputChannelinputChannel,Looperlooper){
mReceiverPtr=nativeInit(this,inputChannel,mMessageQueue);
}
privatestaticnativeintnativeInit(InputEventReceiverreceiver,
InputChannelinputChannel,MessageQueuemessageQueue);
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
[cpp] view plaincopy
staticjintnativeInit(JNIEnv*env,jclassclazz,jobjectreceiverObj,
jobjectinputChannelObj,jobjectmessageQueueObj){
sp<NativeInputEventReceiver>receiver=newNativeInputEventReceiver(env,
receiverObj,inputChannel,messageQueue);
status_tstatus=receiver->initialize();
}
status_tNativeInputEventReceiver::initialize(){
intreceiveFd=mInputConsumer.getChannel()->getFd();
mMessageQueue->getLooper()->addFd(receiveFd,0,ALOOPER_EVENT_INPUT,this,NULL);
returnOK;
}
frameworks/native/libs/utils/Looper.cpp
[cpp] view plaincopy
intLooper::addFd(intfd,intident,intevents,constsp<LooperCallback>&callback,void*data){
request.callback=callback;
}
2.应用程序View响应过程
frameworks/native/libs/utils/Looper.cpp
[cpp] view plaincopy
intLooper::pollInner(inttimeoutMillis){
awoken();//阻塞,等待
intcallbackResult=response.request.callback->handleEvent(fd,events,data);
}
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
[cpp] view plaincopy
intNativeInputEventReceiver::handleEvent(intreceiveFd,intevents,void*data){
status_tstatus=consumeEvents(env,false/*consumeBatches*/,-1);
}
status_tNativeInputEventReceiver::consumeEvents(JNIEnv*env,
boolconsumeBatches,nsecs_tframeTime){
env->CallVoidMethod(mReceiverObjGlobal,
gInputEventReceiverClassInfo.dispatchInputEvent,seq,inputEventObj);
}
frameworks/base/core/java/android/view/InputEventReceiver.java
[cpp] view plaincopy
privatevoiddispatchInputEvent(intseq,InputEventevent){
mSeqMap.put(event.getSequenceNumber(),seq);
onInputEvent(event);
}
frameworks/base/core/java/android/view/ViewRootImpl.java
[cpp] view plaincopy
finalclassWindowInputEventReceiverextendsInputEventReceiver{
publicWindowInputEventReceiver(InputChannelinputChannel,Looperlooper){
super(inputChannel,looper);
}
@Override
publicvoidonInputEvent(InputEventevent){
enqueueInputEvent(event,this,0,true);
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver,intflags,booleanprocessImmediately){
scheduleProcessInputEvents();
}
/////////////////////////////////////////////////////////////
有关handler机制请看下文:
http://blog.csdn.net/itachi85/article/details/8035333
[cpp] view plaincopy
finalViewRootHandlermHandler=newViewRootHandler();
privatevoidscheduleProcessInputEvents(){
Messagemsg=mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
mHandler.sendMessage(msg);
}
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
caseMSG_PROCESS_INPUT_EVENTS:
doProcessInputEvents();
}
}
///////////////////////////////////////////////////////
[cpp] view plaincopy
voiddoProcessInputEvents(){
deliverInputEvent(q);
}
privatevoiddeliverInputEvent(QueuedInputEventq){
deliverKeyEvent(q);
deliverPointerEvent(q);
deliverTrackballEvent(q);
deliverGenericMotionEvent(q);
}
privatevoiddeliverKeyEvent(QueuedInputEventq){
imm.dispatchKeyEvent(mView.getContext(),seq,event,mInputMethodCallback);//分发给输入法
deliverKeyEventPostIme(q);//分发给View
/*
privatevoiddeliverKeyEventPostIme(QueuedInputEventq){
mView.dispatchKeyEvent(event)
}
*/
}
privatevoiddeliverPointerEvent(QueuedInputEventq){
booleanhandled=mView.dispatchPointerEvent(event);//分发给View
}
privatevoiddeliverTrackballEvent(QueuedInputEventq){
imm.dispatchTrackballEvent(mView.getContext(),seq,event,
mInputMethodCallback);//分发给输入法
deliverTrackballEventPostIme(q);//分发给View
/*
privatevoiddeliverTrackballEventPostIme(QueuedInputEventq){
mView.dispatchTrackballEvent(event)
}
*/
}
privatevoiddeliverGenericMotionEvent(QueuedInputEventq){
imm.dispatchGenericMotionEvent(mView.getContext(),seq,event,
mInputMethodCallback);//分发给输入法
deliverGenericMotionEventPostIme(q);//分发给View
/*
privatevoiddeliverGenericMotionEventPostIme(QueuedInputEventq){
updateJoystickDirection(event,false);//游戏手柄的摇杆就是在这处理
mView.dispatchGenericMotionEvent(event)
}
*/
}
分发给应用程序Activity:
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
[java] view plaincopy
privatefinalclassDecorViewextendsFrameLayoutimplementsRootViewSurfaceTaker{
publicbooleandispatchKeyEvent(KeyEventevent){
finalCallbackcb=getCallback();
//cb为应用程序MainActivity
finalbooleanhandled=cb!=null&&mFeatureId<0?cb.dispatchKeyEvent(event):super.dispatchKeyEvent(event);
//给应用程序Activity的dispatchKeyEvent处理或交给View的dispatchKeyEvent
}
}
而上述应用程序中的dispatchKeyEvent一般会调用其父类的该方法,例如:
packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
[java] view plaincopy
publicbooleandispatchKeyEvent(KeyEventevent){
returnsuper.dispatchKeyEvent(event);
}
应用程序Activity在分发给与之关联的某个View,如果这个View没有处理、最终交给该Activity自己处理。
应用程序有关View的设置:
[java] view plaincopy
privateDialogmMenuWin;
mMenuWin=newDialog(aActivity,R.style.CameraDialog);
mMenuWin.setContentView(mMenuLayout);
mMenuWin.setOnClickListener();//鼠标单击
mMenuWin.setOnLongClickListener();//
mMenuWin.setOnTouchListener();//触摸板
mMenuWin.setOnKeyListener(newOnKeyListener(){
publicbooleanonKey();//按键
publicvoidonClick(Viewv);//鼠标单击
}
frameworks/base/core/java/android/app/Activity.java
[java] view plaincopy
publicbooleandispatchKeyEvent(KeyEventevent){
onUserInteraction();
Windowwin=getWindow();
if(win.superDispatchKeyEvent(event)){//首先由Window消化,即如果View消化了、则Activity将不在回调onKeyDown
returntrue;
}
Viewdecor=mDecor;//如果没被消化,会调用Activity的onKeyDown
if(decor==null)decor=win.getDecorView();
returnevent.dispatch(this,decor!=null?decor.getKeyDispatcherState():null,this);
}
}
我们重点分析win.superDispatchKeyEvent,也就是View的处理流程:
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
[java] view plaincopy
publicclassPhoneWindowextendsWindowimplementsMenuBuilder.Callback{
publicbooleansuperDispatchKeyEvent(KeyEventevent){
returnmDecor.superDispatchKeyEvent(event);
}
}
privatefinalclassDecorViewextendsFrameLayoutimplementsRootViewSurfaceTaker{
publicbooleansuperDispatchKeyEvent(KeyEventevent){
super.dispatchKeyEvent(event)
}
}
frameworks/base/core/java/android/view/ViewGroup.java //分发给View的关键部分!!!
[java] view plaincopy
publicbooleandispatchKeyEvent(KeyEventevent){
mInputEventConsistencyVerifier.onKeyEvent(event,1);
super.dispatchKeyEvent(event)
}
frameworks/base/core/java/android/view/View.java
[java] view plaincopy
publicbooleandispatchKeyEvent(KeyEventevent){
li.mOnKeyListener.onKey(this,event.getKeyCode(),event);//回调应用程序View相应方法
event.dispatch(this,mAttachInfo!=null?mAttachInfo.mKeyDispatchState:null,this)
/*
frameworks/base/core/java/android/view/KeyEvent.java
publicfinalbooleandispatch(Callbackreceiver,DispatcherStatestate,
Objecttarget){
//按键响应
booleanres=receiver.onKeyDown(mKeyCode,this);//应用程序回调函数
}
*/
}
publicfinalbooleandispatchPointerEvent(MotionEventevent){
if(event.isTouchEvent()){
returndispatchTouchEvent(event);
}else{
returndispatchGenericMotionEvent(event);
}
}
publicbooleandispatchTouchEvent(MotionEventevent){
//触摸板响应
li.mOnTouchListener.onTouch(this,event)//应用程序继承OnTouchListener,实现的回调接口
//鼠标左键响应
onTouchEvent(event)
/*
publicbooleanonTouchEvent(MotionEventevent){
performClick();
//该接口调用li.mOnClickListener.onClick(this);为应用程序继承OnClickListener的回调函数
}
*/
}
以下不再做分析
dispatchGenericMotionEvent
dispatchTrackballEvent
dispatchConfigurationChanged //添加或删除键盘设备Activity重启,见http://blog.csdn.net/tankai19880619/article/details/16805401
三、Input设备与Activity关系
1.InputReaderThread线程检测到设备插入删除
frameworks/base/service/input/InputReader.cpp
[cpp] view plaincopy
voidInputReader::loopOnce(){
size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);
/*
frameworks/base/services/input/EventHub.cpp
size_tEventHub::getEvents(inttimeoutMillis,RawEvent*buffer,size_tbufferSize){
int32_treadSize=read(device->fd,readBuffer,
sizeof(structinput_event)*capacity);//从驱动读取事件
}
*/
processEventsLocked(mEventBuffer,count);
}
voidInputReader::processEventsLocked(constRawEvent*rawEvents,size_tcount){
caseEventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
}
voidInputReader::handleConfigurationChangedLocked(nsecs_twhen){
updateGlobalMetaStateLocked();
//Enqueueconfigurationchanged.
NotifyConfigurationChangedArgsargs(when);
mQueuedListener->notifyConfigurationChanged(&args);
}
说明:有的平台需要在接入硬件键盘时Activity不需要刷新;可以在上处做屏蔽:
[cpp] view plaincopy
//addbytank
//donotsendconfigurationchange
//NotifyConfigurationChangedArgsargs(when);
//mQueuedListener->notifyConfigurationChanged(&args);
//endtank
2.InputReaderThread线程分发给InputDispatcherThread线程
frameworks/base/service/input/InputDispatcher.cpp
[cpp] view plaincopy
voidInputDispatcher::notifyConfigurationChanged(constNotifyConfigurationChangedArgs*args){
needWake=enqueueInboundEventLocked(newEntry);
if(needWake){
mLooper->wake();
}
}
3.InputReaderThread线程收到消息并处理
frameworks/base/service/input/InputDispatcher.cpp
[cpp] view plaincopy
boolInputDispatcherThread::threadLoop(){
mDispatcher->dispatchOnce();
returntrue;
}
voidInputDispatcher::dispatchOnce(){
dispatchOnceInnerLocked(&nextWakeupTime);
}
voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime){
caseEventEntry::TYPE_CONFIGURATION_CHANGED:{
ConfigurationChangedEntry*typedEntry=
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done=dispatchConfigurationChangedLocked(currentTime,typedEntry);
}
}
boolInputDispatcher::dispatchConfigurationChangedLocked(
nsecs_tcurrentTime,ConfigurationChangedEntry*entry){
CommandEntry*commandEntry=postCommandLocked(
&InputDispatcher::doNotifyConfigurationChangedInterruptible);
}
voidInputDispatcher::doNotifyConfigurationChangedInterruptible(
CommandEntry*commandEntry){
mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
}
如上,不再做分析:
frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
[cpp] view plaincopy
voidNativeInputManager::notifyConfigurationChanged(nsecs_twhen){
env->CallVoidMethod(mServiceObj,gServiceClassInfo.notifyConfigurationChanged,when);
}
frameworks/base/services/java/com/android/server/input/InputManagerService.cpp
[cpp] view plaincopy
privatevoidnotifyConfigurationChanged(longwhenNanos){
mWindowManagerCallbacks.notifyConfigurationChanged();
}
如上,不再做分析:
frameworks/base/service/java/com/android/server/wm/InputMonitor.java
[cpp] view plaincopy
publicvoidnotifyConfigurationChanged(){
mService.sendNewConfiguration();
}
frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
[cpp] view plaincopy
voidsendNewConfiguration(){
mActivityManager.updateConfiguration(null);
/*
mActivityManager=ActivityManagerNative.getDefault();
frameworks/base/core/java/android/app/ActivityManagerNative.java
staticpublicIActivityManagergetDefault(){
returngDefault.get();
}
privatestaticfinalSingleton<IActivityManager>gDefault=newSingleton<IActivityManager>(){
IBinderb=ServiceManager.getService("activity");
IActivityManageram=asInterface(b);
returnam;
}
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
publicstaticvoidsetSystemProcess(){
ActivityManagerServicem=mSelf;
ServiceManager.addService("activity",m,true);
}
*/
}
4.交由ActivityManagerService进程处理
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
[cpp] view plaincopy
publicvoidupdateConfiguration(Configurationvalues){
updateConfigurationLocked(values,null,false,false);
}
booleanupdateConfigurationLocked(Configurationvalues,
ActivityRecordstarting,booleanpersistent,booleaninitLocale){
kept=mMainStack.ensureActivityConfigurationLocked(starting,changes);
publicvoidsetWindowManager(WindowManagerServicewm){
mWindowManager=wm;
}
}
frameworks/base/services/java/com/android/server/am/ActivityStack.java
[cpp] view plaincopy
finalbooleanensureActivityConfigurationLocked(ActivityRecordr,
intglobalChanges){
//一般会重启Activity
if((changes&(~r.info.getRealConfigChanged()))!=0||r.forceNewConfig){
relaunchActivityLocked(r,r.configChangeFlags,false);
returnfalse;
}
//应用程序AndroidMenifest中写标记将不会重启
r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
}
frameworks/base/core/java/android/app/ActivityThread.java
[cpp] view plaincopy
publicvoidscheduleActivityConfigurationChanged(IBindertoken){
queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED,token);
}
//消息循环同上,不再分析
publicvoidhandleMessage(Messagemsg){
caseACTIVITY_CONFIGURATION_CHANGED:
handleActivityConfigurationChanged((IBinder)msg.obj);
}
finalvoidhandleActivityConfigurationChanged(IBindertoken){
performConfigurationChanged(r.activity,mCompatConfiguration);
}
privatestaticvoidperformConfigurationChanged(ComponentCallbacks2cb,Configurationconfig){
cb.onConfigurationChanged(config);//回调Activity类的onConfigurationChanged方法
}
四、项目问题
resumeTopActivity时的Activity重启。http://blog.csdn.net/jivin_shen/article/details/6839175
操作逻辑:打开Launcher界面下的一个应用(比如播放器),完后接入USB键盘;之后退出该应用,也就是resumeTopActivity到Launcher时也引发了config配置更新导致的Activity重启。
原理以及解决部分:
frameworks/base/services/java/com/android/server/am/ActivityStack.java
[cpp] view plaincopy
finalbooleanresumeTopActivityLocked(ActivityRecordprev){
returnresumeTopActivityLocked(prev,null);
}
finalbooleanresumeTopActivityLocked(ActivityRecordprev,Bundleoptions){
Configurationconfig=mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
next.mayFreezeScreenLocked(next.app)?next.appToken:null);
}
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
[cpp] view plaincopy
publicConfigurationupdateOrientationFromAppTokens(
ConfigurationcurrentConfig,IBinderfreezeThisOneIfNeeded){
config=updateOrientationFromAppTokensLocked(currentConfig,
freezeThisOneIfNeeded);
}
privateConfigurationupdateOrientationFromAppTokensLocked(
ConfigurationcurrentConfig,IBinderfreezeThisOneIfNeeded){
computeScreenConfigurationLocked(mTempConfiguration)
}
booleancomputeScreenConfigurationLocked(Configurationconfig){
if((sources&InputDevice.SOURCE_TOUCHSCREEN)==InputDevice.SOURCE_TOUCHSCREEN){
//changebytank
config.touchscreen=Configuration.TOUCHSCREEN_NOTOUCH;
//config.touchscreen=Configuration.TOUCHSCREEN_FINGER;
//endtank
}
elseif((sources&InputDevice.SOURCE_DPAD)==InputDevice.SOURCE_DPAD
&&config.navigation==Configuration.NAVIGATION_NONAV){
//changebytank
//config.navigation=Configuration.NAVIGATION_DPAD;
//navigationPresence|=presenceFlag;
//endtank
}
if(device.getKeyboardType()==InputDevice.KEYBOARD_TYPE_ALPHABETIC){
//changebytank
//config.keyboard=Configuration.KEYBOARD_QWERTY;
//keyboardPresence|=presenceFlag;
//endtank
}
}
面板设备与虚拟驱动导致的up上报两次:
1.drop类按键
down或up:
dispatchOnceInnerLocked>
dropInboundEventLocked>synthesizeCancelationEventsForAllConnectionsLocked- synthesizeCancelationEventsForConnectionLocked>inputState.synthesizeCancelationEvents->mKeyMementos.itemAt(i), 最后上报系统(synthesizeCancelationEventsForConnectionLocked调用 enqueueDispatchEntryLocked)
2.非drop类按键
down:
dispatchOnceInnerLocked->
dispatchKeyLocked->dispatchEventLocked->prepareDispatchCycleLocked->enqueueDispatchEntriesLocked->enqueueDispatchEntryLocked->InputState::trackKey->addKeyMemento //只在down时保存对up的处理
问题:
面板down->drop
虚拟down->非drop,保存up
面板down->drop,将虚拟保存的up送上去
虚拟up->非drop,直接上报
结果――两个虚拟的up
修改方法:
frameworks/base/service/input/InputDispatcher.cpp
[cpp] view plaincopy
voidInputDispatcher::enqueueDispatchEntryLocked(
constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget,
int32_tdispatchMode)
{
if(!connection->inputState.trackKey(keyEntry,
dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags)/*addbytank@tcl.comend*/||(dispatchEntry->resolvedFlags==0x28))
{
#ifDEBUG_DISPATCH_CYCLE
ALOGD("channel'%s'~enqueueDispatchEntryLocked:skippinginconsistentkeyevent",
connection->getInputChannelName());
#endif
deletedispatchEntry;
return;//skiptheinconsistentevent
}
/*
//addbytankai
if(dispatchEntry->resolvedFlags==0x28&&keyEntry->deviceId==3){
ALOGD("TK--------->>>deletesimKeyMementosup\n");
deletedispatchEntry;
return;//skiptheinconsistentevent
}
//endtankai
*/
}
更多相关文章
- FregServer进程,发送BC_TRANSACTION,唤醒ServiceManager进程,返回BR
- Android(安卓)图片阴影处理分析!
- Android在WebView上构建Web应用程序
- Android应用程序常见编译问题解决
- Android应用程序显示欢迎画面并开机自启动
- Android:UI更新方法四:在Worker Thread中runOnUiThread直接刷新U
- Android图像处理相关文章
- 几个通用的类,迷你型的Android下载框架
- 在Android中使用Timer,并创建一个应用程序