Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01d8c49e authored by Vadim Tryshev's avatar Vadim Tryshev
Browse files

Restoring last focused view when teleporting to a cluster.

The UX spec requires each cluster to remember which view was last
focused in it, and focus on it upon the teleportation to this
cluster.

This CL implements saving and restoring the focus.
It also introduces a public API so that an app could switch to a
cluster as if it was teleported to.

Bug: 32151632
Test: Manual checks; CTS are coming after feature freeze.
Change-Id: I0dc816776386015a7f1235f93e3dd9c03dfffcd6
parent e298756b
Loading
Loading
Loading
Loading
+16 −15
Original line number Diff line number Diff line
@@ -43411,6 +43411,7 @@ package android.view {
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public boolean restoreLastFocus();
    method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
    method public void scrollBy(int, int);
@@ -61421,31 +61422,31 @@ package java.util.concurrent {
    ctor public CopyOnWriteArrayList();
    ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    ctor public CopyOnWriteArrayList(E[]);
    method public synchronized boolean add(E);
    method public synchronized void add(int, E);
    method public synchronized boolean addAll(java.util.Collection<? extends E>);
    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
    method public synchronized boolean addIfAbsent(E);
    method public synchronized void clear();
    method public boolean add(E);
    method public void add(int, E);
    method public boolean addAll(java.util.Collection<? extends E>);
    method public boolean addAll(int, java.util.Collection<? extends E>);
    method public int addAllAbsent(java.util.Collection<? extends E>);
    method public boolean addIfAbsent(E);
    method public void clear();
    method public java.lang.Object clone();
    method public boolean contains(java.lang.Object);
    method public boolean containsAll(java.util.Collection<?>);
    method public void forEach(java.util.function.Consumer<? super E>);
    method public E get(int);
    method public int indexOf(E, int);
    method public int indexOf(java.lang.Object);
    method public int indexOf(E, int);
    method public boolean isEmpty();
    method public java.util.Iterator<E> iterator();
    method public int lastIndexOf(E, int);
    method public int lastIndexOf(java.lang.Object);
    method public java.util.ListIterator<E> listIterator(int);
    method public int lastIndexOf(E, int);
    method public java.util.ListIterator<E> listIterator();
    method public synchronized E remove(int);
    method public synchronized boolean remove(java.lang.Object);
    method public synchronized boolean removeAll(java.util.Collection<?>);
    method public synchronized boolean retainAll(java.util.Collection<?>);
    method public synchronized E set(int, E);
    method public java.util.ListIterator<E> listIterator(int);
    method public E remove(int);
    method public boolean remove(java.lang.Object);
    method public boolean removeAll(java.util.Collection<?>);
    method public boolean retainAll(java.util.Collection<?>);
    method public E set(int, E);
    method public int size();
    method public java.util.List<E> subList(int, int);
    method public java.lang.Object[] toArray();
+16 −15
Original line number Diff line number Diff line
@@ -46553,6 +46553,7 @@ package android.view {
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public boolean restoreLastFocus();
    method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
    method public void scrollBy(int, int);
@@ -64923,31 +64924,31 @@ package java.util.concurrent {
    ctor public CopyOnWriteArrayList();
    ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    ctor public CopyOnWriteArrayList(E[]);
    method public synchronized boolean add(E);
    method public synchronized void add(int, E);
    method public synchronized boolean addAll(java.util.Collection<? extends E>);
    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
    method public synchronized boolean addIfAbsent(E);
    method public synchronized void clear();
    method public boolean add(E);
    method public void add(int, E);
    method public boolean addAll(java.util.Collection<? extends E>);
    method public boolean addAll(int, java.util.Collection<? extends E>);
    method public int addAllAbsent(java.util.Collection<? extends E>);
    method public boolean addIfAbsent(E);
    method public void clear();
    method public java.lang.Object clone();
    method public boolean contains(java.lang.Object);
    method public boolean containsAll(java.util.Collection<?>);
    method public void forEach(java.util.function.Consumer<? super E>);
    method public E get(int);
    method public int indexOf(E, int);
    method public int indexOf(java.lang.Object);
    method public int indexOf(E, int);
    method public boolean isEmpty();
    method public java.util.Iterator<E> iterator();
    method public int lastIndexOf(E, int);
    method public int lastIndexOf(java.lang.Object);
    method public java.util.ListIterator<E> listIterator(int);
    method public int lastIndexOf(E, int);
    method public java.util.ListIterator<E> listIterator();
    method public synchronized E remove(int);
    method public synchronized boolean remove(java.lang.Object);
    method public synchronized boolean removeAll(java.util.Collection<?>);
    method public synchronized boolean retainAll(java.util.Collection<?>);
    method public synchronized E set(int, E);
    method public java.util.ListIterator<E> listIterator(int);
    method public E remove(int);
    method public boolean remove(java.lang.Object);
    method public boolean removeAll(java.util.Collection<?>);
    method public boolean retainAll(java.util.Collection<?>);
    method public E set(int, E);
    method public int size();
    method public java.util.List<E> subList(int, int);
    method public java.lang.Object[] toArray();
+16 −15
Original line number Diff line number Diff line
@@ -43680,6 +43680,7 @@ package android.view {
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public boolean restoreLastFocus();
    method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
    method public void scrollBy(int, int);
@@ -61710,31 +61711,31 @@ package java.util.concurrent {
    ctor public CopyOnWriteArrayList();
    ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    ctor public CopyOnWriteArrayList(E[]);
    method public synchronized boolean add(E);
    method public synchronized void add(int, E);
    method public synchronized boolean addAll(java.util.Collection<? extends E>);
    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
    method public synchronized boolean addIfAbsent(E);
    method public synchronized void clear();
    method public boolean add(E);
    method public void add(int, E);
    method public boolean addAll(java.util.Collection<? extends E>);
    method public boolean addAll(int, java.util.Collection<? extends E>);
    method public int addAllAbsent(java.util.Collection<? extends E>);
    method public boolean addIfAbsent(E);
    method public void clear();
    method public java.lang.Object clone();
    method public boolean contains(java.lang.Object);
    method public boolean containsAll(java.util.Collection<?>);
    method public void forEach(java.util.function.Consumer<? super E>);
    method public E get(int);
    method public int indexOf(E, int);
    method public int indexOf(java.lang.Object);
    method public int indexOf(E, int);
    method public boolean isEmpty();
    method public java.util.Iterator<E> iterator();
    method public int lastIndexOf(E, int);
    method public int lastIndexOf(java.lang.Object);
    method public java.util.ListIterator<E> listIterator(int);
    method public int lastIndexOf(E, int);
    method public java.util.ListIterator<E> listIterator();
    method public synchronized E remove(int);
    method public synchronized boolean remove(java.lang.Object);
    method public synchronized boolean removeAll(java.util.Collection<?>);
    method public synchronized boolean retainAll(java.util.Collection<?>);
    method public synchronized E set(int, E);
    method public java.util.ListIterator<E> listIterator(int);
    method public E remove(int);
    method public boolean remove(java.lang.Object);
    method public boolean removeAll(java.util.Collection<?>);
    method public boolean retainAll(java.util.Collection<?>);
    method public E set(int, E);
    method public int size();
    method public java.util.List<E> subList(int, int);
    method public java.lang.Object[] toArray();
+15 −0
Original line number Diff line number Diff line
@@ -6106,6 +6106,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            if (mParent != null) {
                mParent.requestChildFocus(this, this);
                if (!isKeyboardNavigationCluster() && mParent instanceof ViewGroup) {
                    ((ViewGroup) mParent).saveFocus();
                }
            }
            if (mAttachInfo != null) {
@@ -9440,6 +9443,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return requestFocus(View.FOCUS_DOWN);
    }
    /**
     * Gives focus to the last focused view in the view hierarchy that has this view as a root.
     * If the last focused view cannot be found, fall back to calling {@link #requestFocus()}.
     * Nested keyboard navigation clusters are excluded from the hierarchy considered for saving the
     * last focus.
     *
     * @return Whether this view or one of its descendants actually took focus.
     */
    public boolean restoreLastFocus() {
        return requestFocus();
    }
    /**
     * Call this to try to give focus to a specific view or to one of its
     * descendants and give it a hint about what direction focus is heading.
+46 −0
Original line number Diff line number Diff line
@@ -136,6 +136,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager

    // The view contained within this ViewGroup that has or contains focus.
    private View mFocused;
    // The last view contained within this ViewGroup (excluding nested keyboard navigation clusters)
    // that had or contained focus.
    private View mLastFocused;

    /**
     * A Transformation used when drawing children, to
@@ -719,6 +722,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        if (mFocused != null) {
            mFocused.unFocus(this);
            mFocused = null;
            mLastFocused = null;
        }
        super.handleFocusGainInternal(direction, previouslyFocusedRect);
    }
@@ -748,6 +752,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
    }

    /**
     * Saves the current focus as the last focus for this view and all its ancestors.
     * If the view is inside a keyboard navigation cluster, stops at the root of the cluster since
     * the cluster forms a separate keyboard navigation hierarchy from the focus saving point of
     * view.
     */
    void saveFocus() {
        mLastFocused = mFocused;

        if (!isKeyboardNavigationCluster() && mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).saveFocus();
        }
    }

    @Override
    public void focusableViewAvailable(View v) {
        if (mParent != null
@@ -3035,6 +3053,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return false;
    }

    @Override
    public boolean restoreLastFocus() {
        if (mLastFocused != null && !mLastFocused.isKeyboardNavigationCluster()
                && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
                && (mLastFocused.mViewFlags & VISIBILITY_MASK) == VISIBLE
                && mLastFocused.restoreLastFocus()) {
            return true;
        }
        return super.restoreLastFocus();
    }

    /**
     * {@inheritDoc}
     *
@@ -4887,6 +4916,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            view.unFocus(null);
            clearChildFocus = true;
        }
        if (view == mLastFocused) {
            mLastFocused = null;
        }

        view.clearAccessibilityFocus();

@@ -4997,6 +5029,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                view.unFocus(null);
                clearChildFocus = true;
            }
            if (view == mLastFocused) {
                mLastFocused = null;
            }

            view.clearAccessibilityFocus();

@@ -5070,6 +5105,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        boolean clearChildFocus = false;

        needGlobalAttributesUpdate(false);
        mLastFocused = null;

        for (int i = count - 1; i >= 0; i--) {
            final View view = children[i];
@@ -5141,6 +5177,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        if (child == mFocused) {
            child.clearFocus();
        }
        if (child == mLastFocused) {
            mLastFocused = null;
        }

        child.clearAccessibilityFocus();

@@ -6143,6 +6182,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            output = debugIndent(depth);
            output += "mFocused";
            Log.d(VIEW_LOG_TAG, output);
            mFocused.debug(depth + 1);
        }
        if (mLastFocused != null) {
            output = debugIndent(depth);
            output += "mLastFocused";
            Log.d(VIEW_LOG_TAG, output);
            mLastFocused.debug(depth + 1);
        }
        if (mChildrenCount != 0) {
            output = debugIndent(depth);
Loading