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

Side by Side Diff: chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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 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.document;
6
7 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_LOW_END_D EVICE;
8
9 import android.app.Activity;
10 import android.app.ActivityManager;
11 import android.app.ActivityManager.RunningServiceInfo;
12 import android.app.Instrumentation;
13 import android.app.PendingIntent;
14 import android.content.Context;
15 import android.content.Intent;
16 import android.net.Uri;
17 import android.os.Build;
18 import android.test.MoreAsserts;
19 import android.test.suitebuilder.annotation.MediumTest;
20 import android.view.ContextMenu;
21 import android.view.View;
22
23 import com.google.android.apps.chrome.R;
24
25 import org.chromium.base.ApplicationStatus;
26 import org.chromium.base.ThreadUtils;
27 import org.chromium.base.test.util.MinAndroidSdkLevel;
28 import org.chromium.base.test.util.Restriction;
29 import org.chromium.base.test.util.UrlUtils;
30 import org.chromium.chrome.browser.BookmarkUtils;
31 import org.chromium.chrome.browser.ChromeActivity;
32 import org.chromium.chrome.browser.ChromeMobileApplication;
33 import org.chromium.chrome.browser.ChromeTabbedActivity;
34 import org.chromium.chrome.browser.EmptyTabObserver;
35 import org.chromium.chrome.browser.IntentHandler;
36 import org.chromium.chrome.browser.Tab;
37 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
38 import org.chromium.chrome.browser.tabmodel.TabModel;
39 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
40 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel;
41 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Initializa tionObserver;
42 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelImpl;
43 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelSelector;
44 import org.chromium.chrome.browser.tabmodel.document.OffTheRecordDocumentTabMode l;
45 import org.chromium.chrome.test.MultiActivityTestBase;
46 import org.chromium.chrome.test.util.ActivityUtils;
47 import org.chromium.chrome.test.util.DisableInTabbedMode;
48 import org.chromium.content.app.SandboxedProcessService;
49 import org.chromium.content.browser.test.util.CallbackHelper;
50 import org.chromium.content.browser.test.util.Criteria;
51 import org.chromium.content.browser.test.util.CriteriaHelper;
52 import org.chromium.content.browser.test.util.TouchCommon;
53 import org.chromium.content_public.browser.LoadUrlParams;
54 import org.chromium.ui.base.PageTransition;
55
56 import java.lang.ref.WeakReference;
57 import java.util.List;
58 import java.util.concurrent.Callable;
59
60 /**
61 * Tests the interactions of the DocumentTabModel with Android's ActivityManager . This test suite
62 * actually fires Intents to start different DocumentActivities.
63 *
64 * Note that this is different instrumenting one DocumentActivity in particular, which should be
65 * tested using the DocumentActivityTestBase class.
66 */
67 @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
68 @DisableInTabbedMode
69 public class DocumentModeTest extends MultiActivityTestBase {
70 private static final String URL_1 = "data:text/html;charset=utf-8,Page%201";
71 private static final String URL_2 = "data:text/html;charset=utf-8,Page%202";
72 private static final String URL_3 = "data:text/html;charset=utf-8,Page%203";
73 private static final String URL_4 = "data:text/html;charset=utf-8,Page%204";
74
75 private static final String HTML_LINK = "<html><head><meta "
76 + "name='viewport' content='width=device-width initial-scale=0.5, ma ximum-scale=0.5'>"
77 + "<style>body {margin: 0em;} div {width: 100%; height: 100%; backgr ound: #011684;}"
78 + "</style></head><body><a href='data:text/html;charset=utf-8,white' target='_blank'>"
79 + "<div></div></a></body></html>";
80 private static final float HTML_SCALE = 0.5f;
81
82 private boolean mInitializationCompleted;
83
84 private Context mContext;
85 private String mUrl;
86 private String mReferrer;
87
88 private static class TestTabObserver extends EmptyTabObserver {
89 private ContextMenu mContextMenu;
90
91 @Override
92 public void onContextMenuShown(Tab tab, ContextMenu menu) {
93 mContextMenu = menu;
94 }
95 }
96
97 private static void launchMainIntent(Context context) throws Exception {
98 Intent intent = new Intent(Intent.ACTION_MAIN);
99 intent.setPackage(context.getPackageName());
100 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
101 context.startActivity(intent);
102 MultiActivityTestBase.waitUntilChromeInForeground();
103 }
104
105 private static void fireViewIntent(Context context, Uri data) throws Excepti on {
106 Intent intent = new Intent(Intent.ACTION_VIEW, data);
107 intent.setClassName(context.getPackageName(), ChromeLauncherActivity.cla ss.getName());
108 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
109 context.startActivity(intent);
110 MultiActivityTestBase.waitUntilChromeInForeground();
111 }
112
113 /**
114 * Launches three tabs via Intents with ACTION_VIEW.
115 */
116 private int[] launchThreeTabs() throws Exception {
117 int[] tabIds = new int[3];
118 tabIds[0] = launchViaViewIntent(false, URL_1);
119 tabIds[1] = launchViaViewIntent(false, URL_2);
120 tabIds[2] = launchViaViewIntent(false, URL_3);
121 assertFalse(tabIds[0] == tabIds[1]);
122 assertFalse(tabIds[0] == tabIds[2]);
123 assertFalse(tabIds[1] == tabIds[2]);
124 assertEquals(3,
125 ChromeMobileApplication.getDocumentTabModelSelector().getModel(f alse).getCount());
126 return tabIds;
127 }
128
129 @Override
130 public void setUp() throws Exception {
131 super.setUp();
132 mContext = getInstrumentation().getTargetContext();
133 }
134
135 /**
136 * Confirm that you can't start ChromeTabbedActivity while the user is runni ng in Document mode.
137 */
138 @MediumTest
139 public void testDontStartTabbedActivityInDocumentMode() throws Exception {
140 launchThreeTabs();
141
142 // Try launching a ChromeTabbedActivity.
143 Runnable runnable = new Runnable() {
144 @Override
145 public void run() {
146 Intent intent = new Intent();
147 intent.setAction(Intent.ACTION_VIEW);
148 intent.setClassName(mContext, ChromeTabbedActivity.class.getName ());
149 intent.setData(Uri.parse(URL_1));
150 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTI VITY_NEW_DOCUMENT);
151 mContext.startActivity(intent);
152 }
153 };
154 ActivityUtils.waitForActivity(getInstrumentation(), ChromeTabbedActivity .class, runnable);
155
156 // ApplicationStatus should note that the ChromeTabbedActivity isn't run ning anymore.
157 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
158 @Override
159 public boolean isSatisfied() {
160 List<WeakReference<Activity>> activities = ApplicationStatus.get RunningActivities();
161 for (WeakReference<Activity> activity : activities) {
162 if (activity.get() instanceof ChromeTabbedActivity) return f alse;
163 }
164 return true;
165 }
166 }));
167 }
168
169 /**
170 * Confirm that firing an Intent without a properly formatted document://ID? url scheme causes
171 * the DocumentActivity to finish itself and hopefully not flat crash (thoug h that'd be better
172 * than letting the user live in both tabbed and document mode simultaneousl y crbug.com/445136).
173 */
174 @MediumTest
175 public void testFireInvalidIntent() throws Exception {
176 launchThreeTabs();
177
178 final DocumentTabModelSelector selector =
179 ChromeMobileApplication.getDocumentTabModelSelector();
180 final Activity lastTrackedActivity = ApplicationStatus.getLastTrackedFoc usedActivity();
181
182 // Send the user home, then fire an Intent with invalid data.
183 MultiActivityTestBase.launchHomescreenIntent(mContext);
184 Intent intent = new Intent(lastTrackedActivity.getIntent());
185 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW _DOCUMENT);
186 intent.setData(Uri.parse("toteslegitscheme://"));
187 mContext.startActivity(intent);
188
189 // A DocumentActivity gets started, but it should immediately call finis hAndRemoveTask()
190 // because of the broken Intent.
191 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
192 @Override
193 public boolean isSatisfied() {
194 Activity activity = ApplicationStatus.getLastTrackedFocusedActiv ity();
195 return activity != lastTrackedActivity;
196 }
197 }));
198
199 // We shouldn't record that a new Tab exists.
200 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
201 @Override
202 public boolean isSatisfied() {
203 return selector.getCurrentModel().getCount() == 3
204 && selector.getTotalTabCount() == 3;
205 }
206 }));
207 }
208
209 /**
210 * Confirm that firing an Intent for a document that has an ID for an alread y existing Tab kills
211 * the original.
212 */
213 @MediumTest
214 public void testDuplicateTabIDsKillsOldActivities() throws Exception {
215 launchThreeTabs();
216
217 final DocumentTabModelSelector selector =
218 ChromeMobileApplication.getDocumentTabModelSelector();
219 final int lastTabId = selector.getCurrentTabId();
220 final Activity lastTrackedActivity = ApplicationStatus.getLastTrackedFoc usedActivity();
221
222 // Send the user home, then fire an Intent with an old Tab ID and a new URL.
223 MultiActivityTestBase.launchHomescreenIntent(mContext);
224 Intent intent = new Intent(lastTrackedActivity.getIntent());
225 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW _DOCUMENT);
226 intent.setData(Uri.parse("document://" + lastTabId + "?" + URL_4));
227 mContext.startActivity(intent);
228
229 // Funnily enough, Android doesn't differentiate between URIs with diffe rent queries when
230 // refocusing Activities based on the Intent data. This means we can't do a check to see
231 // that the new Activity appears with URL_4 -- we just get a new instanc e of URL_3.
232 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
233 @Override
234 public boolean isSatisfied() {
235 Activity activity = ApplicationStatus.getLastTrackedFocusedActiv ity();
236 if (!(activity instanceof ChromeActivity)) return false;
237
238 ChromeActivity chromeActivity = (ChromeActivity) activity;
239 Tab tab = chromeActivity.getActivityTab();
240 return tab != null && lastTrackedActivity != activity
241 && !selector.isIncognitoSelected()
242 && lastTabId == selector.getCurrentTabId();
243 }
244 }));
245
246 // Although we get a new DocumentActivity, the old one with the same tab ID gets killed.
247 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
248 @Override
249 public boolean isSatisfied() {
250 return selector.getCurrentModel().getCount() == 3
251 && selector.getTotalTabCount() == 3;
252 }
253 }));
254 }
255
256 /**
257 * Confirm that firing a View Intent with a null URL acts like a Main Intent .
258 */
259 @MediumTest
260 public void testRelaunchLatestTabWithInvalidViewIntent() throws Exception {
261 launchThreeTabs();
262
263 final DocumentTabModelSelector selector =
264 ChromeMobileApplication.getDocumentTabModelSelector();
265 final int lastTabId = selector.getCurrentTabId();
266
267 final Activity lastTrackedActivity = ApplicationStatus.getLastTrackedFoc usedActivity();
268
269 // Send Chrome to the background, then bring it back.
270 MultiActivityTestBase.launchHomescreenIntent(mContext);
271 fireViewIntent(mContext, null);
272
273 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
274 @Override
275 public boolean isSatisfied() {
276 return lastTrackedActivity == ApplicationStatus.getLastTrackedFo cusedActivity()
277 && !selector.isIncognitoSelected()
278 && lastTabId == selector.getCurrentTabId();
279 }
280 }));
281
282 assertEquals(3, selector.getCurrentModel().getCount());
283 assertEquals(3, selector.getTotalTabCount());
284 }
285
286 /**
287 * Confirm that clicking the Chrome icon (e.g. firing an Intent with ACTION_ MAIN) brings back
288 * the last viewed Tab.
289 */
290 @MediumTest
291 public void testRelaunchLatestTab() throws Exception {
292 launchThreeTabs();
293
294 final DocumentTabModelSelector selector =
295 ChromeMobileApplication.getDocumentTabModelSelector();
296 final int lastTabId = selector.getCurrentTabId();
297
298 // Send Chrome to the background, then bring it back.
299 MultiActivityTestBase.launchHomescreenIntent(mContext);
300 launchMainIntent(mContext);
301
302 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
303 @Override
304 public boolean isSatisfied() {
305 return !selector.isIncognitoSelected() && lastTabId == selector. getCurrentTabId();
306 }
307 }));
308
309 assertEquals(3, selector.getCurrentModel().getCount());
310 assertEquals(3, selector.getTotalTabCount());
311 }
312
313 @MediumTest
314 public void testReferrerExtra() throws Exception {
315 Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonito r(
316 DocumentActivity.class.getName(), null, false);
317 launchMainIntent(mContext);
318
319 // Wait for tab model to become initialized.
320 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
321 @Override
322 public boolean isSatisfied() {
323 return ChromeMobileApplication.isDocumentTabModelSelectorInitial izedForTests();
324 }
325 }));
326
327 DocumentTabModelSelector selector = ChromeMobileApplication.getDocumentT abModelSelector();
328 selector.addObserver(new EmptyTabModelSelectorObserver() {
329 @Override
330 public void onNewTabCreated(Tab tab) {
331 tab.addObserver(new EmptyTabObserver() {
332 @Override
333 public void onLoadUrl(Tab tab, LoadUrlParams params, int loa dType) {
334 mUrl = params.getUrl();
335 if (params.getReferrer() != null) {
336 mReferrer = params.getReferrer().getUrl();
337 }
338 }
339 });
340 }
341 });
342
343 // Wait for document activity from the main intent to launch before firi ng the next
344 // intent.
345 DocumentActivity doc = (DocumentActivity) monitor.waitForActivityWithTim eout(500);
346 assertNotNull("DocumentActivity did not start", doc);
347
348 // Fire the Intent with EXTRA_REFERRER.
349 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(URL_1));
350 intent.setClassName(mContext.getPackageName(), ChromeLauncherActivity.cl ass.getName());
351 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
352 intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(URL_2));
353 IntentHandler.addTrustedIntentExtras(intent, mContext);
354 mContext.startActivity(intent);
355
356 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
357 @Override
358 public boolean isSatisfied() {
359 return URL_1.equals(mUrl);
360 }
361 }));
362
363 assertEquals(URL_2, mReferrer);
364 }
365
366 /**
367 * Confirm that setting the index brings the correct tab forward.
368 */
369 @MediumTest
370 public void testSetIndex() throws Exception {
371 int[] tabIds = launchThreeTabs();
372
373 final DocumentTabModelSelector selector =
374 ChromeMobileApplication.getDocumentTabModelSelector();
375 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
376 @Override
377 public void run() {
378 TabModelUtils.setIndex(selector.getCurrentModel(), 0);
379 }
380 });
381
382 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
383 @Override
384 public boolean isSatisfied() {
385 return !selector.isIncognitoSelected() && selector.getCurrentMod el().index() == 0;
386 }
387 }));
388
389 assertEquals(3, selector.getCurrentModel().getCount());
390 assertEquals(3, selector.getTotalTabCount());
391 assertEquals(tabIds[0], selector.getCurrentTab().getId());
392 }
393
394 /** Check that Intents that request reusing Tabs are honored. */
395 @MediumTest
396 public void testReuseIntent() throws Exception {
397 // Create a tab, then send the user back to the Home screen.
398 int tabId = launchViaViewIntent(false, URL_1);
399 assertTrue(ChromeMobileApplication.isDocumentTabModelSelectorInitialized ForTests());
400 final DocumentTabModelSelector selector =
401 ChromeMobileApplication.getDocumentTabModelSelector();
402 assertEquals(1, selector.getModel(false).getCount());
403 launchHomescreenIntent(mContext);
404
405 // Fire an Intent to reuse the same tab as before.
406 Runnable runnable = new Runnable() {
407 @Override
408 public void run() {
409 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(URL_1)) ;
410 intent.setClass(mContext, ChromeLauncherActivity.class);
411 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
412 intent.putExtra(BookmarkUtils.REUSE_URL_MATCHING_TAB_ELSE_NEW_TA B, true);
413 mContext.startActivity(intent);
414 }
415 };
416 ActivityUtils.waitForActivity(getInstrumentation(), ChromeLauncherActivi ty.class, runnable);
417 waitUntilChromeInForeground();
418 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
419 @Override
420 public boolean isSatisfied() {
421 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedA ctivity();
422 return lastActivity instanceof DocumentActivity;
423 }
424 }));
425 assertEquals(tabId, selector.getCurrentTabId());
426 assertFalse(selector.isIncognitoSelected());
427
428 // Create another tab.
429 final int secondTabId = launchViaViewIntent(false, URL_2);
430 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
431 @Override
432 public boolean isSatisfied() {
433 return selector.getModel(false).getCount() == 2
434 && selector.getCurrentTabId() == secondTabId;
435 }
436 }));
437 }
438
439 /**
440 * Tests both ways of launching Incognito tabs: via an Intent, and via
441 * {@ref ChromeLauncherActivity#launchDocumentInstance()}.
442 */
443 @MediumTest
444 public void testIncognitoLaunches() throws Exception {
445 assertFalse(ChromeMobileApplication.isDocumentTabModelSelectorInitialize dForTests());
446
447 // Make sure that an untrusted Intent can't launch an IncognitoDocumentA ctivity.
448 Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonito r(
449 DocumentActivity.class.getName(), null, false);
450 assertFalse(ChromeMobileApplication.isDocumentTabModelSelectorInitialize dForTests());
451 assertEquals(0, ApplicationStatus.getRunningActivities().size());
452 Runnable runnable = new Runnable() {
453 @Override
454 public void run() {
455 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(URL_1)) ;
456 intent.setClass(mContext, ChromeLauncherActivity.class);
457 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
458 intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true );
459 mContext.startActivity(intent);
460 }
461 };
462 ActivityUtils.waitForActivity(getInstrumentation(), ChromeLauncherActivi ty.class, runnable);
463 DocumentActivity doc = (DocumentActivity) monitor.waitForActivityWithTim eout(1000);
464 assertNull(doc);
465
466 // Create an Incognito tab via an Intent extra.
467 final int firstId = launchViaViewIntent(true, URL_2);
468 assertTrue(ChromeMobileApplication.isDocumentTabModelSelectorInitialized ForTests());
469 final DocumentTabModelSelector selector =
470 ChromeMobileApplication.getDocumentTabModelSelector();
471 final TabModel incognitoModel = selector.getModel(true);
472 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
473 @Override
474 public boolean isSatisfied() {
475 return firstId == selector.getCurrentTabId() && selector.getTota lTabCount() == 1;
476 }
477 }));
478 assertEquals(incognitoModel, selector.getCurrentModel());
479
480 // Launch via ChromeLauncherActivity.launchInstance().
481 final int secondId = launchViaLaunchDocumentInstance(true, URL_3);
482 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
483 @Override
484 public boolean isSatisfied() {
485 return secondId == selector.getCurrentTabId() && selector.getTot alTabCount() == 2;
486 }
487 }));
488 assertTrue(selector.isIncognitoSelected());
489 assertEquals(incognitoModel, selector.getCurrentModel());
490 assertEquals(secondId, TabModelUtils.getCurrentTabId(incognitoModel));
491 }
492
493 /**
494 * Confirm that the incognito tabs and TabModel are destroyed when the "clos e all" notification
495 * Intent is fired.
496 */
497 @MediumTest
498 public void testIncognitoNotificationClosesTabs() throws Exception {
499 final int regularId = launchViaLaunchDocumentInstance(false, URL_1);
500 final DocumentTabModelSelector selector =
501 ChromeMobileApplication.getDocumentTabModelSelector();
502 assertFalse(selector.isIncognitoSelected());
503
504 final int incognitoId = launchViaLaunchDocumentInstance(true, URL_2);
505 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
506 @Override
507 public boolean isSatisfied() {
508 return selector.isIncognitoSelected() && selector.getCurrentTabI d() == incognitoId;
509 }
510 }));
511 assertEquals(0, selector.getCurrentModel().index());
512 assertEquals(1, selector.getCurrentModel().getCount());
513
514 PendingIntent closeAllIntent =
515 ChromeLauncherActivity.getRemoveAllIncognitoTabsIntent(mContext) ;
516 closeAllIntent.send();
517
518 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
519 @Override
520 public boolean isSatisfied() {
521 return selector.getCurrentTabId() == regularId;
522 }
523 }));
524 OffTheRecordDocumentTabModel tabModel =
525 (OffTheRecordDocumentTabModel) selector.getModel(true);
526 assertFalse(selector.isIncognitoSelected());
527 assertFalse(tabModel.isDocumentTabModelImplCreated());
528 }
529
530 /**
531 * Tests if a tab is covered by its child activity.
532 */
533 @MediumTest
534 public void testCoveredByChildActivity() throws Exception {
535 final int tabId = launchViaLaunchDocumentInstance(false, URL_1);
536 final DocumentTabModel model =
537 ChromeMobileApplication.getDocumentTabModelSelector().getModelFo rTabId(tabId);
538 final Tab tab = model.getTabAt(0);
539 assertTrue(tab instanceof DocumentTab);
540 final DocumentTab documentTab = (DocumentTab) tab;
541
542 // We need to wait until the UI for document tab is initialized. So we c reate the
543 // InitializationObserver and set its satisfied criteria the same as
544 // DocumentActivity.mTabInitializationObserver.
545 InitializationObserver observer = new InitializationObserver(model) {
546 @Override
547 public boolean isSatisfied(int currentState) {
548 return currentState >= DocumentTabModelImpl.STATE_LOAD_TAB_S TATE_BG_END
549 || model.isTabStateReady(tabId);
550 }
551
552 @Override
553 public boolean isCanceled() {
554 return false;
555 }
556
557 @Override
558 public void runImmediately() {
559 // This observer is created before DocumentActivity.mTabInit ializationObserver.
560 // Postpone setting mInitializationCompleted afterwards.
561 ThreadUtils.postOnUiThread(new Runnable() {
562 @Override
563 public void run() {
564 mInitializationCompleted = true;
565 }
566 });
567 }
568 };
569 observer.runWhenReady();
570
571 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
572 @Override
573 public boolean isSatisfied() {
574 return mInitializationCompleted;
575 }
576 }));
577
578 assertFalse(documentTab.isCoveredByChildActivity());
579 assertFalse(model.isCoveredByChildActivity(tabId));
580
581 documentTab.setCoveredByChildActivity(true);
582 assertTrue(documentTab.isCoveredByChildActivity());
583 assertTrue(model.isCoveredByChildActivity(tabId));
584
585 documentTab.setCoveredByChildActivity(false);
586 assertFalse(documentTab.isCoveredByChildActivity());
587 assertFalse(model.isCoveredByChildActivity(tabId));
588 }
589
590 /**
591 * Tests that tab ID is properly set when tabs change.
592 */
593 @MediumTest
594 public void testLastTabIdUpdates() throws Exception {
595 launchLinkDocument();
596
597 final DocumentActivity firstActivity =
598 (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivi ty();
599
600 // Save the current tab ID.
601 final DocumentTabModelSelector selector =
602 ChromeMobileApplication.getDocumentTabModelSelector();
603 final TabModel tabModel = selector.getModel(false);
604 final int firstTabId = selector.getCurrentTabId();
605 final int firstTabIndex = tabModel.index();
606
607 openLinkInBackgroundTab();
608
609 // Do a plain click to make the link open in a new foreground Document.
610 Runnable fgTrigger = new Runnable() {
611 @Override
612 public void run() {
613 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
614 @Override
615 public void run() {
616 View view = firstActivity.findViewById(android.R.id.cont ent).getRootView();
617 TouchCommon.singleClickView(view);
618 }
619 });
620 }
621 };
622 ActivityUtils.waitForActivity(getInstrumentation(), DocumentActivity.cla ss, fgTrigger);
623 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
624 @Override
625 public boolean isSatisfied() {
626 if (3 != tabModel.getCount()) return false;
627 if (firstTabIndex == tabModel.index()) return false;
628 if (firstTabId == selector.getCurrentTabId()) return false;
629 return true;
630 }
631 }));
632 MoreAsserts.assertNotEqual(
633 firstActivity, ApplicationStatus.getLastTrackedFocusedActivity() );
634 }
635
636 @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
637 @MediumTest
638 public void testNewTabLoadLowEnd() throws Exception {
639 launchLinkDocument();
640
641 final CallbackHelper tabCreatedCallback = new CallbackHelper();
642 final CallbackHelper tabLoadStartedCallback = new CallbackHelper();
643
644 final DocumentTabModelSelector selector =
645 ChromeMobileApplication.getDocumentTabModelSelector();
646 selector.addObserver(new EmptyTabModelSelectorObserver() {
647 @Override
648 public void onNewTabCreated(final Tab newTab) {
649 selector.removeObserver(this);
650 tabCreatedCallback.notifyCalled();
651
652 assertFalse(newTab.getWebContents().isLoadingToDifferentDocument ());
653
654 newTab.addObserver(new EmptyTabObserver() {
655 @Override
656 public void onPageLoadStarted(Tab tab) {
657 newTab.removeObserver(this);
658 tabLoadStartedCallback.notifyCalled();
659 }
660 });
661 }
662 });
663
664 openLinkInBackgroundTab();
665
666 // Tab should be created, but shouldn't start loading until we switch to it.
667 assertEquals(1, tabCreatedCallback.getCallCount());
668 assertEquals(0, tabLoadStartedCallback.getCallCount());
669
670 TabModelUtils.setIndex(selector.getCurrentModel(), 1);
671 tabLoadStartedCallback.waitForCallback(0);
672 }
673
674 /**
675 * Tests that "Open in new tab" command doesn't create renderer per tab
676 * on low end devices.
677 */
678 @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
679 @MediumTest
680 public void testNewTabRenderersLowEnd() throws Exception {
681 launchLinkDocument();
682
683 // Ignore any side effects that the first background tab might produce.
684 openLinkInBackgroundTab();
685
686 int rendererCountBefore = countRenderers();
687
688 final int newTabCount = 5;
689 for (int i = 0; i != newTabCount; ++i) {
690 openLinkInBackgroundTab();
691 }
692
693 int rendererCountAfter = countRenderers();
694
695 assertEquals(rendererCountBefore, rendererCountAfter);
696 }
697
698 /** Starts a DocumentActivity by using firing a VIEW Intent. */
699 private int launchViaViewIntent(final boolean incognito, final String url) t hrows Exception {
700 // Fire the Intent and wait until Chrome is in the foreground.
701 Runnable runnable = new Runnable() {
702 @Override
703 public void run() {
704 Runnable runnable = new Runnable() {
705 @Override
706 public void run() {
707 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse (URL_1));
708 intent.setClass(mContext, ChromeLauncherActivity.class);
709 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
710 if (incognito) {
711 intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNI TO_TAB, true);
712 IntentHandler.startActivityForTrustedIntent(intent, mContext);
713 } else {
714 mContext.startActivity(intent);
715 }
716 }
717 };
718 ActivityUtils.waitForActivity(getInstrumentation(),
719 (incognito ? IncognitoDocumentActivity.class : DocumentA ctivity.class),
720 runnable);
721 }
722 };
723 return launchUrlViaRunnable(incognito, runnable);
724 }
725
726 /** Starts a DocumentActivity using {@ref ChromeLauncherActivity.launchDocum entInstance().} */
727 private int launchViaLaunchDocumentInstance(
728 final boolean incognito, final String url) throws Exception {
729 Runnable runnable = new Runnable() {
730 @Override
731 public void run() {
732 ChromeLauncherActivity.launchDocumentInstance(null, incognito,
733 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, url,
734 DocumentMetricIds.STARTED_BY_UNKNOWN, PageTransition.LIN K, false, null);
735 }
736 };
737 return launchUrlViaRunnable(incognito, runnable);
738 }
739
740 /**
741 * Launches a DocumentActivity via the given Runnable.
742 * Ideally this would use Observers, but we can't know that the DocumentTabM odelSelector has
743 * been created, and don't want to influence the test by accidentally creati ng it during the
744 * test suite runs.
745 * @return ID of the Tab that was launched.
746 */
747 private int launchUrlViaRunnable(final boolean incognito, final Runnable run nable)
748 throws Exception {
749 final int tabCount =
750 ChromeMobileApplication.isDocumentTabModelSelectorInitializedFor Tests()
751 ? ChromeMobileApplication.getDocumentTabModelSelector().getModel (incognito)
752 .getCount() : 0;
753 final int tabId =
754 ChromeMobileApplication.isDocumentTabModelSelectorInitializedFor Tests()
755 ? ChromeMobileApplication.getDocumentTabModelSelector().getCurre ntTabId()
756 : Tab.INVALID_TAB_ID;
757
758 runnable.run();
759 assertTrue(ChromeMobileApplication.isDocumentTabModelSelectorInitialized ForTests());
760 MultiActivityTestBase.waitUntilChromeInForeground();
761
762 // Wait until the selector is ready and the Tabs have been added to the DocumentTabModel.
763 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
764 @Override
765 public boolean isSatisfied() {
766 if (!ChromeMobileApplication.isDocumentTabModelSelectorInitializ edForTests()) {
767 return false;
768 }
769
770 DocumentTabModelSelector selector =
771 ChromeMobileApplication.getDocumentTabModelSelector();
772 if (selector.isIncognitoSelected() != incognito) return false;
773 if (selector.getModel(incognito).getCount() != (tabCount + 1)) r eturn false;
774 if (selector.getCurrentTabId() == tabId) return false;
775 return true;
776 }
777 }));
778
779 return ChromeMobileApplication.getDocumentTabModelSelector().getCurrentT abId();
780 }
781
782 /**
783 * Launches DocumentActivity with the special URL suitable for openLinkInBac kgroundTab()
784 * invocations.
785 */
786 private void launchLinkDocument() throws Exception {
787 // Load HTML that defines one gigantic link spanning the whole page.
788 launchViaLaunchDocumentInstance(false, UrlUtils.encodeHtmlDataUri(HTML_L INK));
789 final DocumentActivity activity =
790 (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivi ty();
791 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
792 @Override
793 public boolean isSatisfied() {
794 return Float.compare(
795 activity.getCurrentContentViewCore().getScale(), HTML_SC ALE) == 0;
796 }
797 }));
798 }
799
800 /**
801 * Long presses at the center of the page, selects "Open In New Tab" option
802 * from the menu.
803 */
804 private void openLinkInBackgroundTab() throws Exception {
805 // Long press the center of the page, which should bring up the context menu.
806 final TestTabObserver observer = new TestTabObserver();
807 final DocumentActivity activity =
808 (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivi ty();
809 activity.getActivityTab().addObserver(observer);
810 assertNull(observer.mContextMenu);
811 final View view = ThreadUtils.runOnUiThreadBlocking(new Callable<View>() {
812 @Override
813 public View call() throws Exception {
814 return activity.findViewById(android.R.id.content).getRootView() ;
815 }
816 });
817 TouchCommon.longPressView(view, view.getWidth() / 2, view.getHeight() / 2);
818 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
819 @Override
820 public boolean isSatisfied() {
821 return observer.mContextMenu != null;
822 }
823 }));
824
825 activity.getActivityTab().removeObserver(observer);
826
827 // We expect tab to open in the background, i.e. tab index / id should
828 // stay the same.
829 final DocumentTabModelSelector selector =
830 ChromeMobileApplication.getDocumentTabModelSelector();
831 final TabModel tabModel = selector.getModel(false);
832 final int expectedTabCount = tabModel.getCount() + 1;
833 final int expectedTabIndex = tabModel.index();
834 final int expectedTabId = selector.getCurrentTabId();
835
836 // Select the "open in new tab" option to open a tab in the background.
837 ActivityUtils.waitForActivity(getInstrumentation(), DocumentActivity.cla ss,
838 new Runnable() {
839 @Override
840 public void run() {
841 assertTrue(observer.mContextMenu.performIdentifierAction (
842 R.id.contextmenu_open_in_new_tab, 0));
843 }
844 }
845 );
846
847 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
848 @Override
849 public boolean isSatisfied() {
850 if (expectedTabCount != tabModel.getCount()) return false;
851 if (expectedTabIndex != tabModel.index()) return false;
852 if (expectedTabId != selector.getCurrentTabId()) return false;
853 return true;
854 }
855 }));
856
857 assertEquals(activity, ApplicationStatus.getLastTrackedFocusedActivity() );
858 }
859
860 /**
861 * Returns the number of currently running renderer services.
862 */
863 private int countRenderers() {
864 ActivityManager activityManager = (ActivityManager) mContext.getSystemSe rvice(
865 Context.ACTIVITY_SERVICE);
866
867 int rendererCount = 0;
868 List<RunningServiceInfo> serviceInfos = activityManager.getRunningServic es(
869 Integer.MAX_VALUE);
870 for (RunningServiceInfo serviceInfo : serviceInfos) {
871 if (serviceInfo.service.getClassName().startsWith(
872 SandboxedProcessService.class.getName())) {
873 rendererCount++;
874 }
875 }
876
877 return rendererCount;
878 }
879 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698