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

Commit a6a814b7 authored by “Longbo's avatar “Longbo
Browse files

a11y: Show the grab cursor when the cursor is inside the panel's grab-able area

Video: http://shortn/_fCZtSdBOjz

Bug: b/416050648
Test: AutoclickTypePanelTest
Flag: com.android.server.accessibility.enable_autoclick_indicator
Change-Id: If6940936f3a0a7e14b1db2b3d772ccdade8bc76c
parent 429bd452
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -68,6 +69,7 @@ public class AutoclickTypePanel {
    // Initial panel position in screen coordinates.
    private int mPanelStartX, mPanelStartY;
    private boolean mIsDragging = false;
    private PointerIcon mCurrentCursor;

    // Types of click the AutoclickTypePanel supports.
    @IntDef({
@@ -182,11 +184,24 @@ public class AutoclickTypePanel {
        mLongPressButton =
                mContentView.findViewById(R.id.accessibility_autoclick_long_press_layout);

        // Initialize the cursor icons.
        mCurrentCursor = PointerIcon.getSystemIcon(context, PointerIcon.TYPE_ARROW);

        initializeButtonState();

        // Set up touch event handling for the panel to allow the user to drag and reposition the
        // panel by touching and moving it.
        mContentView.setOnTouchListener(this::onPanelTouch);

        // Set hover behavior for the panel, show grab when hovering.
        mContentView.setOnHoverListener((v, event) -> {
            mCurrentCursor = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_GRAB);
            v.setPointerIcon(mCurrentCursor);
            return false;
        });

        // Show default cursor when hovering over buttons.
        setDefaultCursorForButtons();
    }

    /**
@@ -210,6 +225,13 @@ public class AutoclickTypePanel {
                v.getLocationOnScreen(location);
                mPanelStartX = location[0];
                mPanelStartY = location[1];
                // Show grabbing cursor when dragging starts.
                boolean isSynthetic =
                        (event.getFlags() & MotionEvent.FLAG_IS_GENERATED_GESTURE) != 0;
                if (!isSynthetic) {
                    mCurrentCursor = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_GRABBING);
                    v.setPointerIcon(mCurrentCursor);
                }
                return true;
            case MotionEvent.ACTION_MOVE:
                mIsDragging = true;
@@ -235,6 +257,9 @@ public class AutoclickTypePanel {
                    snapToNearestEdge(mParams);
                }
                mIsDragging = false;
                // Show grab cursor when dragging ends.
                mCurrentCursor = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_GRAB);
                v.setPointerIcon(mCurrentCursor);
                return true;
        }
        return false;
@@ -602,6 +627,22 @@ public class AutoclickTypePanel {
        }
    }

    private void setDefaultCursorForButtons() {
        View[] buttons = {
                mLeftClickButton, mRightClickButton, mDoubleClickButton,
                mScrollButton, mDragButton, mLongPressButton,
                mPauseButton, mPositionButton
        };

        for (View button : buttons) {
            button.setOnHoverListener((v, event) -> {
                mCurrentCursor = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
                v.setPointerIcon(mCurrentCursor);
                return false;
            });
        }
    }

    @VisibleForTesting
    boolean getExpansionStateForTesting() {
        return mExpanded;
@@ -629,6 +670,11 @@ public class AutoclickTypePanel {
        return mIsDragging;
    }

    @VisibleForTesting
    PointerIcon getCurrentCursorForTesting() {
        return mCurrentCursor;
    }

    /**
     * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window
     * Manager.
+47 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.testing.TestableContext;
import android.testing.TestableLooper;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
@@ -538,6 +539,52 @@ public class AutoclickTypePanelTest {
        assertThat(mHovered).isFalse();
    }

    @Test
    public void cursorIcon_fullDragCycle() {
        View contentView = mAutoclickTypePanel.getContentViewForTesting();
        int[] panelLocation = new int[2];
        contentView.getLocationOnScreen(panelLocation);

        // Set up drag coordinates.
        float startX = panelLocation[0] + 10;
        float startY = panelLocation[1] + 10;
        float moveX = startX + 50;
        float moveY = startY + 20;

        // 1. Initial state.
        PointerIcon initialCursor = mAutoclickTypePanel.getCurrentCursorForTesting();

        // 2. DOWN event - Touch starts.
        MotionEvent downEvent = MotionEvent.obtain(
                0, 0, MotionEvent.ACTION_DOWN, startX, startY, 0);
        contentView.dispatchTouchEvent(downEvent);
        PointerIcon touchStartCursor = mAutoclickTypePanel.getCurrentCursorForTesting();

        // 3. MOVE event - Dragging starts.
        MotionEvent moveEvent = MotionEvent.obtain(
                0, 0, MotionEvent.ACTION_MOVE, moveX, moveY, 0);
        contentView.dispatchTouchEvent(moveEvent);
        PointerIcon draggingCursor = mAutoclickTypePanel.getCurrentCursorForTesting();

        // 4. UP event - Drag ends.
        MotionEvent upEvent = MotionEvent.obtain(
                0, 0, MotionEvent.ACTION_UP, moveX, moveY, 0);
        contentView.dispatchTouchEvent(upEvent);
        PointerIcon afterDragCursor = mAutoclickTypePanel.getCurrentCursorForTesting();

        // Initial state should be default cursor.
        assertThat(initialCursor.getType()).isEqualTo(PointerIcon.TYPE_ARROW);

        // After touch down - cursor should change to grabbing.
        assertThat(touchStartCursor.getType()).isEqualTo(PointerIcon.TYPE_GRABBING);

        // During drag - should be in dragging state with grabbing cursor.
        assertThat(draggingCursor.getType()).isEqualTo(PointerIcon.TYPE_GRABBING);

        // After drag ends - should not be dragging and cursor should be grab.
        assertThat(afterDragCursor.getType()).isEqualTo(PointerIcon.TYPE_GRAB);
    }

    private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) {
        GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
        assertThat(gradientDrawable.getColor().getDefaultColor())