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

Commit e02bfb6f authored by Michael Wright's avatar Michael Wright Committed by Android (Google) Code Review
Browse files

Merge "Add unhandledInputEvent API to ViewRoot"

parents f4c1996d 899d7056
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -33183,7 +33183,8 @@ package android.webkit {
    method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
    method public void onScaleChanged(android.webkit.WebView, float, float);
    method public deprecated void onTooManyRedirects(android.webkit.WebView, android.os.Message, android.os.Message);
    method public void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
    method public void onUnhandledInputEvent(android.webkit.WebView, android.view.InputEvent);
    method public deprecated void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
    method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
    method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+75 −33
Original line number Diff line number Diff line
@@ -234,6 +234,7 @@ public final class ViewRootImpl implements ViewParent,

    InputStage mFirstInputStage;
    InputStage mFirstPostImeInputStage;
    InputStage mSyntheticInputStage;

    boolean mWindowAttributesChanged = false;
    int mWindowAttributesChangesFlag = 0;
@@ -599,8 +600,8 @@ public final class ViewRootImpl implements ViewParent,

                // Set up the input pipeline.
                CharSequence counterSuffix = attrs.getTitle();
                InputStage syntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -3007,6 +3008,7 @@ public final class ViewRootImpl implements ViewParent,
    private final static int MSG_INVALIDATE_WORLD = 23;
    private final static int MSG_WINDOW_MOVED = 24;
    private final static int MSG_FLUSH_LAYER_UPDATES = 25;
    private final static int MSG_SYNTHESIZE_INPUT_EVENT = 26;

    final class ViewRootHandler extends Handler {
        @Override
@@ -3056,6 +3058,8 @@ public final class ViewRootImpl implements ViewParent,
                    return "MSG_WINDOW_MOVED";
                case MSG_FLUSH_LAYER_UPDATES:
                    return "MSG_FLUSH_LAYER_UPDATES";
                case MSG_SYNTHESIZE_INPUT_EVENT:
                    return "MSG_SYNTHESIZE_INPUT_EVENT";
            }
            return super.getMessageName(message);
        }
@@ -3218,6 +3222,10 @@ public final class ViewRootImpl implements ViewParent,
                enqueueInputEvent(event, receiver, 0, true);
                args.recycle();
            } break;
            case MSG_SYNTHESIZE_INPUT_EVENT: {
                InputEvent event = (InputEvent)msg.obj;
                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
            } break;
            case MSG_DISPATCH_KEY_FROM_IME: {
                if (LOCAL_LOGV) Log.v(
                    TAG, "Dispatching key "
@@ -3227,7 +3235,8 @@ public final class ViewRootImpl implements ViewParent,
                    // The IME is trying to say this event is from the
                    // system!  Bad bad bad!
                    //noinspection UnusedAssignment
                    event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
                    event = KeyEvent.changeFlags(event, event.getFlags() &
                            ~KeyEvent.FLAG_FROM_SYSTEM);
                }
                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
            } break;
@@ -4023,6 +4032,7 @@ public final class ViewRootImpl implements ViewParent,
        private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
        private final SyntheticTouchNavigationHandler mTouchNavigation =
                new SyntheticTouchNavigationHandler();
        private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();

        public SyntheticInputStage() {
            super(null);
@@ -4045,7 +4055,11 @@ public final class ViewRootImpl implements ViewParent,
                    mTouchNavigation.process(event);
                    return FINISH_HANDLED;
                }
            } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
                mKeyboard.process((KeyEvent)q.mEvent);
                return FINISH_HANDLED;
            }

            return FORWARD;
        }

