ContentViewCoreSelectionTest.java revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 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
5package org.chromium.content.browser;
6
7import android.content.ClipData;
8import android.content.ClipboardManager;
9import android.content.Context;
10import android.test.suitebuilder.annotation.SmallTest;
11
12import org.chromium.base.ThreadUtils;
13import org.chromium.base.test.util.Feature;
14import org.chromium.base.test.util.UrlUtils;
15import org.chromium.content.browser.test.util.Criteria;
16import org.chromium.content.browser.test.util.CriteriaHelper;
17import org.chromium.content.browser.test.util.DOMUtils;
18import org.chromium.content_shell_apk.ContentShellTestBase;
19
20/**
21 * Integration tests for text selection-related behavior.
22 */
23public class ContentViewCoreSelectionTest extends ContentShellTestBase {
24    private static final String DATA_URL = UrlUtils.encodeHtmlDataUri(
25            "<html><head><meta name=\"viewport\"" +
26            "content=\"width=device-width, initial-scale=1.1, maximum-scale=1.5\" /></head>" +
27            "<body><form action=\"about:blank\">" +
28            "<input id=\"empty_input_text\" type=\"text\" />" +
29            "<br/><p><span id=\"plain_text_1\">This is Plain Text One</span></p>" +
30            "<br/><p><span id=\"plain_text_2\">This is Plain Text Two</span></p>" +
31            "<br/><input id=\"empty_input_text\" type=\"text\" />" +
32            "<br/><input id=\"input_text\" type=\"text\" value=\"Sample Text\" />" +
33            "<br/><textarea id=\"empty_textarea\" rows=\"2\" cols=\"20\"></textarea>" +
34            "<br/><textarea id=\"textarea\" rows=\"2\" cols=\"20\">Sample Text</textarea>" +
35            "</form></body></html>");
36
37    private ContentViewCore mContentViewCore;
38
39    @Override
40    public void setUp() throws Exception {
41        super.setUp();
42
43        launchContentShellWithUrl(DATA_URL);
44        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
45
46        mContentViewCore = getContentViewCore();
47        assertWaitForPageScaleFactorMatch(1.1f);
48        assertWaitForSelectActionBarVisible(false);
49        assertWaitForPastePopupStatus(false);
50    }
51
52    @SmallTest
53    @Feature({"TextSelection"})
54    public void testSelectionClearedAfterLossOfFocus() throws Throwable {
55        requestFocusOnUiThread(true);
56
57        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
58        assertWaitForSelectActionBarVisible(true);
59
60        requestFocusOnUiThread(false);
61        assertWaitForSelectActionBarVisible(false);
62        assertFalse(mContentViewCore.hasSelection());
63
64        requestFocusOnUiThread(true);
65        assertWaitForSelectActionBarVisible(false);
66        assertFalse(mContentViewCore.hasSelection());
67    }
68
69    @SmallTest
70    @Feature({"TextSelection"})
71    public void testSelectionPreservedAfterLossOfFocusIfRequested() throws Throwable {
72        requestFocusOnUiThread(true);
73
74        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
75        assertWaitForSelectActionBarVisible(true);
76        assertTrue(mContentViewCore.hasSelection());
77
78        mContentViewCore.preserveSelectionOnNextLossOfFocus();
79        requestFocusOnUiThread(false);
80        assertWaitForSelectActionBarVisible(false);
81        assertTrue(mContentViewCore.hasSelection());
82
83        requestFocusOnUiThread(true);
84        assertWaitForSelectActionBarVisible(true);
85        assertTrue(mContentViewCore.hasSelection());
86
87        // Losing focus yet again should properly clear the selection.
88        requestFocusOnUiThread(false);
89        assertWaitForSelectActionBarVisible(false);
90        assertFalse(mContentViewCore.hasSelection());
91    }
92
93    @SmallTest
94    @Feature({"TextSelection"})
95    public void testSelectionPreservedAfterReshown() throws Throwable {
96        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
97        assertWaitForSelectActionBarVisible(true);
98        assertTrue(mContentViewCore.hasSelection());
99
100        setVisibileOnUiThread(false);
101        assertWaitForSelectActionBarVisible(false);
102        assertTrue(mContentViewCore.hasSelection());
103
104        setVisibileOnUiThread(true);
105        assertWaitForSelectActionBarVisible(true);
106        assertTrue(mContentViewCore.hasSelection());
107    }
108
109    @SmallTest
110    @Feature({"TextSelection"})
111    public void testSelectionPreservedAfterReattached() throws Throwable {
112        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
113        assertWaitForSelectActionBarVisible(true);
114        assertTrue(mContentViewCore.hasSelection());
115
116        setAttachedOnUiThread(false);
117        assertWaitForSelectActionBarVisible(false);
118        assertTrue(mContentViewCore.hasSelection());
119
120        setAttachedOnUiThread(true);
121        assertWaitForSelectActionBarVisible(true);
122        assertTrue(mContentViewCore.hasSelection());
123    }
124
125    @SmallTest
126    @Feature({"TextInput"})
127    public void testPastePopupNotShownOnLongPressingNonEmptyInput() throws Throwable {
128        copyStringToClipboard();
129        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
130        assertWaitForPastePopupStatus(true);
131        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
132        assertWaitForSelectActionBarVisible(true);
133        assertWaitForPastePopupStatus(false);
134    }
135
136    @SmallTest
137    @Feature({"TextInput"})
138    public void testPastePopupClearedOnTappingEmptyInput() throws Throwable {
139        copyStringToClipboard();
140        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
141        assertWaitForPastePopupStatus(true);
142        DOMUtils.clickNode(this, mContentViewCore, "empty_input_text");
143        assertWaitForPastePopupStatus(false);
144    }
145
146    @SmallTest
147    @Feature({"TextInput"})
148    public void testPastePopupClearedOnTappingNonEmptyInput() throws Throwable {
149        copyStringToClipboard();
150        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
151        assertWaitForPastePopupStatus(true);
152        DOMUtils.clickNode(this, mContentViewCore, "input_text");
153        assertWaitForPastePopupStatus(false);
154    }
155
156    @SmallTest
157    @Feature({"TextInput"})
158    public void testPastePopupClearedOnTappingOutsideInput() throws Throwable {
159        copyStringToClipboard();
160        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
161        assertWaitForPastePopupStatus(true);
162        DOMUtils.clickNode(this, mContentViewCore, "plain_text_2");
163        assertWaitForPastePopupStatus(false);
164    }
165
166    @SmallTest
167    @Feature({"TextInput"})
168    public void testPastePopupClearedOnLongPressingOutsideInput() throws Throwable {
169        copyStringToClipboard();
170        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
171        assertWaitForPastePopupStatus(true);
172        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_2");
173        assertWaitForPastePopupStatus(false);
174    }
175
176    private void assertWaitForSelectActionBarVisible(
177            final boolean visible) throws InterruptedException {
178        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
179            @Override
180            public boolean isSatisfied() {
181                return visible == mContentViewCore.isSelectActionBarShowing();
182            }
183        }));
184    }
185
186    private void setVisibileOnUiThread(final boolean show) {
187        final ContentViewCore contentViewCore = mContentViewCore;
188        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
189            @Override
190            public void run() {
191                if (show) {
192                    contentViewCore.onShow();
193                } else {
194                    contentViewCore.onHide();
195                }
196            }
197        });
198    }
199
200    private void setAttachedOnUiThread(final boolean attached) {
201        final ContentViewCore contentViewCore = mContentViewCore;
202        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
203            @Override
204            public void run() {
205                if (attached) {
206                    contentViewCore.onAttachedToWindow();
207                } else {
208                    contentViewCore.onDetachedFromWindow();
209                }
210            }
211        });
212    }
213
214    private void requestFocusOnUiThread(final boolean gainFocus) {
215        final ContentViewCore contentViewCore = mContentViewCore;
216        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
217            @Override
218            public void run() {
219                contentViewCore.onFocusChanged(gainFocus);
220            }
221        });
222    }
223
224    private void copyStringToClipboard() {
225        ClipboardManager clipboardManager =
226                (ClipboardManager) getActivity().getSystemService(
227                        Context.CLIPBOARD_SERVICE);
228        ClipData clip = ClipData.newPlainText("test", "Text to copy");
229                clipboardManager.setPrimaryClip(clip);
230    }
231
232    private void assertWaitForPastePopupStatus(final boolean show) throws InterruptedException {
233        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
234            @Override
235            public boolean isSatisfied() {
236                return show == mContentViewCore.getPastePopupForTest().isShowing();
237            }
238        }));
239    }
240}
241