大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > Android技巧 > Android输入输出系统之TouchEvent流程

Android输入输出系统之TouchEvent流程

关键词:输入输出流程系统AndroidTouchEvent  阅读(728) 赞(20)

[摘要]本文是对Android输入输出系统之TouchEvent流程的讲解,对学习Android编程技术有所帮助,与大家分享。

一个是InputReader,一个是InputDispatcher。方法是dispatchTouch。

入口点是InputReader 的loopOnce方法.

InputReader里面有个线程叫做InputReaderThread,threadLoop

[code="java"]InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}

InputReaderThread::~InputReaderThread() {
}

bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}

Java代码
voidInputDispatcher::dispatchOnce(){
nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();

nsecs_tnextWakeupTime=LONG_LONG_MAX;
{//acquirelock
AutoMutex_l(mLock);
dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);

if(runCommandsLockedInterruptible()){
nextWakeupTime=LONG_LONG_MIN;//forcenextpolltowakeupimmediately
}
}//releaselock

//Waitforcallbackortimeoutorwake.(makesureweroundup,notdown)
nsecs_tcurrentTime=now();
int32_ttimeoutMillis;
if(nextWakeupTime>currentTime){
uint64_ttimeout=uint64_t(nextWakeupTime-currentTime);
timeout=(timeout+999999LL)/1000000LL;
timeoutMillis=timeout>INT_MAX?-1:int32_t(timeout);
}else{
timeoutMillis=0;
}

mLooper->pollOnce(timeoutMillis);
}


Java代码
caseEventEntry::TYPE_MOTION:{
MotionEntry*typedEntry=static_cast<MotionEntry*>(mPendingEvent);
if(dropReason==DROP_REASON_NOT_DROPPED&&isAppSwitchDue){
dropReason=DROP_REASON_APP_SWITCH;
}
done=dispatchMotionLocked(currentTime,typedEntry,
&dropReason,nextWakeupTime);
break;


Java代码
boolInputDispatcher::dispatchMotionLocked(
nsecs_tcurrentTime,MotionEntry*entry,DropReason*dropReason,nsecs_t*nextWakeupTime){
//Preprocessing.
if(!entry->dispatchInProgress){
entry->dispatchInProgress=true;
resetTargetsLocked();

logOutboundMotionDetailsLocked("dispatchMotion-",entry);
}

//Cleanupifdroppingtheevent.
if(*dropReason!=DROP_REASON_NOT_DROPPED){
resetTargetsLocked();
setInjectionResultLocked(entry,*dropReason==DROP_REASON_POLICY
?INPUT_EVENT_INJECTION_SUCCEEDED:INPUT_EVENT_INJECTION_FAILED);
returntrue;
}

boolisPointerEvent=entry->source&AINPUT_SOURCE_CLASS_POINTER;

//Identifytargets.
if(!mCurrentInputTargetsValid){
int32_tinjectionResult;
if(isPointerEvent){
//Pointerevent.(eg.touchscreen)
injectionResult=findTouchedWindowTargetsLocked(currentTime,
entry,nextWakeupTime);
}else{
//Nontouchevent.(eg.trackball)
injectionResult=findFocusedWindowTargetsLocked(currentTime,
entry,nextWakeupTime);
}
if(injectionResult==INPUT_EVENT_INJECTION_PENDING){
returnfalse;
}

setInjectionResultLocked(entry,injectionResult);
if(injectionResult!=INPUT_EVENT_INJECTION_SUCCEEDED){
returntrue;
}

addMonitoringTargetsLocked();
commitTargetsLocked();
}

//Dispatchthemotion.
dispatchEventToCurrentInputTargetsLocked(currentTime,entry,false);
returntrue;
}


Java代码
startDispatchCycleLocked中的方法
status=connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
motionEntry->source,action,flags,motionEntry->edgeFlags,motionEntry->metaState,
xOffset,yOffset,
motionEntry->xPrecision,motionEntry->yPrecision,
motionEntry->downTime,firstMotionSample->eventTime,
motionEntry->pointerCount,motionEntry->pointerIds,
firstMotionSample->pointerCoords);


Java代码
ViewRoot有个InputHandler


