blob: 432ec84b880579ccd627546c193393af807563b0 [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.cts.util.WidgetTestUtils;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;
import android.widget.TextView.BufferType;
/**
* Test {@link ScrollingMovementMethod}. 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 ScrollingMovementMethodTest extends ActivityInstrumentationTestCase2<CtsActivity> {
private static final int LITTLE_SPACE = 20;
private static final String THREE_LINES_TEXT = "first line\nsecond line\nlast line";
private TextView mTextView;
private Spannable mSpannable;
private int mScaledTouchSlop;
public ScrollingMovementMethodTest() {
super("com.android.cts.text", CtsActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mTextView = new TextView(getActivity());
mTextView.setText(THREE_LINES_TEXT, BufferType.EDITABLE);
mSpannable = (Spannable) mTextView.getText();
mScaledTouchSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop();
}
public void testConstructor() {
new ScrollingMovementMethod();
}
public void testGetInstance() {
MovementMethod method0 = ScrollingMovementMethod.getInstance();
assertTrue(method0 instanceof ScrollingMovementMethod);
MovementMethod method1 = ScrollingMovementMethod.getInstance();
assertSame(method0, method1);
}
public void testOnTouchEventHorizontalMotion() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
final ScrollingMovementMethod method = new ScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
mTextView.setText("hello world", BufferType.SPANNABLE);
mTextView.setSingleLine();
mSpannable = (Spannable) mTextView.getText();
int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
float rightMost = mTextView.getLayout().getLineRight(0) - mTextView.getWidth()
+ mTextView.getTotalPaddingLeft() + mTextView.getTotalPaddingRight();
int leftMost = mTextView.getScrollX();
final long now = SystemClock.uptimeMillis();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// press
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
}
}));
final int tinyDist = -(mScaledTouchSlop - 1);
int previousScrollX = mTextView.getScrollX();
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for short distance
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, tinyDist, 0, 0));
}
}));
assertEquals(previousScrollX, mTextView.getScrollX());
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
// release
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, tinyDist, 0, 0));
}
}));
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// press
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
}
}));
final int distFar = -mScaledTouchSlop;
previousScrollX = mTextView.getScrollX();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for enough distance
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, distFar, 0, 0));
}
}));
assertTrue(mTextView.getScrollX() > previousScrollX);
assertTrue(mTextView.getScrollX() < rightMost);
previousScrollX = mTextView.getScrollX();
final int distTooFar = (int) (-rightMost * 10);
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for long distance
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, distTooFar, 0, 0));
}
}));
assertTrue(mTextView.getScrollX() > previousScrollX);
assertEquals(rightMost, mTextView.getScrollX(), 1.0f);
previousScrollX = mTextView.getScrollX();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move back
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, 0, 0, 0));
}
}));
assertTrue(mTextView.getScrollX() < previousScrollX);
assertEquals(leftMost, mTextView.getScrollX());
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// release
mResult = method.onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0, 0, 0));
}
}));
}
public void testOnTouchEventVerticalMotion() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
final ScrollingMovementMethod method = new ScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
mTextView.setLines(1);
getActivity().setContentView(mTextView,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
float bottom = mTextView.getLayout().getHeight() - mTextView.getHeight()
+ mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
int top = mTextView.getScrollY();
final long now = SystemClock.uptimeMillis();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// press
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_DOWN, 0, 0, 0));
}
}));
final int tinyDist = -(mScaledTouchSlop - 1);
int previousScrollY = mTextView.getScrollY();
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for short distance
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_MOVE, 0, tinyDist, 0));
}
}));
assertEquals(previousScrollY, mTextView.getScrollY());
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
// release
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_UP, 0, tinyDist, 0));
}
}));
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// press
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_DOWN, 0, 0, 0));
}
}));
final int distFar = -mScaledTouchSlop;
previousScrollY = mTextView.getScrollY();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for enough distance
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_MOVE, 0, distFar, 0));
}
}));
assertTrue(mTextView.getScrollY() > previousScrollY);
assertTrue(mTextView.getScrollX() < bottom);
previousScrollY = mTextView.getScrollY();
final int distTooFar = (int) (-bottom * 10);
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move for long distance
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_MOVE, 0, distTooFar, 0));
}
}));
assertTrue(mTextView.getScrollY() > previousScrollY);
assertEquals(bottom, mTextView.getScrollY(), 0f);
previousScrollY = mTextView.getScrollY();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// move back
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_MOVE, 0, 0, 0));
}
}));
assertTrue(mTextView.getScrollY() < previousScrollY);
assertEquals(top, mTextView.getScrollX());
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
// release
mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
MotionEvent.ACTION_UP, 0, 0, 0));
}
}));
}
public void testOnTouchEventExceptional() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
runActionOnUiThread(new Runnable() {
public void run() {
int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
runActionOnUiThread(new Runnable() {
public void run() {
try {
new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable, null);
} catch (NullPointerException e) {
// NPE is acceptable
}
long now = SystemClock.uptimeMillis();
try {
new ScrollingMovementMethod().onTouchEvent(mTextView, null,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
try {
new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, - 10000, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new ScrollingMovementMethod().onTouchEvent(mTextView, null,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, - 10000, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, - 10000, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new ScrollingMovementMethod().onTouchEvent(mTextView, null,
MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, - 10000, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
}
});
}
public void testCanSelectArbitrarily() {
assertFalse(new ScrollingMovementMethod().canSelectArbitrarily());
}
public void testOnKeyDownVerticalMovement() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
runActionOnUiThread(new Runnable() {
public void run() {
getActivity().setContentView(mTextView);
}
});
assertNotNull(mTextView.getLayout());
assertVisibleLineInTextView(0);
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_DOWN,
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
}
});
assertVisibleLineInTextView(1);
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_UP,
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
}
});
assertVisibleLineInTextView(0);
}
public void testOnKeyDownHorizontalMovement() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
runActionOnUiThread(new Runnable() {
public void run() {
mTextView.setText("short");
mTextView.setSingleLine();
int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
int previousScrollX = mTextView.getScrollX();
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_RIGHT));
}
});
assertTrue(mTextView.getScrollX() > previousScrollX);
previousScrollX = mTextView.getScrollX();
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT));
}
});
assertTrue(mTextView.getScrollX() < previousScrollX);
previousScrollX = mTextView.getScrollX();
assertVisibleLineInTextView(0);
runActionOnUiThread(new Runnable() {
public void run() {
assertFalse(method.onKeyDown(mTextView, mSpannable, 0,
new KeyEvent(KeyEvent.ACTION_DOWN, 0)));
}
});
assertEquals(previousScrollX, mTextView.getScrollX());
assertVisibleLineInTextView(0);
}
public void testOnKeyDownExceptions() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
runActionOnUiThread(new Runnable() {
public void run() {
getActivity().setContentView(mTextView);
}
});
assertNotNull(mTextView.getLayout());
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
try {
method.onKeyDown(null, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT,
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_RIGHT,
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.onKeyDown(mTextView, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT, null);
} catch (NullPointerException e) {
// NPE is acceptable
}
}
});
}
public void testVerticalMovement() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
mTextView.setLines(1);
getActivity().setContentView(mTextView,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.down(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(1);
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.down(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(2);
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.down(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(2);
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.up(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(1);
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.up(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(0);
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.up(mTextView, mSpannable);
}
}));
assertVisibleLineInTextView(0);
runActionOnUiThread(new Runnable() {
public void run() {
try {
method.up(null, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.up(mTextView, null);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.down(null, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.down(mTextView, null);
} catch (NullPointerException e) {
// NPE is acceptable
}
}
});
}
public void testMovementWithNullLayout() {
assertNull(mTextView.getLayout());
try {
new MyScrollingMovementMethod().down(mTextView, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new MyScrollingMovementMethod().up(mTextView, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new MyScrollingMovementMethod().left(mTextView, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
new MyScrollingMovementMethod().right(mTextView, mSpannable);
} catch (NullPointerException e) {
// NPE is acceptable
}
long now = SystemClock.uptimeMillis();
try {
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
new ScrollingMovementMethod().onKeyDown(mTextView, mSpannable,
KeyEvent.KEYCODE_DPAD_RIGHT, event);
} catch (NullPointerException e) {
// NPE is acceptable
}
new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
try {
new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable,
MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, - 10000, 0, 0));
} catch (NullPointerException e) {
// NPE is acceptable
}
}
public void testInitialize() {
new ScrollingMovementMethod().initialize(null, null);
}
public void testOnTrackballEvent() {
long now = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(now, now, 0, 2, -2, 0);
MyScrollingMovementMethod mockMethod = new MyScrollingMovementMethod();
assertFalse(mockMethod.onTrackballEvent(mTextView, mSpannable, event));
assertFalse(mockMethod.onTrackballEvent(null, mSpannable, event));
assertFalse(mockMethod.onTrackballEvent(mTextView, mSpannable, null));
assertFalse(mockMethod.onTrackballEvent(mTextView, null, event));
}
public void testOnKeyUp() {
ScrollingMovementMethod method = new ScrollingMovementMethod();
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));
}
public void testOnTakeFocus() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
final ScrollingMovementMethod method = new ScrollingMovementMethod();
// wait until the text view gets layout
assertNull(mTextView.getLayout());
try {
method.onTakeFocus(mTextView, mSpannable, View.FOCUS_BACKWARD);
} catch (NullPointerException e) {
// NPE is acceptable
}
runActionOnUiThread(new Runnable() {
public void run() {
int height = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
height));
}
});
Layout layout = mTextView.getLayout();
assertNotNull(layout);
int previousScrollY = mTextView.getScrollY();
runActionOnUiThread(new Runnable() {
public void run() {
method.onTakeFocus(mTextView, mSpannable, View.FOCUS_BACKWARD);
}
});
assertTrue(mTextView.getScrollY() >= previousScrollY);
assertVisibleLineInTextView(2);
previousScrollY = mTextView.getScrollY();
runActionOnUiThread(new Runnable() {
public void run() {
method.onTakeFocus(mTextView, mSpannable, View.FOCUS_FORWARD);
}
});
assertTrue(mTextView.getScrollY() <= previousScrollY);
assertVisibleLineInTextView(0);
runActionOnUiThread(new Runnable() {
public void run() {
try {
method.onTakeFocus(null, mSpannable, View.FOCUS_FORWARD);
} catch (NullPointerException e) {
// NPE is acceptable
}
try {
method.onTakeFocus(mTextView, null, View.FOCUS_FORWARD);
} catch (NullPointerException e) {
// NPE is acceptable
}
}
});
}
public void testHorizontalMovement() throws Throwable {
/*
* All these assertions depends on whether the TextView has a layout.The text view will not
* get layout in setContent method but in otherhandler'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.
*/
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
mTextView.setText("short");
mTextView.setSingleLine();
int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
});
assertNotNull(mTextView.getLayout());
int previousScrollX = mTextView.getScrollX();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.right(mTextView, mSpannable);
}
}));
assertTrue(mTextView.getScrollX() > previousScrollX);
previousScrollX = mTextView.getScrollX();
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.right(mTextView, mSpannable);
}
}));
assertEquals(previousScrollX, mTextView.getScrollX());
previousScrollX = mTextView.getScrollX();
assertTrue(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.left(mTextView, mSpannable);
}
}));
assertTrue(mTextView.getScrollX() < previousScrollX);
previousScrollX = mTextView.getScrollX();
assertFalse(getActionResult(new ActionRunnerWithResult() {
public void run() {
mResult = method.left(mTextView, mSpannable);
}
}));
assertEquals(previousScrollX, mTextView.getScrollX());
}
public void testOnKeyOther() throws Throwable {
runActionOnUiThread(new Runnable() {
public void run() {
getActivity().setContentView(mTextView);
}
});
assertNotNull(mTextView.getLayout());
assertVisibleLineInTextView(0);
final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyOther(mTextView, null,
new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
KeyEvent.KEYCODE_DPAD_DOWN, 2));
}
});
assertVisibleLineInTextView(1);
runActionOnUiThread(new Runnable() {
public void run() {
method.onKeyOther(mTextView, null,
new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
KeyEvent.KEYCODE_DPAD_UP, 2));
}
});
assertVisibleLineInTextView(0);
}
private void assertVisibleLineInTextView(int line) {
Layout layout = mTextView.getLayout();
int scrollY = mTextView.getScrollY();
int padding = mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
assertTrue(layout.getLineForVertical(scrollY) <= line);
assertTrue(layout.getLineForVertical(scrollY + mTextView.getHeight() - padding) >= line);
}
private boolean getActionResult(ActionRunnerWithResult actionRunner) throws Throwable {
runActionOnUiThread(actionRunner);
return actionRunner.getResult();
}
private void runActionOnUiThread(Runnable actionRunner) throws Throwable {
runTestOnUiThread(actionRunner);
getInstrumentation().waitForIdleSync();
}
private static abstract class ActionRunnerWithResult implements Runnable {
protected boolean mResult = false;
public boolean getResult() {
return mResult;
}
}
private static class MyScrollingMovementMethod extends ScrollingMovementMethod {
@Override
protected boolean down(TextView widget, Spannable buffer) {
return super.down(widget, buffer);
}
@Override
protected boolean left(TextView widget, Spannable buffer) {
return super.left(widget, buffer);
}
@Override
protected boolean right(TextView widget, Spannable buffer) {
return super.right(widget, buffer);
}
@Override
protected boolean up(TextView widget, Spannable buffer) {
return super.up(widget, buffer);
}
}
}