privateintprocessKeyEvent(QueuedInputEvent q) {
......
// Deliver the key to the view hierarchy.if (mView.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
if (shouldDropInputEvent(q)) {
return FINISH_NOT_HANDLED;
......
// Handle automatic focus changes.// 转换成焦点事件if (event.getAction() == KeyEvent.ACTION_DOWN) {
intdirection=0;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
if (event.hasNoModifiers()) {
direction = View.FOCUS_LEFT;
break;
.....
if (direction != 0) {
// 查找当前获焦的ViewViewfocused= mView.findFocus();
if (focused != null) {
// 查找下一个获焦的ViewViewv= 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 view// 计算当前获焦的View的位置
focused.getFocusedRect(mTempRect);
if (mView instanceof ViewGroup) {
((ViewGroup) mView).offsetDescendantRectToMyCoords(
focused, mTempRect);
((ViewGroup) mView).offsetRectIntoDescendantCoords(
v, mTempRect);
// 尝试分发焦点给下一个获焦的Viewif (v.requestFocus(direction, mTempRect)) {
playSoundEffect(SoundEffectConstants
.getContantForFocusDirection(direction));
return FINISH_HANDLED;
// Give the focused view a last chance to handle the dpad key.// 最后的善后机会if (mView.dispatchUnhandledMove(focused, direction)) {
return FINISH_HANDLED;
} else {
// find the best view to give focus to in this non-touch-mode with no-focus// 当前无获焦的View,则默认查找原点为(0, 0)Viewv= focusSearch(null, direction);
// 直接尝试将焦点分发给找到的Viewif (v != null && v.requestFocus(direction)) {
return FINISH_HANDLED;
return FORWARD;
publicbooleanrequestFocus(int direction, Rect previouslyFocusedRect) {
return requestFocusNoSearch(direction, previouslyFocusedRect);
privatebooleanrequestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusableif ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
(mViewFlags & VISIBILITY_MASK) != VISIBLE) {
returnfalse;
// need to be focusable in touch mode if in touch modeif (isInTouchMode() &&
(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
returnfalse;
// need to not have any parents blocking usif (hasAncestorThatBlocksDescendantFocus()) {
returnfalse;
handleFocusGainInternal(direction, previouslyFocusedRect);
returntrue;
protectedbooleanonRequestFocusInDescendants(int direction,
Rect previouslyFocusedRect) {
int index;
int increment;
int end;
intcount= mChildrenCount;
if ((direction & FOCUS_FORWARD) != 0) {
index = 0;
increment = 1;
end = count;
} else {
index = count - 1;
increment = -1;
end = -1;
final View[] children = mChildren;
for (inti= index; i != end; i += increment) {
Viewchild= children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
if (child.requestFocus(direction, previouslyFocusedRect)) {
returntrue;
returnfalse;
voidsetFlags(int flags, int mask) {
finalbooleanaccessibilityEnabled=
AccessibilityManager.getInstance(mContext).isEnabled();
finalbooleanoldIncludeForAccessibility= accessibilityEnabled && includeForAccessibility();
intold= mViewFlags;
mViewFlags = (mViewFlags & ~mask) | (flags & mask);
intchanged= mViewFlags ^ old;
if (changed == 0) {
return;
intprivateFlags= mPrivateFlags;
// 检查可获焦状态是否改变/* Check if the FOCUSABLE bit has changed */if (((changed & FOCUSABLE_MASK) != 0) &&
((privateFlags & PFLAG_HAS_BOUNDS) !=0)) {
if (((old & FOCUSABLE_MASK) == FOCUSABLE)
&& ((privateFlags & PFLAG_FOCUSED) != 0)) {
/* Give up focus if we are no longer focusable */
clearFocus();
} elseif (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE)
&& ((privateFlags & PFLAG_FOCUSED) == 0)) {
* Tell the view system that we are now available to take focus
* if no one else already has it.
if (mParent != null) mParent.focusableViewAvailable(this);
// 检查可见状态是否改变finalintnewVisibility= flags & VISIBILITY_MASK;
if (newVisibility == VISIBLE) {
if ((changed & VISIBILITY_MASK) != 0) {
* If this view is becoming visible, invalidate it in case it changed while
* it was not visible. Marking it drawn ensures that the invalidation will
* go through.
mPrivateFlags |= PFLAG_DRAWN;
invalidate(true);
needGlobalAttributesUpdate(true);
// a view becoming visible is worth notifying the parent// about in case nothing has focus. even if this specific view// isn't focusable, it may contain something that is, so let// the root view try to give this focus if nothing else does.if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) {
mParent.focusableViewAvailable(this);
.....
publicvoidfocusableViewAvailable(View v) {
if (mParent != null// shortcut: don't report a new focusable view if we block our descendants from// getting focus
&& (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
&& (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
// shortcut: don't report a new focusable view if we already are focused// (and we don't prefer our descendants)// note: knowing that mFocused is non-null is not a good enough reason// to break the traversal since in that case we'd actually have to find// the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and// an ancestor of v; this will get checked for at ViewAncestor
&& !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
mParent.focusableViewAvailable(v);
@OverridepublicvoidfocusableViewAvailable(View v) {
checkThread();
if (mView != null) {
if (!mView.hasFocus()) {
v.requestFocus();
} else {
// the one case where will transfer focus away from the current one// is if the current view is a view group that prefers to give focus// to its children first AND the view is a descendant of it.Viewfocused= mView.findFocus();
if (focused instanceof ViewGroup) {
ViewGroupgroup= (ViewGroup) focused;
if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
&& isViewDescendantOf(v, focused)) {
v.requestFocus();