Java代码
privatefinalInputHandlermInputHandler=newInputHandler(){
publicvoidhandleKey(KeyEventevent,RunnablefinishedCallback){
startInputEvent(finishedCallback);
dispatchKey(event,true);
}

publicvoidhandleMotion(MotionEventevent,RunnablefinishedCallback){
startInputEvent(finishedCallback);
dispatchMotion(event,true);
}
};


InputHandler注册给了系统

Java代码
InputQueue.registerInputChannel(mInputChannel,mInputHandler,
Looper.myQueue());


Java代码
dispatchMotion(event,true);方法如下
rivatevoiddispatchMotion(MotionEventevent,booleansendDone){
intsource=event.getSource();
if((source&InputDevice.SOURCE_CLASS_POINTER)!=0){
dispatchPointer(event,sendDone);
}elseif((source&InputDevice.SOURCE_CLASS_TRACKBALL)!=0){
dispatchTrackball(event,sendDone);
}else{
//TODO
Log.v(TAG,"Droppingunsupportedmotionevent(unimplemented):"+event);
if(sendDone){
finishInputEvent();
}
}
}


调用了dispatchPointer

ViewRoot本身就是Handler直接sendMessageAtTime

然后就进入了View的焦点系统。

下面就说一下Activity的焦点是怎么回事。

Java代码
InputDisapatcher.cpp中调用了如下方法

dispatchEventToCurrentInputTargetsLocked(currentTime,motionEntry,
true/*resumeWithAppendedMotionSample*/);


然后

Java代码
dispatchEventToCurrentInputTargetsLocked


调用了如下方法

Java代码
int32_tInputDispatcher::findFocusedWindowTargetsLocked(nsecs_tcurrentTime,
constEventEntry*entry,nsecs_t*nextWakeupTime){
mCurrentInputTargets.clear();

int32_tinjectionResult;

//Ifthereisnocurrentlyfocusedwindowandnofocusedapplication
//thendroptheevent.
if(!mFocusedWindow){
if(mFocusedApplication){
#ifDEBUG_FOCUS
LOGD("Waitingbecausethereisnofocusedwindowbutthereisa"
"focusedapplicationthatmayeventuallyaddawindow:%s.",
getApplicationWindowLabelLocked(mFocusedApplication,NULL).string());
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
mFocusedApplication,NULL,nextWakeupTime);
gotoUnresponsive;
}

LOGI("Droppingeventbecausethereisnofocusedwindoworfocusedapplication.");
injectionResult=INPUT_EVENT_INJECTION_FAILED;
gotoFailed;
}

//Checkpermissions.
if(!checkInjectionPermission(mFocusedWindow,entry->injectionState)){
injectionResult=INPUT_EVENT_INJECTION_PERMISSION_DENIED;
gotoFailed;
}

//Ifthecurrentlyfocusedwindowispausedthenkeepwaiting.
if(mFocusedWindow->paused){
#ifDEBUG_FOCUS
LOGD("Waitingbecausefocusedwindowispaused.");
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
mFocusedApplication,mFocusedWindow,nextWakeupTime);
gotoUnresponsive;
}

//Ifthecurrentlyfocusedwindowisstillworkingonpreviouseventsthenkeepwaiting.
if(!isWindowFinishedWithPreviousInputLocked(mFocusedWindow)){
#ifDEBUG_FOCUS
LOGD("Waitingbecausefocusedwindowstillprocessingpreviousinput.");
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
mFocusedApplication,mFocusedWindow,nextWakeupTime);
gotoUnresponsive;
}

//Success!Outputtargets.
injectionResult=INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindow,InputTarget::FLAG_FOREGROUND,BitSet32(0));

//Done.
Failed:
Unresponsive:
nsecs_ttimeSpentWaitingForApplication=getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatisticsLocked(currentTime,entry,
injectionResult,timeSpentWaitingForApplication);
#ifDEBUG_FOCUS
LOGD("findFocusedWindowfinished:injectionResult=%d,"
"timeSpendWaitingForApplication=%0.1fms",
injectionResult,timeSpentWaitingForApplication/1000000.0);
#endif
returninjectionResult;
}


move事件的处理和Down事件的处理很不相同。

