From 381b491845038b79f62d80c8e65d346fd9b5d1e7 Mon Sep 17 00:00:00 2001 From: Alexander-- Date: Sun, 15 Mar 2020 09:19:22 +0659 Subject: [PATCH] Prevent foocus from escaping open navigation drawer When contents of NewPipe navigation drawer change, NavigationMenuView (which is actually a RecyclerView) removes and re-adds all its adapter children, which leads to temporary loss of focus on currently focused drawer child. This situation was not anticipated by developers of original support library DrawerLayout: while NavigationMenuView itself is able to keep focus from escaping via onRequestFocusInDescendants(), the implementation of that method in DrawerLayout does not pass focus to previously focused View. In fact it does not pass focus correctly at all because the AOSP implementation of that method does not call addFocusables() and simply focuses the first available VISIBLE View, without regard to state of drawers. --- .../newpipe/views/FocusAwareDrawerLayout.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/views/FocusAwareDrawerLayout.java b/app/src/main/java/org/schabi/newpipe/views/FocusAwareDrawerLayout.java index 2354427a3..45e4a8e34 100644 --- a/app/src/main/java/org/schabi/newpipe/views/FocusAwareDrawerLayout.java +++ b/app/src/main/java/org/schabi/newpipe/views/FocusAwareDrawerLayout.java @@ -19,6 +19,7 @@ package org.schabi.newpipe.views; import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; @@ -44,6 +45,34 @@ public final class FocusAwareDrawerLayout extends DrawerLayout { super(context, attrs, defStyle); } + @Override + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { + // SDK implementation of this method picks whatever visible View takes the focus first without regard to addFocusables + // if the open drawer is temporarily empty, the focus escapes outside of it, which can be confusing + + boolean hasOpenPanels = false; + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + + DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) child.getLayoutParams(); + + if (lp.gravity != 0 && isDrawerVisible(child)) { + hasOpenPanels = true; + + if (child.requestFocus(direction, previouslyFocusedRect)) { + return true; + } + } + } + + if (hasOpenPanels) { + return false; + } + + return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); + } + @Override public void addFocusables(ArrayList views, int direction, int focusableMode) { boolean hasOpenPanels = false;