Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java

Issue 335943002: [Android] Composited selection handle rendering (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@input_native_handles_final
Patch Set: Fix animation tests Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.content.browser.input;
6
7 import android.content.ClipData;
8 import android.content.ClipboardManager;
9 import android.content.Context;
10 import android.graphics.Rect;
11 import android.test.suitebuilder.annotation.MediumTest;
12 import android.text.Editable;
13 import android.text.Selection;
14 import android.view.KeyEvent;
15 import android.view.View;
16
17 import org.chromium.base.test.util.DisabledTest;
18 import org.chromium.base.test.util.Feature;
19 import org.chromium.base.test.util.UrlUtils;
20 import org.chromium.content.browser.RenderCoordinates;
21 import org.chromium.content.browser.test.util.Criteria;
22 import org.chromium.content.browser.test.util.CriteriaHelper;
23 import org.chromium.content.browser.test.util.DOMUtils;
24 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
25 import org.chromium.content.browser.test.util.TestTouchUtils;
26 import org.chromium.content.browser.test.util.TouchCommon;
27 import org.chromium.content_shell_apk.ContentShellTestBase;
28
29 /**
30 * Tests the insertion handle that allows users to paste text.
31 */
32 public class InsertionHandleTest extends ContentShellTestBase {
33 private static final String META_DISABLE_ZOOM =
34 "<meta name=\"viewport\" content=\"" +
35 "height=device-height," +
36 "width=device-width," +
37 "initial-scale=1.0," +
38 "minimum-scale=1.0," +
39 "maximum-scale=1.0," +
40 "\" />";
41
42 private static final String TEXTAREA_ID = "textarea";
43 private static final String TEXTAREA_DATA_URL = UrlUtils.encodeHtmlDataUri(
44 "<html><head>" + META_DISABLE_ZOOM + "</head><body>" +
45 "<textarea id=\"" + TEXTAREA_ID + "\" cols=\"20\" rows=\"10\">" +
46 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ei usmod tempor " +
47 "incididunt ut labore et dolore magna aliqua. Ut enim ad minim venia m, quis nostrud " +
48 "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequa t. Duis aute " +
49 "irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " +
50 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in c ulpa qui " +
51 "officia deserunt mollit anim id est laborum." +
52 "</textarea>" +
53 "</body></html>");
54
55 private static final String INPUT_TEXT_ID = "input_text";
56 private static final String INPUT_TEXT_DATA_URL = UrlUtils.encodeHtmlDataUri (
57 "<html><head>" + META_DISABLE_ZOOM + "</head><body>" +
58 "<input id=\"input_text\" type=\"text\" value=\"" +
59 "T0D0(cjhopman): put amusing sample text here. Make sure it is at le ast " +
60 "100 characters. 123456789012345678901234567890\" size=20></input>" +
61 "</body></html>");
62
63 // Offset to compensate for the fact that the handle is below the text.
64 private static final int VERTICAL_OFFSET = 10;
65 private static final int HANDLE_POSITION_TOLERANCE = 20;
66 private static final String PASTE_TEXT = "**test text to paste**";
67
68
69 public void launchWithUrl(String url) throws Throwable {
70 launchContentShellWithUrl(url);
71 assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
72 assertWaitForPageScaleFactorMatch(1.0f);
73
74 // The TestInputMethodManagerWrapper intercepts showSoftInput so that a keyboard is never
75 // brought up.
76 getContentViewCore().getImeAdapterForTest().setInputMethodManagerWrapper (
77 new TestInputMethodManagerWrapper(getContentViewCore()));
78 }
79
80 @MediumTest
81 @Feature({"TextSelection", "TextInput", "Main"})
82 public void testUnselectHidesHandle() throws Throwable {
83 launchWithUrl(TEXTAREA_DATA_URL);
84 clickNodeToShowInsertionHandle(TEXTAREA_ID);
85
86 // Unselecting should cause the handle to disappear.
87 unselectOnMainSync();
88 assertTrue(waitForHandleShowingEquals(false));
89 }
90
91 @MediumTest
92 @Feature({"TextSelection", "TextInput", "Main"})
93 public void testUpdateContainerViewAndUnselectHidesHandle() throws Throwable {
94 launchWithUrl(TEXTAREA_DATA_URL);
95 replaceContainerView();
96
97 clickNodeToShowInsertionHandle(TEXTAREA_ID);
98
99 // Unselecting should cause the handle to disappear.
100 unselectOnMainSync();
101 assertTrue(waitForHandleShowingEquals(false));
102 }
103
104 /**
105 * @MediumTest
106 * @Feature({"TextSelection", "TextInput", "Main"})
107 * http://crbug.com/169648
108 */
109 @DisabledTest
110 public void testKeyEventHidesHandle() throws Throwable {
111 launchWithUrl(TEXTAREA_DATA_URL);
112 clickNodeToShowInsertionHandle(TEXTAREA_ID);
113
114 getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyE vent.KEYCODE_X));
115 getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEve nt.KEYCODE_X));
116 assertTrue(waitForHandleShowingEquals(false));
117 }
118
119 /**
120 * @MediumTest
121 * @Feature({"TextSelection", "TextInput", "Main"})
122 * http://crbug.com/169648
123 */
124 @DisabledTest
125 public void testDragInsertionHandle() throws Throwable {
126 launchWithUrl(TEXTAREA_DATA_URL);
127
128 clickNodeToShowInsertionHandle(TEXTAREA_ID);
129
130 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
131 HandleView handle = ihc.getHandleViewForTest();
132
133 int initialX = handle.getPositionX();
134 int initialY = handle.getPositionY();
135 int dragToX = initialX + 120;
136 int dragToY = initialY + 120;
137
138 dragHandleTo(dragToX, dragToY);
139 assertWaitForHandleNear(dragToX, dragToY);
140 }
141
142
143 @MediumTest
144 @Feature({"TextSelection", "TextInput", "Main"})
145 public void testPasteAtInsertionHandle() throws Throwable {
146 launchWithUrl(TEXTAREA_DATA_URL);
147
148 clickNodeToShowInsertionHandle(TEXTAREA_ID);
149
150 int offset = getSelectionStart();
151 String initialText = getEditableText();
152
153 saveToClipboard(PASTE_TEXT);
154 pasteOnMainSync();
155
156 String expectedText =
157 initialText.substring(0, offset) + PASTE_TEXT + initialText.subst ring(offset);
158 assertTrue(waitForEditableTextEquals(expectedText));
159 assertTrue(waitForHandleShowingEquals(false));
160 }
161
162 /**
163 * @MediumTest
164 * @Feature({"TextSelection", "TextInput", "Main"})
165 * http://crbug.com/169648
166 */
167 @DisabledTest
168 public void testDragInsertionHandleInputText() throws Throwable {
169 launchWithUrl(INPUT_TEXT_DATA_URL);
170
171 clickNodeToShowInsertionHandle(INPUT_TEXT_ID);
172
173 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
174 HandleView handle = ihc.getHandleViewForTest();
175
176 int initialX = handle.getPositionX();
177 int initialY = handle.getPositionY();
178 int dragToX = initialX + 120;
179 int dragToY = initialY;
180 dragHandleTo(dragToX, dragToY);
181 assertWaitForHandleNear(dragToX, initialY);
182
183 TestTouchUtils.sleepForDoubleTapTimeout(getInstrumentation());
184
185 initialX = handle.getPositionX();
186 initialY = handle.getPositionY();
187 dragToY = initialY + 120;
188 dragHandleTo(initialX, dragToY);
189 // Vertical drag should not change the y-position.
190 assertWaitForHandleNear(initialX, initialY);
191 }
192
193 /**
194 * @MediumTest
195 * @Feature({"TextSelection", "TextInput", "Main"})
196 * http://crbug.com/169648
197 */
198 @DisabledTest
199 public void testDragInsertionHandleInputTextOutsideBounds() throws Throwable {
200 launchWithUrl(INPUT_TEXT_DATA_URL);
201
202 clickNodeToShowInsertionHandle(INPUT_TEXT_ID);
203
204 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
205 HandleView handle = ihc.getHandleViewForTest();
206
207 int initialX = handle.getPositionX();
208 int initialY = handle.getPositionY();
209 int dragToX = initialX;
210 int dragToY = initialY + 150;
211
212 // A vertical drag should not move the insertion handle.
213 dragHandleTo(dragToX, dragToY);
214 assertWaitForHandleNear(initialX, initialY);
215
216 // The input box does not go to the edge of the screen, and neither shou ld the insertion
217 // handle.
218 dragToX = getContentViewCore().getContainerView().getWidth();
219 dragHandleTo(dragToX, dragToY);
220 assertTrue(handle.getPositionX() < dragToX - 100);
221 }
222
223 @Override
224 protected void tearDown() throws Exception {
225 super.tearDown();
226 // No way to just clear clipboard, so setting to empty string instead.
227 saveToClipboard("");
228 }
229
230 private void clickNodeToShowInsertionHandle(String nodeId) throws Throwable {
231 // On the first click the keyboard will be displayed but no insertion ha ndles. On the second
232 // click (only if it changes the selection), the insertion handle is dis played. So that the
233 // second click changes the selection, the two clicks should be in suffi ciently different
234 // locations.
235 Rect nodeBounds = DOMUtils.getNodeBounds(getContentViewCore(), nodeId);
236
237 RenderCoordinates renderCoordinates = getContentViewCore().getRenderCoor dinates();
238 int offsetX = getContentViewCore().getViewportSizeOffsetWidthPix();
239 int offsetY = getContentViewCore().getViewportSizeOffsetHeightPix();
240 float left = renderCoordinates.fromLocalCssToPix(nodeBounds.left) + offs etX;
241 float right = renderCoordinates.fromLocalCssToPix(nodeBounds.right) + of fsetX;
242 float top = renderCoordinates.fromLocalCssToPix(nodeBounds.top) + offset Y;
243 float bottom = renderCoordinates.fromLocalCssToPix(nodeBounds.bottom) + offsetY;
244
245 TouchCommon touchCommon = new TouchCommon(this);
246 touchCommon.singleClickView(getContentViewCore().getContainerView(),
247 (int)(left + 3 * (right - left) / 4), (int)(top + (bottom - top) / 2));
248
249
250 TestTouchUtils.sleepForDoubleTapTimeout(getInstrumentation());
251 assertTrue(waitForHasSelectionPosition());
252
253 // TODO(cjhopman): Wait for keyboard display finished?
254 touchCommon.singleClickView(getContentViewCore().getContainerView(),
255 (int)(left + (right - left) / 4), (int)(top + (bottom - top) / 2 ));
256 assertTrue(waitForHandleShowingEquals(true));
257 assertTrue(waitForHandleViewStopped());
258 }
259
260 private boolean waitForHandleViewStopped() throws Throwable {
261 // If the polling interval is too short, slowly moving may be detected a s not moving.
262 final int POLLING_INTERVAL = 200;
263 return CriteriaHelper.pollForCriteria(new Criteria() {
264 int mPositionX = -1;
265 int mPositionY = -1;
266 @Override
267 public boolean isSatisfied() {
268 int lastPositionX = mPositionX;
269 int lastPositionY = mPositionY;
270 InsertionHandleController ihc =
271 getContentViewCore().getInsertionHandleControllerForTest ();
272 HandleView handle = ihc.getHandleViewForTest();
273 mPositionX = handle.getPositionX();
274 mPositionY = handle.getPositionY();
275 return !handle.isDragging() &&
276 mPositionX == lastPositionX && mPositionY == lastPositio nY;
277 }
278 }, CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL, POLLING_INTERVAL);
279 }
280
281 private boolean waitForEditableTextEquals(final String expectedText)
282 throws Throwable {
283 return CriteriaHelper.pollForCriteria(new Criteria() {
284 @Override
285 public boolean isSatisfied() {
286 return getEditableText().trim().equals(expectedText.trim());
287 }
288 });
289 }
290
291 private boolean waitForHasSelectionPosition()
292 throws Throwable {
293 return CriteriaHelper.pollForCriteria(new Criteria() {
294 @Override
295 public boolean isSatisfied() {
296 int start = getSelectionStart();
297 int end = getSelectionEnd();
298 return start > 0 && start == end;
299 }
300 });
301 }
302
303 private void dragHandleTo(int dragToX, int dragToY, int steps) throws Throwa ble {
304 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
305 HandleView handle = ihc.getHandleViewForTest();
306 int initialX = handle.getPositionX();
307 int initialY = handle.getPositionY();
308 View view = getContentViewCore().getContainerView();
309
310 int fromLocation[] = TestTouchUtils.getAbsoluteLocationFromRelative(view , initialX,
311 initialY + VERTICAL_OFFSET);
312 int toLocation[] = TestTouchUtils.getAbsoluteLocationFromRelative(view, dragToX,
313 dragToY + VERTICAL_OFFSET);
314
315 long downTime = TestTouchUtils.dragStart(getInstrumentation(), fromLocat ion[0],
316 fromLocation[1]);
317 assertWaitForHandleDraggingEquals(true);
318 TestTouchUtils.dragTo(getInstrumentation(), fromLocation[0], toLocation[ 0],
319 fromLocation[1], toLocation[1], steps, downTime);
320 TestTouchUtils.dragEnd(getInstrumentation(), toLocation[0], toLocation[1 ], downTime);
321 assertWaitForHandleDraggingEquals(false);
322 assertTrue(waitForHandleViewStopped());
323 }
324
325 private void dragHandleTo(int dragToX, int dragToY) throws Throwable {
326 dragHandleTo(dragToX, dragToY, 5);
327 }
328
329 private void assertWaitForHandleDraggingEquals(final boolean expected) throw s Throwable {
330 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
331 final HandleView handle = ihc.getHandleViewForTest();
332 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
333 @Override
334 public boolean isSatisfied() {
335 return handle.isDragging() == expected;
336 }
337 }));
338 }
339
340 private static boolean isHandleNear(HandleView handle, int x, int y) {
341 return (Math.abs(handle.getPositionX() - x) < HANDLE_POSITION_TOLERANCE) &&
342 (Math.abs(handle.getPositionY() - VERTICAL_OFFSET - y) < HANDLE_ POSITION_TOLERANCE);
343 }
344
345 private void assertWaitForHandleNear(final int x, final int y) throws Throwa ble {
346 InsertionHandleController ihc = getContentViewCore().getInsertionHandleC ontrollerForTest();
347 final HandleView handle = ihc.getHandleViewForTest();
348 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
349 @Override
350 public boolean isSatisfied() {
351 return isHandleNear(handle, x, y);
352 }
353 }));
354 }
355
356 private boolean waitForHandleShowingEquals(final boolean shouldBeShowing)
357 throws Throwable {
358 return CriteriaHelper.pollForCriteria(new Criteria() {
359 @Override
360 public boolean isSatisfied() {
361 InsertionHandleController ihc =
362 getContentViewCore().getInsertionHandleControllerForTest ();
363 boolean isShowing = ihc != null && ihc.isShowing();
364 return isShowing == shouldBeShowing;
365 }
366 });
367 }
368
369 private void pasteOnMainSync() {
370 getInstrumentation().runOnMainSync(new Runnable() {
371 @Override
372 public void run() {
373 getContentViewCore().getInsertionHandleControllerForTest().paste ();
374 }
375 });
376 }
377
378 private void unselectOnMainSync() {
379 getInstrumentation().runOnMainSync(new Runnable() {
380 @Override
381 public void run() {
382 getContentViewCore().getImeAdapterForTest().unselect();
383 }
384 });
385 }
386
387 private int getSelectionStart() {
388 return Selection.getSelectionStart(getEditable());
389 }
390
391 private int getSelectionEnd() {
392 return Selection.getSelectionEnd(getEditable());
393 }
394
395 private Editable getEditable() {
396 return getContentViewCore().getEditableForTest();
397 }
398
399 private String getEditableText() {
400 return getEditable().toString();
401 }
402
403 private void saveToClipboard(String text) {
404 ClipboardManager clipMgr =
405 (ClipboardManager) getActivity().getSystemService(Context.CLIPBO ARD_SERVICE);
406 clipMgr.setPrimaryClip(ClipData.newPlainText(null, text));
407 }
408 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698