am 49c771c4: Merge "WebView accessibility key bindings do not allow mapping of all meta keys. Exception when turning off acessibility and having a WebView showing content." into honeycomb

* commit '49c771c4da8bb7cf135e6afed3a901b1744beb67':
  WebView accessibility key bindings do not allow mapping of all meta keys. Exception when turning off acessibility and having a WebView showing content.
This commit is contained in:
Svetoslav Ganov
2011-01-11 17:45:37 -08:00
committed by Android Git Automerger
3 changed files with 94 additions and 89 deletions

View File

@@ -20,7 +20,6 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -41,7 +40,7 @@ import java.util.Stack;
* aware of one navigation axis which is in fact the default behavior
* of webViews while using the DPAD/TrackBall.
* </p>
* In general a key binding is a mapping from meta state + key code to
* 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}.
* </p>
@@ -77,8 +76,8 @@ class AccessibilityInjector {
private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
// these are the same for all instances so make them process wide
private static SparseArray<AccessibilityWebContentKeyBinding> sBindings =
new SparseArray<AccessibilityWebContentKeyBinding>();
private static ArrayList<AccessibilityWebContentKeyBinding> sBindings =
new ArrayList<AccessibilityWebContentKeyBinding>();
// handle to the WebView this injector is associated with.
private final WebView mWebView;
@@ -120,10 +119,15 @@ class AccessibilityInjector {
mLastDownEventHandled = false;
int key = event.getMetaState() << AccessibilityWebContentKeyBinding.OFFSET_META_STATE |
event.getKeyCode() << AccessibilityWebContentKeyBinding.OFFSET_KEY_CODE;
AccessibilityWebContentKeyBinding binding = null;
for (AccessibilityWebContentKeyBinding candidate : sBindings) {
if (event.getKeyCode() == candidate.getKeyCode()
&& event.hasModifiers(candidate.getModifiers())) {
binding = candidate;
break;
}
}
AccessibilityWebContentKeyBinding binding = sBindings.get(key);
if (binding == null) {
return false;
}
@@ -302,7 +306,12 @@ class AccessibilityInjector {
if (DEBUG) {
Log.d(LOG_TAG, "Dispatching: " + event);
}
AccessibilityManager.getInstance(mWebView.getContext()).sendAccessibilityEvent(event);
// accessibility may be disabled while waiting for the selection string
AccessibilityManager accessibilityManager =
AccessibilityManager.getInstance(mWebView.getContext());
if (accessibilityManager.isEnabled()) {
accessibilityManager.sendAccessibilityEvent(event);
}
}
/**
@@ -332,9 +341,6 @@ class AccessibilityInjector {
SimpleStringSplitter semiColonSplitter = new SimpleStringSplitter(';');
semiColonSplitter.setString(webContentKeyBindingsString);
ArrayList<AccessibilityWebContentKeyBinding> bindings =
new ArrayList<AccessibilityWebContentKeyBinding>();
while (semiColonSplitter.hasNext()) {
String bindingString = semiColonSplitter.next();
if (TextUtils.isEmpty(bindingString)) {
@@ -348,80 +354,58 @@ class AccessibilityInjector {
continue;
}
try {
int key = Integer.decode(keyValueArray[0].trim());
long keyCodeAndModifiers = Long.decode(keyValueArray[0].trim());
String[] actionStrings = keyValueArray[1].split(":");
int[] actions = new int[actionStrings.length];
for (int i = 0, count = actions.length; i < count; i++) {
actions[i] = Integer.decode(actionStrings[i].trim());
}
bindings.add(new AccessibilityWebContentKeyBinding(key, actions));
sBindings.add(new AccessibilityWebContentKeyBinding(keyCodeAndModifiers, actions));
} catch (NumberFormatException nfe) {
Log.e(LOG_TAG, "Disregarding malformed key binding: " + bindingString);
}
}
for (AccessibilityWebContentKeyBinding binding : bindings) {
sBindings.put(binding.getKey(), binding);
}
}
/**
* Represents a web content key-binding.
*/
private class AccessibilityWebContentKeyBinding {
private static final class AccessibilityWebContentKeyBinding {
private static final int OFFSET_META_STATE = 0x00000010;
private static final int MODIFIERS_OFFSET = 32;
private static final long MODIFIERS_MASK = 0xFFFFFFF00000000L;
private static final int MASK_META_STATE = 0xFFFF0000;
private static final int KEY_CODE_OFFSET = 0;
private static final long KEY_CODE_MASK = 0x00000000FFFFFFFFL;
private static final int OFFSET_KEY_CODE = 0x00000000;
private static final int ACTION_OFFSET = 24;
private static final int ACTION_MASK = 0xFF000000;
private static final int MASK_KEY_CODE = 0x0000FFFF;
private static final int FIRST_ARGUMENT_OFFSET = 16;
private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
private static final int OFFSET_ACTION = 0x00000018;
private static final int SECOND_ARGUMENT_OFFSET = 8;
private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
private static final int MASK_ACTION = 0xFF000000;
private static final int THIRD_ARGUMENT_OFFSET = 0;
private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
private static final int OFFSET_FIRST_ARGUMENT = 0x00000010;
private final long mKeyCodeAndModifiers;
private static final int MASK_FIRST_ARGUMENT = 0x00FF0000;
private static final int OFFSET_SECOND_ARGUMENT = 0x00000008;
private static final int MASK_SECOND_ARGUMENT = 0x0000FF00;
private static final int OFFSET_THIRD_ARGUMENT = 0x00000000;
private static final int MASK_THIRD_ARGUMENT = 0x000000FF;
private int mKey;
private int [] mActionSequence;
/**
* @return The binding key with key code and meta state.
*
* @see #MASK_KEY_CODE
* @see #MASK_META_STATE
* @see #OFFSET_KEY_CODE
* @see #OFFSET_META_STATE
*/
public int getKey() {
return mKey;
}
private final int [] mActionSequence;
/**
* @return The key code of the binding key.
*/
public int getKeyCode() {
return (mKey & MASK_KEY_CODE) >> OFFSET_KEY_CODE;
return (int) ((mKeyCodeAndModifiers & KEY_CODE_MASK) >> KEY_CODE_OFFSET);
}
/**
* @return The meta state of the binding key.
*/
public int getMetaState() {
return (mKey & MASK_META_STATE) >> OFFSET_META_STATE;
public int getModifiers() {
return (int) ((mKeyCodeAndModifiers & MODIFIERS_MASK) >> MODIFIERS_OFFSET);
}
/**
@@ -442,48 +426,45 @@ class AccessibilityInjector {
* @param index The action code for a given action <code>index</code>.
*/
public int getActionCode(int index) {
return (mActionSequence[index] & MASK_ACTION) >> OFFSET_ACTION;
return (mActionSequence[index] & ACTION_MASK) >> ACTION_OFFSET;
}
/**
* @param index The first argument for a given action <code>index</code>.
*/
public int getFirstArgument(int index) {
return (mActionSequence[index] & MASK_FIRST_ARGUMENT) >> OFFSET_FIRST_ARGUMENT;
return (mActionSequence[index] & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
}
/**
* @param index The second argument for a given action <code>index</code>.
*/
public int getSecondArgument(int index) {
return (mActionSequence[index] & MASK_SECOND_ARGUMENT) >> OFFSET_SECOND_ARGUMENT;
return (mActionSequence[index] & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
}
/**
* @param index The third argument for a given action <code>index</code>.
*/
public int getThirdArgument(int index) {
return (mActionSequence[index] & MASK_THIRD_ARGUMENT) >> OFFSET_THIRD_ARGUMENT;
return (mActionSequence[index] & THIRD_ARGUMENT_MASK) >> THIRD_ARGUMENT_OFFSET;
}
/**
* Creates a new instance.
* @param key The key for the binding (key and meta state)
* @param keyCodeAndModifiers The key for the binding (key and modifiers).
* @param actionSequence The sequence of action for the binding.
* @see #getKey()
*/
public AccessibilityWebContentKeyBinding(int key, int[] actionSequence) {
mKey = key;
public AccessibilityWebContentKeyBinding(long keyCodeAndModifiers, int[] actionSequence) {
mKeyCodeAndModifiers = keyCodeAndModifiers;
mActionSequence = actionSequence;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("key: ");
builder.append(getKey());
builder.append(", metaState: ");
builder.append(getMetaState());
builder.append("modifiers: ");
builder.append(getModifiers());
builder.append(", keyCode: ");
builder.append(getKeyCode());
builder.append(", actions[");

View File

@@ -4545,16 +4545,28 @@ public class WebView extends AbsoluteLayout
// 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.
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 (AccessibilityManager.getInstance(mContext).isEnabled()) {
// 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.
mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
return true;
} else {
// Clean up if accessibility was disabled after loading the current URL.
mAccessibilityScriptInjected = false;
}
} else if (mAccessibilityInjector != null) {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
if (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;
}
} else {
// Clean up if accessibility was disabled after loading the current URL.
mAccessibilityInjector = null;
}
}
if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
@@ -4733,16 +4745,28 @@ public class WebView extends AbsoluteLayout
// 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.
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 (AccessibilityManager.getInstance(mContext).isEnabled()) {
// 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.
mWebViewCore.sendMessage(EventHub.KEY_UP, event);
return true;
} else {
// Clean up if accessibility was disabled after loading the current URL.
mAccessibilityScriptInjected = false;
}
} else if (mAccessibilityInjector != null) {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
if (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;
}
} else {
// Clean up if accessibility was disabled after loading the current URL.
mAccessibilityInjector = null;
}
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP

View File

@@ -91,16 +91,16 @@
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;
0x200000013=0x03020701:0x03010201:0x03000101:0x03030001:0x03040001:0x03050001:0x03060001;
<!-- Left Alt+DPAD/Trackball DOWN transitions from an axis to another and sends an event. -->
<!-- Axis transitions: 1 -> 0; 2 -> 1; 7 -> 2; 3 -> 7; 4 -> 7; 5 -> 7; 6 -> 7; -->
0x120014=0x03010001:0x03020101:0x03070201:0x03030701:0x03040701:0x03050701:0x03060701;
0x200000014=0x03010001:0x03020101:0x03070201:0x03030701:0x03040701:0x03050701:0x03060701;
<!-- Left Alt+DPAD/Trackball LEFT transitions from an axis to another and sends an event. -->
<!-- Axis transitions: 4 -> 3; 5 -> 4; 6 -> 5; 0 -> 6; 1 -> 6; 2 -> 6; 7 -> 6; -->
0x120015=0x03040301:0x03050401:0x03060501:0x03000601:0x03010601:0x03020601:0x03070601;
0x200000015=0x03040301:0x03050401:0x03060501:0x03000601:0x03010601:0x03020601:0x03070601;
<!-- Left Alt+DPAD/Trackball RIGHT transitions from an axis to another and sends an event. -->
<!-- Axis transitions: 5 -> 6; 4 -> 5; 3 -> 4; 2 -> 3; 7 -> 3; 1 -> 3; 0 -> 3; -->
0x120016=0x03050601:0x03040501:0x03030401:0x03020301:0x03070301:0x03010301:0x03000301;
0x200000016=0x03050601:0x03040501:0x03030401:0x03020301:0x03070301:0x03010301:0x03000301;
</string>
<!-- Default for Settings.System.USER_ROTATION -->