Merge "Allow focusable in touch mode views to ignore touchscreen focus blocks" into lmp-dev
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 90eb516..0079cc9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5048,8 +5048,17 @@
      *         View, false otherwise.
      *
      * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS
+     * @see ViewGroup#getTouchscreenBlocksFocus()
      */
     public boolean hasFocusable() {
+        if (!isFocusableInTouchMode()) {
+            for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) {
+                final ViewGroup g = (ViewGroup) p;
+                if (g.shouldBlockFocusForTouchscreen()) {
+                    return false;
+                }
+            }
+        }
         return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable();
     }
 
@@ -7439,11 +7448,12 @@
      * @return Whether any ancestor of this view blocks descendant focus.
      */
     private boolean hasAncestorThatBlocksDescendantFocus() {
+        final boolean focusableInTouchMode = isFocusableInTouchMode();
         ViewParent ancestor = mParent;
         while (ancestor instanceof ViewGroup) {
             final ViewGroup vgAncestor = (ViewGroup) ancestor;
             if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS
-                    || vgAncestor.shouldBlockFocusForTouchscreen()) {
+                    || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) {
                 return true;
             } else {
                 ancestor = vgAncestor.getParent();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 04c8b0b..1028a0c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -669,7 +669,7 @@
                 // shortcut: don't report a new focusable view if we block our descendants from
                 // getting focus
                 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
-                && !shouldBlockFocusForTouchscreen()
+                && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
                 // shortcut: don't report a new focusable view if we already are focused
                 // (and we don't prefer our descendants)
                 //
@@ -865,6 +865,17 @@
         return mFocused;
     }
 
+    View getDeepestFocusedChild() {
+        View v = this;
+        while (v != null) {
+            if (v.isFocused()) {
+                return v;
+            }
+            v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
+        }
+        return null;
+    }
+
     /**
      * Returns true if this view has or contains focus
      *
@@ -911,8 +922,7 @@
         }
 
         final int descendantFocusability = getDescendantFocusability();
-        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS &&
-                !shouldBlockFocusForTouchscreen()) {
+        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
             final int count = mChildrenCount;
             final View[] children = mChildren;
 
@@ -936,8 +946,11 @@
 
         final int descendantFocusability = getDescendantFocusability();
 
-        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS &&
-                !shouldBlockFocusForTouchscreen()) {
+        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
+            if (shouldBlockFocusForTouchscreen()) {
+                focusableMode |= FOCUSABLES_TOUCH_MODE;
+            }
+
             final int count = mChildrenCount;
             final View[] children = mChildren;
 
@@ -955,7 +968,8 @@
         // among the focusable children would be more interesting.
         if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
                 // No focusable descendants
-                || (focusableCount == views.size())) && !shouldBlockFocusForTouchscreen()) {
+                || (focusableCount == views.size())) &&
+                (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
             super.addFocusables(views, direction, focusableMode);
         }
     }
@@ -971,9 +985,12 @@
         if (touchscreenBlocksFocus) {
             mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
             if (hasFocus()) {
-                final View newFocus = focusSearch(FOCUS_FORWARD);
-                if (newFocus != null) {
-                    newFocus.requestFocus();
+                final View focusedChild = getDeepestFocusedChild();
+                if (!focusedChild.isFocusableInTouchMode()) {
+                    final View newFocus = focusSearch(FOCUS_FORWARD);
+                    if (newFocus != null) {
+                        newFocus.requestFocus();
+                    }
                 }
             }
         } else {
@@ -2485,10 +2502,6 @@
         }
         int descendantFocusability = getDescendantFocusability();
 
-        if (shouldBlockFocusForTouchscreen()) {
-            return false;
-        }
-
         switch (descendantFocusability) {
             case FOCUS_BLOCK_DESCENDANTS:
                 return super.requestFocus(direction, previouslyFocusedRect);