@@ -4882,6 +4896,33 @@ public final class ViewRootImpl implements ViewParent,
        };
    }

    final class SyntheticKeyboardHandler {
        public void process(KeyEvent event) {
            if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
                return;
            }

            final KeyCharacterMap kcm = event.getKeyCharacterMap();
            final int keyCode = event.getKeyCode();
            final int metaState = event.getMetaState();

            // Check for fallback actions specified by the key character map.
            KeyCharacterMap.FallbackAction fallbackAction =
                    kcm.getFallbackAction(keyCode, metaState);
            if (fallbackAction != null) {
                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
                KeyEvent fallbackEvent = KeyEvent.obtain(
                        event.getDownTime(), event.getEventTime(),
                        event.getAction(), fallbackAction.keyCode,
                        event.getRepeatCount(), fallbackAction.metaState,
                        event.getDeviceId(), event.getScanCode(),
                        flags, event.getSource(), null);
                fallbackAction.recycle();
                enqueueInputEvent(fallbackEvent);
            }
        }
    }

    /**
     * Returns true if the key is used for keyboard navigation.
     * @param keyEvent The key event.
@@ -5461,6 +5502,7 @@ public final class ViewRootImpl implements ViewParent,
        public static final int FLAG_FINISHED = 1 << 2;
        public static final int FLAG_FINISHED_HANDLED = 1 << 3;
        public static final int FLAG_RESYNTHESIZED = 1 << 4;
        public static final int FLAG_UNHANDLED = 1 << 5;

        public QueuedInputEvent mNext;

@@ -5475,6 +5517,14 @@ public final class ViewRootImpl implements ViewParent,
            return mEvent instanceof MotionEvent
                    && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
        }

        public boolean shouldSendToSynthesizer() {
            if ((mFlags & FLAG_UNHANDLED) != 0) {
                return true;
            }

            return false;
        }
    }

    private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
@@ -5578,7 +5628,13 @@ public final class ViewRootImpl implements ViewParent,
            mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
        }

        InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
@@ -5810,43 +5866,29 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.sendMessage(msg);
    }

    public void dispatchKeyFromIme(KeyEvent event) {
        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
    public void synthesizeInputEvent(InputEvent event) {
        Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }

    public void dispatchUnhandledKey(KeyEvent event) {
        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            // Some fallback keys are decided by the ViewRoot as they might have special
            // properties (e.g. are locale aware). These take precedence over fallbacks defined by
            // the kcm.
            final KeyCharacterMap kcm = event.getKeyCharacterMap();
            final int keyCode = event.getKeyCode();
            final int metaState = event.getMetaState();

            // Check for fallback actions specified by the key character map.
            KeyCharacterMap.FallbackAction fallbackAction =
                    kcm.getFallbackAction(keyCode, metaState);
            if (fallbackAction != null) {
                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
                KeyEvent fallbackEvent = KeyEvent.obtain(
                        event.getDownTime(), event.getEventTime(),
                        event.getAction(), fallbackAction.keyCode,
                        event.getRepeatCount(), fallbackAction.metaState,
                        event.getDeviceId(), event.getScanCode(),
                        flags, event.getSource(), null);
                fallbackAction.recycle();
                dispatchInputEvent(fallbackEvent);
            }
        }
    public void dispatchKeyFromIme(KeyEvent event) {
        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }

    /**
     * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
     *
     * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
     * passes in.
     */
    public void dispatchUnhandledInputEvent(InputEvent event) {
        if (event instanceof KeyEvent) {
            dispatchUnhandledKey((KeyEvent) event);
            return;
        if (event instanceof MotionEvent) {
            event = MotionEvent.obtain((MotionEvent) event);
        }
        synthesizeInputEvent(event);
    }

    public void dispatchAppVisibility(boolean visible) {
+33 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.webkit;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Message;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.ViewRootImpl;

@@ -272,11 +273,42 @@ public class WebViewClient {
     *
     * @param view The WebView that is initiating the callback.
     * @param event The key event.
     * @deprecated This method is subsumed by the more generic onUnhandledInputEvent.
     */
    @Deprecated
    public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
        onUnhandledInputEventInternal(view, event);
    }

    /**
     * Notify the host application that a input event was not handled by the WebView.
     * Except system keys, WebView always consumes input events in the normal flow
     * or if shouldOverrideKeyEvent returns true. This is called asynchronously
     * from where the event is dispatched. It gives the host application a chance
     * to handle the unhandled input events.
     *
     * Note that if the event is a {@link MotionEvent}, then it's lifetime is only that of the
     * function call. If the WebViewClient wishes to use the event beyond that, then it <i>must</i>
     * create a copy of the event.
     *
     * It is the responsibility of overriders of this method to call {@link onUnhandledKeyEvent}
     * when appropriate if they wish to continue receiving events through it.
     *
     * @param view The WebView that is initiating the callback.
     * @param event The input event.
     */
    public void onUnhandledInputEvent(WebView view, InputEvent event) {
        if (event instanceof KeyEvent) {
            onUnhandledKeyEvent(view, (KeyEvent) event);
            return;
        }
        onUnhandledInputEventInternal(view, event);
    }

    private void onUnhandledInputEventInternal(WebView view, InputEvent event) {
        ViewRootImpl root = view.getViewRootImpl();
        if (root != null) {
            root.dispatchUnhandledKey(event);
            root.dispatchUnhandledInputEvent(event);
        }
    }