1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.text.method.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import android.app.Activity; 23 import android.app.Instrumentation; 24 import android.os.SystemClock; 25 import android.support.test.InstrumentationRegistry; 26 import android.support.test.annotation.UiThreadTest; 27 import android.support.test.filters.MediumTest; 28 import android.support.test.rule.ActivityTestRule; 29 import android.support.test.runner.AndroidJUnit4; 30 import android.text.Layout; 31 import android.text.SpannableString; 32 import android.text.TextPaint; 33 import android.text.method.Touch; 34 import android.util.DisplayMetrics; 35 import android.util.TypedValue; 36 import android.view.MotionEvent; 37 import android.view.ViewGroup; 38 import android.widget.TextView; 39 40 import org.junit.Before; 41 import org.junit.Rule; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 45 @MediumTest 46 @RunWith(AndroidJUnit4.class) 47 public class TouchTest { 48 private static final String LONG_TEXT = "Scrolls the specified widget to the specified " + 49 "coordinates, except constrains the X scrolling position to the horizontal regions " + 50 "of the text that will be visible after scrolling to the specified Y position." + 51 "This is the description of the test." + 52 "Scrolls the specified widget to the specified " + 53 "coordinates, except constrains the X scrolling position to the horizontal regions " + 54 "of the text that will be visible after scrolling to the specified Y position." + 55 "This is the description of the test."; 56 57 private Instrumentation mInstrumentation; 58 private Activity mActivity; 59 private boolean mReturnFromTouchEvent; 60 private TextView mTextView; 61 62 @Rule 63 public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class); 64 65 @UiThreadTest 66 @Before 67 public void setup() { 68 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 69 mActivity = mActivityRule.getActivity(); 70 mTextView = new TextViewNoIme(mActivity); 71 mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); 72 } 73 74 @Test 75 public void testScrollTo() throws Throwable { 76 mActivityRule.runOnUiThread(() -> { 77 final float pixelPerSp = 78 mActivity.getResources().getDisplayMetrics().scaledDensity; 79 // Explicitly set the width so that |LONG_TEXT| causes horizontal scroll. 80 mActivity.setContentView(mTextView, new ViewGroup.LayoutParams( 81 (int)(100 * pixelPerSp), ViewGroup.LayoutParams.MATCH_PARENT)); 82 mTextView.setSingleLine(true); 83 mTextView.setLines(2); 84 }); 85 mInstrumentation.waitForIdleSync(); 86 TextPaint paint = mTextView.getPaint(); 87 final Layout layout = mTextView.getLayout(); 88 89 mActivityRule.runOnUiThread(() -> mTextView.setText(LONG_TEXT)); 90 mInstrumentation.waitForIdleSync(); 91 92 // get the total length of string 93 final int width = getTextWidth(LONG_TEXT, paint); 94 95 mActivityRule.runOnUiThread( 96 () -> Touch.scrollTo(mTextView, layout, width - mTextView.getWidth() - 1, 0)); 97 mInstrumentation.waitForIdleSync(); 98 assertEquals(width - mTextView.getWidth() - 1, mTextView.getScrollX()); 99 assertEquals(0, mTextView.getScrollY()); 100 101 // the X to which scroll is greater than the total length of string. 102 mActivityRule.runOnUiThread(() -> Touch.scrollTo(mTextView, layout, width + 100, 5)); 103 mInstrumentation.waitForIdleSync(); 104 assertEquals(width - mTextView.getWidth(), mTextView.getScrollX(), 1.0f); 105 assertEquals(5, mTextView.getScrollY()); 106 107 mActivityRule.runOnUiThread(() -> Touch.scrollTo(mTextView, layout, width - 10, 5)); 108 mInstrumentation.waitForIdleSync(); 109 assertEquals(width - mTextView.getWidth(), mTextView.getScrollX(), 1.0f); 110 assertEquals(5, mTextView.getScrollY()); 111 } 112 113 @Test 114 public void testOnTouchEvent() throws Throwable { 115 // Create a string that is wider than the screen. 116 DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics(); 117 int screenWidth = metrics.widthPixels; 118 TextPaint paint = mTextView.getPaint(); 119 String text = LONG_TEXT; 120 int textWidth = Math.round(paint.measureText(text)); 121 while (textWidth < screenWidth) { 122 text += LONG_TEXT; 123 textWidth = Math.round(paint.measureText(text)); 124 } 125 126 // Drag the difference between the text width and the screen width. 127 int dragAmount = Math.min(screenWidth, textWidth - screenWidth); 128 assertTrue(dragAmount > 0); 129 final String finalText = text; 130 final SpannableString spannable = new SpannableString(finalText); 131 mActivityRule.runOnUiThread(() -> { 132 mActivity.setContentView(mTextView); 133 mTextView.setSingleLine(true); 134 mTextView.setText(finalText); 135 }); 136 mInstrumentation.waitForIdleSync(); 137 138 long downTime = SystemClock.uptimeMillis(); 139 long eventTime = SystemClock.uptimeMillis(); 140 final MotionEvent event1 = MotionEvent.obtain(downTime, eventTime, 141 MotionEvent.ACTION_DOWN, dragAmount, 0, 0); 142 final MotionEvent event2 = MotionEvent.obtain(downTime, eventTime, 143 MotionEvent.ACTION_MOVE, 0, 0, 0); 144 final MotionEvent event3 = MotionEvent.obtain(downTime, eventTime, 145 MotionEvent.ACTION_UP, 0, 0, 0); 146 assertEquals(0, mTextView.getScrollX()); 147 assertEquals(0, mTextView.getScrollY()); 148 mReturnFromTouchEvent = false; 149 mActivityRule.runOnUiThread( 150 () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event1)); 151 mInstrumentation.waitForIdleSync(); 152 assertTrue(mReturnFromTouchEvent); 153 // TextView has not been scrolled. 154 assertEquals(0, mTextView.getScrollX()); 155 assertEquals(0, mTextView.getScrollY()); 156 assertEquals(0, Touch.getInitialScrollX(mTextView, spannable)); 157 assertEquals(0, Touch.getInitialScrollY(mTextView, spannable)); 158 159 mReturnFromTouchEvent = false; 160 mActivityRule.runOnUiThread( 161 () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event2)); 162 mInstrumentation.waitForIdleSync(); 163 assertTrue(mReturnFromTouchEvent); 164 // TextView has been scrolled. 165 assertEquals(dragAmount, mTextView.getScrollX()); 166 assertEquals(0, mTextView.getScrollY()); 167 assertEquals(0, Touch.getInitialScrollX(mTextView, spannable)); 168 assertEquals(0, Touch.getInitialScrollY(mTextView, spannable)); 169 170 mReturnFromTouchEvent = false; 171 mActivityRule.runOnUiThread( 172 () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event3)); 173 mInstrumentation.waitForIdleSync(); 174 assertTrue(mReturnFromTouchEvent); 175 // TextView has not been scrolled. 176 assertEquals(dragAmount, mTextView.getScrollX()); 177 assertEquals(0, mTextView.getScrollY()); 178 assertEquals(-1, Touch.getInitialScrollX(mTextView, spannable)); 179 assertEquals(-1, Touch.getInitialScrollY(mTextView, spannable)); 180 } 181 182 private int getTextWidth(String str, TextPaint paint) { 183 float totalWidth = 0f; 184 float[] widths = new float[str.length()]; 185 paint.getTextWidths(str, widths); 186 for (float f : widths) { 187 totalWidth += f; 188 } 189 return (int) totalWidth; 190 } 191 } 192