新建立的Window在处理焦点的时候,按下事件没有起来之前,保持了原来的焦点窗口。除非ACTION_UP事件收到以后

Java代码
/*Updatesthecachedwindowinformationprovidedtotheinputdispatcher.*/
publicvoidupdateInputWindowsLw(){
//Populatetheinputwindowlistwithinformationaboutallofthewindowsthat
//couldpotentiallyreceiveinput.
//Asanoptimization,wecouldtrytoprunethelistofwindowsbutthisturns
//outtobedifficultbecauseonlythenativecodeknowsforsurewhichwindow
//currentlyhastouchfocus.
finalArrayList<WindowState>windows=mWindows;
finalintN=windows.size();
for(inti=N-1;i>=0;i--){
finalWindowStatechild=windows.get(i);
if(child.mInputChannel==null||child.mRemoved){
//Skipthiswindowbecauseitcannotpossiblyreceiveinput.
continue;
}

finalintflags=child.mAttrs.flags;
finalinttype=child.mAttrs.type;

finalbooleanhasFocus=(child==mInputFocus);
finalbooleanisVisible=child.isVisibleLw();
finalbooleanhasWallpaper=(child==mWallpaperTarget)
&&(type!=WindowManager.LayoutParams.TYPE_KEYGUARD);

//Addawindowtoourlistofinputwindows.
finalInputWindowinputWindow=mTempInputWindows.add();
inputWindow.inputChannel=child.mInputChannel;
inputWindow.name=child.toString();
inputWindow.layoutParamsFlags=flags;
inputWindow.layoutParamsType=type;
inputWindow.dispatchingTimeoutNanos=child.getInputDispatchingTimeoutNanos();
inputWindow.visible=isVisible;
inputWindow.canReceiveKeys=child.canReceiveKeys();
inputWindow.hasFocus=hasFocus;
inputWindow.hasWallpaper=hasWallpaper;
inputWindow.paused=child.mAppToken!=null?child.mAppToken.paused:false;
inputWindow.layer=child.mLayer;
inputWindow.ownerPid=child.mSession.mPid;
inputWindow.ownerUid=child.mSession.mUid;

finalRectframe=child.mFrame;
inputWindow.frameLeft=frame.left;
inputWindow.frameTop=frame.top;
inputWindow.frameRight=frame.right;
inputWindow.frameBottom=frame.bottom;

finalRectvisibleFrame=child.mVisibleFrame;
inputWindow.visibleFrameLeft=visibleFrame.left;
inputWindow.visibleFrameTop=visibleFrame.top;
inputWindow.visibleFrameRight=visibleFrame.right;
inputWindow.visibleFrameBottom=visibleFrame.bottom;

switch(child.mTouchableInsets){
default:
caseViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
inputWindow.touchableAreaLeft=frame.left;
inputWindow.touchableAreaTop=frame.top;
inputWindow.touchableAreaRight=frame.right;
inputWindow.touchableAreaBottom=frame.bottom;
break;

caseViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:{
Rectinset=child.mGivenContentInsets;
inputWindow.touchableAreaLeft=frame.left+inset.left;
inputWindow.touchableAreaTop=frame.top+inset.top;
inputWindow.touchableAreaRight=frame.right-inset.right;
inputWindow.touchableAreaBottom=frame.bottom-inset.bottom;
break;
}

caseViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:{
Rectinset=child.mGivenVisibleInsets;
inputWindow.touchableAreaLeft=frame.left+inset.left;
inputWindow.touchableAreaTop=frame.top+inset.top;
inputWindow.touchableAreaRight=frame.right-inset.right;
inputWindow.touchableAreaBottom=frame.bottom-inset.bottom;
break;
}
}
}

//Sendwindowstonativecode.
mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());

//Clearthelistinpreparationforthenextround.
//AlsoavoidskeepingInputChannelobjectsreferencedunnecessarily.
mTempInputWindows.clear();
}


真正的Input的控制是通过以下方式

/**
* Z-ordered (bottom-most first) list of all Window objects.
*/
final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();

Java代码
/**
*Z-ordered(bottom-mostfirst)listofallWindowobjects.
*/
finalArrayList<WindowState>mWindows=newArrayList<WindowState>();


