diff options
| author | Evan Rosky <erosky@google.com> | 2017-02-15 13:26:51 -0800 |
|---|---|---|
| committer | Evan Rosky <erosky@google.com> | 2017-03-29 22:18:56 +0000 |
| commit | 18b886e8b2fa9d02869132a2e8f1eca997b22f6f (patch) | |
| tree | 0acde218633156067e8f2fc9ef8053cf7ac29bc2 /core/java/android/view/FocusFinder.java | |
| parent | 6f3bc05868061cfcc63e8fe8cb00147b03c1c64a (diff) | |
Allow cluster navigation to jump into touchscreenBlocksFocus
Adds an exception to touchscreenBlocksFocus ViewGroups which
are also keyboardNavigationClusters. The behavior we want is
that cluster navigation can jump into touchscreenBlocksFocus
clusters but normal keyboard navigation can't. Once focus is
in a touchscreenBlocksFocus cluster; however, we allow focus
navigation to move freely within that cluster. It remains in
that cluster until a subsequent cluster navigation brings it
back out.
Adds back the touchscreenBlocksFocus attributes to Toolbar
and actionbar so that they behave like they did before.
Bug: 34363323
Test: Added CTS test. Verified desired behavior in a test app
Change-Id: I555bf5570b16a57f0d4c8a020ae509a1e1b33910
(cherry picked from commit aee802f3bc3da699315a7040728e5483483099ff)
Diffstat (limited to 'core/java/android/view/FocusFinder.java')
| -rw-r--r-- | core/java/android/view/FocusFinder.java | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index 61c92018a406..ae1ee42c8720 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.PackageManager; import android.graphics.Rect; import android.util.ArrayMap; import android.util.SparseArray; @@ -88,8 +89,9 @@ public class FocusFinder { private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) { View next = null; + ViewGroup effectiveRoot = getEffectiveRoot(root, focused); if (focused != null) { - next = findNextUserSpecifiedFocus(root, focused, direction); + next = findNextUserSpecifiedFocus(effectiveRoot, focused, direction); } if (next != null) { return next; @@ -97,9 +99,9 @@ public class FocusFinder { ArrayList<View> focusables = mTempList; try { focusables.clear(); - root.addFocusables(focusables, direction); + effectiveRoot.addFocusables(focusables, direction); if (!focusables.isEmpty()) { - next = findNextFocus(root, focused, focusedRect, direction, focusables); + next = findNextFocus(effectiveRoot, focused, focusedRect, direction, focusables); } } finally { focusables.clear(); @@ -108,6 +110,35 @@ public class FocusFinder { } /** + * Returns the "effective" root of a view. The "effective" root is the closest ancestor + * within-which focus should cycle. + * <p> + * For example: normal focus navigation would stay within a ViewGroup marked as + * touchscreenBlocksFocus and keyboardNavigationCluster until a cluster-jump out. + * @return the "effective" root of {@param focused} + */ + private ViewGroup getEffectiveRoot(ViewGroup root, View focused) { + if (focused == null) { + return root; + } + ViewParent effective = focused.getParent(); + do { + if (effective == root) { + return root; + } + ViewGroup vg = (ViewGroup) effective; + if (vg.getTouchscreenBlocksFocus() + && focused.getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TOUCHSCREEN) + && vg.isKeyboardNavigationCluster()) { + return vg; + } + effective = effective.getParent(); + } while (effective != null); + return root; + } + + /** * Find the root of the next keyboard navigation cluster after the current one. * @param root The view tree to look inside. Cannot be null * @param currentCluster The starting point of the search. Null means the default cluster |
