| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.webapps; | 5 package org.chromium.chrome.browser.webapps; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.SharedPreferences; | 10 import android.content.SharedPreferences; |
| 11 import android.support.test.InstrumentationRegistry; | 11 import android.support.test.InstrumentationRegistry; |
| 12 import android.support.test.filters.MediumTest; | 12 import android.support.test.filters.MediumTest; |
| 13 import android.view.View; | 13 import android.view.View; |
| 14 | 14 |
| 15 import org.junit.After; | 15 import org.junit.After; |
| 16 import org.junit.Assert; | 16 import org.junit.Assert; |
| 17 import org.junit.Before; | 17 import org.junit.Before; |
| 18 import org.junit.Rule; | 18 import org.junit.Rule; |
| 19 import org.junit.Test; | 19 import org.junit.Test; |
| 20 import org.junit.runner.RunWith; | 20 import org.junit.runner.RunWith; |
| 21 | 21 |
| 22 import org.chromium.base.ApplicationStatus; | 22 import org.chromium.base.ApplicationStatus; |
| 23 import org.chromium.base.ContextUtils; | 23 import org.chromium.base.ContextUtils; |
| 24 import org.chromium.base.ThreadUtils; | |
| 25 import org.chromium.base.test.util.CommandLineFlags; | 24 import org.chromium.base.test.util.CommandLineFlags; |
| 26 import org.chromium.base.test.util.Feature; | 25 import org.chromium.base.test.util.Feature; |
| 27 import org.chromium.base.test.util.RetryOnFailure; | 26 import org.chromium.base.test.util.RetryOnFailure; |
| 28 import org.chromium.base.test.util.UrlUtils; | 27 import org.chromium.base.test.util.UrlUtils; |
| 29 import org.chromium.blink_public.platform.WebDisplayMode; | 28 import org.chromium.blink_public.platform.WebDisplayMode; |
| 30 import org.chromium.chrome.browser.ChromeActivity; | 29 import org.chromium.chrome.browser.ChromeActivity; |
| 31 import org.chromium.chrome.browser.ChromeSwitches; | 30 import org.chromium.chrome.browser.ChromeSwitches; |
| 32 import org.chromium.chrome.browser.ChromeTabbedActivity; | 31 import org.chromium.chrome.browser.ChromeTabbedActivity; |
| 33 import org.chromium.chrome.browser.ShortcutHelper; | 32 import org.chromium.chrome.browser.ShortcutHelper; |
| 34 import org.chromium.chrome.browser.ShortcutSource; | 33 import org.chromium.chrome.browser.ShortcutSource; |
| 35 import org.chromium.chrome.browser.tab.Tab; | 34 import org.chromium.chrome.browser.tab.Tab; |
| 36 import org.chromium.chrome.browser.tab.TabIdManager; | 35 import org.chromium.chrome.browser.tab.TabIdManager; |
| 37 import org.chromium.chrome.test.ChromeJUnit4ClassRunner; | 36 import org.chromium.chrome.test.ChromeJUnit4ClassRunner; |
| 38 import org.chromium.chrome.test.MultiActivityTestRule; | 37 import org.chromium.chrome.test.MultiActivityTestRule; |
| 39 import org.chromium.chrome.test.util.ActivityUtils; | |
| 40 import org.chromium.chrome.test.util.ApplicationTestUtils; | 38 import org.chromium.chrome.test.util.ApplicationTestUtils; |
| 41 import org.chromium.chrome.test.util.browser.TabLoadObserver; | |
| 42 import org.chromium.content.browser.test.util.Criteria; | 39 import org.chromium.content.browser.test.util.Criteria; |
| 43 import org.chromium.content.browser.test.util.CriteriaHelper; | 40 import org.chromium.content.browser.test.util.CriteriaHelper; |
| 44 import org.chromium.content.browser.test.util.JavaScriptUtils; | |
| 45 import org.chromium.content.browser.test.util.TouchCommon; | |
| 46 import org.chromium.content_public.common.ScreenOrientationValues; | 41 import org.chromium.content_public.common.ScreenOrientationValues; |
| 47 import org.chromium.net.test.EmbeddedTestServer; | 42 import org.chromium.net.test.EmbeddedTestServer; |
| 48 | 43 |
| 49 /** | 44 /** |
| 50 * Tests that WebappActivities are launched correctly. | 45 * Tests that WebappActivities are launched correctly. |
| 51 * | 46 * |
| 52 * This test seems a little wonky because WebappActivities launched differently,
depending on what | 47 * This test seems a little wonky because WebappActivities launched differently,
depending on what |
| 53 * OS the user is on. Pre-L, WebappActivities were manually instanced and assig
ned by the | 48 * OS the user is on. Pre-L, WebappActivities were manually instanced and assig
ned by the |
| 54 * WebappManager. On L and above, WebappActivities are automatically instanced
by Android and the | 49 * WebappManager. On L and above, WebappActivities are automatically instanced
by Android and the |
| 55 * FLAG_ACTIVITY_NEW_DOCUMENT mechanism. Moreover, we don't have access to the
task list pre-L so | 50 * FLAG_ACTIVITY_NEW_DOCUMENT mechanism. Moreover, we don't have access to the
task list pre-L so |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 fireWebappIntent(WEBAPP_2_ID, WEBAPP_2_URL, WEBAPP_2_TITLE, WEBAPP_ICON,
true); | 261 fireWebappIntent(WEBAPP_2_ID, WEBAPP_2_URL, WEBAPP_2_TITLE, WEBAPP_ICON,
true); |
| 267 CriteriaHelper.pollUiThread(new Criteria() { | 262 CriteriaHelper.pollUiThread(new Criteria() { |
| 268 @Override | 263 @Override |
| 269 public boolean isSatisfied() { | 264 public boolean isSatisfied() { |
| 270 return isWebappActivityReady(ApplicationStatus.getLastTrackedFoc
usedActivity()); | 265 return isWebappActivityReady(ApplicationStatus.getLastTrackedFoc
usedActivity()); |
| 271 } | 266 } |
| 272 }); | 267 }); |
| 273 } | 268 } |
| 274 | 269 |
| 275 /** | 270 /** |
| 276 * Tests that WebappActivities handle window.open() properly in tabbed mode. | |
| 277 */ | |
| 278 @Test | |
| 279 @MediumTest | |
| 280 @Feature({"Webapps"}) | |
| 281 public void testWebappHandlesWindowOpenInTabbedMode() throws Exception { | |
| 282 triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, getOnClickLi
nkUrl(), true); | |
| 283 } | |
| 284 | |
| 285 /** | |
| 286 * Tests that WebappActivities handle suppressed window.open() properly in t
abbed mode. | |
| 287 */ | |
| 288 @Test | |
| 289 @MediumTest | |
| 290 @Feature({"Webapps"}) | |
| 291 public void testWebappHandlesSuppressedWindowOpenInTabbedMode() throws Excep
tion { | |
| 292 triggerWindowOpenAndWaitForLoad( | |
| 293 ChromeTabbedActivity.class, getHrefNoReferrerLinkUrl(), false); | |
| 294 } | |
| 295 | |
| 296 private <T extends ChromeActivity> void triggerWindowOpenAndWaitForLoad( | |
| 297 Class<T> classToWaitFor, String linkHtml, boolean checkContents) thr
ows Exception { | |
| 298 final WebappActivity firstActivity = | |
| 299 startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, W
EBAPP_ICON); | |
| 300 final int firstWebappId = firstActivity.getActivityTab().getId(); | |
| 301 | |
| 302 // Load up the test page. | |
| 303 new TabLoadObserver(firstActivity.getActivityTab()).fullyLoadUrl(linkHtm
l); | |
| 304 | |
| 305 // Do a plain click to make the link open in the main browser via a wind
ow.open(). | |
| 306 // If the window is opened successfully, javascript on the first page tr
iggers and changes | |
| 307 // its URL as a signal for this test. | |
| 308 Runnable fgTrigger = new Runnable() { | |
| 309 @Override | |
| 310 public void run() { | |
| 311 ThreadUtils.runOnUiThreadBlocking(new Runnable() { | |
| 312 @Override | |
| 313 public void run() { | |
| 314 View view = firstActivity.findViewById(android.R.id.cont
ent).getRootView(); | |
| 315 TouchCommon.singleClickView(view); | |
| 316 } | |
| 317 }); | |
| 318 } | |
| 319 }; | |
| 320 ChromeActivity secondActivity = ActivityUtils.waitForActivity( | |
| 321 InstrumentationRegistry.getInstrumentation(), classToWaitFor, fg
Trigger); | |
| 322 mTestRule.waitForFullLoad(secondActivity, "The Google"); | |
| 323 if (checkContents) { | |
| 324 Assert.assertEquals("New WebContents was not created", "SUCCESS", | |
| 325 firstActivity.getActivityTab().getTitle()); | |
| 326 } | |
| 327 Assert.assertNotSame("Wrong Activity in foreground", firstActivity, | |
| 328 ApplicationStatus.getLastTrackedFocusedActivity()); | |
| 329 | |
| 330 // Close the child window to kick the user back to the WebappActivity. | |
| 331 JavaScriptUtils.executeJavaScript( | |
| 332 secondActivity.getActivityTab().getWebContents(), "window.close(
)"); | |
| 333 CriteriaHelper.pollUiThread(new Criteria() { | |
| 334 @Override | |
| 335 public boolean isSatisfied() { | |
| 336 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedA
ctivity(); | |
| 337 if (!isWebappActivityReady(lastActivity)) return false; | |
| 338 | |
| 339 WebappActivity webappActivity = (WebappActivity) lastActivity; | |
| 340 return webappActivity.getActivityTab().getId() == firstWebappId; | |
| 341 } | |
| 342 }); | |
| 343 ApplicationTestUtils.waitUntilChromeInForeground(); | |
| 344 } | |
| 345 | |
| 346 /** | |
| 347 * Starts a WebappActivity for the given data and waits for it to be initial
ized. We can't use | 271 * Starts a WebappActivity for the given data and waits for it to be initial
ized. We can't use |
| 348 * ActivityUtils.waitForActivity() because of the way WebappActivity is inst
anced on pre-L | 272 * ActivityUtils.waitForActivity() because of the way WebappActivity is inst
anced on pre-L |
| 349 * devices. | 273 * devices. |
| 350 */ | 274 */ |
| 351 private WebappActivity startWebappActivity(String id, String url, String tit
le, String icon) { | 275 private WebappActivity startWebappActivity(String id, String url, String tit
le, String icon) { |
| 352 fireWebappIntent(id, url, title, icon, true); | 276 fireWebappIntent(id, url, title, icon, true); |
| 353 CriteriaHelper.pollUiThread(new Criteria() { | 277 CriteriaHelper.pollUiThread(new Criteria() { |
| 354 @Override | 278 @Override |
| 355 public boolean isSatisfied() { | 279 public boolean isSatisfied() { |
| 356 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedA
ctivity(); | 280 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedA
ctivity(); |
| 357 return isWebappActivityReady(lastActivity); | 281 return isWebappActivityReady(lastActivity); |
| 358 } | 282 } |
| 359 }); | 283 }); |
| 360 return (WebappActivity) ApplicationStatus.getLastTrackedFocusedActivity(
); | 284 return (WebappActivity) ApplicationStatus.getLastTrackedFocusedActivity(
); |
| 361 } | 285 } |
| 362 | 286 |
| 363 /** Returns true when the last Activity is a WebappActivity and is ready for
testing .*/ | 287 /** Returns true when the last Activity is a WebappActivity and is ready for
testing .*/ |
| 364 private boolean isWebappActivityReady(Activity lastActivity) { | 288 private boolean isWebappActivityReady(Activity lastActivity) { |
| 365 if (!(lastActivity instanceof WebappActivity)) return false; | 289 if (!(lastActivity instanceof WebappActivity)) return false; |
| 366 | 290 |
| 367 WebappActivity webappActivity = (WebappActivity) lastActivity; | 291 WebappActivity webappActivity = (WebappActivity) lastActivity; |
| 368 if (webappActivity.getActivityTab() == null) return false; | 292 if (webappActivity.getActivityTab() == null) return false; |
| 369 | 293 |
| 370 View rootView = webappActivity.findViewById(android.R.id.content); | 294 View rootView = webappActivity.findViewById(android.R.id.content); |
| 371 if (!rootView.hasWindowFocus()) return false; | 295 if (!rootView.hasWindowFocus()) return false; |
| 372 | 296 |
| 373 return true; | 297 return true; |
| 374 } | 298 } |
| 375 | |
| 376 /** Defines one gigantic link spanning the whole page that creates a new | |
| 377 * window with chrome/test/data/android/google.html. Disallowing a referrer
from being | |
| 378 * sent triggers another codepath. | |
| 379 */ | |
| 380 private String getHrefNoReferrerLinkUrl() { | |
| 381 return UrlUtils.encodeHtmlDataUri("<html>" | |
| 382 + " <head>" | |
| 383 + " <title>href no referrer link page</title>" | |
| 384 + " <meta name='viewport'" | |
| 385 + " content='width=device-width initial-scale=0.5, maximu
m-scale=0.5'>" | |
| 386 + " <style>" | |
| 387 + " body {margin: 0em;} div {width: 100%; height: 100%; bac
kground: #011684;}" | |
| 388 + " </style>" | |
| 389 + " </head>" | |
| 390 + " <body>" | |
| 391 + " <a href='" + mTestServer.getURL("/chrome/test/data/androi
d/google.html") | |
| 392 + "' target='_blank' rel='noreferrer'><div></div></a>" | |
| 393 + " </body>"); | |
| 394 } | |
| 395 | |
| 396 /** Returns a URL where clicking the body triggers a window.open() call to o
pen | |
| 397 * chrome/test/data/android/google.html. */ | |
| 398 private String getOnClickLinkUrl() { | |
| 399 return UrlUtils.encodeHtmlDataUri("<html>" | |
| 400 + " <head>" | |
| 401 + " <title>window.open page</title>" | |
| 402 + " <meta name='viewport'" | |
| 403 + " content='width=device-width initial-scale=0.5, maximu
m-scale=0.5'>" | |
| 404 + " <style>" | |
| 405 + " body {margin: 0em;} div {width: 100%; height: 100%; bac
kground: #011684;}" | |
| 406 + " </style>" | |
| 407 + " <script>" | |
| 408 + " function openNewWindow() {" | |
| 409 + " var site = window.open('" | |
| 410 + mTestServer.getURL("/chrome/test/data/android/google.html") +
"');" | |
| 411 + " document.title = site ? 'SUCCESS' : 'FAILURE';" | |
| 412 + " }" | |
| 413 + " </script>" | |
| 414 + " </head>" | |
| 415 + " <body id='body'>" | |
| 416 + " <div onclick='openNewWindow()'></div>" | |
| 417 + " </body>" | |
| 418 + "</html>"); | |
| 419 } | |
| 420 } | 299 } |
| OLD | NEW |