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

Commit 1abe85c8 authored by Vadim Tryshev's avatar Vadim Tryshev
Browse files

Converting action bars to clusters.

ActionBar keyboard navigation logic is now implemented via clusters.
Old implementation using setTouchscreenBlocksFocus and Ctrl+Shift+<
shortcut is removed.

Looking at the code, I can’t rule out existence of all 3 categories
(1) action bars with a nested toolbar, (2) action bars without a
nested toolbar and (3) Toolbars outside of action bars.
Because of this, I set “cluster” attribute both on action bar and
toolbar, and have code to avoid nested clusters in case (1).

Support lib’s action/tool bars aren’t converted, however, they
didn’t regress since Ctrl+Shift+< never worked for them. Will be
done after feature freeze.

Bug: 32151632
Test: Manual checks.
Change-Id: Ieb93980088c0fb385a9bc8a5d218ffc269b94dc5
parent 4a07b957
Loading
Loading
Loading
Loading
+1 −97
Original line number Diff line number Diff line
@@ -31,13 +31,12 @@ import android.view.ActionMode;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewHierarchyEncoder;
import android.view.ViewParent;
import android.view.Window;
import android.widget.SpinnerAdapter;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@@ -1093,66 +1092,10 @@ public abstract class ActionBar {
    public void setWindowTitle(CharSequence title) {
    }

    /**
     * Attempts to move focus to the ActionBar if it does not already contain the focus.
     *
     * @return {@code true} if focus changes or {@code false} if focus doesn't change.
     * @hide
     */
    public boolean requestFocus() {
        return false;
    }

    /** @hide */
    public void onDestroy() {
    }

    /**
     * Common implementation for requestFocus that takes in the Toolbar and moves focus
     * to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
     * in the ActionBar and then prevents it again once it leaves.
     *
     * @param viewGroup The toolbar ViewGroup
     * @return {@code true} if focus changes or {@code false} if focus doesn't change.
     * @hide
     */
    protected boolean requestFocus(ViewGroup viewGroup) {
        if (viewGroup != null && !viewGroup.hasFocus()) {
            final ViewGroup toolbar = viewGroup.getTouchscreenBlocksFocus() ? viewGroup : null;
            ViewParent parent = viewGroup.getParent();
            ViewGroup container = null;
            while (parent != null && parent instanceof ViewGroup) {
                final ViewGroup vgParent = (ViewGroup) parent;
                if (vgParent.getTouchscreenBlocksFocus()) {
                    container = vgParent;
                    break;
                }
                parent = vgParent.getParent();
            }
            if (container != null) {
                container.setTouchscreenBlocksFocus(false);
            }
            if (toolbar != null) {
                toolbar.setTouchscreenBlocksFocus(false);
            }
            viewGroup.requestFocus();
            final View focused = viewGroup.findFocus();
            if (focused != null) {
                focused.setOnFocusChangeListener(new FollowOutOfActionBar(viewGroup,
                        container, toolbar));
            } else {
                if (container != null) {
                    container.setTouchscreenBlocksFocus(true);
                }
                if (toolbar != null) {
                    toolbar.setTouchscreenBlocksFocus(true);
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Listener interface for ActionBar navigation events.
     *
@@ -1474,43 +1417,4 @@ public abstract class ActionBar {
            encoder.addProperty("gravity", gravity);
        }
    }

    /**
     * Tracks the focused View until it leaves the ActionBar, then it resets the
     * touchscreenBlocksFocus value.
     */
    private static class FollowOutOfActionBar implements OnFocusChangeListener, Runnable {
        private final ViewGroup mFocusRoot;
        private final ViewGroup mContainer;
        private final ViewGroup mToolbar;

        public FollowOutOfActionBar(ViewGroup focusRoot, ViewGroup container, ViewGroup toolbar) {
            mContainer = container;
            mToolbar = toolbar;
            mFocusRoot = focusRoot;
        }

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                v.setOnFocusChangeListener(null);
                mFocusRoot.post(this);
            }
        }

        @Override
        public void run() {
            final View focused = mFocusRoot.findFocus();
            if (focused != null) {
                focused.setOnFocusChangeListener(this);
            } else {
                if (mContainer != null) {
                    mContainer.setTouchscreenBlocksFocus(true);
                }
                if (mToolbar != null) {
                    mToolbar.setTouchscreenBlocksFocus(true);
                }
            }
        }
    }
}
+9 −26
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package android.app;

import static java.lang.Character.MIN_VALUE;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.policy.PhoneWindow;

import android.annotation.CallSuper;
import android.annotation.DrawableRes;
@@ -114,22 +118,14 @@ import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.autofill.VirtualViewDelegate;
import android.view.autofill.AutoFillId;
import android.view.autofill.Dataset;
import android.view.autofill.DatasetField;
import android.view.autofill.AutoFillId;
import android.view.autofill.FillResponse;
import android.view.autofill.VirtualViewDelegate;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.Toast;
import android.widget.Toolbar;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.policy.PhoneWindow;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -139,6 +135,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static java.lang.Character.MIN_VALUE;

/**
 * An activity is a single, focused thing that the user can do.  Almost all
 * activities interact with the user, so the Activity class takes care of
@@ -852,7 +850,6 @@ public class Activity extends ContextThemeWrapper
    SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK;

    private boolean mHasCurrentPermissionsRequest;
    private boolean mEatKeyUpEvent;

    @GuardedBy("this")
    private WeakReference<IAutoFillAppCallback> mAutoFillCallback;
@@ -3181,20 +3178,6 @@ public class Activity extends ContextThemeWrapper
        if (keyCode == KeyEvent.KEYCODE_MENU &&
                mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
            return true;
        } else if (event.isCtrlPressed() &&
                event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
            // Capture the Control-< and send focus to the ActionBar
            final int action = event.getAction();
            if (action == KeyEvent.ACTION_DOWN) {
                final ActionBar actionBar = getActionBar();
                if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
                    mEatKeyUpEvent = true;
                    return true;
                }
            } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
                mEatKeyUpEvent = false;
                return true;
            }
        }

        Window win = getWindow();
+18 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
@@ -331,6 +332,23 @@ public class Toolbar extends ViewGroup {
        a.recycle();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        // If the container is a cluster, unmark itself as a cluster to avoid having nested
        // clusters.
        ViewParent parent = getParent();
        while (parent != null && parent instanceof ViewGroup) {
            final ViewGroup vgParent = (ViewGroup) parent;
            if (vgParent.isKeyboardNavigationCluster()) {
                setKeyboardNavigationCluster(false);
                break;
            }
            parent = vgParent.getParent();
        }
    }

    /**
     * Specifies the theme to use when inflating popup menus. By default, uses
     * the same theme as the toolbar itself.
+5 −14
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@

package com.android.internal.app;

import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ToolbarWidgetWrapper;

import android.annotation.Nullable;
import android.app.ActionBar;
import android.content.Context;
@@ -29,19 +34,11 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowCallbackWrapper;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;

import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ToolbarWidgetWrapper;

import java.util.ArrayList;

public class ToolbarActionBar extends ActionBar {
@@ -509,12 +506,6 @@ public class ToolbarActionBar extends ActionBar {
        }
    }

    /** @hide */
    @Override
    public boolean requestFocus() {
        return requestFocus(mDecorToolbar.getViewGroup());
    }

    private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
        public ToolbarCallbackWrapper(Window.Callback wrapped) {
            super(wrapped);
+4 −13
Original line number Diff line number Diff line
@@ -16,13 +16,6 @@

package com.android.internal.app;

import android.animation.ValueAnimator;
import android.content.res.TypedArray;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Toolbar;

import com.android.internal.R;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.MenuBuilder;
@@ -39,6 +32,7 @@ import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
@@ -46,6 +40,7 @@ import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.ActionMode;
@@ -55,10 +50,12 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewParent;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -970,12 +967,6 @@ public class WindowDecorActionBar extends ActionBar implements
        return false;
    }

    /** @hide */
    @Override
    public boolean requestFocus() {
        return requestFocus(mDecorToolbar.getViewGroup());
    }

    /**
     * @hide
     */
Loading