Loading core/java/android/view/FocusFinder.java +10 −7 Original line number Diff line number Diff line Loading @@ -127,20 +127,23 @@ public class FocusFinder { if (focused == null || focused == root) { return root; } ViewParent effective = focused.getParent(); ViewGroup effective = null; ViewParent nextParent = focused.getParent(); do { if (effective == root) { return root; if (nextParent == root) { return effective != null ? effective : root; } ViewGroup vg = (ViewGroup) effective; ViewGroup vg = (ViewGroup) nextParent; if (vg.getTouchscreenBlocksFocus() && focused.getContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_TOUCHSCREEN) && vg.isKeyboardNavigationCluster()) { return vg; // Don't stop and return here because the cluster could be nested and we only // care about the top-most one. effective = vg; } effective = effective.getParent(); } while (effective != null); nextParent = nextParent.getParent(); } while (nextParent instanceof ViewGroup); return root; } Loading core/java/android/view/View.java +33 −3 Original line number Diff line number Diff line Loading @@ -9767,6 +9767,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; } /** * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters * will be ignored. * * @return the keyboard navigation cluster that this view is in (can be this view) * or {@code null} if not in one */ View findKeyboardNavigationCluster() { if (mParent instanceof View) { View cluster = ((View) mParent).findKeyboardNavigationCluster(); if (cluster != null) { return cluster; } else if (isKeyboardNavigationCluster()) { return this; } } return null; } /** * Set whether this view is a root of a keyboard navigation cluster. * Loading @@ -9789,9 +9808,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ public void setFocusedInCluster() { if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).setFocusInCluster(this); public final void setFocusedInCluster() { View top = findKeyboardNavigationCluster(); if (top == this) { return; } ViewParent parent = mParent; View child = this; while (parent instanceof ViewGroup) { ((ViewGroup) parent).setFocusedInCluster(child); if (parent == top) { return; } child = (View) parent; parent = parent.getParent(); } } Loading core/java/android/view/ViewGroup.java +22 −28 Original line number Diff line number Diff line Loading @@ -807,33 +807,27 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mDefaultFocus != null || super.hasDefaultFocus(); } void setFocusInCluster(View child) { // Stop at the root of the cluster if (child.isKeyboardNavigationCluster()) { return; } void setFocusedInCluster(View child) { mFocusedInCluster = child; if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).setFocusInCluster(this); } } void clearFocusInCluster(View child) { /** * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing * it. * <br> * This is intended to be run on {@code child}'s immediate parent. This is necessary because * the chain is sometimes cleared after {@code child} has been detached. */ void clearFocusedInCluster(View child) { if (mFocusedInCluster != child) { return; } if (child.isKeyboardNavigationCluster()) { return; } mFocusedInCluster = null; if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusInCluster(this); } View top = findKeyboardNavigationCluster(); ViewParent parent = this; do { ((ViewGroup) parent).mFocusedInCluster = null; parent = parent.getParent(); } while (parent != top && parent instanceof ViewGroup); } @Override Loading Loading @@ -1281,7 +1275,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) { if (touchscreenBlocksFocus) { mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS; if (hasFocus()) { if (hasFocus() && !isKeyboardNavigationCluster()) { final View focusedChild = getDeepestFocusedChild(); if (!focusedChild.isFocusableInTouchMode()) { final View newFocus = focusSearch(FOCUS_FORWARD); Loading Loading @@ -1316,7 +1310,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // cluster, focus is free to move around within it. return getTouchscreenBlocksFocus() && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) && (!hasFocus() || !isKeyboardNavigationCluster()); && !(isKeyboardNavigationCluster() && (hasFocus() || (findKeyboardNavigationCluster() != this))); } @Override Loading Loading @@ -3217,8 +3212,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) { if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster() && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE && mFocusedInCluster.restoreFocusInCluster(direction)) { return true; Loading Loading @@ -5182,7 +5176,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = true; } if (view == mFocusedInCluster) { clearFocusInCluster(view); clearFocusedInCluster(view); } view.clearAccessibilityFocus(); Loading Loading @@ -5302,7 +5296,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus = view; } if (view == mFocusedInCluster) { clearFocusInCluster(view); clearFocusedInCluster(view); } view.clearAccessibilityFocus(); Loading Loading @@ -5458,7 +5452,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus(child); } if (child == mFocusedInCluster) { clearFocusInCluster(child); clearFocusedInCluster(child); } child.clearAccessibilityFocus(); Loading Loading
core/java/android/view/FocusFinder.java +10 −7 Original line number Diff line number Diff line Loading @@ -127,20 +127,23 @@ public class FocusFinder { if (focused == null || focused == root) { return root; } ViewParent effective = focused.getParent(); ViewGroup effective = null; ViewParent nextParent = focused.getParent(); do { if (effective == root) { return root; if (nextParent == root) { return effective != null ? effective : root; } ViewGroup vg = (ViewGroup) effective; ViewGroup vg = (ViewGroup) nextParent; if (vg.getTouchscreenBlocksFocus() && focused.getContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_TOUCHSCREEN) && vg.isKeyboardNavigationCluster()) { return vg; // Don't stop and return here because the cluster could be nested and we only // care about the top-most one. effective = vg; } effective = effective.getParent(); } while (effective != null); nextParent = nextParent.getParent(); } while (nextParent instanceof ViewGroup); return root; } Loading
core/java/android/view/View.java +33 −3 Original line number Diff line number Diff line Loading @@ -9767,6 +9767,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; } /** * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters * will be ignored. * * @return the keyboard navigation cluster that this view is in (can be this view) * or {@code null} if not in one */ View findKeyboardNavigationCluster() { if (mParent instanceof View) { View cluster = ((View) mParent).findKeyboardNavigationCluster(); if (cluster != null) { return cluster; } else if (isKeyboardNavigationCluster()) { return this; } } return null; } /** * Set whether this view is a root of a keyboard navigation cluster. * Loading @@ -9789,9 +9808,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ public void setFocusedInCluster() { if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).setFocusInCluster(this); public final void setFocusedInCluster() { View top = findKeyboardNavigationCluster(); if (top == this) { return; } ViewParent parent = mParent; View child = this; while (parent instanceof ViewGroup) { ((ViewGroup) parent).setFocusedInCluster(child); if (parent == top) { return; } child = (View) parent; parent = parent.getParent(); } } Loading
core/java/android/view/ViewGroup.java +22 −28 Original line number Diff line number Diff line Loading @@ -807,33 +807,27 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mDefaultFocus != null || super.hasDefaultFocus(); } void setFocusInCluster(View child) { // Stop at the root of the cluster if (child.isKeyboardNavigationCluster()) { return; } void setFocusedInCluster(View child) { mFocusedInCluster = child; if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).setFocusInCluster(this); } } void clearFocusInCluster(View child) { /** * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing * it. * <br> * This is intended to be run on {@code child}'s immediate parent. This is necessary because * the chain is sometimes cleared after {@code child} has been detached. */ void clearFocusedInCluster(View child) { if (mFocusedInCluster != child) { return; } if (child.isKeyboardNavigationCluster()) { return; } mFocusedInCluster = null; if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusInCluster(this); } View top = findKeyboardNavigationCluster(); ViewParent parent = this; do { ((ViewGroup) parent).mFocusedInCluster = null; parent = parent.getParent(); } while (parent != top && parent instanceof ViewGroup); } @Override Loading Loading @@ -1281,7 +1275,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) { if (touchscreenBlocksFocus) { mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS; if (hasFocus()) { if (hasFocus() && !isKeyboardNavigationCluster()) { final View focusedChild = getDeepestFocusedChild(); if (!focusedChild.isFocusableInTouchMode()) { final View newFocus = focusSearch(FOCUS_FORWARD); Loading Loading @@ -1316,7 +1310,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // cluster, focus is free to move around within it. return getTouchscreenBlocksFocus() && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) && (!hasFocus() || !isKeyboardNavigationCluster()); && !(isKeyboardNavigationCluster() && (hasFocus() || (findKeyboardNavigationCluster() != this))); } @Override Loading Loading @@ -3217,8 +3212,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) { if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster() && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE && mFocusedInCluster.restoreFocusInCluster(direction)) { return true; Loading Loading @@ -5182,7 +5176,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = true; } if (view == mFocusedInCluster) { clearFocusInCluster(view); clearFocusedInCluster(view); } view.clearAccessibilityFocus(); Loading Loading @@ -5302,7 +5296,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus = view; } if (view == mFocusedInCluster) { clearFocusInCluster(view); clearFocusedInCluster(view); } view.clearAccessibilityFocus(); Loading Loading @@ -5458,7 +5452,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus(child); } if (child == mFocusedInCluster) { clearFocusInCluster(child); clearFocusedInCluster(child); } child.clearAccessibilityFocus(); Loading