另外的touch的target并不是通过input focus 获得的。而是通过visible来获得

Java代码
int32_tInputDispatcher::findTouchedWindowTargetsLocked(nsecs_tcurrentTime,
constMotionEntry*entry,nsecs_t*nextWakeupTime){
enumInjectionPermission{
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
INJECTION_PERMISSION_DENIED
};

mCurrentInputTargets.clear();

nsecs_tstartTime=now();

//Forsecurityreasons,wedeferupdatingthetouchstateuntilwearesurethat
//eventinjectionwillbeallowed.
//
//FIXMEIntheoriginalcode,screenWasOffcouldneverbesettotrue.
//ThereasonisthatthePOLICY_FLAG_WOKE_HERE
//andPOLICY_FLAG_BRIGHT_HEREflagsweresetonlywhenpreprocessingraw
//EV_KEY,EV_RELandEV_ABSevents.Asithappens,thetoucheventwas
//actuallyenqueuedusingthepolicyFlagsthatappearedinthefinalEV_SYN
//eventsuponwhichnopreprocessingtookplace.SopolicyFlagswasalways0.
//Inthenewnativeinputdispatcherwe'reabitmorecarefulaboutevent
//preprocessingsothetoucheswereceivecanactuallyhavenon-zeropolicyFlags.
//Unfortunatelyweobtainundesirablebehavior.
//
//Here'swhathappens:
//
//Whenthedevicedimsinanticipationofgoingtosleep,touches
//inwindowswhichhaveFLAG_TOUCHABLE_WHEN_WAKINGcause
//thedevicetobrightenandresettheuseractivitytimer.
//Touchesonotherwindows(suchasthelauncherwindow)
//aredropped.Thenafteramoment,thedevicegoestosleep.Oops.
//
//AlsonoticehowscreenWasOffwasbeinginitializedusingPOLICY_FLAG_BRIGHT_HERE
//insteadofPOLICY_FLAG_WOKE_HERE...
//
boolscreenWasOff=false;//originalpolicy:policyFlags&POLICY_FLAG_BRIGHT_HERE;

int32_taction=entry->action;
int32_tmaskedAction=action&AMOTION_EVENT_ACTION_MASK;

//Updatethetouchstateasneededbasedonthepropertiesofthetouchevent.
int32_tinjectionResult=INPUT_EVENT_INJECTION_PENDING;
InjectionPermissioninjectionPermission=INJECTION_PERMISSION_UNKNOWN;
if(maskedAction==AMOTION_EVENT_ACTION_DOWN){
mTempTouchState.reset();
mTempTouchState.down=true;
}else{
mTempTouchState.copyFrom(mTouchState);
}

boolisSplit=mTempTouchState.split&&mTempTouchState.down;
if(maskedAction==AMOTION_EVENT_ACTION_DOWN
||(isSplit&&maskedAction==AMOTION_EVENT_ACTION_POINTER_DOWN)){
/*Case1:Newsplittablepointergoingdown.*/

int32_tpointerIndex=getMotionEventActionPointerIndex(action);
int32_tx=int32_t(entry->firstSample.pointerCoords[pointerIndex].x);
int32_ty=int32_t(entry->firstSample.pointerCoords[pointerIndex].y);
constInputWindow*newTouchedWindow=NULL;
constInputWindow*topErrorWindow=NULL;

//Traversewindowsfromfronttobacktofindtouchedwindowandoutsidetargets.
size_tnumWindows=mWindows.size();
for(size_ti=0;i<numWindows;i++){
constInputWindow*window=&mWindows.editItemAt(i);
int32_tflags=window->layoutParamsFlags;

if(flags&InputWindow::FLAG_SYSTEM_ERROR){
if(!topErrorWindow){
topErrorWindow=window;
}
}

if(window->visible){
if(!(flags&InputWindow::FLAG_NOT_TOUCHABLE)){
boolisTouchModal=(flags&(InputWindow::FLAG_NOT_FOCUSABLE
|InputWindow::FLAG_NOT_TOUCH_MODAL))==0;
if(isTouchModal||window->touchableAreaContainsPoint(x,y)){
if(!screenWasOff||flags&InputWindow::FLAG_TOUCHABLE_WHEN_WAKING){
newTouchedWindow=window;
}
break;//foundtouchedwindow,exitwindowloop
}
}

if(maskedAction==AMOTION_EVENT_ACTION_DOWN
&&(flags&InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)){
int32_toutsideTargetFlags=InputTarget::FLAG_OUTSIDE;
if(isWindowObscuredAtPointLocked(window,x,y)){
outsideTargetFlags|=InputTarget::FLAG_WINDOW_IS_OBSCURED;
}

mTempTouchState.addOrUpdateWindow(window,outsideTargetFlags,BitSet32(0));
}
}
}

//Ifthereisanerrorwindowbutitisnottakingfocus(typicallybecause
//itisinvisible)thenwaitforit.Anyotherfocusedwindowmayin
//factbeinANRstate.
if(topErrorWindow&&newTouchedWindow!=topErrorWindow){
#ifDEBUG_FOCUS
LOGD("Waitingbecausesystemerrorwindowispending.");
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
NULL,NULL,nextWakeupTime);
injectionPermission=INJECTION_PERMISSION_UNKNOWN;
gotoUnresponsive;
}

//Figureoutwhethersplittingwillbeallowedforthiswindow.
if(newTouchedWindow
&&(newTouchedWindow->layoutParamsFlags&InputWindow::FLAG_SPLIT_TOUCH)){
//Newwindowsupportssplitting.
isSplit=true;
}elseif(isSplit){
//Newwindowdoesnotsupportsplittingbutwehavealreadysplitevents.
//Assignthepointertothefirstforegroundwindowwefind.
//(MaybeNULLwhichiswhyweputthiscodeblockbeforethenextcheck.)
newTouchedWindow=mTempTouchState.getFirstForegroundWindow();
}

//Ifwedidnotfindatouchedwindowthenfail.
if(!newTouchedWindow){
if(mFocusedApplication){
#ifDEBUG_FOCUS
LOGD("Waitingbecausethereisnotouchedwindowbutthereisa"
"focusedapplicationthatmayeventuallyaddanewwindow:%s.",
getApplicationWindowLabelLocked(mFocusedApplication,NULL).string());
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
mFocusedApplication,NULL,nextWakeupTime);
gotoUnresponsive;
}

LOGI("Droppingeventbecausethereisnotouchedwindoworfocusedapplication.");
injectionResult=INPUT_EVENT_INJECTION_FAILED;
gotoFailed;
}

