diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index 11bd815c685d5..915e2dc22fb06 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,484 +16,335 @@ package android.webkit; +import android.content.Context; +import android.os.Vibrator; import android.provider.Settings; -import android.text.TextUtils; -import android.text.TextUtils.SimpleStringSplitter; -import android.util.Log; +import android.speech.tts.TextToSpeech; import android.view.KeyEvent; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.webkit.WebViewCore.EventHub; -import java.util.ArrayList; -import java.util.Stack; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; /** - * This class injects accessibility into WebViews with disabled JavaScript or - * WebViews with enabled JavaScript but for which we have no accessibility - * script to inject. - *
- * Note: To avoid changes in the framework upon changing the available - * navigation axis, or reordering the navigation axis, or changing - * the key bindings, or defining sequence of actions to be bound to - * a given key this class is navigation axis agnostic. It is only - * aware of one navigation axis which is in fact the default behavior - * of webViews while using the DPAD/TrackBall. - * - * In general a key binding is a mapping from modifiers + key code to - * a sequence of actions. For more detail how to specify key bindings refer to - * {@link android.provider.Settings.Secure#ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS}. - * - * The possible actions are invocations to - * {@link #setCurrentAxis(int, boolean, String)}, or - * {@link #traverseCurrentAxis(int, boolean, String)} - * {@link #traverseGivenAxis(int, int, boolean, String)} - * {@link #prefromAxisTransition(int, int, boolean, String)} - * referred via the values of: - * {@link #ACTION_SET_CURRENT_AXIS}, - * {@link #ACTION_TRAVERSE_CURRENT_AXIS}, - * {@link #ACTION_TRAVERSE_GIVEN_AXIS}, - * {@link #ACTION_PERFORM_AXIS_TRANSITION}, - * respectively. - * The arguments for the action invocation are specified as offset - * hexademical pairs. Note the last argument of the invocation - * should NOT be specified in the binding as it is provided by - * this class. For details about the key binding implementation - * refer to {@link AccessibilityWebContentKeyBinding}. + * Handles injecting accessibility JavaScript and related JavaScript -> Java + * APIs. */ class AccessibilityInjector { - private static final String LOG_TAG = "AccessibilityInjector"; + // The WebViewClassic this injector is responsible for managing. + private final WebViewClassic mWebViewClassic; - private static final boolean DEBUG = true; + // Cached reference to mWebViewClassic.getContext(), for convenience. + private final Context mContext; - private static final int ACTION_SET_CURRENT_AXIS = 0; - 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; + // Cached reference to mWebViewClassic.getWebView(), for convenience. + private final WebView mWebView; - // the default WebView behavior abstracted as a navigation axis - private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7; + // The Java objects that are exposed to JavaScript. + private TextToSpeech mTextToSpeech; - // these are the same for all instances so make them process wide - private static ArrayListevent.
- *
- * @return True if the event was processed.
+ * Attempts to load scripting interfaces for accessibility.
+ * + * This should be called when the window is attached. + *
*/ - public boolean onKeyEvent(KeyEvent event) { - // We do not handle ENTER in any circumstances. - if (isEnterActionKey(event.getKeyCode())) { + public void addAccessibilityApisIfNecessary() { + if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) { + return; + } + + addTtsApis(); + } + + /** + * Attempts to unload scripting interfaces for accessibility. + *+ * This should be called when the window is detached. + *
+ */ + public void removeAccessibilityApisIfNecessary() { + removeTtsApis(); + } + + /** + * Attempts to handle key events when accessibility is turned on. + * + * @param event The key event to handle. + * @return {@code true} if the event was handled. + */ + public boolean handleKeyEventIfNecessary(KeyEvent event) { + if (!isAccessibilityEnabled()) { + mAccessibilityScriptInjected = false; + toggleFallbackAccessibilityInjector(false); return false; } - if (event.getAction() == KeyEvent.ACTION_UP) { - return mLastDownEventHandled; - } - - mLastDownEventHandled = false; - - AccessibilityWebContentKeyBinding binding = null; - for (AccessibilityWebContentKeyBinding candidate : sBindings) { - if (event.getKeyCode() == candidate.getKeyCode() - && event.hasModifiers(candidate.getModifiers())) { - binding = candidate; - break; + if (mAccessibilityScriptInjected) { + // 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 (event.getAction() == KeyEvent.ACTION_UP) { + mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_UP, 0, 0, event); + } else if (event.getAction() == KeyEvent.ACTION_DOWN) { + mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_DOWN, 0, 0, event); + } else { + return false; } + + return true; } - if (binding == null) { + if (mAccessibilityInjector != null) { + // 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 mAccessibilityInjector.onKeyEvent(event); + } + + return false; + } + + /** + * Attempts to handle selection change events when accessibility is using a + * non-JavaScript method. + * + * @param selectionString The selection string. + */ + public void handleSelectionChangedIfNecessary(String selectionString) { + if (mAccessibilityInjector != null) { + mAccessibilityInjector.onSelectionStringChange(selectionString); + } + } + + /** + * Prepares for injecting accessibility scripts into a new page. + * + * @param url The URL that will be loaded. + */ + public void onPageStarted(String url) { + mAccessibilityScriptInjected = false; + } + + /** + * Attempts to inject the accessibility script using a {@code