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

Commit 3d54146c authored by Sally Yuen's avatar Sally Yuen Committed by Automerger Merge Worker
Browse files

Merge "Add accessibility support for Drag & Drop" into sc-v2-dev am: 69b9a3fb am: 748f7adf

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15667830

Change-Id: Ifb7e2b5801d3f4231fb3ad2521b1e7b6085033db
parents 647f163c 748f7adf
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -174,6 +174,11 @@ interface IWindowSession {
    IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
            float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);

    /**
     * Drops the content of the current drag operation for accessibility
     */
    boolean dropForAccessibility(IWindow window, int x, int y);

    /**
     * Report the result of a drop action targeted to the given window.
     * consumed is 'true' when the drop was accepted by a valid recipient,
+130 −7
Original line number Diff line number Diff line
@@ -3515,6 +3515,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *                    1             PFLAG4_ALLOW_CLICK_WHEN_DISABLED
     *                   1              PFLAG4_DETACHED
     *                  1               PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE
     *                 1                PFLAG4_DRAG_A11Y_STARTED
     * |-------|-------|-------|-------|
     */
@@ -3586,6 +3587,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000;
    /**
     * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START}
     */
    private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000;
    /* End of masks for mPrivateFlags4 */
    /** @hide */
@@ -10395,8 +10401,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if (mTouchDelegate != null) {
            info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
        }
        if (startedSystemDragForAccessibility()) {
            info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL);
        }
        if (canAcceptAccessibilityDrop()) {
            info.addAction(AccessibilityAction.ACTION_DRAG_DROP);
        }
    }
    /**
     * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
     * additional data.
@@ -14233,9 +14248,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                return true;
            }
        }
        if (action == R.id.accessibilityActionDragDrop) {
            if (!canAcceptAccessibilityDrop()) {
                return false;
            }
            try {
                if (mAttachInfo != null && mAttachInfo.mSession != null) {
                    final int[] location = new int[2];
                    getLocationInWindow(location);
                    final int centerX = location[0] + getWidth() / 2;
                    final int centerY = location[1] + getHeight() / 2;
                    return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow,
                            centerX, centerY);
                }
            } catch (RemoteException e) {
                Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e);
            }
            return false;
        } else if (action == R.id.accessibilityActionDragCancel) {
            if (!startedSystemDragForAccessibility()) {
                return false;
            }
            if (mAttachInfo != null && mAttachInfo.mDragToken != null) {
                cancelDragAndDrop();
                return true;
            }
            return false;
        }
        return false;
    }
    private boolean canAcceptAccessibilityDrop() {
        if (!canAcceptDrag()) {
            return false;
        }
        ListenerInfo li = mListenerInfo;
        return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null);
    }
    private boolean traverseAtGranularity(int granularity, boolean forward,
            boolean extendSelection) {
        CharSequence text = getIterableTextForAccessibility();
@@ -26681,6 +26732,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
        }
        Rect bounds = new Rect();
        getBoundsOnScreen(bounds, true);
        Point lastTouchPoint = new Point();
        mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint);
        final ViewRootImpl root = mAttachInfo.mViewRootImpl;
        // Skip surface logic since shadows and animation are not required during the a11y drag
        final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled();
        if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) {
            try {
                IBinder token = mAttachInfo.mSession.performDrag(
                        mAttachInfo.mWindow, flags, null,
                        mAttachInfo.mViewRootImpl.getLastTouchSource(),
                        0f, 0f, 0f, 0f, data);
                if (ViewDebug.DEBUG_DRAG) {
                    Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token);
                }
                if (token != null) {
                    root.setLocalDragState(myLocalState);
                    mAttachInfo.mDragToken = token;
                    mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this);
                    setAccessibilityDragStarted(true);
                }
                return token != null;
            } catch (Exception e) {
                Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e);
                return false;
            }
        }
        Point shadowSize = new Point();
        Point shadowTouchPoint = new Point();
        shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
@@ -26705,7 +26787,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
        }
        final ViewRootImpl root = mAttachInfo.mViewRootImpl;
        final SurfaceSession session = new SurfaceSession();
        final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
                .setName("drag surface")
@@ -26728,12 +26809,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                surface.unlockCanvasAndPost(canvas);
            }
            // repurpose 'shadowSize' for the last touch point
            root.getLastTouchPoint(shadowSize);
            token = mAttachInfo.mSession.performDrag(
                    mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(),
                    shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
            token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
                    root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
                    shadowTouchPoint.x, shadowTouchPoint.y, data);
            if (ViewDebug.DEBUG_DRAG) {
                Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
            }
@@ -26745,6 +26823,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mAttachInfo.mDragToken = token;
                // Cache the local state object for delivery with DragEvents
                root.setLocalDragState(myLocalState);
                if (a11yEnabled) {
                    // Set for AccessibilityEvents
                    mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this);
                }
            }
            return token != null;
        } catch (Exception e) {
@@ -26758,6 +26840,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
    }
    void setAccessibilityDragStarted(boolean started) {
        int pflags4 = mPrivateFlags4;
        if (started) {
            pflags4 |= PFLAG4_DRAG_A11Y_STARTED;
        } else {
            pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED;
        }
        if (pflags4 != mPrivateFlags4) {
            mPrivateFlags4 = pflags4;
            sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED);
        }
    }
    private boolean startedSystemDragForAccessibility() {
        return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0;
    }
    /**
     * Cancels an ongoing drag and drop operation.
     * <p>
@@ -26975,6 +27075,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        switch (event.mAction) {
            case DragEvent.ACTION_DRAG_STARTED: {
                if (result && li.mOnDragListener != null) {
                    sendWindowContentChangedAccessibilityEvent(
                            AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                }
            } break;
            case DragEvent.ACTION_DRAG_ENTERED: {
                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
                refreshDrawableState();
@@ -26983,7 +27089,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                refreshDrawableState();
            } break;
            case DragEvent.ACTION_DROP: {
                if (result && (li.mOnDragListener != null | li.mOnReceiveContentListener != null)) {
                    sendWindowContentChangedAccessibilityEvent(
                            AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED);
                }
            } break;
            case DragEvent.ACTION_DRAG_ENDED: {
                sendWindowContentChangedAccessibilityEvent(
                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                mPrivateFlags2 &= ~View.DRAG_MASK;
                refreshDrawableState();
            } break;
@@ -26996,6 +27110,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0;
    }
    void sendWindowContentChangedAccessibilityEvent(int changeType) {
        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
            AccessibilityEvent event = AccessibilityEvent.obtain();
            event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
            event.setContentChangeTypes(changeType);
            sendAccessibilityEventUnchecked(event);
        }
    }
    /**
     * This needs to be a better API (NOT ON VIEW) before it is exposed.  If
     * it is ever exposed at all.
+3 −0
Original line number Diff line number Diff line
@@ -412,6 +412,9 @@ public interface ViewParent {
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED}
     *            </ul>
     */
    public void notifySubtreeAccessibilityStateChanged(
+23 −0
Original line number Diff line number Diff line
@@ -650,6 +650,7 @@ public final class ViewRootImpl implements ViewParent,
    /* Drag/drop */
    ClipDescription mDragDescription;
    View mCurrentDragView;
    View mStartedDragViewForA11y;
    volatile Object mLocalDragState;
    final PointF mDragPoint = new PointF();
    final PointF mLastTouchPoint = new PointF();
@@ -7583,6 +7584,11 @@ public final class ViewRootImpl implements ViewParent,
            if (what == DragEvent.ACTION_DRAG_STARTED) {
                mCurrentDragView = null;    // Start the current-recipient tracking
                mDragDescription = event.mClipDescription;
                if (mStartedDragViewForA11y != null) {
                    // Send a drag started a11y event
                    mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
                            AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
                }
            } else {
                if (what == DragEvent.ACTION_DRAG_ENDED) {
                    mDragDescription = null;
@@ -7657,6 +7663,16 @@ public final class ViewRootImpl implements ViewParent,

                // When the drag operation ends, reset drag-related state
                if (what == DragEvent.ACTION_DRAG_ENDED) {
                    if (mStartedDragViewForA11y != null) {
                        // If the drag failed, send a cancelled event from the source. Otherwise,
                        // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED
                        if (!event.getResult()) {
                            mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
                                    AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED);
                        }
                        mStartedDragViewForA11y.setAccessibilityDragStarted(false);
                    }
                    mStartedDragViewForA11y = null;
                    mCurrentDragView = null;
                    setLocalDragState(null);
                    mAttachInfo.mDragToken = null;
@@ -7736,6 +7752,13 @@ public final class ViewRootImpl implements ViewParent,
        mCurrentDragView = newDragTarget;
    }

    /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */
    void setDragStartedViewForAccessibility(View view) {
        if (mStartedDragViewForA11y == null) {
            mStartedDragViewForA11y = view;
        }
    }

    private AudioManager getAudioManager() {
        if (mView == null) {
            throw new IllegalStateException("getAudioManager called when there is no mView");
+5 −0
Original line number Diff line number Diff line
@@ -498,4 +498,9 @@ public class WindowlessWindowManager implements IWindowSession {
    public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
            RemoteCallback callback) {
    }

    @Override
    public boolean dropForAccessibility(IWindow window, int x, int y) {
        return false;
    }
}
Loading