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

Commit 393a954d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "API for setting default focus per cluster."

parents 896619a7 5ca73981
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -584,6 +584,7 @@ package android {
    field public static final int flipInterval = 16843129; // 0x1010179
    field public static final int focusable = 16842970; // 0x10100da
    field public static final int focusableInTouchMode = 16842971; // 0x10100db
    field public static final int focusedByDefault = 16844101; // 0x1010545
    field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
    field public static final int font = 16844082; // 0x1010532
    field public static final int fontFamily = 16843692; // 0x10103ac
@@ -43512,6 +43513,7 @@ package android.view {
    method public final boolean isFocusable();
    method public final boolean isFocusableInTouchMode();
    method public boolean isFocused();
    method public final boolean isFocusedByDefault();
    method public boolean isHapticFeedbackEnabled();
    method public boolean isHardwareAccelerated();
    method public boolean isHorizontalFadingEdgeEnabled();
@@ -43642,8 +43644,8 @@ package android.view {
    method public final void requestUnbufferedDispatch(android.view.MotionEvent);
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public boolean restoreDefaultFocus(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);
@@ -43681,6 +43683,7 @@ package android.view {
    method public void setFitsSystemWindows(boolean);
    method public void setFocusable(boolean);
    method public void setFocusableInTouchMode(boolean);
    method public void setFocusedByDefault(boolean);
    method public void setForeground(android.graphics.drawable.Drawable);
    method public void setForegroundGravity(int);
    method public void setForegroundTintList(android.content.res.ColorStateList);
+4 −1
Original line number Diff line number Diff line
@@ -693,6 +693,7 @@ package android {
    field public static final int flipInterval = 16843129; // 0x1010179
    field public static final int focusable = 16842970; // 0x10100da
    field public static final int focusableInTouchMode = 16842971; // 0x10100db
    field public static final int focusedByDefault = 16844101; // 0x1010545
    field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
    field public static final int font = 16844082; // 0x1010532
    field public static final int fontFamily = 16843692; // 0x10103ac
@@ -46736,6 +46737,7 @@ package android.view {
    method public final boolean isFocusable();
    method public final boolean isFocusableInTouchMode();
    method public boolean isFocused();
    method public final boolean isFocusedByDefault();
    method public boolean isHapticFeedbackEnabled();
    method public boolean isHardwareAccelerated();
    method public boolean isHorizontalFadingEdgeEnabled();
@@ -46866,8 +46868,8 @@ package android.view {
    method public final void requestUnbufferedDispatch(android.view.MotionEvent);
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public boolean restoreDefaultFocus(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);
@@ -46905,6 +46907,7 @@ package android.view {
    method public void setFitsSystemWindows(boolean);
    method public void setFocusable(boolean);
    method public void setFocusableInTouchMode(boolean);
    method public void setFocusedByDefault(boolean);
    method public void setForeground(android.graphics.drawable.Drawable);
    method public void setForegroundGravity(int);
    method public void setForegroundTintList(android.content.res.ColorStateList);
+4 −1
Original line number Diff line number Diff line
@@ -584,6 +584,7 @@ package android {
    field public static final int flipInterval = 16843129; // 0x1010179
    field public static final int focusable = 16842970; // 0x10100da
    field public static final int focusableInTouchMode = 16842971; // 0x10100db
    field public static final int focusedByDefault = 16844101; // 0x1010545
    field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
    field public static final int font = 16844082; // 0x1010532
    field public static final int fontFamily = 16843692; // 0x10103ac
@@ -43802,6 +43803,7 @@ package android.view {
    method public final boolean isFocusable();
    method public final boolean isFocusableInTouchMode();
    method public boolean isFocused();
    method public final boolean isFocusedByDefault();
    method public boolean isHapticFeedbackEnabled();
    method public boolean isHardwareAccelerated();
    method public boolean isHorizontalFadingEdgeEnabled();
@@ -43932,8 +43934,8 @@ package android.view {
    method public final void requestUnbufferedDispatch(android.view.MotionEvent);
    method public static int resolveSize(int, int);
    method public static int resolveSizeAndState(int, int, int);
    method public boolean restoreDefaultFocus(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);
@@ -43971,6 +43973,7 @@ package android.view {
    method public void setFitsSystemWindows(boolean);
    method public void setFocusable(boolean);
    method public void setFocusableInTouchMode(boolean);
    method public void setFocusedByDefault(boolean);
    method public void setForeground(android.graphics.drawable.Drawable);
    method public void setForegroundGravity(int);
    method public void setForegroundTintList(android.content.res.ColorStateList);
+84 −10
Original line number Diff line number Diff line
@@ -2502,7 +2502,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *                  1                PFLAG3_CLUSTER
     *                 1                 PFLAG3_SECTION
     *                1                  PFLAG3_FINGER_DOWN
     *           xxxxx                   * NO LONGER NEEDED, SHOULD BE REUSED *
     *               1                   PFLAG3_FOCUSED_BY_DEFAULT
     *           xxxx                    * NO LONGER NEEDED, SHOULD BE REUSED *
     *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
     *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
     *        1                          PFLAG3_TEMPORARY_DETACH
@@ -2722,6 +2723,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    private static final int PFLAG3_FINGER_DOWN = 0x20000;
    /**
     * Flag indicating that this view is the default-focus view.
     *
     * @see #isFocusedByDefault()
     * @see #setFocusedByDefault(boolean)
     */
    private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000;
    /**
     * Whether this view has rendered elements that overlap (see {@link
     * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
@@ -4765,6 +4774,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                        setKeyboardNavigationSection(a.getBoolean(attr, true));
                    }
                    break;
                case R.styleable.View_focusedByDefault:
                    if (a.peekValue(attr) != null) {
                        setFocusedByDefault(a.getBoolean(attr, true));
                    }
                    break;
            }
        }
@@ -6156,8 +6170,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            if (mParent != null) {
                mParent.requestChildFocus(this, this);
                if (!isKeyboardNavigationCluster() && mParent instanceof ViewGroup) {
                    ((ViewGroup) mParent).saveFocus();
                if (mParent instanceof ViewGroup) {
                    ((ViewGroup) mParent).setDefaultFocus(this);
                }
            }
@@ -9210,6 +9224,66 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
    }
    /**
     * Returns whether this View should receive focus when the focus is restored for the view
     * hierarchy containing this view.
     * <p>
     * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
     * window or serves as a target of cluster or section navigation.
     *
     * @see #restoreDefaultFocus(int)
     *
     * @return {@code true} if this view is the default-focus view, {@code false} otherwise
     * @attr ref android.R.styleable#View_focusedByDefault
     */
    @ViewDebug.ExportedProperty(category = "focusedByDefault")
    public final boolean isFocusedByDefault() {
        return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0;
    }
    /**
     * Sets whether this View should receive focus when the focus is restored for the view
     * hierarchy containing this view.
     * <p>
     * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
     * window or serves as a target of cluster or section navigation.
     *
     * @param isFocusedByDefault {@code true} to set this view as the default-focus view,
     *                           {@code false} otherwise.
     *
     * @see #restoreDefaultFocus(int)
     *
     * @attr ref android.R.styleable#View_focusedByDefault
     */
    public void setFocusedByDefault(boolean isFocusedByDefault) {
        if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) {
            return;
        }
        if (isFocusedByDefault) {
            mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT;
        } else {
            mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT;
        }
        if (mParent instanceof ViewGroup) {
            if (isFocusedByDefault) {
                ((ViewGroup) mParent).setDefaultFocus(this);
            } else {
                ((ViewGroup) mParent).cleanDefaultFocus(this);
            }
        }
    }
    /**
     * Returns whether the view hierarchy with this view as a root contain a default-focus view.
     *
     * @return {@code true} if this view has default focus, {@code false} otherwise
     */
    boolean hasDefaultFocus() {
        return isFocusedByDefault();
    }
    /**
     * Find the nearest keyboard navigation group in the specified direction. The group type can be
     * either a cluster or a section.
@@ -9586,15 +9660,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    }
    /**
     * 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.
     * Gives focus to the default-focus view in the view hierarchy that has this view as a root.
     * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}.
     * Nested keyboard navigation clusters are excluded from the hierarchy.
     *
     * @return Whether this view or one of its descendants actually took focus.
     * @param direction The direction of the focus
     * @return Whether this view or one of its descendants actually took focus
     */
    public boolean restoreLastFocus() {
        return requestFocus();
    public boolean restoreDefaultFocus(@FocusDirection int direction) {
        return requestFocus(direction);
    }
    /**
+59 −25
Original line number Diff line number Diff line
@@ -136,9 +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;
    // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
    // that is or contains a default-focus view.
    private View mDefaultFocus;

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

    /**
     * Saves the current focus as the last focus for this view and all its ancestors.
     * Sets the specified child view as the default 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
     * the cluster forms a separate keyboard navigation hierarchy from the default focus point of
     * view.
     */
    void saveFocus() {
        mLastFocused = mFocused;
    void setDefaultFocus(View child) {
        if (child.isKeyboardNavigationCluster()) {
            return;
        }

        mDefaultFocus = child;

        if (mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).setDefaultFocus(this);
        }
    }

    /**
     * Destroys the default focus chain.
     */
    void cleanDefaultFocus(View child) {
        if (mDefaultFocus != child) {
            return;
        }

        if (child.isKeyboardNavigationCluster()) {
            return;
        }

        mDefaultFocus = null;

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

    @Override
    boolean hasDefaultFocus() {
        return mDefaultFocus != null || super.hasDefaultFocus();
    }

    @Override
    public void focusableViewAvailable(View v) {
        if (mParent != null
@@ -3054,14 +3082,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    }

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

    /**
@@ -4720,6 +4748,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
            notifyChildOfDragStart(child);
        }

        if (child.hasDefaultFocus()) {
            // When adding a child that contains default focus, either during inflation or while
            // manually assembling the hierarchy, update the ancestor default-focus chain.
            setDefaultFocus(child);
        }
    }

    private void addInArray(View child, int index) {
@@ -4931,8 +4965,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            view.unFocus(null);
            clearChildFocus = true;
        }
        if (view == mLastFocused) {
            mLastFocused = null;
        if (view == mDefaultFocus) {
            mDefaultFocus = null;
        }

        view.clearAccessibilityFocus();
@@ -5044,8 +5078,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                view.unFocus(null);
                clearChildFocus = true;
            }
            if (view == mLastFocused) {
                mLastFocused = null;
            if (view == mDefaultFocus) {
                mDefaultFocus = null;
            }

            view.clearAccessibilityFocus();
@@ -5120,7 +5154,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        boolean clearChildFocus = false;

        needGlobalAttributesUpdate(false);
        mLastFocused = null;
        mDefaultFocus = null;

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

        child.clearAccessibilityFocus();
@@ -6276,11 +6310,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            Log.d(VIEW_LOG_TAG, output);
            mFocused.debug(depth + 1);
        }
        if (mLastFocused != null) {
        if (mDefaultFocus != null) {
            output = debugIndent(depth);
            output += "mLastFocused";
            output += "mDefaultFocus";
            Log.d(VIEW_LOG_TAG, output);
            mLastFocused.debug(depth + 1);
            mDefaultFocus.debug(depth + 1);
        }
        if (mChildrenCount != 0) {
            output = debugIndent(depth);
Loading