diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index 008a615b5bcba..8008a6bffc8e7 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -318,12 +318,15 @@ class AccessibilityInjector { /** * Attempts to handle selection change events when accessibility is using a * non-JavaScript method. + *
+ * This must not be called from the main thread. * - * @param selectionString The selection string. + * @param selection The selection string. + * @param token The selection request token. */ - public void handleSelectionChangedIfNecessary(String selectionString) { + public void onSelectionStringChangedWebCoreThread(String selection, int token) { if (mAccessibilityInjectorFallback != null) { - mAccessibilityInjectorFallback.onSelectionStringChange(selectionString); + mAccessibilityInjectorFallback.onSelectionStringChangedWebCoreThread(selection, token); } } diff --git a/core/java/android/webkit/AccessibilityInjectorFallback.java b/core/java/android/webkit/AccessibilityInjectorFallback.java index 783b3db3b3850..6417527b96300 100644 --- a/core/java/android/webkit/AccessibilityInjectorFallback.java +++ b/core/java/android/webkit/AccessibilityInjectorFallback.java @@ -27,8 +27,9 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.webkit.WebViewCore.EventHub; +import com.android.internal.os.SomeArgs; + import java.util.ArrayList; -import java.util.Stack; /** * This class injects accessibility into WebViews with disabled JavaScript or @@ -48,8 +49,7 @@ import java.util.Stack; *
* The possible actions are invocations to * {@link #setCurrentAxis(int, boolean, String)}, or - * {@link #traverseCurrentAxis(int, boolean, String)} - * {@link #traverseGivenAxis(int, int, boolean, String)} + * {@link #traverseGivenAxis(int, int, boolean, String, boolean)} * {@link #performAxisTransition(int, int, boolean, String)} * referred via the values of: * {@link #ACTION_SET_CURRENT_AXIS}, @@ -74,6 +74,9 @@ class AccessibilityInjectorFallback { private static final int ACTION_PERFORM_AXIS_TRANSITION = 3; private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4; + /** Timeout after which asynchronous granular movement is aborted. */ + private static final int MODIFY_SELECTION_TIMEOUT = 500; + // WebView navigation axes from WebViewCore.h, plus an additional axis for // the default behavior. private static final int NAVIGATION_AXIS_CHARACTER = 0; @@ -81,7 +84,8 @@ class AccessibilityInjectorFallback { private static final int NAVIGATION_AXIS_SENTENCE = 2; @SuppressWarnings("unused") private static final int NAVIGATION_AXIS_HEADING = 3; - private static final int NAVIGATION_AXIS_SIBLING = 5; + @SuppressWarnings("unused") + private static final int NAVIGATION_AXIS_SIBLING = 4; @SuppressWarnings("unused") private static final int NAVIGATION_AXIS_PARENT_FIRST_CHILD = 5; private static final int NAVIGATION_AXIS_DOCUMENT = 6; @@ -99,8 +103,11 @@ class AccessibilityInjectorFallback { private final WebViewClassic mWebView; private final WebView mWebViewInternal; - // events scheduled for sending as soon as we receive the selected text - private final StackselectionString has changed.
- */
- public void onSelectionStringChange(String selectionString) {
- if (DEBUG) {
- Log.d(LOG_TAG, "Selection string: " + selectionString);
+ /* package */ void onSelectionStringChangedWebCoreThread(
+ final String selection, final int token) {
+ synchronized (mCallbackLock) {
+ mCallbackReceived = true;
+ mCallbackResult = (selection != null);
+ mCallbackLock.notifyAll();
}
- mIsLastSelectionStringNull = (selectionString == null);
- if (mScheduledEventStack.isEmpty()) {
+
+ // Managing state and sending events must take place on the UI thread.
+ mWebViewInternal.post(new Runnable() {
+ @Override
+ public void run() {
+ onSelectionStringChangedMainThread(selection, token);
+ }
+ });
+ }
+
+ private void onSelectionStringChangedMainThread(String selection, int token) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Selection string: " + selection);
+ }
+
+ if (token != mScheduledToken) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Selection string has incorrect token: " + token);
+ }
return;
}
- AccessibilityEvent event = mScheduledEventStack.pop();
- if ((event != null) && (selectionString != null)) {
- event.getText().add(selectionString);
+
+ mIsLastSelectionStringNull = (selection == null);
+
+ final AccessibilityEvent event = mScheduledEvent;
+ mScheduledEvent = null;
+
+ if ((event != null) && (selection != null)) {
+ event.getText().add(selection);
event.setFromIndex(0);
- event.setToIndex(selectionString.length());
+ event.setToIndex(selection.length());
sendAccessibilityEvent(event);
+ event.recycle();
}
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index a867d39d158e2..a4347a4829f53 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1024,30 +1024,26 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
static final int UPDATE_MATCH_COUNT = 126;
static final int CENTER_FIT_RECT = 127;
static final int SET_SCROLLBAR_MODES = 129;
- static final int SELECTION_STRING_CHANGED = 130;
- static final int HIT_TEST_RESULT = 131;
- static final int SAVE_WEBARCHIVE_FINISHED = 132;
-
- static final int SET_AUTOFILLABLE = 133;
- static final int AUTOFILL_COMPLETE = 134;
-
- static final int SCREEN_ON = 136;
- static final int UPDATE_ZOOM_DENSITY = 139;
- static final int EXIT_FULLSCREEN_VIDEO = 140;
-
- static final int COPY_TO_CLIPBOARD = 141;
- static final int INIT_EDIT_FIELD = 142;
- static final int REPLACE_TEXT = 143;
- static final int CLEAR_CARET_HANDLE = 144;
- static final int KEY_PRESS = 145;
- static final int RELOCATE_AUTO_COMPLETE_POPUP = 146;
- static final int FOCUS_NODE_CHANGED = 147;
- static final int AUTOFILL_FORM = 148;
- static final int SCROLL_EDIT_TEXT = 149;
- static final int EDIT_TEXT_SIZE_CHANGED = 150;
- static final int SHOW_CARET_HANDLE = 151;
- static final int UPDATE_CONTENT_BOUNDS = 152;
- static final int SCROLL_HANDLE_INTO_VIEW = 153;
+ static final int HIT_TEST_RESULT = 130;
+ static final int SAVE_WEBARCHIVE_FINISHED = 131;
+ static final int SET_AUTOFILLABLE = 132;
+ static final int AUTOFILL_COMPLETE = 133;
+ static final int SCREEN_ON = 134;
+ static final int UPDATE_ZOOM_DENSITY = 135;
+ static final int EXIT_FULLSCREEN_VIDEO = 136;
+ static final int COPY_TO_CLIPBOARD = 137;
+ static final int INIT_EDIT_FIELD = 138;
+ static final int REPLACE_TEXT = 139;
+ static final int CLEAR_CARET_HANDLE = 140;
+ static final int KEY_PRESS = 141;
+ static final int RELOCATE_AUTO_COMPLETE_POPUP = 142;
+ static final int FOCUS_NODE_CHANGED = 143;
+ static final int AUTOFILL_FORM = 144;
+ static final int SCROLL_EDIT_TEXT = 145;
+ static final int EDIT_TEXT_SIZE_CHANGED = 146;
+ static final int SHOW_CARET_HANDLE = 147;
+ static final int UPDATE_CONTENT_BOUNDS = 148;
+ static final int SCROLL_HANDLE_INTO_VIEW = 149;
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
@@ -1766,6 +1762,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
}
+ /* package */ void handleSelectionChangedWebCoreThread(String selection, int token) {
+ if (isAccessibilityInjectionEnabled()) {
+ getAccessibilityInjector().onSelectionStringChangedWebCoreThread(selection, token);
+ }
+ }
+
private boolean isAccessibilityInjectionEnabled() {
final AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
if (!manager.isEnabled()) {
@@ -7496,13 +7498,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
mVerticalScrollBarMode = msg.arg2;
break;
- case SELECTION_STRING_CHANGED:
- if (isAccessibilityInjectionEnabled()) {
- getAccessibilityInjector()
- .handleSelectionChangedIfNecessary((String) msg.obj);
- }
- break;
-
case FOCUS_NODE_CHANGED:
mIsEditingText = (msg.arg1 == mFieldPointer);
if (mAutoCompletePopup != null && !mIsEditingText) {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index ccb84e6a02cd0..4a09636aae4ec 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -41,6 +41,8 @@ import android.view.View;
import android.webkit.WebViewClassic.FocusNodeHref;
import android.webkit.WebViewInputDispatcher.WebKitCallbacks;
+import com.android.internal.os.SomeArgs;
+
import junit.framework.Assert;
import java.io.OutputStream;
@@ -1545,12 +1547,14 @@ public final class WebViewCore {
case MODIFY_SELECTION:
mTextSelectionChangeReason
= TextSelectionData.REASON_ACCESSIBILITY_INJECTOR;
- String modifiedSelectionString =
- nativeModifySelection(mNativeClass, msg.arg1,
- msg.arg2);
- mWebViewClassic.mPrivateHandler.obtainMessage(
- WebViewClassic.SELECTION_STRING_CHANGED,
- modifiedSelectionString).sendToTarget();
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final String modifiedSelectionString = nativeModifySelection(
+ mNativeClass, args.argi1, args.argi2);
+ // If accessibility is on, the main thread may be
+ // waiting for a response. Send on webcore thread.
+ mWebViewClassic.handleSelectionChangedWebCoreThread(
+ modifiedSelectionString, args.argi3);
+ args.recycle();
mTextSelectionChangeReason
= TextSelectionData.REASON_UNKNOWN;
break;