summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--core/java/android/view/ViewRootImpl.java108
-rw-r--r--core/java/android/webkit/WebViewClient.java34
3 files changed, 110 insertions, 35 deletions
diff --git a/api/current.txt b/api/current.txt
index 6d577963f711..f6d976e9b74a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ea52924234cf..beebeb193d49 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -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) {
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 688c2518bf67..33a6df6a9131 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -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);
}
}