//Settargetflags.
int32_ttargetFlags=InputTarget::FLAG_FOREGROUND;
if(isSplit){
targetFlags|=InputTarget::FLAG_SPLIT;
}
if(isWindowObscuredAtPointLocked(newTouchedWindow,x,y)){
targetFlags|=InputTarget::FLAG_WINDOW_IS_OBSCURED;
}

//Updatethetemporarytouchstate.
BitSet32pointerIds;
if(isSplit){
uint32_tpointerId=entry->pointerIds[pointerIndex];
pointerIds.markBit(pointerId);
}
mTempTouchState.addOrUpdateWindow(newTouchedWindow,targetFlags,pointerIds);
}else{
/*Case2:Pointermove,up,cancelornon-splittablepointerdown.*/

//Ifthepointerisnotcurrentlydown,thenignoretheevent.
if(!mTempTouchState.down){
LOGI("Droppingeventbecausethepointerisnotdown.");
injectionResult=INPUT_EVENT_INJECTION_FAILED;
gotoFailed;
}
}

//Checkpermissiontoinjectintoalltouchedforegroundwindowsandensurethere
//isatleastonetouchedforegroundwindow.
{
boolhaveForegroundWindow=false;
for(size_ti=0;i<mTempTouchState.windows.size();i++){
constTouchedWindow&touchedWindow=mTempTouchState.windows[i];
if(touchedWindow.targetFlags&InputTarget::FLAG_FOREGROUND){
haveForegroundWindow=true;
if(!checkInjectionPermission(touchedWindow.window,entry->injectionState)){
injectionResult=INPUT_EVENT_INJECTION_PERMISSION_DENIED;
injectionPermission=INJECTION_PERMISSION_DENIED;
gotoFailed;
}
}
}
if(!haveForegroundWindow){
#ifDEBUG_INPUT_DISPATCHER_POLICY
LOGD("Droppingeventbecausethereisnotouchedforegroundwindowtoreceiveit.");
#endif
injectionResult=INPUT_EVENT_INJECTION_FAILED;
gotoFailed;
}

//Permissiongrantedtoinjectionintoalltouchedforegroundwindows.
injectionPermission=INJECTION_PERMISSION_GRANTED;
}

