--- /dev/null
+/*
+ * 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 {
+ }
+}