OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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.chrome.browser; |
| 6 |
| 7 import android.content.Intent; |
| 8 import android.net.Uri; |
| 9 import android.provider.Browser; |
| 10 import android.test.FlakyTest; |
| 11 import android.text.TextUtils; |
| 12 import android.view.KeyEvent; |
| 13 |
| 14 import junit.framework.Assert; |
| 15 |
| 16 import org.chromium.base.ThreadUtils; |
| 17 import org.chromium.base.test.util.DisabledTest; |
| 18 import org.chromium.base.test.util.Feature; |
| 19 import org.chromium.chrome.test.ChromeTabbedActivityTestBase; |
| 20 import org.chromium.chrome.test.util.ChromeTabUtils; |
| 21 import org.chromium.chrome.test.util.TestHttpServerClient; |
| 22 import org.chromium.content.browser.test.util.Criteria; |
| 23 import org.chromium.content.browser.test.util.CriteriaHelper; |
| 24 import org.chromium.content.browser.test.util.DOMUtils; |
| 25 import org.chromium.content.browser.test.util.JavaScriptUtils; |
| 26 import org.chromium.content.browser.test.util.KeyUtils; |
| 27 |
| 28 import java.util.concurrent.TimeoutException; |
| 29 |
| 30 /** |
| 31 * Test the behavior of tabs when opening a URL from an external app, more speci
fically how we reuse |
| 32 * tabs. |
| 33 */ |
| 34 public class TabsOpenedFromExternalAppTest extends ChromeTabbedActivityTestBase
{ |
| 35 |
| 36 private static final String EXTERNAL_APP_1_ID = "app1"; |
| 37 private static final String EXTERNAL_APP_2_ID = "app2"; |
| 38 |
| 39 static class ElementFocusedCriteria implements Criteria { |
| 40 private final Tab mTab; |
| 41 private final String mElementId; |
| 42 |
| 43 public ElementFocusedCriteria(Tab tab, String elementId) { |
| 44 mTab = tab; |
| 45 // Add quotes to match returned value from JS. |
| 46 mElementId = "\"" + elementId + "\""; |
| 47 } |
| 48 |
| 49 @Override |
| 50 public boolean isSatisfied() { |
| 51 String nodeId; |
| 52 try { |
| 53 StringBuilder sb = new StringBuilder(); |
| 54 sb.append("(function() {"); |
| 55 sb.append(" if (document.activeElement && document.activeElemen
t.id) {"); |
| 56 sb.append(" return document.activeElement.id;"); |
| 57 sb.append(" }"); |
| 58 sb.append(" return null;"); |
| 59 sb.append("})();"); |
| 60 |
| 61 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForRes
ult( |
| 62 mTab.getWebContents(), sb.toString()); |
| 63 if (jsonText.equalsIgnoreCase("null") || "".equals(jsonText)) { |
| 64 nodeId = null; |
| 65 } |
| 66 nodeId = jsonText; |
| 67 } catch (InterruptedException e) { |
| 68 e.printStackTrace(); |
| 69 Assert.fail("Failed to retrieve focused node: InterruptedExcepti
on was thrown"); |
| 70 return false; |
| 71 } catch (TimeoutException e) { |
| 72 e.printStackTrace(); |
| 73 Assert.fail("Failed to retrieve focused node: TimeoutException w
as thrown"); |
| 74 return false; |
| 75 } |
| 76 return TextUtils.equals(mElementId, nodeId); |
| 77 } |
| 78 } |
| 79 |
| 80 static class ElementTextIsCriteria implements Criteria { |
| 81 private final Tab mTab; |
| 82 private final String mElementId; |
| 83 private final String mExpectedText; |
| 84 |
| 85 public ElementTextIsCriteria(Tab tab, String elementId, String expectedT
ext) { |
| 86 mTab = tab; |
| 87 mElementId = elementId; |
| 88 mExpectedText = expectedText; |
| 89 } |
| 90 |
| 91 @Override |
| 92 public boolean isSatisfied() { |
| 93 try { |
| 94 String text = DOMUtils.getNodeValue(mTab.getWebContents(), mElem
entId); |
| 95 return TextUtils.equals(mExpectedText, text); |
| 96 } catch (InterruptedException e) { |
| 97 e.printStackTrace(); |
| 98 return false; |
| 99 } catch (TimeoutException e) { |
| 100 e.printStackTrace(); |
| 101 return false; |
| 102 } |
| 103 } |
| 104 } |
| 105 |
| 106 @Override |
| 107 public void startMainActivity() { |
| 108 // We'll start the activity explicitly in the tests, as we need to start
it with an intent |
| 109 // in a specific test. |
| 110 } |
| 111 |
| 112 /** |
| 113 * Launch the specified URL as if it was triggered by an external applicatio
n with id appId. |
| 114 * Returns when the URL has been navigated to. |
| 115 * @throws InterruptedException |
| 116 */ |
| 117 private void launchUrlFromExternalApp(String url, String appId, boolean crea
teNewTab) |
| 118 throws InterruptedException { |
| 119 final Intent intent = new Intent(Intent.ACTION_VIEW); |
| 120 if (appId != null) { |
| 121 intent.putExtra(Browser.EXTRA_APPLICATION_ID, appId); |
| 122 } |
| 123 if (createNewTab) { |
| 124 intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); |
| 125 } |
| 126 intent.setData(Uri.parse(url)); |
| 127 |
| 128 final Tab originalTab = getActivity().getActivityTab(); |
| 129 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 130 @Override |
| 131 public void run() { |
| 132 getActivity().onNewIntent(intent); |
| 133 } |
| 134 }); |
| 135 if (createNewTab) { |
| 136 assertTrue("Failed to select different tab", |
| 137 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
| 138 @Override |
| 139 public boolean isSatisfied() { |
| 140 return getActivity().getActivityTab() != originalTab
; |
| 141 } |
| 142 })); |
| 143 } |
| 144 ChromeTabUtils.waitForTabPageLoaded(getActivity().getActivityTab(), url)
; |
| 145 } |
| 146 |
| 147 /** |
| 148 * Tests that URLs opened from the same external app don't create new tabs. |
| 149 * @throws InterruptedException |
| 150 */ |
| 151 /** |
| 152 * @LargeTest |
| 153 * @Feature({"Navigation"}) |
| 154 * Bug 5856404 |
| 155 */ |
| 156 @FlakyTest |
| 157 public void testNoNewTabForSameApp() throws InterruptedException { |
| 158 startMainActivityFromLauncher(); |
| 159 |
| 160 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 161 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 162 |
| 163 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 164 |
| 165 // Launch a first URL from an app. |
| 166 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 167 // It should have opened in a new tab. |
| 168 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 169 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 170 assertEquals("Selected tab is not on the right URL.", url1, |
| 171 getActivity().getActivityTab().getUrl()); |
| 172 |
| 173 // Launch a new URL from the same app, it should open in the same tab. |
| 174 originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 175 launchUrlFromExternalApp(url2, EXTERNAL_APP_1_ID, false); |
| 176 newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 177 assertEquals("Incorrect number of tabs open", originalTabCount, newTabCo
unt); |
| 178 assertEquals("Selected tab is not on the right URL.", url2, |
| 179 getActivity().getActivityTab().getUrl()); |
| 180 |
| 181 // And pressing back should close Clank. |
| 182 assertTrue("Window does not have focus before pressing back.", |
| 183 getActivity().hasWindowFocus()); |
| 184 KeyUtils.singleKeyEventView(getInstrumentation(), getActivity().getActiv
ityTab().getView(), |
| 185 KeyEvent.KEYCODE_BACK); |
| 186 getInstrumentation().waitForIdleSync(); |
| 187 assertFalse("Window still has focus after pressing back.", getActivity()
.hasWindowFocus()); |
| 188 } |
| 189 |
| 190 /** |
| 191 * Tests that URLs opened from an unspecified external app (no Browser.EXTRA
_APPLICATION_ID in |
| 192 * the intent extras) don't create new tabs. |
| 193 * @throws InterruptedException |
| 194 * TODO(jcivelli): http:/b/5882419 we disabled this behavior so this test is
disabled until we |
| 195 * figure out what we want to do. |
| 196 */ |
| 197 /** |
| 198 * @LargeTest |
| 199 * @Feature({"Navigation"}) |
| 200 * Bug 5856404 |
| 201 */ |
| 202 @DisabledTest |
| 203 public void testNewTabForUnknownApp() throws InterruptedException { |
| 204 startMainActivityFromLauncher(); |
| 205 |
| 206 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 207 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 208 |
| 209 |
| 210 // Launch a first URL with an app. |
| 211 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 212 |
| 213 assertEquals("Selected tab is not on the right URL.", url1, |
| 214 getActivity().getActivityTab().getUrl()); |
| 215 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 216 |
| 217 // Launch the same URL without app ID. It should open a new tab. |
| 218 originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 219 launchUrlFromExternalApp(url1, null, false); |
| 220 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 221 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 222 assertEquals("Selected tab is not on the right URL.", url1, |
| 223 getActivity().getActivityTab().getUrl()); |
| 224 |
| 225 // Launch another URL without app ID. It should open a new tab. |
| 226 originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 227 launchUrlFromExternalApp(url2, null, false); |
| 228 newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 229 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 230 assertEquals("Selected tab is not on the right URL.", url2, |
| 231 getActivity().getActivityTab().getUrl()); |
| 232 |
| 233 // And pressing back should close Clank. |
| 234 assertTrue("Window does not have focus before pressing back.", |
| 235 getActivity().hasWindowFocus()); |
| 236 KeyUtils.singleKeyEventView(getInstrumentation(), getActivity().getActiv
ityTab().getView(), |
| 237 KeyEvent.KEYCODE_BACK); |
| 238 getInstrumentation().waitForIdleSync(); |
| 239 assertFalse("Window still has focus after pressing back.", getActivity()
.hasWindowFocus()); |
| 240 } |
| 241 |
| 242 /** |
| 243 * Tests that URLs opened with the Browser.EXTRA_CREATE_NEW_TAB extra in |
| 244 * the intent do create new tabs. |
| 245 * @throws InterruptedException |
| 246 */ |
| 247 /** |
| 248 * Bug: crbug.com/155004 |
| 249 * @LargeTest |
| 250 * @Feature({"Navigation"}) |
| 251 */ |
| 252 @DisabledTest |
| 253 public void testNewTabWithNewTabExtra() throws InterruptedException { |
| 254 startMainActivityFromLauncher(); |
| 255 |
| 256 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 257 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 258 |
| 259 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 260 |
| 261 // Launch a first URL from an app. |
| 262 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 263 // It should have opened in a new tab. |
| 264 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 265 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 266 assertEquals("Selected tab is not on the right URL.", url1, |
| 267 getActivity().getActivityTab().getUrl()); |
| 268 |
| 269 // Launch a new URL from the same app with the right extra to open in a
new tab. |
| 270 originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 271 launchUrlFromExternalApp(url2, EXTERNAL_APP_1_ID, true); |
| 272 newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 273 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 274 assertEquals("Selected tab is not on the right URL.", url2, |
| 275 getActivity().getActivityTab().getUrl()); |
| 276 |
| 277 // And pressing back should close Clank. |
| 278 assertTrue("Window does not have focus before pressing back.", |
| 279 getActivity().hasWindowFocus()); |
| 280 KeyUtils.singleKeyEventView(getInstrumentation(), getActivity().getActiv
ityTab().getView(), |
| 281 KeyEvent.KEYCODE_BACK); |
| 282 getInstrumentation().waitForIdleSync(); |
| 283 assertFalse("Window still has focus after pressing back.", getActivity()
.hasWindowFocus()); |
| 284 } |
| 285 |
| 286 /** |
| 287 * Similar to testNoNewTabForSameApp but actually starting the application (
not just opening a |
| 288 * tab) from the external app. |
| 289 * @throws InterruptedException |
| 290 */ |
| 291 /** |
| 292 * @LargeTest |
| 293 * @Feature({"Navigation", "Main"}) |
| 294 * Bug 5856404 |
| 295 */ |
| 296 @FlakyTest |
| 297 public void testNoNewTabForSameAppOnStart() throws InterruptedException { |
| 298 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 299 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 300 |
| 301 // Launch Clank from the external app. |
| 302 startMainActivityFromExternalApp(url1, EXTERNAL_APP_1_ID); |
| 303 assertEquals("Selected tab is not on the right URL.", url1, |
| 304 getActivity().getActivityTab().getUrl()); |
| 305 |
| 306 // Launch a new URL from the same app, it should open in the same tab. |
| 307 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 308 launchUrlFromExternalApp(url2, EXTERNAL_APP_1_ID, false); |
| 309 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 310 assertEquals("Incorrect number of tabs open", originalTabCount, newTabCo
unt); |
| 311 assertEquals("Selected tab is not on the right URL.", url2, |
| 312 getActivity().getActivityTab().getUrl()); |
| 313 |
| 314 // And pressing back should close Clank. |
| 315 assertTrue("Window does not have focus before pressing back.", |
| 316 getActivity().hasWindowFocus()); |
| 317 KeyUtils.singleKeyEventView(getInstrumentation(), getActivity().getActiv
ityTab().getView(), |
| 318 KeyEvent.KEYCODE_BACK); |
| 319 getInstrumentation().waitForIdleSync(); |
| 320 assertFalse("Window still has focus after pressing back.", getActivity()
.hasWindowFocus()); |
| 321 } |
| 322 |
| 323 /** |
| 324 * Test that URLs opened from different external apps do create new tabs. |
| 325 * @throws InterruptedException |
| 326 * |
| 327 * @LargeTest |
| 328 * crbug.com/157773 |
| 329 */ |
| 330 @FlakyTest |
| 331 @Feature({"Navigation", "Main"}) |
| 332 public void testNewTabForDifferentApps() throws InterruptedException { |
| 333 startMainActivityFromLauncher(); |
| 334 |
| 335 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 336 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 337 String url3 = TestHttpServerClient.getUrl("chrome/test/data/android/test
.html"); |
| 338 |
| 339 // Launch a first URL from an app1. |
| 340 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 341 |
| 342 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 343 |
| 344 // Launch a second URL from an app2, it should open in a new tab. |
| 345 launchUrlFromExternalApp(url2, EXTERNAL_APP_2_ID, false); |
| 346 |
| 347 // It should have opened in a new tab. |
| 348 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 349 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 350 assertEquals("Selected tab is not on the right URL.", url2, |
| 351 getActivity().getActivityTab().getUrl()); |
| 352 |
| 353 // Also try with no app id, it should also open in a new tab. |
| 354 originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 355 launchUrlFromExternalApp(url3, null, false); |
| 356 newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 357 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 358 assertEquals("Selected tab is not on the right URL.", url3, |
| 359 getActivity().getActivityTab().getUrl()); |
| 360 } |
| 361 |
| 362 /** |
| 363 * Tests that a tab is not reused when launched from the same app as an alre
ady opened tab and |
| 364 * when the user typed in the location bar. |
| 365 * @throws InterruptedException |
| 366 */ |
| 367 /** |
| 368 * @LargeTest |
| 369 * @Feature({"Navigation"}) |
| 370 * Bug 6467101 |
| 371 */ |
| 372 @FlakyTest |
| 373 public void testNewTabWhenLocationBarEdited() throws InterruptedException { |
| 374 startMainActivityFromLauncher(); |
| 375 |
| 376 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 377 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 378 |
| 379 // Launch a first URL from an app. |
| 380 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 381 |
| 382 // Now simulate the user typing something in the location bar. |
| 383 typeInOmnibox("hi", true); |
| 384 |
| 385 // Launch a second URL from the same app, it should open in a new tab. |
| 386 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 387 launchUrlFromExternalApp(url2, EXTERNAL_APP_1_ID, false); |
| 388 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 389 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 390 assertEquals("Selected tab is not on the right URL.", url2, |
| 391 getActivity().getActivityTab().getUrl()); |
| 392 } |
| 393 |
| 394 /** |
| 395 * Tests that a tab is not reused when launched from the same app as an alre
ady opened tab and |
| 396 * when the user has entered text in the page. |
| 397 * @throws InterruptedException |
| 398 */ |
| 399 /** |
| 400 * @LargeTest |
| 401 * @Feature({"Navigation"}) |
| 402 * Bug 6467101 |
| 403 */ |
| 404 @FlakyTest |
| 405 public void testNewTabWhenPageEdited() throws InterruptedException, TimeoutE
xception { |
| 406 startMainActivityFromLauncher(); |
| 407 |
| 408 String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/goog
le.html"); |
| 409 String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/abou
t.html"); |
| 410 |
| 411 // Launch a first URL from an app. |
| 412 launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); |
| 413 |
| 414 // Click the text-field and type something. |
| 415 Tab tab = getActivity().getActivityTab(); |
| 416 DOMUtils.clickNode(this, tab.getContentViewCore(), "textField"); |
| 417 |
| 418 // Some processing needs to happen before the test-field has the focus. |
| 419 assertTrue("Text-field in page not focused.", CriteriaHelper.pollForCrit
eria( |
| 420 new ElementFocusedCriteria( |
| 421 getActivity().getActivityTab(), "textField"), 2000, 200)
); |
| 422 |
| 423 // Now type something. |
| 424 getInstrumentation().sendStringSync("banana"); |
| 425 |
| 426 // We also have to wait for the text to happen in the page. |
| 427 assertTrue("Page does not have the text typed in.", CriteriaHelper.pollF
orCriteria( |
| 428 new ElementTextIsCriteria(getActivity().getActivityTab(), "textF
ield", |
| 429 "banana"), 2000, 200)); |
| 430 |
| 431 // Launch a second URL from the same app, it should open in a new tab. |
| 432 int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 433 launchUrlFromExternalApp(url2, EXTERNAL_APP_1_ID, false); |
| 434 int newTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); |
| 435 assertEquals("Incorrect number of tabs open", originalTabCount + 1, newT
abCount); |
| 436 assertEquals("Selected tab is not on the right URL.", url2, |
| 437 getActivity().getActivityTab().getUrl()); |
| 438 } |
| 439 } |
OLD | NEW |