summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/webkit/AccessibilityInjector.java11
-rw-r--r--core/java/android/webkit/WebView.java35
-rw-r--r--core/java/android/webkit/WebViewCore.java29
-rw-r--r--core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java570
4 files changed, 592 insertions, 53 deletions
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index 6bb4320..db66305 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -113,6 +113,11 @@ class AccessibilityInjector {
* @return True if the event was processed.
*/
public boolean onKeyEvent(KeyEvent event) {
+ // We do not handle ENTER in any circumstances.
+ if (isEnterActionKey(event.getKeyCode())) {
+ return false;
+ }
+
if (event.getAction() == KeyEvent.ACTION_UP) {
return mLastDownEventHandled;
}
@@ -367,6 +372,12 @@ class AccessibilityInjector {
}
}
+ private boolean isEnterActionKey(int keyCode) {
+ return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+ || keyCode == KeyEvent.KEYCODE_ENTER
+ || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
+ }
+
/**
* Represents a web content key-binding.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index cf1ce6b..9bd57cd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,9 +16,6 @@
package android.webkit;
-import android.view.HardwareCanvas;
-import com.android.internal.R;
-
import android.annotation.Widget;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -31,7 +28,6 @@ import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -57,7 +53,6 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.SystemClock;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.text.Selection;
@@ -66,6 +61,7 @@ import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.view.Gravity;
+import android.view.HardwareCanvas;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -92,7 +88,6 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
-import android.widget.EdgeGlow;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.OverScroller;
@@ -677,6 +672,8 @@ public class WebView extends AbsoluteLayout
static final int SET_AUTOFILLABLE = 133;
static final int AUTOFILL_COMPLETE = 134;
+ static final int SELECT_AT = 135;
+
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
@@ -728,7 +725,8 @@ public class WebView extends AbsoluteLayout
"SET_TOUCH_HIGHLIGHT_RECTS", // = 131;
"SAVE_WEBARCHIVE_FINISHED", // = 132;
"SET_AUTOFILLABLE", // = 133;
- "AUTOFILL_COMPLETE" // = 134;
+ "AUTOFILL_COMPLETE", // = 134;
+ "SELECT_AT" // = 135;
};
// If the site doesn't use the viewport meta tag to specify the viewport,
@@ -7600,6 +7598,10 @@ public class WebView extends AbsoluteLayout
}
break;
+ case SELECT_AT:
+ nativeSelectAt(msg.arg1, msg.arg2);
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -7957,24 +7959,6 @@ public class WebView extends AbsoluteLayout
cursorData());
}
- /*
- * Called from JNI when the cursor has moved. This method
- * sends a message to the WebCore requesting the given
- * nodePtr in the given framePrt to be selected which will
- * result in firing an accessibility event announing its
- * content.
- *
- * Note: Accessibility support.
- */
- @SuppressWarnings("unused")
- // called from JNI
- private void sendMoveSelection(int framePtr, int nodePtr) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && mAccessibilityInjector != null) {
- mWebViewCore.sendMessage(EventHub.MOVE_SELECTION, framePtr, nodePtr);
- }
- }
-
/**
* Called by JNI to send a message to the webcore thread that the user
* touched the webpage.
@@ -8283,6 +8267,7 @@ public class WebView extends AbsoluteLayout
private native Point nativeSelectableText();
private native void nativeSelectAll();
private native void nativeSelectBestAt(Rect rect);
+ private native void nativeSelectAt(int x, int y);
private native int nativeSelectionX();
private native int nativeSelectionY();
private native int nativeFindIndex();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 0992079..0451a13 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -641,18 +641,6 @@ final class WebViewCore {
*/
private native String nativeModifySelection(int direction, int granularity);
- /**
- * Moves the selection to given node i.e. selects that node.
- *
- * Note: Accessibility support.
- *
- * @param framePtr Pointer to the frame containing the node to be selected.
- * @param nodePtr Pointer to the node to be selected.
- *
- * @return The selection string.
- */
- private native String nativeMoveSelection(int framePtr, int nodePtr);
-
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
@@ -1018,9 +1006,6 @@ final class WebViewCore {
static final int PROXY_CHANGED = 193;
- // accessibility support
- static final int MOVE_SELECTION = 194;
-
// private message ids
private static final int DESTROY = 200;
@@ -1439,12 +1424,6 @@ final class WebViewCore {
modifiedSelectionString).sendToTarget();
break;
- case MOVE_SELECTION:
- String movedSelectionString = nativeMoveSelection(msg.arg1, msg.arg2);
- mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED,
- movedSelectionString).sendToTarget();
- break;
-
case LISTBOX_CHOICES:
SparseBooleanArray choices = (SparseBooleanArray)
msg.obj;
@@ -2714,6 +2693,14 @@ final class WebViewCore {
hMode, vMode).sendToTarget();
}
+ // called by JNI
+ @SuppressWarnings("unused")
+ private void selectAt(int x, int y) {
+ if (mWebView != null) {
+ mWebView.mPrivateHandler.obtainMessage(WebView.SELECT_AT, x, y).sendToTarget();
+ }
+ }
+
private void useMockDeviceOrientation() {
mDeviceMotionAndOrientationManager.useMock();
}
diff --git a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
index 4edd127..16108e6 100644
--- a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
+++ b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
@@ -51,7 +51,7 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
private static final long TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE = 1000;
/** The count of tests to detect when to shut down the service. */
- private static final int TEST_CASE_COUNT = 8;
+ private static final int TEST_CASE_COUNT = 16;
/** The meta state for pressed left ALT. */
private static final int META_STATE_ALT_LEFT_ON = KeyEvent.META_ALT_ON
@@ -140,7 +140,8 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
"</p>" +
"<p>" +
"d" +
- "<input>e</input>" +
+ "<p/>" +
+ "e" +
"</p>" +
"</body>" +
"</html>";
@@ -179,6 +180,10 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
assertSelectionString(null);
+ // go to the fifth character (reverse)
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("e");
+
// go to the fourth character (reverse)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
assertSelectionString("d");
@@ -199,6 +204,10 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
assertSelectionString(null);
+ // go to the first character
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("a");
+
// go to the second character (reverse again)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
assertSelectionString("<b>b</b>");
@@ -223,11 +232,11 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
"</p>" +
"<p>" +
" scattered " +
- "<input>all</input>" +
- " over " +
+ "<p/>" +
+ " all over " +
"</p>" +
"<div>" +
- "<button>the place.</button>" +
+ "<p>the place.</p>" +
"</div>" +
"</body>" +
"</html>";
@@ -284,7 +293,7 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
// go to the last word (reverse)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
- assertSelectionString("place");
+ assertSelectionString("place.");
// go to the eight word
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
@@ -322,6 +331,10 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
assertSelectionString(null);
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("This");
+
// go to the second word (reverse again)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
assertSelectionString("is");
@@ -384,6 +397,10 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
assertSelectionString(null);
+ // go to the fifth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("This is the second sentence of the second paragraph.");
+
// go to the fourth sentence (reverse)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
assertSelectionString("This is the first sentence of the second paragraph.");
@@ -405,6 +422,11 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
assertSelectionString(null);
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("This is the first sentence of the first paragraph and has an "
+ + "<b>inline bold tag</b>.");
+
// go to the second sentence (reverse again)
sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
assertSelectionString("This is the second sentence of the first paragraph.");
@@ -747,6 +769,539 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
}
/**
+ * Tests that the selection does not cross anchor boundaries. This is a
+ * workaround for the asymmetric and inconsistent handling of text with
+ * links by WebKit while traversing by sentence.
+ */
+ @LargeTest
+ public void testEnforceSelectionDoesNotCrossAnchorBoundary1() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>First</div>" +
+ "<p>" +
+ "<a href=\"\">Second</a> Third" +
+ "</p>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"\">Second</a>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Third");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Third");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"\">Second</a>");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests that the selection does not cross anchor boundaries. This is a
+ * workaround for the asymmetric and inconsistent handling of text with
+ * links by WebKit while traversing by sentence.
+ */
+ @LargeTest
+ public void testEnforceSelectionDoesNotCrossAnchorBoundary2() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>First</div>" +
+ "<a href=\"#\">Second</a>" +
+ "&nbsp;" +
+ "<a href=\"#\">Third</a>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">Second</a>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("&nbsp;");
+
+ // go to the fourth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">Third</a>");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the fourth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\">Third</a>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("&nbsp;");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\">Second</a>");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests that the selection does not cross anchor boundaries. This is a
+ * workaround for the asymmetric and inconsistent handling of text with
+ * links by WebKit while traversing by sentence.
+ */
+ @LargeTest
+ public void testEnforceSelectionDoesNotCrossAnchorBoundary3() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>" +
+ "First" +
+ "<div>" +
+ "<div>" +
+ "<a href=\"#\">Second</a>" +
+ "</div>" +
+ "<div>" +
+ "Third" +
+ "</div>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">Second</a>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Third");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Third");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\">Second</a>");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests skipping of content with hidden visibility.
+ */
+ @LargeTest
+ public void testSkipVisibilityHidden() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>First </div>" +
+ "<div style=\"visibility:hidden;\">Second</div>" +
+ "<div> Third</div>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // change navigation axis to word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
+ assertSelectionString("1"); // expect the word navigation axis
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the third word (the second is invisible)
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Third");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third word (the second is invisible)
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Third");
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests skipping of content with display none.
+ */
+ @LargeTest
+ public void testSkipDisplayNone() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>First</div>" +
+ "<div style=\"display: none;\">Second</div>" +
+ "<div>Third</div>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // change navigation axis to word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
+ assertSelectionString("1"); // expect the word navigation axis
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the third word (the second is invisible)
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Third");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third word (the second is invisible)
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Third");
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first word
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests for the selection not getting stuck.
+ *
+ * Note: The selection always proceeds but if it can
+ * be selecting the same content i.e. between the start
+ * and end are contained the same text nodes.
+ */
+ @LargeTest
+ public void testSelectionTextProceed() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<a href=\"#\">First</a>" +
+ "<span><a href=\"#\"><span>Second</span>&nbsp;<small>a</small></a>" +
+ "</span>&nbsp;<a href=\"#\">Third</a>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">First</a>");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("&nbsp;");
+
+ // go to the fourth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">Third</a>");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\">Third</a>");
+
+ // NOTE: Here we are a bit asymmetric around whitespace but we can live with it
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("&nbsp;");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<a href=\"#\">First</a>");
+
+ // go to before the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<a href=\"#\">First</a>");
+ }
+
+ /**
+ * Tests if input elements are selected rather skipped.
+ */
+ @LargeTest
+ public void testSelectionOfInputElements() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<p>" +
+ "First" +
+ "</p>" +
+ "<input type=\"text\"/>" +
+ "<p>" +
+ "Second" +
+ "</p>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<input type=\"text\">");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Second");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Second");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<input type=\"text\">");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+
+ // go to before the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString(null);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+ }
+
+ /**
+ * Tests traversing of input controls.
+ */
+ @LargeTest
+ public void testSelectionOfInputElements2() throws Exception {
+ // a bit ugly but helps detect beginning and end of all tests so accessibility
+ // and the mock service are not toggled on every test (expensive)
+ sExecutedTestCount++;
+
+ String html =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<head>" +
+ "</head>" +
+ "<body>" +
+ "<div>" +
+ "First" +
+ "<input type=\"text\"/>" +
+ "<span>" +
+ "<input type=\"text\"/>" +
+ "</span>" +
+ "<button type=\"button\">Click Me!</button>" +
+ "<div>" +
+ "<input type=\"submit\"/>" +
+ "</div>" +
+ "<p>" +
+ "Second" +
+ "</p>" +
+ "</div>" +
+ "</body>" +
+ "</html>";
+
+ WebView webView = createWebVewWithHtml(html);
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("First");
+
+ // go to the second sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<input type=\"text\">");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<input type=\"text\">");
+
+ // go to the fourth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<button type=\"button\">Click Me!</button>");
+
+ // go to the fifth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("<input type=\"submit\">");
+
+ // go to the sixth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString("Second");
+
+ // go to past the last sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ assertSelectionString(null);
+
+ // go to the sixth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("Second");
+
+ // go to the fifth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<input type=\"submit\">");
+
+ // go to the fourth sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<button type=\"button\">Click Me!</button>");
+
+ // go to the third sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("<input type=\"text\">");
+
+ // go to the first sentence
+ sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
+ assertSelectionString("First");
+ }
+
+ /**
* Enable accessibility and the mock accessibility service.
*/
private void enableAccessibilityAndMockAccessibilityService() {
@@ -887,7 +1442,8 @@ public class AccessibilityInjectorTest extends AndroidTestCase {
*/
private void restoreDefaultWebContentKeyBindings() {
Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS, mDefaultKeyBindings);
+ Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
+ mDefaultKeyBindings);
}
/**