diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 20f2c36d242b7..e12c0b0d93b84 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4163,11 +4163,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sUseDefaultFocusHighlight; - /** - * True if zero-sized views can be focused. - */ - private static boolean sCanFocusZeroSized; - private String mTransitionName; static class TintInfo { @@ -4748,8 +4743,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sUseDefaultFocusHighlight = context.getResources().getBoolean( com.android.internal.R.bool.config_useDefaultFocusHighlight); - sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; - sCompatibilityDone = true; } } @@ -6957,7 +6950,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, void clearFocusInternal(View focused, boolean propagate, boolean refocus) { if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { mPrivateFlags &= ~PFLAG_FOCUSED; - clearParentsWantFocus(); if (propagate && mParent != null) { mParent.clearChildFocus(this); @@ -10939,9 +10931,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * descendants. * * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns - * false), or if it can't be focused due to other conditions (not focusable in touch mode - * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not - * enabled, or has no size). + * false), or if it is focusable and it is not focusable in touch mode + * ({@link #isFocusableInTouchMode}) while the device is in touch mode. * * See also {@link #focusSearch(int)}, which is what you call to say that you * have focus, and you want your parent to look for the next one. @@ -10979,17 +10970,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @TestApi public boolean restoreFocusNotInCluster() { - return requestFocus(); + return requestFocus(View.FOCUS_DOWN); } /** * Gives focus to the default-focus view in the view hierarchy that has this view as a root. - * If the default-focus view cannot be found, falls back to calling {@link #requestFocus()}. + * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. * * @return Whether this view or one of its descendants actually took focus */ public boolean restoreDefaultFocus() { - return requestFocus(); + return requestFocus(View.FOCUS_DOWN); } /** @@ -11048,7 +11039,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { // need to be focusable - if (!canTakeFocus()) { + if ((mViewFlags & FOCUSABLE) != FOCUSABLE + || (mViewFlags & VISIBILITY_MASK) != VISIBLE + || (mViewFlags & ENABLED_MASK) != ENABLED) { return false; } @@ -11063,21 +11056,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } - if (!isLaidOut()) { - mPrivateFlags |= PFLAG_WANTS_FOCUS; - } - handleFocusGainInternal(direction, previouslyFocusedRect); return true; } - void clearParentsWantFocus() { - if (mParent instanceof View) { - ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; - ((View) mParent).clearParentsWantFocus(); - } - } - /** * Call this to try to give focus to a specific view or to one of its descendants. This is a * special variant of {@link #requestFocus() } that will allow views that are not focusable in @@ -13449,13 +13431,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo.mUnbufferedDispatchRequested = true; } - private boolean canTakeFocus() { - return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) - && ((mViewFlags & FOCUSABLE) == FOCUSABLE) - && ((mViewFlags & ENABLED_MASK) == ENABLED) - && (sCanFocusZeroSized || !isLaidOut() || (mBottom > mTop) && (mRight > mLeft)); - } - /** * Set flags controlling behavior of this view. * @@ -13475,7 +13450,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return; } int privateFlags = mPrivateFlags; - boolean shouldNotifyFocusableAvailable = false; // If focusable is auto, update the FOCUSABLE bit. int focusableChangedByAuto = 0; @@ -13514,7 +13488,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { - shouldNotifyFocusableAvailable = true; + mParent.focusableViewAvailable(this); } } } @@ -13537,7 +13511,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // 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. - shouldNotifyFocusableAvailable = true; + if ((mParent != null) && ((mViewFlags & ENABLED_MASK) == ENABLED) + && (mBottom > mTop) && (mRight > mLeft)) { + mParent.focusableViewAvailable(this); + } } } @@ -13546,18 +13523,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // a view becoming enabled should notify the parent as long as the view is also // visible and the parent wasn't already notified by becoming visible during this // setFlags invocation. - shouldNotifyFocusableAvailable = true; + if ((mViewFlags & VISIBILITY_MASK) == VISIBLE + && ((changed & VISIBILITY_MASK) == 0)) { + if ((mParent != null) && (mViewFlags & ENABLED_MASK) == ENABLED) { + mParent.focusableViewAvailable(this); + } + } } else { if (hasFocus()) clearFocus(); } } - if (shouldNotifyFocusableAvailable) { - if (mParent != null && canTakeFocus()) { - mParent.focusableViewAvailable(this); - } - } - /* Check if the GONE bit has changed */ if ((changed & GONE) != 0) { needGlobalAttributesUpdate(false); @@ -20047,58 +20023,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - final boolean wasLaidOut = isLaidOut(); - mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; - if (!wasLaidOut && isFocused()) { - mPrivateFlags &= ~PFLAG_WANTS_FOCUS; - if (canTakeFocus()) { - // We have a robust focus, so parents should no longer be wanting focus. - clearParentsWantFocus(); - } else if (!getViewRootImpl().isInLayout()) { - // This is a weird case. Most-likely the user, rather than ViewRootImpl, called - // layout. In this case, there's no guarantee that parent layouts will be evaluated - // and thus the safest action is to clear focus here. - clearFocusInternal(null, /* propagate */ true, /* refocus */ false); - clearParentsWantFocus(); - } else if (!hasParentWantsFocus()) { - // original requestFocus was likely on this view directly, so just clear focus - clearFocusInternal(null, /* propagate */ true, /* refocus */ false); - } - // otherwise, we let parents handle re-assigning focus during their layout passes. - } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { - mPrivateFlags &= ~PFLAG_WANTS_FOCUS; - View focused = findFocus(); - if (focused != null) { - // Try to restore focus as close as possible to our starting focus. - if (!restoreDefaultFocus() && !hasParentWantsFocus()) { - // Give up and clear focus once we've reached the top-most parent which wants - // focus. - focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); - } - } - } - if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } } - private boolean hasParentWantsFocus() { - ViewParent parent = mParent; - while (parent instanceof ViewGroup) { - ViewGroup pv = (ViewGroup) parent; - if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { - return true; - } - parent = pv.mParent; - } - return false; - } - /** * Called from layout when this view should * assign a size and position to each of its children. @@ -20205,23 +20138,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mOverlay.getOverlayView().setRight(newWidth); mOverlay.getOverlayView().setBottom(newHeight); } - // If this isn't laid out yet, focus assignment will be handled during the "deferment/ - // backtracking" of requestFocus during layout, so don't touch focus here. - if (!sCanFocusZeroSized && isLaidOut()) { - if (newWidth <= 0 || newHeight <= 0) { - if (hasFocus()) { - clearFocus(); - if (mParent instanceof ViewGroup) { - ((ViewGroup) mParent).clearFocusedInCluster(); - } - } - clearAccessibilityFocus(); - } else if (oldWidth <= 0 || oldHeight <= 0) { - if (mParent != null && canTakeFocus()) { - mParent.focusableViewAvailable(this); - } - } - } rebuildOutline(); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d0fcc5dfb8144..929beaea42b85 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3215,31 +3215,22 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } int descendantFocusability = getDescendantFocusability(); - boolean result; switch (descendantFocusability) { case FOCUS_BLOCK_DESCENDANTS: - result = super.requestFocus(direction, previouslyFocusedRect); - break; + return super.requestFocus(direction, previouslyFocusedRect); case FOCUS_BEFORE_DESCENDANTS: { final boolean took = super.requestFocus(direction, previouslyFocusedRect); - result = took ? took : onRequestFocusInDescendants(direction, - previouslyFocusedRect); - break; + return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); } case FOCUS_AFTER_DESCENDANTS: { final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect); - result = took ? took : super.requestFocus(direction, previouslyFocusedRect); - break; + 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); } - if (result && !isLaidOut() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) { - mPrivateFlags |= PFLAG_WANTS_FOCUS; - } - return result; } /**