blob: 482edb0866646505e1631457a2390a8c3d196391 [file] [log] [blame]
/*
* 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 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.view.WindowManager;
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
*/
public class ArrowKeyMovementMethodTest extends ActivityInstrumentationTestCase2<CtsActivity> {
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.text", CtsActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mMetaListener = new MyMetaKeyKeyListener();
mArrowKeyMovementMethod = new ArrowKeyMovementMethod();
initTextViewWithNullLayout();
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
getActivity().setContentView(mTextView);
mTextView.setFocusable(true);
mTextView.requestFocus();
}
});
getInstrumentation().waitForIdleSync();
assertNotNull(mTextView.getLayout());
assertTrue(mTextView.isFocused());
}
public void testConstructor() {
new ArrowKeyMovementMethod();
}
public void testCanSelectArbitrarily() {
assertTrue(new ArrowKeyMovementMethod().canSelectArbitrarily());
}
public void testGetInstance() {
MovementMethod method0 = ArrowKeyMovementMethod.getInstance();
assertNotNull(method0);
MovementMethod method1 = ArrowKeyMovementMethod.getInstance();
assertNotNull(method1);
assertSame(method0, method1);
}
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);
}
public void testOnTakeFoucusWithNullLayout() {
initTextViewWithNullLayout();
assertSelectEndOfContent();
}
public void testOnTakeFocusWithNullParameters() {
initTextViewWithNullLayout();
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
}
}
@UiThreadTest
public void testOnKeyDownWithKeyCodeUp() {
// shift+alt tests
KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP,
0, KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON);
// first line
// second |line
// last line
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressBothShiftAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, shiftAltEvent));
// |first line
// second |line
// last line
assertSelection(SPACE_IN_2ND_LINE, 0);
// shift tests
KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0,
KeyEvent.META_SHIFT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressShift();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, shiftEvent));
// 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, shiftEvent));
// |first line
// second |line
// last line
assertSelection(SPACE_IN_2ND_LINE, 0);
// alt tests
KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0,
KeyEvent.META_ALT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, altEvent));
// |first line
// second line
// last line
assertSelection(0);
// no-meta tests
KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP,
0, 0);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
MetaKeyKeyListener.resetMetaState(mEditable);
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
// first lin|e
// second line
// last line
assertSelection(correspondingIn1stLine);
// Move to beginning of first line (behavior changed in L)
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
// |first line
// second line
// last line
assertSelection(0);
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
// first lin|e
// second line
// last line
assertSelection(0);
}
@UiThreadTest
public void testOnKeyDownWithKeyCodeDown() {
// shift+alt tests
KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON);
// first line
// second |line
// last line
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressBothShiftAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, shiftAltEvent));
// first line
// second |line
// last line|
assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
// shift tests
KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
0, KeyEvent.META_SHIFT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressShift();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, shiftEvent));
// 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, shiftEvent));
// first line
// second |line
// last line|
assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
// alt tests
KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, 0,
KeyEvent.META_ALT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, altEvent));
// first line
// second line
// last line|
assertSelection(END_OF_ALL_TEXT);
// no-meta tests
KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
0, 0);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
MetaKeyKeyListener.resetMetaState(mEditable);
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, noMetaEvent));
// first line
// second line
// last lin|e
assertSelection(correspondingIn3rdLine);
// move to end of last line (behavior changed in L)
Selection.setSelection(mEditable, END_OF_ALL_TEXT - 1);
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, noMetaEvent));
// first line
// second line
// last line|
assertSelection(END_OF_ALL_TEXT);
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_DOWN, noMetaEvent));
// first line
// second line
// last line|
assertSelection(END_OF_ALL_TEXT);
}
@UiThreadTest
public void testOnKeyDownWithKeyCodeLeft() {
// shift+alt tests
KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT, 0, KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON);
// first line
// second |line
// last line
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressBothShiftAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_LEFT, shiftAltEvent));
// 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, shiftAltEvent));
// first line
// |second |line
// last line
assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
// shift tests
KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
0, KeyEvent.META_SHIFT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressShift();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_LEFT, shiftEvent));
// 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, shiftEvent));
// first line
// secon|d |line
// last line
assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 2);
// alt tests
KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, 0,
KeyEvent.META_ALT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_LEFT, altEvent));
// first line
// |second line
// last line
assertSelection(START_OF_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_LEFT, altEvent));
// first line
// |second line
// last line
assertSelection(START_OF_2ND_LINE);
// no-meta tests
KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
0, 0);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
MetaKeyKeyListener.resetMetaState(mEditable);
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_LEFT, noMetaEvent));
// 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, noMetaEvent));
// first line|
// second line
// last line
assertSelection(END_OF_1ST_LINE);
}
@UiThreadTest
public void testOnKeyDownWithKeyCodeRight() {
// shift+alt tests
KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_RIGHT, 0, KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON);
// first line
// second |line
// last line
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressBothShiftAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_RIGHT, shiftAltEvent));
// 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, shiftAltEvent));
// first line
// second |line|
// last line
assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
// shift tests
KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
0, KeyEvent.META_SHIFT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressShift();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_RIGHT, shiftEvent));
// 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, shiftEvent));
// first line
// second |li|ne
// last line
assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 2);
// alt tests
KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
0, KeyEvent.META_ALT_ON);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_RIGHT, altEvent));
// first line
// second line|
// last line
assertSelection(END_OF_2ND_LINE);
pressAlt();
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_RIGHT, altEvent));
// first line
// second line|
// last line
assertSelection(END_OF_2ND_LINE);
// no-meta tests
KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_RIGHT, 0, 0);
Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
MetaKeyKeyListener.resetMetaState(mEditable);
assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_RIGHT, noMetaEvent));
// 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, noMetaEvent));
// first line
// second line
// |last line
assertSelection(START_OF_3RD_LINE);
}
public void testOnKeyDownWithNullLayout() {
initTextViewWithNullLayout();
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
}
}
@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)));
}
@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, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_CENTER)));
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_0, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0)));
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_E, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_E)));
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_UNKNOWN, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_UNKNOWN)));
}
@UiThreadTest
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);
}
public void testOnTouchEventWithNullLayout() {
initTextViewWithNullLayout();
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)));
}
@UiThreadTest
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);
}
public void testOnTouchEventWithNullParameters() {
initTextViewWithNullLayout();
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
}
}
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
}
}
public void testOnTrackballEven() {
assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable,
MotionEvent.obtain(0, 0, 0, 1, 1, 0)));
initTextViewWithNullLayout();
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));
}
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 static final String TEXT_WORDS =
"Lorem ipsum; dolor sit \u00e4met, conse\u0ca0_\u0ca0ctetur? Adipiscing"
+ ".elit.integ\u00e9r. Etiam tristique\ntortor nec ?:? \n\n"
+ "lectus porta consequ\u00e4t... LOReM iPSuM";
@UiThreadTest
public void testFollowingWordStartToEnd() {
// NOTE: there seems to be much variation in how word boundaries are
// navigated; the behaviors asserted here were derived from Google
// Chrome 10.0.648.133 beta.
initTextViewWithNullLayout(TEXT_WORDS);
// |Lorem ipsum; dolor sit $met,
Selection.setSelection(mEditable, 0);
assertSelection(0);
// Lorem| ipsum; dolor sit $met,
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(5);
// Lorem ipsum|; dolor sit $met,
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(11);
// Lorem ipsum; dolor| sit $met,
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(18);
// Lorem ipsum; dolor sit| $met,
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(22);
// $met|, conse$_$ctetur$ Adipiscing.elit.integ$r.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(27);
// $met, conse$_$ctetur|$ Adipiscing.elit.integ$r.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(43);
// TODO: enable these two additional word breaks when implemented
// // $met, conse$_$ctetur$ Adipiscing|.elit.integ$r.
// assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
// assertSelection(61);
//
// // $met, conse$_$ctetur$ Adipiscing.elit|.integ$r.
// assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
// assertSelection(66);
// $met, conse$_$ctetur$ Adipiscing.elit.integ$r|.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(74);
// integ$r. Etiam| tristique$tortor nec ?:? $$lectus porta
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(81);
// integ$r. Etiam tristique|$tortor nec ?:? $$lectus porta
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(94);
// integ$r. Etiam tristique$tortor| nec ?:? $$lectus porta
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(101);
// integ$r. Etiam tristique$tortor nec| ?:? $$lectus porta
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(105);
// integ$r. Etiam tristique$tortor nec ?:? $$lectus| porta
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(123);
// $$lectus porta| consequ$t... LOReM iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(129);
// $$lectus porta consequ$t|... LOReM iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(139);
// $$lectus porta consequ$t... LOReM| iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(149);
// $$lectus porta consequ$t... LOReM iPSuM|
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(155);
// keep trying to push beyond end, which should fail
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(155);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(155);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(155);
}
@UiThreadTest
public void testPrecedingWordEndToStart() {
// NOTE: there seems to be much variation in how word boundaries are
// navigated; the behaviors asserted here were derived from Google
// Chrome 10.0.648.133 beta.
initTextViewWithNullLayout(TEXT_WORDS);
// $$lectus porta consequ$t... LOReM iPSuM|
Selection.setSelection(mEditable, mEditable.length());
assertSelection(155);
// $$lectus porta consequ$t... LOReM |iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(150);
// $$lectus porta consequ$t... |LOReM iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(144);
// $$lectus porta |consequ$t... LOReM iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(130);
// $$lectus |porta consequ$t... LOReM iPSuM
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(124);
// integ$r. Etiam tristique$tortor nec ?:? $$|lectus
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(117);
// integ$r. Etiam tristique$tortor |nec ?:? $$lectus
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(102);
// integ$r. Etiam tristique$|tortor nec ?:? $$lectus
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(95);
// integ$r. Etiam |tristique$tortor nec ?:? $$lectus
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(85);
// integ$r. |Etiam tristique$tortor nec ?:? $$lectus
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(76);
// TODO: enable these two additional word breaks when implemented
// // dolor sit $met, conse$_$ctetur$ Adipiscing.elit.|integ$r.
// assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
// assertSelection(67);
//
// // dolor sit $met, conse$_$ctetur$ Adipiscing.|elit.integ$r.
// assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
// assertSelection(62);
// dolor sit $met, conse$_$ctetur$ |Adipiscing.elit.integ$r.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(51);
// dolor sit $met, |conse$_$ctetur$ Adipiscing.elit.integ$r.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(29);
// dolor sit |$met, conse$_$ctetur$ Adipiscing.elit.integ$r.
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(23);
// Lorem ipsum; dolor |sit $met
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(19);
// Lorem ipsum; |dolor sit $met
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(13);
// Lorem |ipsum; dolor sit $met
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(6);
// |Lorem ipsum; dolor sit $met
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
// keep trying to push before beginning, which should fail
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
}
private static final String TEXT_WORDS_WITH_NUMBERS =
"Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4";
@UiThreadTest
public void testFollowingWordStartToEndWithNumbers() {
initTextViewWithNullLayout(TEXT_WORDS_WITH_NUMBERS);
// |Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4
Selection.setSelection(mEditable, 0);
assertSelection(0);
// Lorem| ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(5);
// Lorem ipsum123,456.90| dolor sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(21);
// Lorem ipsum123,456.90 dolor| sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(29);
// Lorem ipsum123,456.90 dolor sit|.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(33);
// Lorem ipsum123,456.90 dolor sit.. 4|-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(37);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0|=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(41);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0=2| ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(43);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4|
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(55);
// keep trying to push beyond end, which should fail
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(55);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(55);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(55);
}
@UiThreadTest
public void testFollowingWordEndToStartWithNumbers() {
initTextViewWithNullLayout(TEXT_WORDS_WITH_NUMBERS);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4|
Selection.setSelection(mEditable, mEditable.length());
assertSelection(55);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 |ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(44);
// Lorem ipsum123,456.90 dolor sit.. 4-0.0=|2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(42);
// Lorem ipsum123,456.90 dolor sit.. 4-|0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(38);
// Lorem ipsum123,456.90 dolor sit.. |4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(36);
// Lorem ipsum123,456.90 dolor |sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(30);
// Lorem ipsum123,456.90 |dolor sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(24);
// Lorem |ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(6);
// |Lorem ipsum123,456.90 dolor sit.. 4-0.0=2 ADipiscing4
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
// keep trying to push before beginning, which should fail
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
}
private static final String TEXT_WORDS_WITH_1CHAR_FINAL_WORD = "abc d";
@UiThreadTest
public void testFollowingWordStartToEndWithOneCharFinalWord() {
initTextViewWithNullLayout(TEXT_WORDS_WITH_1CHAR_FINAL_WORD);
// |abc d
Selection.setSelection(mEditable, 0);
assertSelection(0);
// abc| d
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(3);
// abc d|
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(mEditable.length());
}
@UiThreadTest
public void testFollowingWordEndToStartWithOneCharFinalWord() {
initTextViewWithNullLayout(TEXT_WORDS_WITH_1CHAR_FINAL_WORD);
// abc d|
Selection.setSelection(mEditable, mEditable.length());
assertSelection(5);
// abc |d
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(4);
// |abc d
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(0);
}
@UiThreadTest
public void testMovementFromMiddleOfWord() {
initTextViewWithNullLayout("before word after");
checkMoveFromInsideWord(7, 10);
// Surrogate characters: bairkan should be considered as a standard letter
final String BAIRKAN = "\uD800\uDF31";
initTextViewWithNullLayout("before wo" + BAIRKAN + "rd after");
checkMoveFromInsideWord(7, 12);
initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + "xx after");
checkMoveFromInsideWord(7, 12);
initTextViewWithNullLayout("before xx" + BAIRKAN + BAIRKAN + " after");
checkMoveFromInsideWord(7, 12);
initTextViewWithNullLayout("before x" + BAIRKAN + "x" + BAIRKAN + " after");
checkMoveFromInsideWord(7, 12);
initTextViewWithNullLayout("before " + BAIRKAN + "x" + BAIRKAN + "x after");
checkMoveFromInsideWord(7, 12);
initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + BAIRKAN + " after");
checkMoveFromInsideWord(7, 12);
}
private void checkMoveFromInsideWord(int wordStart, int wordEnd) {
CharSequence text = mTextView.getText();
// Check following always goes at the end of the word
for (int offset = wordStart; offset != wordEnd + 1; offset++) {
// Skip positions located between a pair of surrogate characters
if (Character.isSurrogatePair(text.charAt(offset - 1), text.charAt(offset))) {
continue;
}
Selection.setSelection(mEditable, offset);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
assertSelection(wordEnd + 1);
}
// Check preceding always goes at the beginning of the word
for (int offset = wordEnd + 1; offset != wordStart; offset--) {
if (Character.isSurrogatePair(text.charAt(offset - 1), text.charAt(offset))) {
continue;
}
Selection.setSelection(mEditable, offset);
assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
assertSelection(wordStart);
}
}
private void initTextViewWithNullLayout() {
initTextViewWithNullLayout(THREE_LINES_TEXT);
}
private void initTextViewWithNullLayout(CharSequence text) {
mTextView = new TextView(getActivity());
mTextView.setText(text, BufferType.EDITABLE);
assertNull(mTextView.getLayout());
mEditable = (Editable) mTextView.getText();
}
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 boolean pressCtrlChord(int keyCode) {
final long now = System.currentTimeMillis();
final KeyEvent keyEvent = new KeyEvent(
now, now, KeyEvent.ACTION_DOWN, keyCode, 0, KeyEvent.META_CTRL_LEFT_ON);
return mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable, keyCode, keyEvent);
}
private void assertSelection(int expectedPosition) {
assertSelection(expectedPosition, expectedPosition);
}
private void assertSelection(int expectedStart, int expectedEnd) {
final int actualStart = Selection.getSelectionStart(mEditable);
final int actualEnd = Selection.getSelectionEnd(mEditable);
assertCharSequenceIndexEquals(mEditable, expectedStart, actualStart);
assertCharSequenceIndexEquals(mEditable, expectedEnd, actualEnd);
}
private static void assertCharSequenceIndexEquals(CharSequence text, int expected, int actual) {
final String message = "expected <" + getCursorSnippet(text, expected) + "> but was <"
+ getCursorSnippet(text, actual) + ">";
assertEquals(message, expected, actual);
}
private static String getCursorSnippet(CharSequence text, int index) {
if (index >= 0 && index < text.length()) {
return text.subSequence(Math.max(0, index - 5), index) + "|"
+ text.subSequence(index, Math.min(text.length() - 1, index + 5));
} else {
return null;
}
}
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 {
}
}