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

Commit 748f7adf 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

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

Change-Id: I16ee567270b03f69a761590b3b38ab369b874768
parents ef208585 69b9a3fb
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -174,6 +174,11 @@ interface IWindowSession {
    IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
    IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
            float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
            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.
     * Report the result of a drop action targeted to the given window.
     * consumed is 'true' when the drop was accepted by a valid recipient,
     * consumed is 'true' when the drop was accepted by a valid recipient,
+130 −7
Original line number Original line 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_ALLOW_CLICK_WHEN_DISABLED
     *                   1              PFLAG4_DETACHED
     *                   1              PFLAG4_DETACHED
     *                  1               PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE
     *                  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;
    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 */
    /* End of masks for mPrivateFlags4 */
    /** @hide */
    /** @hide */
@@ -10384,8 +10390,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if (mTouchDelegate != null) {
        if (mTouchDelegate != null) {
            info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
            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
     * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
     * additional data.
     * additional data.
@@ -14222,9 +14237,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                return true;
                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;
        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,
    private boolean traverseAtGranularity(int granularity, boolean forward,
            boolean extendSelection) {
            boolean extendSelection) {
        CharSequence text = getIterableTextForAccessibility();
        CharSequence text = getIterableTextForAccessibility();
@@ -26664,6 +26715,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
            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 shadowSize = new Point();
        Point shadowTouchPoint = new Point();
        Point shadowTouchPoint = new Point();
        shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
        shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
@@ -26688,7 +26770,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
                    + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
        }
        }
        final ViewRootImpl root = mAttachInfo.mViewRootImpl;
        final SurfaceSession session = new SurfaceSession();
        final SurfaceSession session = new SurfaceSession();
        final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
        final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
                .setName("drag surface")
                .setName("drag surface")
@@ -26711,12 +26792,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                surface.unlockCanvasAndPost(canvas);
                surface.unlockCanvasAndPost(canvas);
            }
            }
            // repurpose 'shadowSize' for the last touch point
            token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
            root.getLastTouchPoint(shadowSize);
                    root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
                    shadowTouchPoint.x, shadowTouchPoint.y, data);
            token = mAttachInfo.mSession.performDrag(
                    mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(),
                    shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
            if (ViewDebug.DEBUG_DRAG) {
            if (ViewDebug.DEBUG_DRAG) {
                Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
                Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
            }
            }
@@ -26728,6 +26806,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mAttachInfo.mDragToken = token;
                mAttachInfo.mDragToken = token;
                // Cache the local state object for delivery with DragEvents
                // Cache the local state object for delivery with DragEvents
                root.setLocalDragState(myLocalState);
                root.setLocalDragState(myLocalState);
                if (a11yEnabled) {
                    // Set for AccessibilityEvents
                    mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this);
                }
            }
            }
            return token != null;
            return token != null;
        } catch (Exception e) {
        } catch (Exception e) {
@@ -26741,6 +26823,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.
     * Cancels an ongoing drag and drop operation.
     * <p>
     * <p>
@@ -26958,6 +27058,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        }
        switch (event.mAction) {
        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: {
            case DragEvent.ACTION_DRAG_ENTERED: {
                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
                refreshDrawableState();
                refreshDrawableState();
@@ -26966,7 +27072,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                refreshDrawableState();
                refreshDrawableState();
            } break;
            } 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: {
            case DragEvent.ACTION_DRAG_ENDED: {
                sendWindowContentChangedAccessibilityEvent(
                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                mPrivateFlags2 &= ~View.DRAG_MASK;
                mPrivateFlags2 &= ~View.DRAG_MASK;
                refreshDrawableState();
                refreshDrawableState();
            } break;
            } break;
@@ -26979,6 +27093,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0;
        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
     * This needs to be a better API (NOT ON VIEW) before it is exposed.  If
     * it is ever exposed at all.
     * it is ever exposed at all.
+3 −0
Original line number Original line 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_SUBTREE}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
     *            <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>
     *            </ul>
     */
     */
    public void notifySubtreeAccessibilityStateChanged(
    public void notifySubtreeAccessibilityStateChanged(
+23 −0
Original line number Original line Diff line number Diff line
@@ -651,6 +651,7 @@ public final class ViewRootImpl implements ViewParent,
    /* Drag/drop */
    /* Drag/drop */
    ClipDescription mDragDescription;
    ClipDescription mDragDescription;
    View mCurrentDragView;
    View mCurrentDragView;
    View mStartedDragViewForA11y;
    volatile Object mLocalDragState;
    volatile Object mLocalDragState;
    final PointF mDragPoint = new PointF();
    final PointF mDragPoint = new PointF();
    final PointF mLastTouchPoint = new PointF();
    final PointF mLastTouchPoint = new PointF();
@@ -7584,6 +7585,11 @@ public final class ViewRootImpl implements ViewParent,
            if (what == DragEvent.ACTION_DRAG_STARTED) {
            if (what == DragEvent.ACTION_DRAG_STARTED) {
                mCurrentDragView = null;    // Start the current-recipient tracking
                mCurrentDragView = null;    // Start the current-recipient tracking
                mDragDescription = event.mClipDescription;
                mDragDescription = event.mClipDescription;
                if (mStartedDragViewForA11y != null) {
                    // Send a drag started a11y event
                    mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
                            AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
                }
            } else {
            } else {
                if (what == DragEvent.ACTION_DRAG_ENDED) {
                if (what == DragEvent.ACTION_DRAG_ENDED) {
                    mDragDescription = null;
                    mDragDescription = null;
@@ -7658,6 +7664,16 @@ public final class ViewRootImpl implements ViewParent,


                // When the drag operation ends, reset drag-related state
                // When the drag operation ends, reset drag-related state
                if (what == DragEvent.ACTION_DRAG_ENDED) {
                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;
                    mCurrentDragView = null;
                    setLocalDragState(null);
                    setLocalDragState(null);
                    mAttachInfo.mDragToken = null;
                    mAttachInfo.mDragToken = null;
@@ -7737,6 +7753,13 @@ public final class ViewRootImpl implements ViewParent,
        mCurrentDragView = newDragTarget;
        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() {
    private AudioManager getAudioManager() {
        if (mView == null) {
        if (mView == null) {
            throw new IllegalStateException("getAudioManager called when there is no mView");
            throw new IllegalStateException("getAudioManager called when there is no mView");
+5 −0
Original line number Original line Diff line number Diff line
@@ -498,4 +498,9 @@ public class WindowlessWindowManager implements IWindowSession {
    public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
    public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
            RemoteCallback callback) {
            RemoteCallback callback) {
    }
    }

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