OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / cts / tests / tests / text / src / android / text / method / cts / ArrowKeyMovementMethodTest.java
diff --git a/cts/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/cts/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
new file mode 100644 (file)
index 0000000..1d6c109
--- /dev/null
@@ -0,0 +1,909 @@
+/*
+ * Copyright (C) 2008 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.method.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.ToBeFixed;
+
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.method.ArrowKeyMovementMethod;
+import android.text.method.MetaKeyKeyListener;
+import android.text.method.MovementMethod;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test {@link ArrowKeyMovementMethod}. The class is an implementation of interface
+ * {@link MovementMethod}. The typical usage of {@link MovementMethod} is tested in
+ * {@link android.widget.cts.TextViewTest} and this test case is only focused on the
+ * implementation of the methods.
+ *
+ * @see android.widget.cts.TextViewTest
+ */
+@TestTargetClass(ArrowKeyMovementMethod.class)
+public class ArrowKeyMovementMethodTest extends ActivityInstrumentationTestCase2<StubActivity> {
+    private static final String THREE_LINES_TEXT = "first line\nsecond line\nlast line";
+    private static final int END_OF_ALL_TEXT = THREE_LINES_TEXT.length();
+    private static final int END_OF_1ST_LINE = THREE_LINES_TEXT.indexOf('\n');
+    private static final int START_OF_2ND_LINE = END_OF_1ST_LINE + 1;
+    private static final int END_OF_2ND_LINE = THREE_LINES_TEXT.indexOf('\n', START_OF_2ND_LINE);
+    private static final int START_OF_3RD_LINE = END_OF_2ND_LINE + 1;
+    private static final int SPACE_IN_2ND_LINE = THREE_LINES_TEXT.indexOf(' ', START_OF_2ND_LINE);
+    private TextView mTextView;
+    private ArrowKeyMovementMethod mArrowKeyMovementMethod;
+    private Editable mEditable;
+    private MyMetaKeyKeyListener mMetaListener;
+
+    public ArrowKeyMovementMethodTest() {
+        super("com.android.cts.stub", StubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mMetaListener = new MyMetaKeyKeyListener();
+        mArrowKeyMovementMethod = new ArrowKeyMovementMethod();
+
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                getActivity().setContentView(mTextView);
+                mTextView.setFocusable(true);
+                mTextView.requestFocus();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertNotNull(mTextView.getLayout());
+        assertTrue(mTextView.isFocused());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test constructor ArrowKeyMovementMethod#ArrowKeyMovementMethod().",
+        method = "ArrowKeyMovementMethod",
+        args = {}
+    )
+    public void testConstructor() {
+        new ArrowKeyMovementMethod();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#canSelectArbitrarily()}. "
+                + "It always returns true.",
+        method = "canSelectArbitrarily",
+        args = {}
+    )
+    public void testCanSelectArbitrarily() {
+        assertTrue(new ArrowKeyMovementMethod().canSelectArbitrarily());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#getInstance()}. "
+                + "This is a method for creating singleton.",
+        method = "getInstance",
+        args = {}
+    )
+    public void testGetInstance() {
+        MovementMethod method0 = ArrowKeyMovementMethod.getInstance();
+        assertNotNull(method0);
+
+        MovementMethod method1 = ArrowKeyMovementMethod.getInstance();
+        assertNotNull(method1);
+        assertSame(method0, method1);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTakeFocus(TextView, Spannable, int)}. "
+                + "Test the method after the widget get layouted.",
+        method = "onTakeFocus",
+        args = {TextView.class, Spannable.class, int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    public void testOnTakeFocus() throws Throwable {
+        /*
+         * The following assertions depend on whether the TextView has a layout.
+         * The text view will not get layout in setContent method but in other
+         * handler's function. Assertion which is following the setContent will
+         * not get the expecting result. It have to wait all the handlers'
+         * operations on the UiTread to finish. So all these cases are divided
+         * into several steps, setting the content at first, waiting the layout,
+         * and checking the assertion at last.
+         */
+        assertSelection(-1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Selection.removeSelection(mEditable);
+                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertSelection(END_OF_ALL_TEXT);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Selection.removeSelection(mEditable);
+                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertSelection(END_OF_ALL_TEXT);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.setSingleLine();
+            }
+        });
+        // wait until the textView gets layout
+        getInstrumentation().waitForIdleSync();
+        assertNotNull(mTextView.getLayout());
+        assertEquals(1, mTextView.getLayout().getLineCount());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Selection.removeSelection(mEditable);
+                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
+            }
+        });
+        assertSelection(END_OF_ALL_TEXT);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Selection.removeSelection(mEditable);
+                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
+            }
+        });
+        assertSelection(END_OF_ALL_TEXT);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTakeFocus(TextView, Spannable, int)}. "
+                + "Test the method before the widget get layouted.",
+        method = "onTakeFocus",
+        args = {TextView.class, Spannable.class, int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    public void testOnTakeFoucusWithNullLayout() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+
+        assertSelectEndOfContent();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTakeFocus(TextView, Spannable, int)}. "
+                + "Test the method with null parameters.",
+        method = "onTakeFocus",
+        args = {TextView.class, Spannable.class, int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#onTakeFocus(TextView, "
+            + "Spannable, int)} when the params view or text is null")
+    public void testOnTakeFocusWithNullParameters() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+        try {
+            mArrowKeyMovementMethod.onTakeFocus(null, mEditable, View.FOCUS_DOWN);
+            fail("The method did not throw NullPointerException when param textView is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, null, View.FOCUS_DOWN);
+            fail("The method did not throw NullPointerException when param spannable is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. KeyEvent parameter is never read.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyDownWithKeyCodeUp() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // |first line
+        // second |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, 0);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // first lin|e
+        // second |line
+        // last line
+        assertEquals(SPACE_IN_2ND_LINE, Selection.getSelectionStart(mEditable));
+        int correspondingIn1stLine = Selection.getSelectionEnd(mEditable);
+        assertTrue(correspondingIn1stLine >= 0);
+        assertTrue(correspondingIn1stLine <= END_OF_1ST_LINE);
+
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // |first line
+        // second |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, 0);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // |first line
+        // second line
+        // last line
+        assertSelection(0);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // first lin|e
+        // second line
+        // last line
+        assertSelection(correspondingIn1stLine);
+
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_UP, null));
+        // first lin|e
+        // second line
+        // last line
+        assertSelection(correspondingIn1stLine);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. KeyEvent parameter is never read.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyDownWithKeyCodeDown() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second |line
+        // last line|
+        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second |line
+        // last lin|e
+        assertEquals(SPACE_IN_2ND_LINE, Selection.getSelectionStart(mEditable));
+        int correspondingIn3rdLine = Selection.getSelectionEnd(mEditable);
+        assertTrue(correspondingIn3rdLine >= START_OF_3RD_LINE);
+        assertTrue(correspondingIn3rdLine <= END_OF_ALL_TEXT);
+
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second |line
+        // last line|
+        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second line
+        // last line|
+        assertSelection(END_OF_ALL_TEXT);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second line
+        // last lin|e
+        assertSelection(correspondingIn3rdLine);
+
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_DOWN, null));
+        // first line
+        // second line
+        // last lin|e
+        assertSelection(correspondingIn3rdLine);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. KeyEvent parameter is never read.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyDownWithKeyCodeLeft() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // |second |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // |second |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // second| |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 1);
+
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // secon|d |line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 2);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // |second line
+        // last line
+        assertSelection(START_OF_2ND_LINE);
+
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // |second line
+        // last line
+        assertSelection(START_OF_2ND_LINE);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line
+        // second| line
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE - 1);
+
+        Selection.setSelection(mEditable, START_OF_2ND_LINE);
+        // first line
+        // |second line
+        // last line
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_LEFT, null));
+        // first line|
+        // second line
+        // last line
+        assertSelection(END_OF_1ST_LINE);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. KeyEvent parameter is never read.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyDownWithKeyCodeRight() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second |line|
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+
+        pressBothShiftAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second |line|
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second |l|ine
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 1);
+
+        pressShift();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second |li|ne
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 2);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second line|
+        // last line
+        assertSelection(END_OF_2ND_LINE);
+
+        pressAlt();
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second line|
+        // last line
+        assertSelection(END_OF_2ND_LINE);
+
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second l|ine
+        // last line
+        assertSelection(SPACE_IN_2ND_LINE + 1);
+
+        Selection.setSelection(mEditable, END_OF_2ND_LINE);
+        // first line
+        // second line|
+        // last line
+        assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_RIGHT, null));
+        // first line
+        // second line
+        // |last line
+        assertSelection(START_OF_3RD_LINE);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. Test the method before the widget get layouted.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#onKeyDown(TextView, "
+            + "Spannable, int, KeyEvent)} when the view does not get layout")
+    public void testOnKeyDownWithNullLayout() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+
+        try {
+            mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable, KeyEvent.KEYCODE_DPAD_RIGHT,
+                    null);
+            fail("The method did not throw NullPointerException when layout of the view is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyOther(TextView, Spannable, KeyEvent)}.",
+        method = "onKeyOther",
+        args = {TextView.class, Spannable.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyOther() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_CENTER, 2)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_0, 2)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_E, 2)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN, 2)));
+
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, 0)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, 0)));
+        assertFalse(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT, 0)));
+
+        // only repeat arrow key events get handled
+        assertTrue(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_UP, 2)));
+        assertTrue(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_DOWN, 2)));
+        assertTrue(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_LEFT, 2)));
+        assertTrue(mArrowKeyMovementMethod.onKeyOther(mTextView, mEditable,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_RIGHT, 2)));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. Test the method with other key code except up, down, left ,right.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    @UiThreadTest
+    public void testOnKeyDownWithOtherKeyCode() {
+        // first line
+        // second |line
+        // last line
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_DPAD_CENTER, null));
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_0, null));
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_E, null));
+        assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
+                KeyEvent.KEYCODE_UNKNOWN, null));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyDown(TextView, Spannable, int, "
+                + "KeyEvent)}. Test the method with null parameters.",
+        method = "onKeyDown",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#onKeyDown(TextView, "
+            + "Spannable, int, KeyEvent)} when the params view or buffer is null")
+    public void testOnKeyDownWithNullParameters() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+        try {
+            mArrowKeyMovementMethod.onKeyDown(null, mEditable, KeyEvent.KEYCODE_DPAD_RIGHT,
+                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
+            fail("The method did not throw NullPointerException when param textView is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            mArrowKeyMovementMethod.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_RIGHT,
+                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
+            fail("The method did not throw NullPointerException when param spannable is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTouchEvent(TextView, Spannable,"
+            + " MotionEvent)}. Test the method while the widget is focused.",
+        method = "onTouchEvent",
+        args = {TextView.class, Spannable.class, MotionEvent.class}
+    )
+    @UiThreadTest
+    @ToBeFixed(bug = "1400249", explanation = "There is a side effect that the "
+            + "view scroll while dragging on the screen. Should be tested in functional test.")
+    public void testOnTouchEvent() throws Throwable {
+        long now = SystemClock.currentThreadTimeMillis();
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
+                MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1, 0)));
+        assertSelection(SPACE_IN_2ND_LINE);
+
+        assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
+                MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1,
+                        KeyEvent.META_SHIFT_ON)));
+        assertSelection(SPACE_IN_2ND_LINE);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTouchEvent(TextView, Spannable, "
+                + "MotionEvent)}. Test the method before the widget get layouted.",
+        method = "onTouchEvent",
+        args = {TextView.class, Spannable.class, MotionEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#onTouchEvent(TextView, "
+            + "Spannable, MotionEvent)} when the view does not get layout")
+    public void testOnTouchEventWithNullLayout() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+        mTextView.setFocusable(true);
+        mTextView.requestFocus();
+        assertTrue(mTextView.isFocused());
+
+        long now = SystemClock.currentThreadTimeMillis();
+        assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
+                    MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1, 0)));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTouchEvent(TextView, Spannable, "
+                + "MotionEvent)}. Test the method while the widget is not focused.",
+        method = "onTouchEvent",
+        args = {TextView.class, Spannable.class, MotionEvent.class}
+    )
+    @UiThreadTest
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. There is no "
+            + "document about the behaviour of this method.")
+    public void testOnTouchEventWithoutFocus() {
+        long now = SystemClock.currentThreadTimeMillis();
+        Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
+        assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
+                MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1, 0)));
+        assertSelection(SPACE_IN_2ND_LINE);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTouchEvent(TextView, Spannable, "
+            + "MotionEvent)}. Test the method with null parameters.",
+        method = "onTouchEvent",
+        args = {TextView.class, Spannable.class, MotionEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#onTouchEvent(TextView, "
+            + "Spannable, MotionEvent)} when the params view, buffer or event is null")
+    public void testOnTouchEventWithNullParameters() {
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+        try {
+            mArrowKeyMovementMethod.onTouchEvent(null, mEditable,
+                    MotionEvent.obtain(0, 0, 0, 1, 1, 0));
+            fail("The method did not throw NullPointerException when param textView is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            mArrowKeyMovementMethod.onTouchEvent(mTextView, null,
+                    MotionEvent.obtain(0, 0, 0, 1, 1, 0));
+            fail("The method did not throw NullPointerException when param spannable is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable, null);
+            fail("The method did not throw NullPointerException when param motionEvent is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#initialize(TextView, Spannable)}. "
+                + "TextView parameter is never read.",
+        method = "initialize",
+        args = {TextView.class, Spannable.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. @throws clause "
+            + "should be added into javadoc of ArrowKeyMovementMethod#initialize(TextView, "
+            + "Spannable)} when the params text is null")
+    public void testInitialize() {
+        Spannable spannable = new SpannableString("test content");
+        ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
+
+        assertEquals(-1, Selection.getSelectionStart(spannable));
+        assertEquals(-1, Selection.getSelectionEnd(spannable));
+        method.initialize(null, spannable);
+        assertEquals(0, Selection.getSelectionStart(spannable));
+        assertEquals(0, Selection.getSelectionEnd(spannable));
+
+        Selection.setSelection(spannable, 2);
+        assertEquals(2, Selection.getSelectionStart(spannable));
+        assertEquals(2, Selection.getSelectionEnd(spannable));
+        method.initialize(null, spannable);
+        assertEquals(0, Selection.getSelectionStart(spannable));
+        assertEquals(0, Selection.getSelectionEnd(spannable));
+
+        try {
+            method.initialize(mTextView, null);
+            fail("The method did not throw NullPointerException when param spannable is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onTrackballEvent(TextView, Spannable, "
+                + "MotionEvent)}. This method always returns false.",
+        method = "onTrackballEvent",
+        args = {TextView.class, Spannable.class, MotionEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. "
+            + "There is no document about behaviour of this method.")
+    public void testOnTrackballEven() {
+        assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable,
+                MotionEvent.obtain(0, 0, 0, 1, 1, 0)));
+
+        initTextViewWithNullLayout();
+        mEditable = (Editable) mTextView.getText();
+
+        assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable,
+                MotionEvent.obtain(0, 0, 0, 1, 1, 0)));
+
+        assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, null,
+                MotionEvent.obtain(0, 0, 0, 1, 1, 0)));
+
+        assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable, null));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test {@link ArrowKeyMovementMethod#onKeyUp(TextView, Spannable, int, KeyEvent)}. "
+                + "It always returns false.",
+        method = "onKeyUp",
+        args = {TextView.class, Spannable.class, int.class, KeyEvent.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete. "
+            + "There is no document about behaviour of this method.")
+    public void testOnKeyUp() {
+        ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
+        SpannableString spannable = new SpannableString("Test Content");
+        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
+        TextView view = new TextView(getActivity());
+
+        assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
+        assertFalse(method.onKeyUp(null, null, 0, null));
+        assertFalse(method.onKeyUp(null, spannable, KeyEvent.KEYCODE_0, event));
+        assertFalse(method.onKeyUp(view, null, KeyEvent.KEYCODE_0, event));
+        assertFalse(method.onKeyUp(view, spannable, 0, event));
+        assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, null));
+    }
+
+    private void initTextViewWithNullLayout() {
+        mTextView = new TextView(getActivity());
+        mTextView.setText(THREE_LINES_TEXT, BufferType.EDITABLE);
+        assertNull(mTextView.getLayout());
+    }
+
+    private void pressMetaKey(int metakey, int expectedState) {
+        mMetaListener.onKeyDown(null, mEditable, metakey, null);
+        assertEquals(1, MetaKeyKeyListener.getMetaState(mEditable, expectedState));
+    }
+
+    private void pressShift() {
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        pressMetaKey(KeyEvent.KEYCODE_SHIFT_LEFT, MetaKeyKeyListener.META_SHIFT_ON);
+    }
+
+    private void pressAlt() {
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        pressMetaKey(KeyEvent.KEYCODE_ALT_LEFT, MetaKeyKeyListener.META_ALT_ON);
+    }
+
+    private void pressBothShiftAlt() {
+        MetaKeyKeyListener.resetMetaState(mEditable);
+        pressMetaKey(KeyEvent.KEYCODE_SHIFT_LEFT, MetaKeyKeyListener.META_SHIFT_ON);
+        pressMetaKey(KeyEvent.KEYCODE_ALT_LEFT, MetaKeyKeyListener.META_ALT_ON);
+    }
+
+    private void assertSelection(int position) {
+        assertSelection(position, position);
+    }
+
+    private void assertSelection(int start, int end) {
+        assertEquals(start, Selection.getSelectionStart(mEditable));
+        assertEquals(end, Selection.getSelectionEnd(mEditable));
+    }
+
+    private void assertSelectEndOfContent() {
+        Selection.removeSelection(mEditable);
+        mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_DOWN);
+        assertSelection(END_OF_ALL_TEXT);
+
+        Selection.removeSelection(mEditable);
+        mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_RIGHT);
+        assertSelection(END_OF_ALL_TEXT);
+
+        assertSelectEndOfContentExceptFocusForward();
+    }
+
+    private void assertSelectEndOfContentExceptFocusForward() {
+        Selection.removeSelection(mEditable);
+        mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
+        assertSelection(END_OF_ALL_TEXT);
+
+        Selection.removeSelection(mEditable);
+        mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
+        assertSelection(END_OF_ALL_TEXT);
+    }
+
+    private static class MyMetaKeyKeyListener extends MetaKeyKeyListener {
+    }
+}