break;
case com.android.internal.R.styleable.View_focusableInTouchMode:
if (a.getBoolean(attr, false)) {
+ // unset auto focus since focusableInTouchMode implies explicit focusable
+ viewFlagValues &= ~FOCUSABLE_AUTO;
viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE;
viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK;
}
}
}
}
+
+ // Invisible and gone views are never focusable.
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
- return (allowAutoFocus
- ? getFocusable() != NOT_FOCUSABLE
- : getFocusable() == FOCUSABLE) && isFocusable();
+
+ // Only use effective focusable value when allowed.
+ if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
+ return true;
+ }
+
+ return false;
}
/**
// which, in touch mode, will not successfully request focus on this view
// because the focusable in touch mode flag is not set
setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE);
+
+ // Clear FOCUSABLE_AUTO if set.
if (focusableInTouchMode) {
+ // Clears FOCUSABLE_AUTO if set.
setFlags(FOCUSABLE, FOCUSABLE_MASK);
}
}
// If focusable is auto, update the FOCUSABLE bit.
int focusableChangedByAuto = 0;
if (((mViewFlags & FOCUSABLE_AUTO) != 0)
- && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
- int newFocus = NOT_FOCUSABLE;
- if ((mViewFlags & (CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
+ && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) {
+ // Heuristic only takes into account whether view is clickable.
+ final int newFocus;
+ if ((mViewFlags & CLICKABLE) != 0) {
newFocus = FOCUSABLE;
} else {
- mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE);
+ newFocus = NOT_FOCUSABLE;
}
mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus;
focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE);
@Override
boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
+ // This should probably be super.hasFocusable, but that would change
+ // behavior. Historically, we have not checked the ancestor views for
+ // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
+
+ // Invisible and gone views are never focusable.
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
- // TODO This should probably be super.hasFocusable, but that would change behavior.
- // The below is a much simpler check than we do in the superclass implementation,
- // but it's been this way for a long time and other code likely relies on it.
- if ((allowAutoFocus ? getFocusable() != NOT_FOCUSABLE : getFocusable() == FOCUSABLE)
- && isFocusable()) {
+ // Only use effective focusable value when allowed.
+ if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
return true;
}
+ // Determine whether we have a focused descendant.
final int descendantFocusability = getDescendantFocusability();
if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
final int count = mChildrenCount;