//Ensurealltouchedforegroundwindowsarereadyfornewinput.
for(size_ti=0;i<mTempTouchState.windows.size();i++){
constTouchedWindow&touchedWindow=mTempTouchState.windows[i];
if(touchedWindow.targetFlags&InputTarget::FLAG_FOREGROUND){
//Ifthetouchedwindowispausedthenkeepwaiting.
if(touchedWindow.window->paused){
#ifDEBUG_INPUT_DISPATCHER_POLICY
LOGD("Waitingbecausetouchedwindowispaused.");
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
NULL,touchedWindow.window,nextWakeupTime);
gotoUnresponsive;
}

//Ifthetouchedwindowisstillworkingonpreviouseventsthenkeepwaiting.
if(!isWindowFinishedWithPreviousInputLocked(touchedWindow.window)){
#ifDEBUG_FOCUS
LOGD("Waitingbecausetouchedwindowstillprocessingpreviousinput.");
#endif
injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
NULL,touchedWindow.window,nextWakeupTime);
gotoUnresponsive;
}
}
}

//Ifthisisthefirstpointergoingdownandthetouchedwindowhasawallpaper
//thenalsoaddthetouchedwallpaperwindowssotheyarelockedinfortheduration
//ofthetouchgesture.
if(maskedAction==AMOTION_EVENT_ACTION_DOWN){
constInputWindow*foregroundWindow=mTempTouchState.getFirstForegroundWindow();
if(foregroundWindow->hasWallpaper){
for(size_ti=0;i<mWindows.size();i++){
constInputWindow*window=&mWindows[i];
if(window->layoutParamsType==InputWindow::TYPE_WALLPAPER){
mTempTouchState.addOrUpdateWindow(window,
InputTarget::FLAG_WINDOW_IS_OBSCURED,BitSet32(0));
}
}
}
}

//Success!Outputtargets.
injectionResult=INPUT_EVENT_INJECTION_SUCCEEDED;

for(size_ti=0;i<mTempTouchState.windows.size();i++){
constTouchedWindow&touchedWindow=mTempTouchState.windows.itemAt(i);
addWindowTargetLocked(touchedWindow.window,touchedWindow.targetFlags,
touchedWindow.pointerIds);
}

//Droptheoutsidetouchwindowsincewewillnotcareabouttheminthenextiteration.
mTempTouchState.removeOutsideTouchWindows();

Failed:
//Checkinjectionpermissiononceandforall.
if(injectionPermission==INJECTION_PERMISSION_UNKNOWN){
if(checkInjectionPermission(NULL,entry->injectionState)){
injectionPermission=INJECTION_PERMISSION_GRANTED;
}else{
injectionPermission=INJECTION_PERMISSION_DENIED;
}
}

//Updatefinalpiecesoftouchstateiftheinjectorhadpermission.
if(injectionPermission==INJECTION_PERMISSION_GRANTED){
if(maskedAction==AMOTION_EVENT_ACTION_UP
||maskedAction==AMOTION_EVENT_ACTION_CANCEL){
//Allpointersuporcanceled.
mTempTouchState.reset();
}elseif(maskedAction==AMOTION_EVENT_ACTION_DOWN){
//Firstpointerwentdown.
if(mTouchState.down){
#ifDEBUG_FOCUS
LOGD("Pointerdownreceivedwhilealreadydown.");
#endif
}
}elseif(maskedAction==AMOTION_EVENT_ACTION_POINTER_UP){
//Onepointerwentup.
if(isSplit){
int32_tpointerIndex=getMotionEventActionPointerIndex(action);
uint32_tpointerId=entry->pointerIds[pointerIndex];

for(size_ti=0;i<mTempTouchState.windows.size();){
TouchedWindow&touchedWindow=mTempTouchState.windows.editItemAt(i);
if(touchedWindow.targetFlags&InputTarget::FLAG_SPLIT){
touchedWindow.pointerIds.clearBit(pointerId);
if(touchedWindow.pointerIds.isEmpty()){
mTempTouchState.windows.removeAt(i);
continue;
}
}
i+=1;
}
}
}

//Savechangestotouchstate.
mTouchState.copyFrom(mTempTouchState);
}else{
#ifDEBUG_FOCUS
LOGD("Notupdatingtouchfocusbecauseinjectionwasdenied.");
#endif
}

