1 /* 2 * Copyright (C) 2016 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.widget; 18 19 import static android.support.test.espresso.Espresso.onView; 20 import static android.support.test.espresso.action.ViewActions.click; 21 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnLeft; 22 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnRight; 23 24 import static junit.framework.Assert.fail; 25 26 import static org.hamcrest.MatcherAssert.assertThat; 27 import static org.hamcrest.Matchers.equalTo; 28 import static org.hamcrest.Matchers.isEmptyString; 29 import static org.hamcrest.Matchers.nullValue; 30 import static org.hamcrest.Matchers.sameInstance; 31 32 import android.app.Activity; 33 import android.app.Instrumentation; 34 import android.support.test.InstrumentationRegistry; 35 import android.support.test.filters.MediumTest; 36 import android.support.test.rule.ActivityTestRule; 37 import android.support.test.runner.AndroidJUnit4; 38 39 import com.android.frameworks.coretests.R; 40 41 import org.junit.Before; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.util.concurrent.CountDownLatch; 47 import java.util.concurrent.TimeUnit; 48 49 @RunWith(AndroidJUnit4.class) 50 @MediumTest 51 public class EditorCursorTest { 52 private final static String LTR_STRING = "aaaaaaaaaaaaaaaaaaaaaa"; 53 private final static String LTR_HINT = "hint"; 54 private final static String RTL_STRING = " "; 55 private final static String RTL_HINT = ""; 56 private final static int CURSOR_BLINK_MS = 500; 57 58 @Rule 59 public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>( 60 TextViewActivity.class); 61 62 private Instrumentation mInstrumentation; 63 private Activity mActivity; 64 private EditText mEditText; 65 66 @Before 67 public void setUp() throws Throwable { 68 mActivity = mActivityRule.getActivity(); 69 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 70 71 mActivityRule.runOnUiThread(() -> { 72 mActivity.setContentView(R.layout.activity_editor_cursor_test); 73 mEditText = mActivity.findViewById(R.id.edittext); 74 }); 75 mInstrumentation.waitForIdleSync(); 76 onView(sameInstance(mEditText)).perform(click()); 77 } 78 79 @Test 80 public void testCursorIsInViewBoundariesWhenOnRightForLtr() throws Throwable { 81 // Asserts that when an EditText has LTR text, and cursor is at the end (right), 82 // cursor is drawn to the right edge of the view 83 setEditTextText(LTR_STRING, LTR_STRING.length()); 84 85 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 86 } 87 88 @Test 89 public void testCursorIsInViewBoundariesWhenOnLeftForLtr() throws Throwable { 90 // Asserts that when an EditText has LTR text, and cursor is at the beginning, 91 // cursor is drawn to the left edge of the view 92 setEditTextText(LTR_STRING, 0); 93 94 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 95 } 96 97 @Test 98 public void testCursorIsInViewBoundariesWhenOnRightForRtl() throws Throwable { 99 // Asserts that when an EditText has RTL text, and cursor is at the end, 100 // cursor is drawn to the left edge of the view 101 setEditTextText(RTL_STRING, 0); 102 103 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 104 } 105 106 @Test 107 public void testCursorIsInViewBoundariesWhenOnLeftForRtl() throws Throwable { 108 // Asserts that when an EditText has RTL text, and cursor is at the beginning, 109 // cursor is drawn to the right edge of the view 110 setEditTextText(RTL_STRING, RTL_STRING.length()); 111 112 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 113 } 114 115 /* Tests for cursor positioning with hint */ 116 @Test 117 public void testCursorIsOnLeft_withFirstStrongLtrAlgorithm() throws Throwable { 118 setEditTextHint(null, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0); 119 assertThat(mEditText.getText().toString(), isEmptyString()); 120 assertThat(mEditText.getHint(), nullValue()); 121 122 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 123 124 setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0); 125 assertThat(mEditText.getText().toString(), isEmptyString()); 126 127 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 128 129 setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0); 130 assertThat(mEditText.getText().toString(), isEmptyString()); 131 132 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 133 } 134 135 @Test 136 public void testCursorIsOnRight_withFirstStrongRtlAlgorithm() throws Throwable { 137 setEditTextHint(null, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0); 138 assertThat(mEditText.getText().toString(), isEmptyString()); 139 assertThat(mEditText.getHint(), nullValue()); 140 141 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 142 143 setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0); 144 assertThat(mEditText.getText().toString(), isEmptyString()); 145 146 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 147 148 setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0); 149 assertThat(mEditText.getText().toString(), isEmptyString()); 150 151 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 152 } 153 154 @Test 155 public void testCursorIsOnLeft_withLtrAlgorithm() throws Throwable { 156 setEditTextHint(null, TextView.TEXT_DIRECTION_LTR, 0); 157 assertThat(mEditText.getText().toString(), isEmptyString()); 158 assertThat(mEditText.getHint(), nullValue()); 159 160 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 161 162 setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_LTR, 0); 163 assertThat(mEditText.getText().toString(), isEmptyString()); 164 165 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 166 167 setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_LTR, 0); 168 assertThat(mEditText.getText().toString(), isEmptyString()); 169 170 onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft()); 171 } 172 173 @Test 174 public void testCursorIsOnRight_withRtlAlgorithm() throws Throwable { 175 setEditTextHint(null, TextView.TEXT_DIRECTION_RTL, 0); 176 assertThat(mEditText.getText().toString(), isEmptyString()); 177 assertThat(mEditText.getHint(), nullValue()); 178 179 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 180 181 setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_RTL, 0); 182 assertThat(mEditText.getText().toString(), isEmptyString()); 183 184 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 185 186 setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_RTL, 0); 187 assertThat(mEditText.getText().toString(), isEmptyString()); 188 189 onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight()); 190 } 191 192 private void setEditTextProperties(final String text, final String hint, 193 final Integer textDirection, final Integer selection) throws Throwable { 194 mActivityRule.runOnUiThread(() -> { 195 if (textDirection != null) mEditText.setTextDirection(textDirection); 196 if (text != null) mEditText.setText(text); 197 if (hint != null) mEditText.setHint(hint); 198 if (selection != null) mEditText.setSelection(selection); 199 }); 200 mInstrumentation.waitForIdleSync(); 201 202 // wait for cursor to be drawn. updateCursorPositions function is called during draw() and 203 // only when cursor is visible during blink. 204 final CountDownLatch latch = new CountDownLatch(1); 205 mEditText.postOnAnimationDelayed(latch::countDown, CURSOR_BLINK_MS); 206 try { 207 assertThat("Problem while waiting for the cursor to blink", 208 latch.await(10, TimeUnit.SECONDS), equalTo(true)); 209 } catch (Exception e) { 210 fail("Problem while waiting for the cursor to blink"); 211 } 212 } 213 214 private void setEditTextHint(final String hint, final int textDirection, final int selection) 215 throws Throwable { 216 setEditTextProperties(null, hint, textDirection, selection); 217 } 218 219 private void setEditTextText(final String text, final Integer selection) throws Throwable { 220 setEditTextProperties(text, null, null, selection); 221 } 222 } 223