protectedintonProcess(QueuedInputEventq){if(q.mEventinstanceofKeyEvent){returnprocessKeyEvent(q);}else{// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();finalintsource=q.mEvent.getSource();if((source&InputDevice.SOURCE_CLASS_POINTER)!=0){returnprocessPointerEvent(q);}elseif((source&InputDevice.SOURCE_CLASS_TRACKBALL)!=0){returnprocessTrackballEvent(q);}else{returnprocessGenericMotionEvent(q);}}}
privateintprocessKeyEvent(QueuedInputEventq){finalKeyEventevent=(KeyEvent)q.mEvent;// Deliver the key to the view hierarchy.if(mView.dispatchKeyEvent(event)){returnFINISH_HANDLED;}// Handle automatic focus changes.if(event.getAction()==KeyEvent.ACTION_DOWN){intdirection=0;switch(event.getKeyCode()){caseKeyEvent.KEYCODE_DPAD_LEFT:if(event.hasNoModifiers()){direction=View.FOCUS_LEFT;}break;caseKeyEvent.KEYCODE_DPAD_RIGHT:if(event.hasNoModifiers()){direction=View.FOCUS_RIGHT;}break;caseKeyEvent.KEYCODE_DPAD_UP:if(event.hasNoModifiers()){direction=View.FOCUS_UP;}break;caseKeyEvent.KEYCODE_DPAD_DOWN:if(event.hasNoModifiers()){direction=View.FOCUS_DOWN;}break;caseKeyEvent.KEYCODE_TAB:if(event.hasNoModifiers()){direction=View.FOCUS_FORWARD;}elseif(event.hasModifiers(KeyEvent.META_SHIFT_ON)){direction=View.FOCUS_BACKWARD;}break;}if(direction!=0){Viewfocused=mView.findFocus();if(focused!=null){Viewv=focused.focusSearch(direction);if(v!=null&&v!=focused){// do the math the get the interesting rect// of previous focused into the coord system of// newly focused viewfocused.getFocusedRect(mTempRect);if(mViewinstanceofViewGroup){((ViewGroup)mView).offsetDescendantRectToMyCoords(focused,mTempRect);((ViewGroup)mView).offsetRectIntoDescendantCoords(v,mTempRect);}if(v.requestFocus(direction,mTempRect)){playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));returnFINISH_HANDLED;}}// Give the focused view a last chance to handle the dpad key.if(mView.dispatchUnhandledMove(focused,direction)){returnFINISH_HANDLED;}}else{// find the best view to give focus to in this non-touch-mode with no-focusViewv=focusSearch(null,direction);if(v!=null&&v.requestFocus(direction)){returnFINISH_HANDLED;}}}}returnFORWARD;}
publicbooleandispatchKeyEvent(KeyEventevent){onUserInteraction();// Let action bars open menus in response to the menu key prioritized over// the window handling itif(event.getKeyCode()==KeyEvent.KEYCODE_MENU&&mActionBar!=null&&mActionBar.onMenuKeyEvent(event)){returntrue;}Windowwin=getWindow();if(win.superDispatchKeyEvent(event)){returntrue;}Viewdecor=mDecor;if(decor==null)decor=win.getDecorView();returnevent.dispatch(this,decor!=null?decor.getKeyDispatcherState():null,this);}
public void requestChildFocus(View child, View focused) {
if (DBG) {
System.out.println(this + " requestChildFocus()");
}
if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
return;
}
// Unfocus us, if necessary
super.unFocus(focused);
// We had a previous notion of who had focus. Clear it.
if (mFocused != child) {
if (mFocused != null) {
mFocused.unFocus(focused);
}
mFocused = child;
}
if (mParent != null) {
mParent.requestChildFocus(this, focused);
}
}
publicbooleandispatchKeyEvent(KeyEventevent){// Give any attached key listener a first crack at the event.//noinspection SimplifiableIfStatementListenerInfoli=mListenerInfo;if(li!=null&&li.mOnKeyListener!=null&&(mViewFlags&ENABLED_MASK)==ENABLED&&li.mOnKeyListener.onKey(this,event.getKeyCode(),event)){returntrue;}if(event.dispatch(this,mAttachInfo!=null?mAttachInfo.mKeyDispatchState:null,this)){returntrue;}returnfalse;}
publicbooleanonKeyUp(intkeyCode,KeyEventevent){if(KeyEvent.isConfirmKey(keyCode)){if((mViewFlags&ENABLED_MASK)==DISABLED){returntrue;}if((mViewFlags&CLICKABLE)==CLICKABLE&&isPressed()){setPressed(false);if(!mHasPerformedLongPress){// This is a tap, so remove the longpress checkremoveLongPressCallback();returnperformClick();}}}returnfalse;}
privateintprocessKeyEvent(QueuedInputEventq){finalKeyEventevent=(KeyEvent)q.mEvent;// 1.Deliver the key to the view hierarchy.if(mView.dispatchKeyEvent(event)){returnFINISH_HANDLED;}// 2.Handle automatic focus changes.if(event.getAction()==KeyEvent.ACTION_DOWN){intdirection=0;switch(event.getKeyCode()){caseKeyEvent.KEYCODE_DPAD_LEFT:if(event.hasNoModifiers()){direction=View.FOCUS_LEFT;}break;caseKeyEvent.KEYCODE_DPAD_RIGHT:if(event.hasNoModifiers()){direction=View.FOCUS_RIGHT;}break;caseKeyEvent.KEYCODE_DPAD_UP:if(event.hasNoModifiers()){direction=View.FOCUS_UP;}break;caseKeyEvent.KEYCODE_DPAD_DOWN:if(event.hasNoModifiers()){direction=View.FOCUS_DOWN;}break;caseKeyEvent.KEYCODE_TAB:if(event.hasNoModifiers()){direction=View.FOCUS_FORWARD;}elseif(event.hasModifiers(KeyEvent.META_SHIFT_ON)){direction=View.FOCUS_BACKWARD;}break;}if(direction!=0){Viewfocused=mView.findFocus();if(focused!=null){Viewv=focused.focusSearch(direction);if(v!=null&&v!=focused){// do the math the get the interesting rect// of previous focused into the coord system of// newly focused viewfocused.getFocusedRect(mTempRect);if(mViewinstanceofViewGroup){((ViewGroup)mView).offsetDescendantRectToMyCoords(focused,mTempRect);((ViewGroup)mView).offsetRectIntoDescendantCoords(v,mTempRect);}if(v.requestFocus(direction,mTempRect)){playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));returnFINISH_HANDLED;}}}else{// find the best view to give focus to in this non-touch-mode with no-focusViewv=focusSearch(null,direction);if(v!=null&&v.requestFocus(direction)){returnFINISH_HANDLED;}}}}returnFORWARD;}
if(direction!=0){Viewfocused=mView.findFocus();if(focused!=null){Viewv=focused.focusSearch(direction);if(v!=null&&v!=focused){// do the math the get the interesting rect// of previous focused into the coord system of// newly focused viewfocused.getFocusedRect(mTempRect);if(mViewinstanceofViewGroup){((ViewGroup)mView).offsetDescendantRectToMyCoords(focused,mTempRect);((ViewGroup)mView).offsetRectIntoDescendantCoords(v,mTempRect);}if(v.requestFocus(direction,mTempRect)){playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));returnFINISH_HANDLED;}}}else{// find the best view to give focus to in this non-touch-mode with no-focusViewv=focusSearch(null,direction);if(v!=null&&v.requestFocus(direction)){returnFINISH_HANDLED;}}}
publicViewfocusSearch(Viewfocused,intdirection){if(isRootNamespace()){// root namespace means we should consider ourselves the top of the// tree for focus searching; otherwise we could be focus searching// into other tabs. see LocalActivityManager and TabHost for more inforeturnFocusFinder.getInstance().findNextFocus(this,focused,direction);}elseif(mParent!=null){returnmParent.focusSearch(focused,direction);}returnnull;}
publicvoidaddFocusables(ArrayList<View>views,intdirection,intfocusableMode){finalintfocusableCount=views.size();finalintdescendantFocusability=getDescendantFocusability();if(descendantFocusability!=FOCUS_BLOCK_DESCENDANTS){finalintcount=mChildrenCount;finalView[]children=mChildren;for(inti=0;i<count;i++){finalViewchild=children[i];if((child.mViewFlags&VISIBILITY_MASK)==VISIBLE){child.addFocusables(views,direction,focusableMode);}}}if(descendantFocusability!=FOCUS_AFTER_DESCENDANTS// No focusable descendants||focusableCount==views.size()){super.addFocusables(views,direction,focusableMode);}}
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
int descendantFocusability = getDescendantFocusability();
switch (descendantFocusability) {
case FOCUS_BLOCK_DESCENDANTS:
return super.requestFocus(direction, previouslyFocusedRect);
case FOCUS_BEFORE_DESCENDANTS: {
final boolean took = super.requestFocus(direction, previouslyFocusedRect);
return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
case FOCUS_AFTER_DESCENDANTS: {
final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
return took ? took : super.requestFocus(direction, previouslyFocusedRect);
}
default:
throw new IllegalStateException("descendant focusability must be "
+ "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
+ "but is " + descendantFocusability);
}
}
privateViewfindNextFocus(ViewGrouproot,Viewfocused,RectfocusedRect,intdirection,ArrayList<View>focusables){if(focused!=null){if(focusedRect==null){focusedRect=mFocusedRect;}// fill in interesting rect from focused//获取焦点View的坐标focused.getFocusedRect(focusedRect);//将焦点View的坐标转换为root坐标系的坐标root.offsetDescendantRectToMyCoords(focused,focusedRect);}else{//省略...}switch(direction){caseView.FOCUS_FORWARD:caseView.FOCUS_BACKWARD:returnfindNextFocusInRelativeDirection(focusables,root,focused,focusedRect,direction);caseView.FOCUS_UP:caseView.FOCUS_DOWN:caseView.FOCUS_LEFT:caseView.FOCUS_RIGHT:returnfindNextFocusInAbsoluteDirection(focusables,root,focused,focusedRect,direction);default:thrownewIllegalArgumentException("Unknown direction: "+direction);}}
ViewfindNextFocusInAbsoluteDirection(ArrayList<View>focusables,ViewGrouproot,Viewfocused,RectfocusedRect,intdirection){// initialize the best candidate to something impossible// (so the first plausible view will become the best choice)//1.先把把矩形设置成最差的情况,在接下来的匹配中被替换掉。mBestCandidateRect.set(focusedRect);switch(direction){caseView.FOCUS_LEFT:mBestCandidateRect.offset(focusedRect.width()+1,0);break;caseView.FOCUS_RIGHT:mBestCandidateRect.offset(-(focusedRect.width()+1),0);break;caseView.FOCUS_UP:mBestCandidateRect.offset(0,focusedRect.height()+1);break;caseView.FOCUS_DOWN:mBestCandidateRect.offset(0,-(focusedRect.height()+1));}Viewclosest=null;//2.遍历focusables,找到最接近的ViewintnumFocusables=focusables.size();for(inti=0;i<numFocusables;i++){Viewfocusable=focusables.get(i);// only interested in other non-root viewsif(focusable==focused||focusable==root)continue;// get focus bounds of other view in same coordinate systemfocusable.getFocusedRect(mOtherRect);root.offsetDescendantRectToMyCoords(focusable,mOtherRect);if(isBetterCandidate(direction,focusedRect,mOtherRect,mBestCandidateRect)){mBestCandidateRect.set(mOtherRect);closest=focusable;}}returnclosest;}
booleanisBetterCandidate(intdirection,Rectsource,Rectrect1,Rectrect2){// to be a better candidate, need to at least be a candidate in the first// place :)if(!isCandidate(source,rect1,direction)){returnfalse;}// we know that rect1 is a candidate.. if rect2 is not a candidate,// rect1 is betterif(!isCandidate(source,rect2,direction)){returntrue;}// if rect1 is better by beam, it winsif(beamBeats(direction,source,rect1,rect2)){returntrue;}// if rect2 is better, then rect1 cant' be :)if(beamBeats(direction,source,rect2,rect1)){returnfalse;}// otherwise, do fudge-tastic comparison of the major and minor axisreturn(getWeightedDistanceFor(majorAxisDistance(direction,source,rect1),minorAxisDistance(direction,source,rect1))<getWeightedDistanceFor(majorAxisDistance(direction,source,rect2),minorAxisDistance(direction,source,rect2)));}