summaryrefslogtreecommitdiff
path: root/core/java/android/view/FocusFinder.java
diff options
context:
space:
mode:
authorEvan Rosky <erosky@google.com>2017-02-15 13:26:51 -0800
committerEvan Rosky <erosky@google.com>2017-03-29 22:18:56 +0000
commit18b886e8b2fa9d02869132a2e8f1eca997b22f6f (patch)
tree0acde218633156067e8f2fc9ef8053cf7ac29bc2 /core/java/android/view/FocusFinder.java
parent6f3bc05868061cfcc63e8fe8cb00147b03c1c64a (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.java37
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