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

Commit d8961979 authored by Arthur Hung's avatar Arthur Hung
Browse files

Fix talkback unable to select pip window buttons

While talkback enabled, single touch would be translated to hover
events, and all touch events would first sent to pip input consumer
then dispatch them to pip menu activity. So we should dispatch these
hover events to dispatchGenericMotionEvent of menu activity to make sure
them would be handled correctly.

- It should unregister PictureInPictureActionReplacingConnection when
  menu activity shown to make sure a11y action can be performed by default.
- Move overridePendingTransition to onCreate to ensure a11y window infos
  can be updated after first time finish.

Bug: 142268623
Test: Enable talkback and launch pip, click buttons on pip window
Test: atest AbstractAccessibilityServiceConnectionTest
Change-Id: I886106d3d36c54e4540e25056c79dad5c82405e8
parent 8e554f88
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ public class PipMenuActivity extends Activity {
    public static final int MESSAGE_UPDATE_ACTIONS = 4;
    public static final int MESSAGE_UPDATE_DISMISS_FRACTION = 5;
    public static final int MESSAGE_ANIMATION_ENDED = 6;
    public static final int MESSAGE_TOUCH_EVENT = 7;
    public static final int MESSAGE_POINTER_EVENT = 7;

    private static final int INITIAL_DISMISS_DELAY = 3500;
    private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
@@ -165,9 +165,9 @@ public class PipMenuActivity extends Activity {
                    break;
                }

                case MESSAGE_TOUCH_EVENT: {
                case MESSAGE_POINTER_EVENT: {
                    final MotionEvent ev = (MotionEvent) msg.obj;
                    dispatchTouchEvent(ev);
                    dispatchPointerEvent(ev);
                    break;
                }
            }
@@ -219,6 +219,9 @@ public class PipMenuActivity extends Activity {
        updateFromIntent(getIntent());
        setTitle(R.string.pip_menu_title);
        setDisablePreviewScreenshots(true);

        // Hide without an animation.
        getWindow().setExitTransition(null);
    }

    @Override
@@ -269,6 +272,17 @@ public class PipMenuActivity extends Activity {
        }
    }

    /**
     * Dispatch a pointer event from {@link PipTouchHandler}.
     */
    private void dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            dispatchTouchEvent(event);
        } else {
            dispatchGenericMotionEvent(event);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!mAllowTouches) {
@@ -288,8 +302,6 @@ public class PipMenuActivity extends Activity {
    public void finish() {
        notifyActivityCallback(null);
        super.finish();
        // Hide without an animation (the menu should already be invisible at this point)
        overridePendingTransition(0, 0);
    }

    @Override
+3 −3
Original line number Diff line number Diff line
@@ -508,12 +508,12 @@ public class PipMenuActivityController {
    }

    /**
     * Handles touch event sent from pip input consumer.
     * Handles a pointer event sent from pip input consumer.
     */
    void handleTouchEvent(MotionEvent ev) {
    void handlePointerEvent(MotionEvent ev) {
        if (mToActivityMessenger != null) {
            Message m = Message.obtain();
            m.what = PipMenuActivity.MESSAGE_TOUCH_EVENT;
            m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
            m.obj = ev;
            try {
                mToActivityMessenger.send(m);
+29 −21
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ public class PipTouchHandler {
    private boolean mSendingHoverAccessibilityEvents;
    private boolean mMovementWithinMinimize;
    private boolean mMovementWithinDismiss;
    private PipAccessibilityInteractionConnection mConnection;

    // Touch state
    private final PipTouchState mTouchState;
@@ -213,9 +214,10 @@ public class PipTouchHandler {
        // Register the listener for input consumer touch events
        inputConsumerController.setInputListener(this::handleTouchEvent);
        inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
        onRegistrationChanged(inputConsumerController.isRegistered());

        mPipBoundsHandler = pipBoundsHandler;
        mConnection = new PipAccessibilityInteractionConnection(mMotionHelper,
                this::onAccessibilityShowMenu, mHandler);
    }

    public void setTouchEnabled(boolean enabled) {
@@ -339,9 +341,7 @@ public class PipTouchHandler {

    private void onRegistrationChanged(boolean isRegistered) {
        mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
                ? new PipAccessibilityInteractionConnection(mMotionHelper,
                        this::onAccessibilityShowMenu, mHandler) : null);

                ? mConnection : null);
        if (!isRegistered && mTouchState.isUserInteracting()) {
            // If the input consumer is unregistered while the user is interacting, then we may not
            // get the final TOUCH_UP event, so clean up the dismiss target as well
@@ -409,27 +409,15 @@ public class PipTouchHandler {
            }
            case MotionEvent.ACTION_HOVER_ENTER:
            case MotionEvent.ACTION_HOVER_MOVE: {
                if (mAccessibilityManager.isEnabled() && !mSendingHoverAccessibilityEvents) {
                    AccessibilityEvent event = AccessibilityEvent.obtain(
                            AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
                    event.setImportantForAccessibility(true);
                    event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
                    event.setWindowId(
                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
                    mAccessibilityManager.sendAccessibilityEvent(event);
                if (!shouldDeliverToMenu && !mSendingHoverAccessibilityEvents) {
                    sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
                    mSendingHoverAccessibilityEvents = true;
                }
                break;
            }
            case MotionEvent.ACTION_HOVER_EXIT: {
                if (mAccessibilityManager.isEnabled() && mSendingHoverAccessibilityEvents) {
                    AccessibilityEvent event = AccessibilityEvent.obtain(
                            AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
                    event.setImportantForAccessibility(true);
                    event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
                    event.setWindowId(
                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
                    mAccessibilityManager.sendAccessibilityEvent(event);
                if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) {
                    sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
                    mSendingHoverAccessibilityEvents = false;
                }
                break;
@@ -445,12 +433,25 @@ public class PipTouchHandler {
                mMenuController.pokeMenu();
            }

            mMenuController.handleTouchEvent(cloneEvent);
            mMenuController.handlePointerEvent(cloneEvent);
        }

        return true;
    }

    private void sendAccessibilityHoverEvent(int type) {
        if (!mAccessibilityManager.isEnabled()) {
            return;
        }

        AccessibilityEvent event = AccessibilityEvent.obtain(type);
        event.setImportantForAccessibility(true);
        event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
        event.setWindowId(
                AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
        mAccessibilityManager.sendAccessibilityEvent(event);
    }

    /**
     * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
     */
@@ -523,6 +524,10 @@ public class PipTouchHandler {
     * Sets the menu visibility.
     */
    private void setMenuState(int menuState, boolean resize) {
        if (mMenuState == menuState && !resize) {
            return;
        }

        if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
            // Save the current snap fraction and if we do not drag or move the PiP, then
            // we store back to this snap fraction.  Otherwise, we'll reset the snap
@@ -571,6 +576,9 @@ public class PipTouchHandler {
        }
        mMenuState = menuState;
        updateMovementBounds(menuState);
        // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
        // as well, or it can't handle a11y focus and pip menu can't perform any action.
        onRegistrationChanged(menuState == MENU_STATE_NONE);
        if (menuState != MENU_STATE_CLOSE) {
            MetricsLoggerWrapper.logPictureInPictureMenuVisible(mContext, menuState == MENU_STATE_FULL);
        }