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

Commit c93fb656 authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

bug:3325039 Making the cursor ring movement send accessibility events.

1. Added a mechanism to select the cursor ring content if accessibility is
   enabled - This is achieved by sending an event to the WebCore thread
   (if accessibility is enabled) to select the content of the cursor when
   the latter moves. Added code in WebViewCore to select the given node
   and notify the UI thread for the selection markup which is delivered
   of the accessibility injector which manages sending accessibility
   events. This is relevant for adding accessibility to WebView if
   JavaScript is not enabled. (If JS is enabled we inject a screenreader
   written in JS).

2. Fixed the event delegation to the accessibility injector since it
   should be able to consume key events of interest and perform some
   action which leads to sending appropriate accessibility event.
   In the previous implementation it was possible that the injector
   consumes the event but the latter was bubbled up.

3. Added function to scroll the selection into view while moving it
   around based on user commands.

Note: This is a part of two project commmit.

Change-Id: Ibb81d0468726efbe3bf6e3add1b19c69e3206638
parent 23ddfbe5
Loading
Loading
Loading
Loading
+34 −13
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ class AccessibilityInjector {
    private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
    private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
    private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
    private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;

    // the default WebView behavior abstracted as a navigation axis
    private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
@@ -153,7 +154,6 @@ class AccessibilityInjector {
                    direction = binding.getFirstArgument(i);
                    // on second null selection string in same direction => WebView handle the event
                    if (direction == mLastDirection && mIsLastSelectionStringNull) {
                        mLastDirection = direction;
                        mIsLastSelectionStringNull = false;
                        return false;
                    }
@@ -170,6 +170,22 @@ class AccessibilityInjector {
                    prefromAxisTransition(fromAxis, toAxis, sendEvent, contentDescription);
                    mLastDownEventHandled = true;
                    break;
                case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS:
                    // This is a special case since we treat the default WebView navigation
                    // behavior as one of the possible navigation axis the user can use.
                    // If we are not on the default WebView navigation axis this is NOP.
                    if (mCurrentAxis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
                        // While WebVew handles navigation we do not get null selection
                        // strings so do not check for that here as the cases above.
                        mLastDirection = binding.getFirstArgument(i);
                        sendEvent = (binding.getSecondArgument(i) == 1);
                        traverseGivenAxis(mLastDirection, NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR,
                            sendEvent, contentDescription);
                        mLastDownEventHandled = false;
                    } else {
                        mLastDownEventHandled = true;
                    }
                    break;
                default:
                    Log.w(LOG_TAG, "Unknown action code: " + actionCode);
            }
@@ -236,12 +252,11 @@ class AccessibilityInjector {
     */
    private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
            String contentDescription) {
        // if the axis is the default let WebView handle the event
        if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
        WebViewCore webViewCore = mWebView.getWebViewCore();
        if (webViewCore == null) {
            return false;
        }
        WebViewCore webViewCore = mWebView.getWebViewCore();
        if (webViewCore != null) {

        AccessibilityEvent event = null;
        if (sendEvent) {
            event = getPartialyPopulatedAccessibilityEvent();
@@ -249,8 +264,14 @@ class AccessibilityInjector {
            event.setContentDescription(contentDescription);
        }
        mScheduledEventStack.push(event);
            webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);

        // if the axis is the default let WebView handle the event which will
        // result in cursor ring movement and selection of its content
        if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
            return false;
        }

        webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);
        return true;
    }

+38 −12
Original line number Diff line number Diff line
@@ -4540,19 +4540,23 @@ public class WebView extends AbsoluteLayout
        // Bubble up the key event if
        // 1. it is a system key; or
        // 2. the host application wants to handle it;
        // 3. the accessibility injector is present and wants to handle it;
        if (event.isSystem()
                || mCallbackProxy.uiOverrideKeyEvent(event)
                || (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event))) {
                || mCallbackProxy.uiOverrideKeyEvent(event)) {
            return false;
        }

        // accessibility support
        if (accessibilityScriptInjected()) {
            // if an accessibility script is injected we delegate to it the key handling.
            // this script is a screen reader which is a fully fledged solution for blind
            // users to navigate in and interact with web pages.
        if (accessibilityScriptInjected()) {
            mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
            return true;
        } else if (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event)) {
            // if an accessibility injector is present (no JavaScript enabled or the site opts
            // out injecting our JavaScript screen reader) we let it decide whether to act on
            // and consume the event.
            return true;
        }

        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