Unresponsive:
//Resettemporarytouchstatetoensurewereleaseunnecessaryreferencestoinputchannels.
mTempTouchState.reset();

nsecs_ttimeSpentWaitingForApplication=getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatisticsLocked(currentTime,entry,
injectionResult,timeSpentWaitingForApplication);
#ifDEBUG_FOCUS
LOGD("findTouchedWindowfinished:injectionResult=%d,injectionPermission=%d,"
"timeSpentWaitingForApplication=%0.1fms",
injectionResult,injectionPermission,timeSpentWaitingForApplication/1000000.0);
#endif
returninjectionResult;
}


最关键的几行代码,说明了Windows是如何找到触屏的输入焦点的:

Cpp代码
if(window->visible){
if(!(flags&InputWindow::FLAG_NOT_TOUCHABLE)){
boolisTouchModal=(flags&(InputWindow::FLAG_NOT_FOCUSABLE
|InputWindow::FLAG_NOT_TOUCH_MODAL))==0;
if(isTouchModal||window->touchableAreaContainsPoint(x,y)){
if(!screenWasOff||flags&InputWindow::FLAG_TOUCHABLE_WHEN_WAKING){
newTouchedWindow=window;
}
break;//foundtouchedwindow,exitwindowloop
}
}

if(maskedAction==AMOTION_EVENT_ACTION_DOWN
&&(flags&InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)){
int32_toutsideTargetFlags=InputTarget::FLAG_OUTSIDE;
if(isWindowObscuredAtPointLocked(window,x,y)){
outsideTargetFlags|=InputTarget::FLAG_WINDOW_IS_OBSCURED;
}

mTempTouchState.addOrUpdateWindow(window,outsideTargetFlags,BitSet32(0));
}
}


Java代码
//Focustrackingfortouch.
structTouchedWindow{
constInputWindow*window;
int32_ttargetFlags;
BitSet32pointerIds;
sp<InputChannel>channel;
};
structTouchState{
booldown;
boolsplit;
Vector<TouchedWindow>windows;

TouchState();
~TouchState();
voidreset();
voidcopyFrom(constTouchState&other);
voidaddOrUpdateWindow(constInputWindow*window,int32_ttargetFlags,BitSet32pointerIds);
voidremoveOutsideTouchWindows();
constInputWindow*getFirstForegroundWindow();
};



另外如何定义按键和其他触屏焦点的:


/*Updatesthecachedwindowinformationprovidedtotheinputdispatcher.*/
publicvoidupdateInputWindowsLw(){
//Populatetheinputwindowlistwithinformationaboutallofthewindowsthat
//couldpotentiallyreceiveinput.
//Asanoptimization,wecouldtrytoprunethelistofwindowsbutthisturns
//outtobedifficultbecauseonlythenativecodeknowsforsurewhichwindow
//currentlyhastouchfocus.
finalArrayList<WindowState>windows=mWindows;
finalintN=windows.size();
for(inti=N-1;i>=0;i--){
finalWindowStatechild=windows.get(i);
if(child.mInputChannel==null||child.mRemoved){
//Skipthiswindowbecauseitcannotpossiblyreceiveinput.
continue;
}

finalintflags=child.mAttrs.flags;
finalinttype=child.mAttrs.type;

<spanstyle="color:#ff6600;">finalbooleanhasFocus=(child==mInputFocus);</span>
//本行代码确定,一次性的focusWindow只有一个。
finalbooleanisVisible=child.isVisibleLw();
finalbooleanhasWallpaper=(child==mWallpaperTarget)
&&(type!=WindowManager.LayoutParams.TYPE_KEYGUARD);




相关评论