1a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch// found in the LICENSE file.
4a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
5a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochpackage org.chromium.content.browser.input;
6a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
7a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.graphics.Point;
8a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.graphics.Rect;
9a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.os.SystemClock;
10a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.text.Editable;
11a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.text.Selection;
12a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.test.suitebuilder.annotation.MediumTest;
13a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.view.MotionEvent;
14a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.view.View;
15a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport android.view.inputmethod.EditorInfo;
16a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
17a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport java.util.concurrent.Callable;
18a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
19a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.base.test.util.Feature;
20a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.base.test.util.UrlUtils;
21a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.base.ThreadUtils;
22a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.ContentView;
23a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.RenderCoordinates;
24a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.CriteriaHelper;
25a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.Criteria;
26a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.DOMUtils;
27a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.TestCallbackHelperContainer;
28a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
29a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.TestTouchUtils;
30a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content.browser.test.util.TouchCommon;
31a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochimport org.chromium.content_shell_apk.ContentShellTestBase;
32a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
33a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdochpublic class SelectionHandleTest extends ContentShellTestBase {
34a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final String META_DISABLE_ZOOM =
35a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "<meta name=\"viewport\" content=\"" +
36a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "height=device-height," +
37a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "width=device-width," +
38a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "initial-scale=1.0," +
39a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "minimum-scale=1.0," +
40a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "maximum-scale=1.0," +
41a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        "\" />";
42a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
43a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    // For these we use a tiny font-size so that we can be more strict on the expected handle
44a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    // positions.
45a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final String TEXTAREA_ID = "textarea";
46a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final String TEXTAREA_DATA_URL = UrlUtils.encodeHtmlDataUri(
47a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "<html><head>" + META_DISABLE_ZOOM + "</head><body>" +
48a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "<textarea id=\"" + TEXTAREA_ID +
49a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "\" cols=\"40\" rows=\"20\" style=\"font-size:6px\">" +
50a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "L r m i s m d l r s t a e , c n e t t r a i i i i g e i , s d d e u m d t m o " +
51a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i c d d n u l b r e d l r m g a l q a U e i a m n m e i m q i n s r d " +
52a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "e e c t t o u l m o a o i n s u a i u p x a o m d c n e u t D i a t " +
53a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i u e o o i r p e e d r t n o u t t v l t s e i l m o o e u u i t u l " +
54a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "p r a u . x e t u s n o c e a c p d t t o p o d n , u t n u p q i " +
55a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "o f c a e e u t o l t n m d s l b r m." +
56a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "L r m i s m d l r s t a e , c n e t t r a i i i i g e i , s d d e u m d t m o " +
57a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i c d d n u l b r e d l r m g a l q a U e i a m n m e i m q i n s r d " +
58a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "e e c t t o u l m o a o i n s u a i u p x a o m d c n e u t D i a t " +
59a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i u e o o i r p e e d r t n o u t t v l t s e i l m o o e u u i t u l " +
60a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "p r a u . x e t u s n o c e a c p d t t o p o d n , u t n u p q i " +
61a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "o f c a e e u t o l t n m d s l b r m." +
62a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "</textarea>" +
63a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "</body></html>");
64a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
65a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final String NONEDITABLE_DIV_ID = "noneditable";
66a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final String NONEDITABLE_DATA_URL = UrlUtils.encodeHtmlDataUri(
67a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "<html><head>" + META_DISABLE_ZOOM + "</head><body>" +
68a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "<div id=\"" + NONEDITABLE_DIV_ID + "\" style=\"width:200; font-size:6px\">" +
69a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "L r m i s m d l r s t a e , c n e t t r a i i i i g e i , s d d e u m d t m o " +
70a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i c d d n u l b r e d l r m g a l q a U e i a m n m e i m q i n s r d " +
71a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "e e c t t o u l m o a o i n s u a i u p x a o m d c n e u t D i a t " +
72a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i u e o o i r p e e d r t n o u t t v l t s e i l m o o e u u i t u l " +
73a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "p r a u . x e t u s n o c e a c p d t t o p o d n , u t n u p q i " +
74a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "o f c a e e u t o l t n m d s l b r m." +
75a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "L r m i s m d l r s t a e , c n e t t r a i i i i g e i , s d d e u m d t m o " +
76a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i c d d n u l b r e d l r m g a l q a U e i a m n m e i m q i n s r d " +
77a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "e e c t t o u l m o a o i n s u a i u p x a o m d c n e u t D i a t " +
78a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "i u e o o i r p e e d r t n o u t t v l t s e i l m o o e u u i t u l " +
79a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "p r a u . x e t u s n o c e a c p d t t o p o d n , u t n u p q i " +
80a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "o f c a e e u t o l t n m d s l b r m." +
81a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "</div>" +
82a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            "</body></html>");
83a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
84a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    // TODO(cjhopman): These tolerances should be based on the actual width/height of a
85a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    // character/line.
86a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final int HANDLE_POSITION_X_TOLERANCE_PIX = 20;
87a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static final int HANDLE_POSITION_Y_TOLERANCE_PIX = 30;
88a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
89a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private enum TestPageType {
90a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        EDITABLE(TEXTAREA_ID, TEXTAREA_DATA_URL, true),
91a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        NONEDITABLE(NONEDITABLE_DIV_ID, NONEDITABLE_DATA_URL, false);
92a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
93a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final String nodeId;
94a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final String dataUrl;
95a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final boolean selectionShouldBeEditable;
96a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
97a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        TestPageType(String nodeId, String dataUrl, boolean selectionShouldBeEditable) {
98a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            this.nodeId = nodeId;
99a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            this.dataUrl = dataUrl;
100a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            this.selectionShouldBeEditable = selectionShouldBeEditable;
101a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }
102a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
103a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
104a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void launchWithUrl(String url) throws Throwable {
105a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        launchContentShellWithUrl(url);
106a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
107a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForPageScaleFactorMatch(1.0f);
108a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
109a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // The TestInputMethodManagerWrapper intercepts showSoftInput so that a keyboard is never
110a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // brought up.
111a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        getImeAdapter().setInputMethodManagerWrapper(
112a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                new TestInputMethodManagerWrapper(getContentViewCore()));
113a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
114a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
115a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForHasSelectionPosition()
116a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            throws Throwable {
117a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
118a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
119a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
120a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int start = getSelectionStart();
121a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int end = getSelectionEnd();
122a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return start > 0 && start == end;
123a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
124a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
125a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
126a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
127a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    /**
128a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * Verifies that when a long-press is performed on static page text,
129a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * selection handles appear and that handles can be dragged to extend the
130a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * selection. Does not check exact handle position as this will depend on
131a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * screen size; instead, position is expected to be correct within
132a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * HANDLE_POSITION_TOLERANCE_PIX.
133a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     */
134a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @MediumTest
135a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @Feature({ "TextSelection", "Main" })
136a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    public void testNoneditableSelectionHandles() throws Throwable {
137a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        doSelectionHandleTest(TestPageType.NONEDITABLE);
138a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
139a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
140a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    /**
141a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * Verifies that when a long-press is performed on editable text (within a
142a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * textarea), selection handles appear and that handles can be dragged to
143a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * extend the selection. Does not check exact handle position as this will
144a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * depend on screen size; instead, position is expected to be correct within
145a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * HANDLE_POSITION_TOLERANCE_PIX.
146a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     */
147a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @MediumTest
148a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @Feature({ "TextSelection" })
149a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    public void testEditableSelectionHandles() throws Throwable {
150a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        doSelectionHandleTest(TestPageType.EDITABLE);
151a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
152a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
153a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void doSelectionHandleTest(TestPageType pageType) throws Throwable {
154a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        launchWithUrl(pageType.dataUrl);
155a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
156a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        clickNodeToShowSelectionHandles(pageType.nodeId);
157a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForSelectionEditableEquals(pageType.selectionShouldBeEditable);
158a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
159a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        HandleView startHandle = getStartHandle();
160a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        HandleView endHandle = getEndHandle();
161a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
162a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        Rect nodeWindowBounds = getNodeBoundsPix(pageType.nodeId);
163a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
164a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int leftX = (nodeWindowBounds.left + nodeWindowBounds.centerX()) / 2;
165a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int centerX = nodeWindowBounds.centerX();
166a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int rightX = (nodeWindowBounds.right + nodeWindowBounds.centerX()) / 2;
167a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
168a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int topY = (nodeWindowBounds.top + nodeWindowBounds.centerY()) / 2;
169a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int centerY = nodeWindowBounds.centerY();
170a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int bottomY = (nodeWindowBounds.bottom + nodeWindowBounds.centerY()) / 2;
171a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
172a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // Drag start handle up and to the left. The selection start should decrease.
173a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleAndCheckSelectionChange(startHandle, leftX, topY, -1, 0);
174a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // Drag end handle down and to the right. The selection end should increase.
175a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleAndCheckSelectionChange(endHandle, rightX, bottomY, 0, 1);
176a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // Drag start handle back to the middle. The selection start should increase.
177a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleAndCheckSelectionChange(startHandle, centerX, centerY, 1, 0);
178a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // Drag end handle up and to the left past the start handle. Both selection start and end
179a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // should decrease.
180a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleAndCheckSelectionChange(endHandle, leftX, topY, -1, -1);
181a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // Drag start handle down and to the right past the end handle. Both selection start and end
182a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // should increase.
183a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleAndCheckSelectionChange(startHandle, rightX, bottomY, 1, 1);
184a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
185a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        clickToDismissHandles();
186a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
187a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
188a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void dragHandleAndCheckSelectionChange(HandleView handle, int dragToX, int dragToY,
189a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            final int expectedStartChange, final int expectedEndChange) throws Throwable {
190a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        String initialText = getContentViewCore().getSelectedText();
191a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final int initialSelectionEnd = getSelectionEnd();
192a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final int initialSelectionStart = getSelectionStart();
193a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
194a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleTo(handle, dragToX, dragToY, 10);
195a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForEitherHandleNear(dragToX, dragToY);
196a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
197a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        if (getContentViewCore().isSelectionEditable()) {
198a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
199a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                @Override
200a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                public boolean isSatisfied() {
201a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    int startChange = getSelectionStart() - initialSelectionStart;
202a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    // TODO(cjhopman): Due to http://crbug.com/244633 we can't really assert that
203a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    // there is no change when we expect to be able to.
204a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    if (expectedStartChange != 0) {
205a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        if ((int) Math.signum(startChange) != expectedStartChange) return false;
206a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    }
207a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
208a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    int endChange = getSelectionEnd() - initialSelectionEnd;
209a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    if (expectedEndChange != 0) {
210a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        if ((int) Math.signum(endChange) != expectedEndChange) return false;
211a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    }
212a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
213a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    return true;
214a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                }
215a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }));
216a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }
217a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
218a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForHandleViewStopped(getStartHandle());
219a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForHandleViewStopped(getEndHandle());
220a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
221a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
222a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForSelectionEditableEquals(final boolean expected) throws Throwable {
223a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
224a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
225a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
226a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return getContentViewCore().isSelectionEditable() == expected;
227a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
228a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
229a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
230a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
231a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForHandleViewStopped(final HandleView handle) throws Throwable {
232a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
233a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            private Point position = new Point(-1, -1);
234a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
235a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
236a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                Point lastPosition = position;
237a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                position = getHandlePosition(handle);
238a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return !handle.isDragging() &&
239a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        position.equals(lastPosition);
240a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
241a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
242a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
243a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
244a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    /**
245a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * Verifies that when a selection is made within static page text, that the
246a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * contextual action bar of the correct type is displayed. Also verified
247a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * that the bar disappears upon deselection.
248a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     */
249a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @MediumTest
250a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @Feature({ "TextSelection" })
251a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    public void testNoneditableSelectionActionBar() throws Throwable {
252a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        doSelectionActionBarTest(TestPageType.NONEDITABLE);
253a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
254a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
255a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    /**
256a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * Verifies that when a selection is made within editable text, that the
257a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * contextual action bar of the correct type is displayed. Also verified
258a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     * that the bar disappears upon deselection.
259a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch     */
260a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @MediumTest
261a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    @Feature({ "TextSelection" })
262a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    public void testEditableSelectionActionBar() throws Throwable {
263a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        doSelectionActionBarTest(TestPageType.EDITABLE);
264a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
265a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
266a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void doSelectionActionBarTest(TestPageType pageType) throws Throwable {
267a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        launchWithUrl(pageType.dataUrl);
268a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertFalse(getContentViewCore().isSelectActionBarShowing());
269a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        clickNodeToShowSelectionHandles(pageType.nodeId);
270a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForSelectActionBarShowingEquals(true);
271a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        clickToDismissHandles();
272a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForSelectActionBarShowingEquals(false);
273a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
274a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
275a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static Point getHandlePosition(final HandleView handle) {
276a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Point>() {
277a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
278a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public Point call() {
279a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return new Point(handle.getAdjustedPositionX(), handle.getAdjustedPositionY());
280a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
281a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        });
282a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
283a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
284a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private static boolean isHandleNear(HandleView handle, int x, int y) {
285a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        Point position = getHandlePosition(handle);
286a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return (Math.abs(position.x - x) < HANDLE_POSITION_X_TOLERANCE_PIX) &&
287a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                (Math.abs(position.y - y) < HANDLE_POSITION_Y_TOLERANCE_PIX);
288a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
289a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
290a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForHandleNear(final HandleView handle, final int x, final int y)
291a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            throws Throwable {
292a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
293a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
294a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
295a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return isHandleNear(handle, x, y);
296a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
297a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
298a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
299a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
300a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForEitherHandleNear(final int x, final int y) throws Throwable {
301a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final HandleView startHandle = getStartHandle();
302a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        final HandleView endHandle = getEndHandle();
303a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
304a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
305a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
306a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return isHandleNear(startHandle, x, y) || isHandleNear(endHandle, x, y);
307a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
308a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
309a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
310a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
311a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForHandlesShowingEquals(final boolean shouldBeShowing) throws Throwable {
312a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
313a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
314a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
315a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                SelectionHandleController shc =
316a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        getContentViewCore().getSelectionHandleControllerForTest();
317a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                boolean isShowing = shc != null && shc.isShowing();
318a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return shouldBeShowing == isShowing;
319a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
320a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
321a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
322a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
323a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
324a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void dragHandleTo(final HandleView handle, final int dragToX, final int dragToY,
325a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            final int steps) throws Throwable {
326a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        ContentView view = getContentView();
327a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() {
328a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
329a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public Boolean call() {
330a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int adjustedX = handle.getAdjustedPositionX();
331a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int adjustedY = handle.getAdjustedPositionY();
332a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int realX = handle.getPositionX();
333a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int realY = handle.getPositionY();
334a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
335a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int realDragToX = dragToX + (realX - adjustedX);
336a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int realDragToY = dragToY + (realY - adjustedY);
337a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
338a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                ContentView view = getContentView();
339a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int[] fromLocation = TestTouchUtils.getAbsoluteLocationFromRelative(
340a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        view, realX, realY);
341a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                int[] toLocation = TestTouchUtils.getAbsoluteLocationFromRelative(
342a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        view, realDragToX, realDragToY);
343a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
344a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                long downTime = SystemClock.uptimeMillis();
345a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
346a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        fromLocation[0], fromLocation[1], 0);
347a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                handle.dispatchTouchEvent(event);
348a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
349a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                if (!handle.isDragging()) return false;
350a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
351a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                for (int i = 0; i < steps; i++) {
352a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    float scale = (float) (i + 1) / steps;
353a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    int x = fromLocation[0] + (int) (scale * (toLocation[0] - fromLocation[0]));
354a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    int y = fromLocation[1] + (int) (scale * (toLocation[1] - fromLocation[1]));
355a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    long eventTime = SystemClock.uptimeMillis();
356a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
357a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                            x, y, 0);
358a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                    handle.dispatchTouchEvent(event);
359a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                }
360a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                long upTime = SystemClock.uptimeMillis();
361a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                event = MotionEvent.obtain(downTime, upTime, MotionEvent.ACTION_UP,
362a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                        toLocation[0], toLocation[1], 0);
363a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                handle.dispatchTouchEvent(event);
364a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
365a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return !handle.isDragging();
366a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
367a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
368a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
369a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
370a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private Rect getNodeBoundsPix(String nodeId) throws Throwable {
371a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        Rect nodeBounds = DOMUtils.getNodeBounds(getContentView(),
372a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                new TestCallbackHelperContainer(getContentView()), nodeId);
373a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
374a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        RenderCoordinates renderCoordinates = getContentView().getRenderCoordinates();
375a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int offsetX = getContentView().getContentViewCore().getViewportSizeOffsetWidthPix();
376a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int offsetY = getContentView().getContentViewCore().getViewportSizeOffsetHeightPix();
377a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
378a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int left = (int) renderCoordinates.fromLocalCssToPix(nodeBounds.left) + offsetX;
379a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int right = (int) renderCoordinates.fromLocalCssToPix(nodeBounds.right) + offsetX;
380a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int top = (int) renderCoordinates.fromLocalCssToPix(nodeBounds.top) + offsetY;
381a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int bottom = (int) renderCoordinates.fromLocalCssToPix(nodeBounds.bottom) + offsetY;
382a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
383a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return new Rect(left, top, right, bottom);
384a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
385a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
386a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void clickNodeToShowSelectionHandles(String nodeId) throws Throwable {
387a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        Rect nodeWindowBounds = getNodeBoundsPix(nodeId);
388a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
389a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        TouchCommon touchCommon = new TouchCommon(this);
390a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int centerX = nodeWindowBounds.centerX();
391a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        int centerY = nodeWindowBounds.centerY();
392a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        touchCommon.longPressView(getContentView(), centerX, centerY);
393a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
394a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForHandlesShowingEquals(true);
395a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
396a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // No words wrap in the sample text so handles should be at the same y
397a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // position.
398a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertEquals(getStartHandle().getPositionY(), getEndHandle().getPositionY());
399a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
400a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // In ContentShell, the handles are initially misplaced when they first appear. This is
401a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // fixed after the first time they are dragged (or the page is scrolled).
402a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        // TODO(cjhopman): Fix this problem in ContentShell: http://crbug.com/243836
403a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        dragHandleTo(getStartHandle(), centerX - 40, centerY - 40, 1);
404a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForHandleViewStopped(getStartHandle());
405a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
406a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
407a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void clickToDismissHandles() throws Throwable {
408a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        TestTouchUtils.sleepForDoubleTapTimeout(getInstrumentation());
409a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        new TouchCommon(this).singleClickView(getContentView(), 0, 0);
410a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertWaitForHandlesShowingEquals(false);
411a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
412a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
413a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private void assertWaitForSelectActionBarShowingEquals(final boolean shouldBeShowing)
414a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            throws InterruptedException {
415a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
416a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            @Override
417a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            public boolean isSatisfied() {
418a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch                return shouldBeShowing == getContentViewCore().isSelectActionBarShowing();
419a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch            }
420a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        }));
421a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
422a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
423a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private ImeAdapter getImeAdapter() {
424a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return getContentViewCore().getImeAdapterForTest();
425a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
426a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
427a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private int getSelectionStart() {
428a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return Selection.getSelectionStart(getEditable());
429a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
430a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
431a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private int getSelectionEnd() {
432a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return Selection.getSelectionEnd(getEditable());
433a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
434a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
435a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private Editable getEditable() {
436a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return getContentViewCore().getEditableForTest();
437a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
438a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
439a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private HandleView getStartHandle() {
440a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        SelectionHandleController shc = getContentViewCore().getSelectionHandleControllerForTest();
441a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return shc.getStartHandleViewForTest();
442a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
443a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch
444a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    private HandleView getEndHandle() {
445a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        SelectionHandleController shc = getContentViewCore().getSelectionHandleControllerForTest();
446a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch        return shc.getEndHandleViewForTest();
447a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch    }
448a031efa9dbd9b321781674193e8ac7636d47eb1dBen Murdoch}
449