@@ -4702,19 +4706,23 @@ public class WebView extends AbsoluteLayout
        // Bubble up the key event if
        // 1. it is a system key; or
        // 2. the host application wants to handle it;
        // 3. the accessibility injector is present and wants to handle it;
        if (event.isSystem()
                || mCallbackProxy.uiOverrideKeyEvent(event)
                || (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event))) {
                || mCallbackProxy.uiOverrideKeyEvent(event)) {
            return false;
        }

        // accessibility support
        if (accessibilityScriptInjected()) {
            // if an accessibility script is injected we delegate to it the key handling.
            // this script is a screen reader which is a fully fledged solution for blind
            // users to navigate in and interact with web pages.
        if (accessibilityScriptInjected()) {
            mWebViewCore.sendMessage(EventHub.KEY_UP, event);
            return true;
        } else if (mAccessibilityInjector != null && mAccessibilityInjector.onKeyEvent(event)) {
            // if an accessibility injector is present (no JavaScript enabled or the site opts
            // out injecting our JavaScript screen reader) we let it decide whether to act on
            // and consume the event.
            return true;
        }

        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
@@ -7791,6 +7799,24 @@ public class WebView extends AbsoluteLayout
                cursorData());
    }

    /*
     * Called from JNI when the cursor has moved. This method
     * sends a message to the WebCore requesting the given
     * nodePtr in the given framePrt to be selected which will
     * result in firing an accessibility event announing its
     * content.
     *
     * Note: Accessibility support.
     */
    @SuppressWarnings("unused")
    // called from JNI
    private void sendMoveSelection(int framePtr, int nodePtr) {
        if (AccessibilityManager.getInstance(mContext).isEnabled()
                && mAccessibilityInjector != null) {
            mWebViewCore.sendMessage(EventHub.MOVE_SELECTION, framePtr, nodePtr);
        }
    }

    // called by JNI
    private void sendMotionUp(int touchGeneration,
            int frame, int node, int x, int y) {
+26 −2
Original line number Diff line number Diff line
@@ -627,6 +627,8 @@ final class WebViewCore {
    /**
     * Modifies the current selection.
     *
     * Note: Accessibility support.
     *
     * @param direction The direction in which to alter the selection.
     * @param granularity The granularity of the selection modification.
     *
@@ -634,6 +636,18 @@ final class WebViewCore {
     */
    private native String nativeModifySelection(int direction, int granularity);

    /**
     * Moves the selection to given node i.e. selects that node.
     *
     * Note: Accessibility support.
     *
     * @param framePtr Pointer to the frame containing the node to be selected.
     * @param nodePtr Pointer to the node to be selected.
     *
     * @return The selection string.
     */
    private native String nativeMoveSelection(int framePtr, int nodePtr);

    // EventHub for processing messages
    private final EventHub mEventHub;
    // WebCore thread handler
@@ -994,6 +1008,9 @@ final class WebViewCore {

        static final int PROXY_CHANGED = 193;

        // accessibility support
        static final int MOVE_SELECTION = 194;

        // private message ids
        private static final int DESTROY =     200;

@@ -1401,9 +1418,16 @@ final class WebViewCore {
                            break;

                        case MODIFY_SELECTION:
                            String selectionString = nativeModifySelection(msg.arg1, msg.arg2);
                            String modifiedSelectionString = nativeModifySelection(msg.arg1,
                                    msg.arg2);
                            mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED,
                                    modifiedSelectionString).sendToTarget();
                            break;

                        case MOVE_SELECTION:
                            String movedSelectionString = nativeMoveSelection(msg.arg1, msg.arg2);
                            mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED,
                                    selectionString).sendToTarget();
                                    movedSelectionString).sendToTarget();
                            break;

                        case LISTBOX_CHOICES:
+4 −4
Original line number Diff line number Diff line
@@ -85,10 +85,10 @@
            0x13=0x01000100;
            <!-- DPAD/Trackball DOWN maps to traverse next on current axis and send an event. -->
            0x14=0x01010100;
            <!-- DPAD/Trackball LEFT maps to action in non-android default navigation axis. -->
            0x15=0x04000000;
            <!-- DPAD/Trackball RIGHT maps to no action in non-android default navigation axis. -->
            0x16=0x04000000;
            <!-- DPAD/Trackball LEFT maps to action in the android default navigation axis. -->
            0x15=0x04000100;
            <!-- DPAD/Trackball RIGHT maps to no action in the android default navigation axis. -->
            0x16=0x04010100;
            <!-- Left Alt+DPAD/Trackball UP transitions from an axis to another and sends an event. -->
            <!-- Axis transitions:  2 -> 7; 1 -> 2; 0 -> 1; 3 -> 0; 4 -> 0; 5 -> 0; 6 -> 0; -->
            0x120013=0x03020701:0x03010201:0x03000101:0x03030001:0x03040001:0x03050001:0x03060001;