From d89619792e616535810baf82c0224bcf8559b753 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 14 Oct 2019 17:00:17 +0800 Subject: [PATCH] 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 --- .../systemui/pip/phone/PipMenuActivity.java | 22 ++++++-- .../pip/phone/PipMenuActivityController.java | 6 +-- .../systemui/pip/phone/PipTouchHandler.java | 50 +++++++++++-------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 5723afd4ae950..c452f64ff6f05 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 62c59e5842ffe..b8e0b81e5e8ef 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 1f36d97ce3083..f59b372762bd4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -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); }