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

Side by Side Diff: chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.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;
6
7 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_E ND_DEVICE;
8 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_PHONE;
9
10 import android.content.DialogInterface;
11 import android.content.pm.ActivityInfo;
12 import android.os.Debug;
13 import android.os.SystemClock;
14 import android.test.FlakyTest;
15 import android.test.suitebuilder.annotation.LargeTest;
16 import android.test.suitebuilder.annotation.MediumTest;
17 import android.test.suitebuilder.annotation.SmallTest;
18 import android.test.suitebuilder.annotation.Smoke;
19 import android.util.Log;
20 import android.view.View;
21
22 import com.google.android.apps.chrome.R;
23
24 import junit.framework.Assert;
25
26 import org.chromium.base.CommandLine;
27 import org.chromium.base.ThreadUtils;
28 import org.chromium.base.annotations.SuppressFBWarnings;
29 import org.chromium.base.test.util.DisabledTest;
30 import org.chromium.base.test.util.Feature;
31 import org.chromium.base.test.util.Restriction;
32 import org.chromium.base.test.util.UrlUtils;
33 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
34 import org.chromium.chrome.browser.compositor.layouts.Layout;
35 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
36 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
37 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
38 import org.chromium.chrome.browser.compositor.layouts.StaticLayout;
39 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
40 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEvent Filter.ScrollDirection;
41 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandl er;
42 import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
43 import org.chromium.chrome.browser.compositor.layouts.phone.stack.Stack;
44 import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackTab;
45 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
46 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
47 import org.chromium.chrome.browser.tabmodel.TabModel;
48 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
49 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
50 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
51 import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
52 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
53 import org.chromium.chrome.browser.toolbar.ToolbarPhone;
54 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
55 import org.chromium.chrome.test.util.ChromeTabUtils;
56 import org.chromium.chrome.test.util.MenuUtils;
57 import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
58 import org.chromium.chrome.test.util.TestHttpServerClient;
59 import org.chromium.content.browser.ContentViewCore;
60 import org.chromium.content.browser.test.util.CallbackHelper;
61 import org.chromium.content.browser.test.util.Criteria;
62 import org.chromium.content.browser.test.util.CriteriaHelper;
63 import org.chromium.content.browser.test.util.JavaScriptUtils;
64 import org.chromium.content.browser.test.util.UiUtils;
65 import org.chromium.content.common.ContentSwitches;
66 import org.chromium.content_public.browser.WebContents;
67 import org.chromium.content_public.browser.WebContentsObserver;
68
69 import java.util.concurrent.Callable;
70 import java.util.concurrent.TimeUnit;
71 import java.util.concurrent.TimeoutException;
72 import java.util.concurrent.atomic.AtomicBoolean;
73 import java.util.concurrent.atomic.AtomicReference;
74
75 /**
76 * General Tab tests.
77 */
78 public class TabsTest extends ChromeTabbedActivityTestBase {
79
80 private static final String TEST_FILE_PATH = "chrome/test/data/android/tabst est/tabs_test.html";
81 private static final String TEST_PAGE_FILE_PATH = "chrome/test/data/google/g oogle.html";
82
83 private float mPxToDp = 1.0f;
84 private float mTabsViewHeightDp;
85 private float mTabsViewWidthDp;
86
87 private boolean mNotifyChangedCalled;
88
89 private static final int SWIPE_TO_RIGHT_DIRECTION = 1;
90 private static final int SWIPE_TO_LEFT_DIRECTION = -1;
91
92 private static final long WAIT_RESIZE_TIMEOUT_MS = 3000;
93
94 private static final int STRESSFUL_TAB_COUNT = 100;
95
96 private static final String RESIZE_TEST_URL = UrlUtils.encodeHtmlDataUri(
97 "<html><head><script>"
98 + " var resizeHappened = false;"
99 + " function onResize() {"
100 + " resizeHappened = true;"
101 + " document.getElementById('test').textContent ="
102 + " window.innerWidth + 'x' + window.innerHeight;"
103 + " }"
104 + "</script></head>"
105 + "<body onresize=\"onResize()\">"
106 + " <div id=\"test\">No resize event has been received yet.</div>"
107 + "</body></html>");
108
109 /**
110 * Verify that spawning a popup from a background tab in a different model w orks properly.
111 * @throws InterruptedException
112 * @throws TimeoutException
113 */
114 @LargeTest
115 @Feature({"Navigation"})
116 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
117 public void testSpawnPopupOnBackgroundTab() throws InterruptedException, Tim eoutException {
118 loadUrl(UrlUtils.getIsolatedTestFileUrl(TEST_FILE_PATH));
119 final Tab tab = getActivity().getActivityTab();
120
121 newIncognitoTabFromMenu();
122
123 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
124 @Override
125 public void run() {
126 tab.getWebContents().evaluateJavaScript(
127 "(function() {"
128 + " window.open('www.google.com');"
129 + "})()",
130 null);
131 }
132 });
133
134 assertTrue("Tab never spawned in normal model.",
135 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
136 @Override
137 public boolean isSatisfied() {
138 return getActivity().getTabModelSelector().getModel(fals e).getCount() == 2;
139 }
140 }));
141 }
142
143 @MediumTest
144 public void testAlertDialogDoesNotChangeActiveModel() throws InterruptedExce ption {
145 newIncognitoTabFromMenu();
146 loadUrl(UrlUtils.getIsolatedTestFileUrl(TEST_FILE_PATH));
147 final Tab tab = getActivity().getActivityTab();
148 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
149 @Override
150 public void run() {
151 tab.getWebContents().evaluateJavaScript(
152 "(function() {"
153 + " alert('hi');"
154 + "})()",
155 null);
156 }
157 });
158
159 final AtomicReference<JavascriptAppModalDialog> dialog =
160 new AtomicReference<JavascriptAppModalDialog>();
161
162 CriteriaHelper.pollForCriteria(new Criteria() {
163 @Override
164 public boolean isSatisfied() {
165 dialog.set(JavascriptAppModalDialog.getCurrentDialogForTest());
166
167 return dialog.get() != null;
168 }
169 });
170
171 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
172 @Override
173 public void run() {
174 dialog.get().onClick(null, DialogInterface.BUTTON_POSITIVE);
175 }
176 });
177
178 dialog.set(null);
179
180 CriteriaHelper.pollForCriteria(new Criteria() {
181 @Override
182 public boolean isSatisfied() {
183 return JavascriptAppModalDialog.getCurrentDialogForTest() == nul l;
184 }
185 });
186
187 assertTrue("Incognito model was not selected",
188 getActivity().getTabModelSelector().isIncognitoSelected());
189 }
190
191 /**
192 * Verify New Tab Open and Close Event not from the context menu.
193 * @throws InterruptedException
194 *
195 * https://crbug.com/490473
196 * @LargeTest
197 * @Feature({"Android-TabSwitcher"})
198 * @Restriction(RESTRICTION_TYPE_PHONE)
199 */
200 @DisabledTest
201 public void testOpenAndCloseNewTabButton() throws InterruptedException {
202 startMainActivityWithURL(UrlUtils.getIsolatedTestFileUrl(TEST_FILE_PATH) );
203 getInstrumentation().runOnMainSync(new Runnable() {
204 @Override
205 public void run() {
206 String title = getActivity().getCurrentTabModel().getTabAt(0).ge tTitle();
207 assertEquals("Data file for TabsTest", title);
208 }
209 });
210 final int tabCount = getActivity().getCurrentTabModel().getCount();
211 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
212 getActivity().getLayoutManager(), true, false);
213 View tabSwitcherButton = getActivity().findViewById(R.id.tab_switcher_bu tton);
214 assertNotNull("'tab_switcher_button' view is not found", tabSwitcherButt on);
215 singleClickView(tabSwitcherButton, tabSwitcherButton.getWidth() / 2,
216 tabSwitcherButton.getHeight() / 2);
217 overviewModeWatcher.waitForBehavior();
218 overviewModeWatcher = new OverviewModeBehaviorWatcher(
219 getActivity().getLayoutManager(), false, true);
220 View newTabButton = getActivity().findViewById(R.id.new_tab_button);
221 assertNotNull("'new_tab_button' view is not found", newTabButton);
222 singleClickView(newTabButton, newTabButton.getWidth() / 2, newTabButton. getHeight() / 2);
223 overviewModeWatcher.waitForBehavior();
224
225 getInstrumentation().runOnMainSync(new Runnable() {
226 @Override
227 public void run() {
228 assertEquals("The tab count is wrong",
229 tabCount + 1, getActivity().getCurrentTabModel().getCoun t());
230 }
231 });
232
233 assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
234 @Override
235 public boolean isSatisfied() {
236 Tab tab = getActivity().getCurrentTabModel().getTabAt(1);
237 String title = tab.getTitle().toLowerCase();
238 String expectedTitle = "new tab";
239 return title.startsWith(expectedTitle);
240 }
241 }));
242
243 ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
244 getInstrumentation().runOnMainSync(new Runnable() {
245 @Override
246 public void run() {
247 assertEquals(tabCount, getActivity().getCurrentTabModel().getCou nt());
248 }
249 });
250 }
251
252 static class SimulateClickOnMainThread implements Runnable {
253 private final LayoutManagerChrome mLayoutManager;
254 private final float mX;
255 private final float mY;
256
257 public SimulateClickOnMainThread(LayoutManagerChrome layoutManager, floa t x, float y) {
258 mLayoutManager = layoutManager;
259 mX = x;
260 mY = y;
261 }
262
263 @Override
264 public void run() {
265 mLayoutManager.simulateClick(mX, mY);
266 }
267 }
268
269 static class SimulateTabSwipeOnMainThread implements Runnable {
270 private final LayoutManagerChrome mLayoutManager;
271 private final float mX;
272 private final float mY;
273 private final float mDeltaX;
274 private final float mDeltaY;
275
276 public SimulateTabSwipeOnMainThread(LayoutManagerChrome layoutManager, f loat x, float y,
277 float dX, float dY) {
278 mLayoutManager = layoutManager;
279 mX = x;
280 mY = y;
281 mDeltaX = dX;
282 mDeltaY = dY;
283 }
284
285 @Override
286 public void run() {
287 mLayoutManager.simulateDrag(mX, mY, mDeltaX, mDeltaY);
288 }
289 }
290
291 /**
292 * Verify that the provided click position closes a tab.
293 * @throws InterruptedException
294 */
295 private void checkCloseTabAtPosition(final float x, final float y)
296 throws InterruptedException {
297 getActivity();
298
299 int initialTabCount = getActivity().getCurrentTabModel().getCount();
300 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
301 getInstrumentation().waitForIdleSync();
302 View button = getActivity().findViewById(R.id.tab_switcher_button);
303 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
304 getActivity().getLayoutManager(), true, false);
305 singleClickView(button, button.getWidth() / 2, button.getHeight() / 2);
306 overviewModeWatcher.waitForBehavior();
307 assertTrue("Expected: " + (initialTabCount + 1) + " tab Got: "
308 + getActivity().getCurrentTabModel().getCount(),
309 (initialTabCount + 1) == getActivity().getCurrentTabModel().getC ount());
310 getInstrumentation().waitForIdleSync();
311 final LayoutManagerChrome layoutManager = updateTabsViewSize();
312 ChromeTabUtils.closeTabWithAction(getInstrumentation(), getActivity(), n ew Runnable() {
313 @Override
314 public void run() {
315 getInstrumentation().runOnMainSync(
316 new SimulateClickOnMainThread(layoutManager, x, y));
317 }
318 });
319 assertTrue("Expected: " + initialTabCount + " tab Got: "
320 + getActivity().getCurrentTabModel().getCount(),
321 initialTabCount == getActivity().getCurrentTabModel().getCount() );
322 }
323
324 /**
325 * Verify close button works in the TabSwitcher in portrait mode.
326 * This code does not handle properly different screen densities.
327 * @throws InterruptedException
328 */
329 @LargeTest
330 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
331 @Feature({"Android-TabSwitcher"})
332 public void testTabSwitcherPortraitCloseButton() throws InterruptedException {
333 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
334 int portraitWidth = Math.min(getActivity().getResources().getDisplayMetr ics().widthPixels,
335 getActivity().getResources().getDisplayMetrics().heightPixels);
336 // Hard-coded coordinates of the close button on the top right of the sc reen.
337 // If the coordinates need to be updated, the easiest is to take a scree nshot and measure.
338 // Note that starting from the right of the screen should cover any scre en size.
339 checkCloseTabAtPosition(portraitWidth * mPxToDp - 32, 70);
340 }
341
342 /**
343 * Verify close button works in the TabSwitcher in landscape mode.
344 * This code does not handle properly different screen densities.
345 * @throws InterruptedException
346 * Bug: crbug.com/170179
347 * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE })
348 * @LargeTest
349 * @Feature({"Android-TabSwitcher"})
350 */
351 @FlakyTest
352 public void testTabSwitcherLandscapeCloseButton() throws InterruptedExceptio n {
353 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
354 // Hard-coded coordinates of the close button on the bottom left of the screen.
355 // If the coordinates need to be updated, the easiest is to take a scree nshot and measure.
356 checkCloseTabAtPosition(31 * mPxToDp, 31 * mPxToDp);
357 }
358
359 /**
360 * Verify that we can open a large number of tabs without running out of
361 * memory. This test waits for the NTP to load before opening the next one.
362 * This is a LargeTest but because we're doing it "slowly", we need to furth er scale
363 * the timeout for adb am instrument and the various events.
364 */
365 /*
366 * @EnormousTest
367 * @TimeoutScale(10)
368 * @Feature({"Android-TabSwitcher"})
369 * Bug crbug.com/166208
370 */
371 @DisabledTest
372 public void testOpenManyTabsSlowly() throws InterruptedException {
373 int startCount = getActivity().getCurrentTabModel().getCount();
374 for (int i = 1; i <= STRESSFUL_TAB_COUNT; ++i) {
375 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
376 getInstrumentation().waitForIdleSync();
377 assertEquals(startCount + i, getActivity().getCurrentTabModel().getC ount());
378 }
379 }
380
381 /**
382 * Verify that we can open a large number of tabs without running out of
383 * memory. This test hammers the "new tab" button quickly to stress the app.
384 *
385 * @LargeTest
386 * @TimeoutScale(10)
387 * @Feature({"Android-TabSwitcher"})
388 *
389 */
390 @FlakyTest
391 public void testOpenManyTabsQuickly() {
392 int startCount = getActivity().getCurrentTabModel().getCount();
393 for (int i = 1; i <= STRESSFUL_TAB_COUNT; ++i) {
394 MenuUtils.invokeCustomMenuActionSync(getInstrumentation(), getActivi ty(),
395 R.id.new_tab_menu_id);
396 assertEquals(startCount + i, getActivity().getCurrentTabModel().getC ount());
397 }
398 }
399
400 /**
401 * Verify that we can open a burst of new tabs, even when there are already
402 * a large number of tabs open.
403 * Bug: crbug.com/180718
404 * @EnormousTest
405 * @TimeoutScale(30)
406 * @Feature({"Navigation"})
407 */
408 @FlakyTest
409 public void testOpenManyTabsInBursts() throws InterruptedException {
410 final int burstSize = 5;
411 final String url = TestHttpServerClient.getUrl(TEST_PAGE_FILE_PATH);
412 final int startCount = getActivity().getCurrentTabModel().getCount();
413 for (int tabCount = startCount; tabCount < STRESSFUL_TAB_COUNT; tabCount += burstSize) {
414 loadUrlInManyNewTabs(url, burstSize);
415 assertEquals(tabCount + burstSize, getActivity().getCurrentTabModel( ).getCount());
416 }
417 }
418
419 /**
420 * Verify opening 10 tabs at once and that each tab loads when selected.
421 */
422 /*
423 * @EnormousTest
424 * @TimeoutScale(30)
425 * @Feature({"Navigation"})
426 * crbug/223110
427 */
428 @FlakyTest
429 public void testOpenManyTabsAtOnce10() throws InterruptedException {
430 openAndVerifyManyTestTabs(10);
431 }
432
433 /**
434 * Verify that we can open a large number of tabs all at once and that each
435 * tab loads when selected.
436 */
437 private void openAndVerifyManyTestTabs(final int num) throws InterruptedExce ption {
438 final String url = TestHttpServerClient.getUrl(TEST_PAGE_FILE_PATH);
439 int startCount = getActivity().getCurrentTabModel().getCount();
440 loadUrlInManyNewTabs(url, num);
441 assertEquals(startCount + num,
442 getActivity().getCurrentTabModel().getCount());
443 }
444
445 class ClickOptionButtonOnMainThread implements Runnable {
446 @Override
447 public void run() {
448 // This is equivalent to clickById(R.id.tab_switcher_button) but doe s not rely on the
449 // event pipeline.
450 View button = getActivity().findViewById(R.id.tab_switcher_button);
451 assertNotNull("Could not find view R.id.tab_switcher_button", button );
452 View toolbar = getActivity().findViewById(R.id.toolbar);
453 assertNotNull("Could not find view R.id.toolbar", toolbar);
454 assertTrue("R.id.toolbar is not a ToolbarPhone", toolbar instanceof ToolbarPhone);
455 ((ToolbarPhone) toolbar).onClick(button);
456 }
457 }
458
459 /**
460 * Displays the tabSwitcher mode and wait for it to settle.
461 */
462 private void showOverviewAndWaitForAnimation() throws InterruptedException {
463 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
464 getActivity().getLayoutManager(), true, false);
465 // For some unknown reasons calling clickById(R.id.tab_switcher_button) sometimes hang.
466 // The following is verbose but more reliable.
467 getInstrumentation().runOnMainSync(new ClickOptionButtonOnMainThread());
468 overviewModeWatcher.waitForBehavior();
469 }
470
471 /**
472 * Exits the tabSwitcher mode and wait for it to settle.
473 */
474 private void hideOverviewAndWaitForAnimation() throws InterruptedException {
475 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
476 getActivity().getLayoutManager(), false, true);
477 getInstrumentation().runOnMainSync(new ClickOptionButtonOnMainThread());
478 overviewModeWatcher.waitForBehavior();
479 }
480
481 /**
482 * Opens tabs to populate the model to a given count.
483 * @param targetTabCount The desired number of tabs in the model.
484 * @param waitToLoad Whether the tabs need to be fully loaded.
485 * @return The new number of tabs in the model.
486 * @throws InterruptedException
487 */
488 private int openTabs(final int targetTabCount, boolean waitToLoad) throws In terruptedException {
489 int tabCount = getActivity().getCurrentTabModel().getCount();
490 while (tabCount < targetTabCount) {
491 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
492 tabCount++;
493 assertEquals("The tab count is wrong",
494 tabCount, getActivity().getCurrentTabModel().getCount());
495 Tab tab = TabModelUtils.getCurrentTab(getActivity().getCurrentTabMod el());
496 while (waitToLoad && tab.isLoading()) {
497 Thread.yield();
498 }
499 }
500 return tabCount;
501 }
502
503 /**
504 * Verifies that when more than 9 tabs are open only at most 8 are drawn. Ba sically it verifies
505 * that the tab culling mechanism works properly.
506 */
507 /*
508 @LargeTest
509 @Feature({"Android-TabSwitcher"})
510 Bug http://crbug.com/156746
511 */
512 @DisabledTest
513 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
514 public void testTabsCulling() throws InterruptedException {
515 // Open one more tabs than maxTabsDrawn.
516 final int maxTabsDrawn = 8;
517 int tabCount = openTabs(maxTabsDrawn + 1, false);
518 showOverviewAndWaitForAnimation();
519
520 // Check counts.
521 LayoutManagerChromePhone layoutManager =
522 (LayoutManagerChromePhone) getActivity().getLayoutManager();
523 int drawnCount = layoutManager.getOverviewLayout().getLayoutTabsDrawnCou nt();
524 int drawnExpected = Math.min(tabCount, maxTabsDrawn);
525 assertEquals("The number of drawn tab is wrong", drawnExpected, drawnCou nt);
526 }
527
528 /**
529 * Checks the stacked tabs in the stack are visible.
530 * @throws InterruptedException
531 */
532 private void checkTabsStacking() throws InterruptedException {
533 final int count = getActivity().getCurrentTabModel().getCount();
534 assertEquals("The number of tab in the stack should match the number of tabs in the model",
535 count, getLayoutTabInStackCount(false));
536
537 assertTrue("The selected tab should always be visible",
538 stackTabIsVisible(false, getActivity().getCurrentTabModel().inde x()));
539 for (int i = 0; i < Stack.MAX_NUMBER_OF_STACKED_TABS_TOP && i < count; i ++) {
540 assertTrue("The stacked tab " + i + " from the top should always be visible",
541 stackTabIsVisible(false, i));
542 }
543 for (int i = 0; i < Stack.MAX_NUMBER_OF_STACKED_TABS_BOTTOM && i < count ; i++) {
544 assertTrue("The stacked tab " + i + " from the bottom should always be visible",
545 stackTabIsVisible(false, count - 1 - i));
546 }
547 }
548
549 /**
550 * Verifies that the tab are actually stacking at the bottom and top of the screen.
551 */
552 /**
553 * Bug: crbug.com/170179
554 * @LargeTest
555 * @Feature({"Android-TabSwitcher"})
556 */
557 @FlakyTest
558 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
559 public void testTabsStacking() throws InterruptedException {
560 final int count = openTabs(12, false);
561
562 // Selecting the first tab to scroll all the way to the top.
563 getInstrumentation().runOnMainSync(new Runnable() {
564 @Override
565 public void run() {
566 TabModelUtils.setIndex(getActivity().getCurrentTabModel(), 0);
567 }
568 });
569 showOverviewAndWaitForAnimation();
570 checkTabsStacking();
571
572 // Selecting the last tab to scroll all the way to the bottom.
573 hideOverviewAndWaitForAnimation();
574 getInstrumentation().runOnMainSync(new Runnable() {
575 @Override
576 public void run() {
577 TabModelUtils.setIndex(getActivity().getCurrentTabModel(), count - 1);
578 }
579 });
580 showOverviewAndWaitForAnimation();
581 checkTabsStacking();
582 }
583
584 /**
585 * @return A stable read of allocated size (native + dalvik) after gc.
586 */
587 @SuppressFBWarnings("DM_GC")
588 private long getStableAllocatedSize() {
589 // Measure the equivalent of allocated size native + dalvik in:
590 // adb shell dumpsys meminfo | grep chrome -A 20
591 int maxTries = 8;
592 int tries = 0;
593 long threshold = 512; // bytes
594 long lastAllocatedSize = Long.MAX_VALUE;
595 long currentAllocatedSize = 0;
596 while (tries < maxTries && Math.abs(currentAllocatedSize - lastAllocated Size) > threshold) {
597 System.gc();
598 try {
599 Thread.sleep(1000 + tries * 500); // Memory measurement is not a n exact science...
600 lastAllocatedSize = currentAllocatedSize;
601 currentAllocatedSize = Debug.getNativeHeapAllocatedSize()
602 + Runtime.getRuntime().totalMemory();
603 //Log.w("MEMORY_MEASURE", "[" + tries + "/" + maxTries + "]" +
604 // "currentAllocatedSize " + currentAllocatedSize);
605 } catch (InterruptedException e) {
606 e.printStackTrace();
607 }
608 tries++;
609 }
610 assertTrue("Could not have a stable read on native allocated size even a fter "
611 + tries + " gc.", tries < maxTries);
612 return currentAllocatedSize;
613 }
614
615 /**
616 * Verify that switching back and forth to the tabswitcher does not leak mem ory.
617 */
618 /**
619 * Bug: crbug.com/303319
620 * @LargeTest
621 * @Feature({"Android-TabSwitcher"})
622 */
623 @FlakyTest
624 @Restriction(RESTRICTION_TYPE_PHONE)
625 public void testTabSwitcherMemoryLeak() throws InterruptedException {
626 openTabs(4, true);
627
628 int maxTries = 10;
629 int tries = 0;
630 long threshold = 1024; // bytes
631 long lastAllocatedSize = 0;
632 long currentAllocatedSize = 2 * threshold;
633 while (tries < maxTries && (lastAllocatedSize + threshold) < currentAllo catedSize) {
634 showOverviewAndWaitForAnimation();
635
636 lastAllocatedSize = currentAllocatedSize;
637 currentAllocatedSize = getStableAllocatedSize();
638 //Log.w("MEMORY_TEST", "[" + tries + "/" + maxTries + "]" +
639 // "currentAllocatedSize " + currentAllocatedSize);
640
641 hideOverviewAndWaitForAnimation();
642 tries++;
643 }
644
645 assertTrue("Native heap allocated size keeps increasing even after "
646 + tries + " iterations", tries < maxTries);
647 }
648
649 /**
650 * Verify that switching back and forth stay stable. This test last for at l east 8 seconds.
651 */
652 @LargeTest
653 @Restriction(RESTRICTION_TYPE_PHONE)
654 @Feature({"Android-TabSwitcher"})
655 public void testTabSwitcherStability() throws InterruptedException {
656 openTabs(8, true);
657
658 // This is about as fast as you can ever click.
659 final long fastestUserInput = 20; // ms
660 for (int i = 0; i < 200; i++) {
661 // Show overview
662 getInstrumentation().runOnMainSync(new ClickOptionButtonOnMainThread ());
663 Thread.sleep(fastestUserInput);
664
665 // hide overview
666 getInstrumentation().runOnMainSync(new ClickOptionButtonOnMainThread ());
667 Thread.sleep(fastestUserInput);
668 }
669 }
670
671 @LargeTest
672 @Feature({"Android-TabSwitcher"})
673 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
674 public void testTabSelectionPortrait() throws InterruptedException {
675 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
676 checkTabSelection(2, 0, false);
677
678 // Ensure all tabs following the selected tab are off the screen when th e animation is
679 // complete.
680 final int count = getLayoutTabInStackCount(false);
681 for (int i = 1; i < count; i++) {
682 float y = getLayoutTabInStackXY(false, i)[1];
683 assertTrue(
684 String.format("Tab %d's final draw Y, %f, should exceed the view height, %f.",
685 i, y, mTabsViewHeightDp),
686 y >= mTabsViewHeightDp);
687 }
688 }
689
690 /**
691 * Bug: crbug.com/170179
692 * @LargeTest
693 * @Feature({"Android-TabSwitcher"})
694 */
695 @FlakyTest
696 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
697 public void testTabSelectionLandscape() throws InterruptedException {
698 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
699 checkTabSelection(2, 0, true);
700
701 // Ensure all tabs following the selected tab are off the screen when th e animation is
702 // complete.
703 final int count = getLayoutTabInStackCount(false);
704 for (int i = 1; i < count; i++) {
705 float x = getLayoutTabInStackXY(false, i)[0];
706 assertTrue(
707 String.format("Tab %d's final draw X, %f, should exceed the view width, %f.",
708 i, x, mTabsViewWidthDp),
709 x >= mTabsViewWidthDp);
710 }
711 }
712
713 /**
714 * Verify that we don't crash and show the overview mode after closing the l ast tab.
715 */
716 @SmallTest
717 @Restriction(RESTRICTION_TYPE_PHONE)
718 @Feature({"Android-TabSwitcher"})
719 public void testCloseLastTabFromMain() throws InterruptedException {
720 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
721 getActivity().getLayoutManager(), true, false);
722 ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
723 getInstrumentation().waitForIdleSync();
724 overviewModeWatcher.waitForBehavior();
725 }
726
727 private LayoutManagerChrome updateTabsViewSize() {
728 View tabsView = getActivity().getTabsView();
729 mTabsViewHeightDp = tabsView.getHeight() * mPxToDp;
730 mTabsViewWidthDp = tabsView.getWidth() * mPxToDp;
731 return getActivity().getLayoutManager();
732 }
733
734 private Stack getStack(final LayoutManagerChrome layoutManager, boolean isIn cognito) {
735 assertTrue("getStack must be executed on the ui thread",
736 ThreadUtils.runningOnUiThread());
737 LayoutManagerChromePhone layoutManagerPhone = (LayoutManagerChromePhone) layoutManager;
738 StackLayout layout = (StackLayout) layoutManagerPhone.getOverviewLayout( );
739 return (layout).getTabStack(isIncognito);
740 }
741
742 private int getLayoutTabInStackCount(final boolean isIncognito) {
743 final LayoutManagerChrome layoutManager = updateTabsViewSize();
744 final int[] count = new int[1];
745 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
746 @Override
747 public void run() {
748 Stack stack = getStack(layoutManager, isIncognito);
749 count[0] = stack.getTabs().length;
750 }
751 });
752 return count[0];
753 }
754
755 private boolean stackTabIsVisible(final boolean isIncognito, final int index ) {
756 final LayoutManagerChrome layoutManager = updateTabsViewSize();
757 final boolean[] isVisible = new boolean[1];
758 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
759 @Override
760 public void run() {
761 Stack stack = getStack(layoutManager, isIncognito);
762 isVisible[0] = (stack.getTabs())[index].getLayoutTab().isVisible ();
763 }
764 });
765 return isVisible[0];
766 }
767
768 private float[] getLayoutTabInStackXY(final boolean isIncognito, final int i ndex) {
769 final LayoutManagerChrome layoutManager = updateTabsViewSize();
770 final float[] xy = new float[2];
771 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
772 @Override
773 public void run() {
774 Stack stack = getStack(layoutManager, isIncognito);
775 xy[0] = (stack.getTabs())[index].getLayoutTab().getX();
776 xy[1] = (stack.getTabs())[index].getLayoutTab().getY();
777 }
778 });
779 return xy;
780 }
781
782 private float[] getStackTabClickTarget(final int tabIndexToSelect, final boo lean isIncognito,
783 final boolean isLandscape) {
784 final LayoutManagerChrome layoutManager = updateTabsViewSize();
785 final float[] target = new float[2];
786 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
787 @Override
788 public void run() {
789 Stack stack = getStack(layoutManager, isIncognito);
790 StackTab[] tabs = stack.getTabs();
791 // The position of the click is expressed from the top left corn er of the content.
792 // The aim is to find an offset that is inside the content but n ot on the close
793 // button. For this, we calculate the center of the visible tab area.
794 LayoutTab layoutTab = tabs[tabIndexToSelect].getLayoutTab();
795 LayoutTab nextLayoutTab = (tabIndexToSelect + 1) < tabs.length
796 ? tabs[tabIndexToSelect + 1].getLayoutTab() : null;
797
798 float tabOffsetX = layoutTab.getX();
799 float tabOffsetY = layoutTab.getY();
800 float tabRightX, tabBottomY;
801 if (isLandscape) {
802 tabRightX = nextLayoutTab != null
803 ? nextLayoutTab.getX()
804 : tabOffsetX + layoutTab.getScaledContentWidth();
805 tabBottomY = tabOffsetY + layoutTab.getScaledContentHeight() ;
806 } else {
807 tabRightX = tabOffsetX + layoutTab.getScaledContentWidth();
808 tabBottomY = nextLayoutTab != null
809 ? nextLayoutTab.getY()
810 : tabOffsetY + layoutTab.getScaledContentHeight();
811 }
812 tabRightX = Math.min(tabRightX, mTabsViewWidthDp);
813 tabBottomY = Math.min(tabBottomY, mTabsViewHeightDp);
814
815 target[0] = (tabOffsetX + tabRightX) / 2.0f;
816 target[1] = (tabOffsetY + tabBottomY) / 2.0f;
817 }
818 });
819 return target;
820 }
821
822 private void checkTabSelection(int additionalTabsToOpen, int tabIndexToSelec t,
823 boolean isLandscape) throws InterruptedException {
824 for (int i = 0; i < additionalTabsToOpen; i++) {
825 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
826 }
827 assertEquals("Number of open tabs does not match",
828 additionalTabsToOpen + 1 , getActivity().getCurrentTabModel().ge tCount());
829 showOverviewAndWaitForAnimation();
830
831 float[] coordinates = getStackTabClickTarget(tabIndexToSelect, false, is Landscape);
832 float clickX = coordinates[0];
833 float clickY = coordinates[1];
834
835 OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehavi orWatcher(
836 getActivity().getLayoutManager(), false, true);
837
838 final LayoutManagerChrome layoutManager = updateTabsViewSize();
839 getInstrumentation().runOnMainSync(new SimulateClickOnMainThread(layoutM anager,
840 (int) clickX, (int) clickY));
841 overviewModeWatcher.waitForBehavior();
842
843 // Make sure we did not accidentally close a tab.
844 assertEquals("Number of open tabs does not match",
845 additionalTabsToOpen + 1 , getActivity().getCurrentTabModel().ge tCount());
846 }
847
848 public void swipeToCloseTab(final int tabIndexToClose, final boolean isLands cape,
849 final boolean isIncognito, final int swipeDirection) throws Interrup tedException {
850 final LayoutManagerChrome layoutManager = updateTabsViewSize();
851 float[] coordinates = getStackTabClickTarget(tabIndexToClose, isIncognit o, isLandscape);
852 final float clickX = coordinates[0];
853 final float clickY = coordinates[1];
854 Log.v("ChromeTest", String.format("clickX %f clickY %f", clickX, clickY) );
855
856 ChromeTabUtils.closeTabWithAction(getInstrumentation(), getActivity(), n ew Runnable() {
857 @Override
858 public void run() {
859 if (isLandscape) {
860 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMai nThread(
861 layoutManager, clickX, clickY, 0, swipeDirection * m TabsViewWidthDp));
862 } else {
863 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMai nThread(
864 layoutManager, clickX, clickY, swipeDirection * mTab sViewHeightDp, 0));
865 }
866 }
867 });
868 assertTrue("Did not finish animation",
869 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
870 @Override
871 public boolean isSatisfied() {
872 Layout layout = getActivity().getLayoutManager().getActi veLayout();
873 return !layout.isLayoutAnimating();
874 }
875 }));
876 }
877
878 private void swipeToCloseNTabs(int number, boolean isLandscape, boolean isIn cognito,
879 int swipeDirection)
880 throws InterruptedException {
881
882 for (int i = number - 1; i >= 0; i--) {
883 swipeToCloseTab(i, isLandscape, isIncognito, swipeDirection);
884 }
885 }
886
887 /**
888 * Test closing few tabs by swiping them in Overview portrait mode.
889 */
890 @MediumTest
891 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
892 @Feature({"Android-TabSwitcher", "Main"})
893 public void testCloseTabPortrait() throws InterruptedException {
894 startMainActivityWithURL(TestHttpServerClient.getUrl("chrome/test/data/a ndroid/test.html"));
895
896 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
897
898 int tabCount = getActivity().getCurrentTabModel().getCount();
899 ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 3);
900 assertEquals("wrong count after new tabs", tabCount + 3,
901 getActivity().getCurrentTabModel().getCount());
902
903 showOverviewAndWaitForAnimation();
904 swipeToCloseNTabs(3, false, false, SWIPE_TO_LEFT_DIRECTION);
905
906 assertEquals("Wrong tab counts after closing a few of them",
907 tabCount, getActivity().getCurrentTabModel().getCount());
908 }
909
910 /**
911 * Test closing few tabs by swiping them in Overview landscape mode.
912 */
913 @MediumTest
914 @Feature({"Android-TabSwitcher", "Main"})
915 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
916 public void testCloseTabLandscape() throws InterruptedException {
917 startMainActivityWithURL(TestHttpServerClient.getUrl("chrome/test/data/a ndroid/test.html"));
918
919 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
920
921 int tabCount = getActivity().getCurrentTabModel().getCount();
922 ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 3);
923 assertEquals("wrong count after new tabs", tabCount + 3,
924 getActivity().getCurrentTabModel().getCount());
925
926 showOverviewAndWaitForAnimation();
927 swipeToCloseTab(0, true, false, SWIPE_TO_LEFT_DIRECTION);
928 swipeToCloseTab(0, true, false, SWIPE_TO_LEFT_DIRECTION);
929 swipeToCloseTab(0, true, false, SWIPE_TO_LEFT_DIRECTION);
930
931 assertEquals("Wrong tab counts after closing a few of them",
932 tabCount, getActivity().getCurrentTabModel().getCount());
933 }
934
935 /**
936 * Test close Incognito tab by swiping in Overview Portrait mode.
937 */
938 @MediumTest
939 @Feature({"Android-TabSwitcher"})
940 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
941 public void testCloseIncognitoTabPortrait() throws InterruptedException {
942 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
943 newIncognitoTabsFromMenu(2);
944
945 showOverviewAndWaitForAnimation();
946 UiUtils.settleDownUI(getInstrumentation());
947 swipeToCloseNTabs(2, false, true, SWIPE_TO_LEFT_DIRECTION);
948 }
949
950 /**
951 * Test close 5 Incognito tabs by swiping in Overview Portrait mode.
952 */
953 @Feature({"Android-TabSwitcher"})
954 @MediumTest
955 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
956 public void testCloseFiveIncognitoTabPortrait() throws InterruptedException {
957 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
958 newIncognitoTabsFromMenu(5);
959
960 showOverviewAndWaitForAnimation();
961 UiUtils.settleDownUI(getInstrumentation());
962 swipeToCloseNTabs(5, false, true, SWIPE_TO_LEFT_DIRECTION);
963 }
964
965 /**
966 * Simple swipe gesture should not close tabs when two Tabstacks are open in Overview mode.
967 * Test in Portrait Mode.
968 */
969 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
970 @MediumTest
971 @Feature({"Android-TabSwitcher"})
972 public void testSwitchTabStackWithoutClosingTabsInPortrait() throws Interrup tedException {
973 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
974 newIncognitoTabFromMenu();
975 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
976
977 showOverviewAndWaitForAnimation();
978 UiUtils.settleDownUI(getInstrumentation());
979 final int normalTabCount = getLayoutTabInStackCount(false);
980 final int incognitoTabCount = getLayoutTabInStackCount(true);
981
982 LayoutManagerChrome layoutManager = updateTabsViewSize();
983
984 // Swipe to Incognito Tabs.
985 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMainThread(layo utManager,
986 mTabsViewWidthDp - 20 , mTabsViewHeightDp / 2 ,
987 SWIPE_TO_LEFT_DIRECTION * mTabsViewWidthDp, 0));
988 UiUtils.settleDownUI(getInstrumentation());
989 assertTrue("Tabs Stack should have been changed to incognito.",
990 getActivity().getCurrentTabModel().isIncognito());
991 assertEquals("Normal tabs count should be unchanged while switching to i ncognito tabs.",
992 normalTabCount, getLayoutTabInStackCount(false));
993
994 // Swipe to regular Tabs.
995 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMainThread(layo utManager,
996 20, mTabsViewHeightDp / 2,
997 SWIPE_TO_RIGHT_DIRECTION * mTabsViewWidthDp, 0));
998 UiUtils.settleDownUI(getInstrumentation());
999 assertEquals("Incognito tabs count should be unchanged while switching b ack to normal "
1000 + "tab stack.", incognitoTabCount, getLayoutTabInStackCount(true ));
1001 assertFalse("Tabs Stack should have been changed to regular tabs.",
1002 getActivity().getCurrentTabModel().isIncognito());
1003 assertEquals("Normal tabs count should be unchanged while switching back to normal tabs.",
1004 normalTabCount, getLayoutTabInStackCount(false));
1005 }
1006
1007 /**
1008 * Simple swipe gesture should not close tabs when two Tabstacks are open in Overview mode.
1009 * Test in Landscape Mode.
1010 */
1011 /*
1012 @MediumTest
1013 @Feature({"Android-TabSwitcher"})
1014 Bug http://crbug.com/157259
1015 */
1016 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
1017 @DisabledTest
1018 public void testSwitchTabStackWithoutClosingTabsInLandscape() throws Interru ptedException {
1019 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
1020 newIncognitoTabFromMenu();
1021 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1022
1023 showOverviewAndWaitForAnimation();
1024 UiUtils.settleDownUI(getInstrumentation());
1025 final int normalTabCount = getLayoutTabInStackCount(false);
1026 final int incognitoTabCount = getLayoutTabInStackCount(true);
1027
1028 LayoutManagerChrome layoutManager = updateTabsViewSize();
1029
1030 // Swipe to Incognito Tabs.
1031 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMainThread(layo utManager,
1032 mTabsViewWidthDp / 2 , mTabsViewHeightDp - 20 ,
1033 0, SWIPE_TO_LEFT_DIRECTION * mTabsViewWidthDp));
1034 UiUtils.settleDownUI(getInstrumentation());
1035 assertTrue("Tabs Stack should have been changed to incognito.",
1036 getActivity().getCurrentTabModel().isIncognito());
1037 assertEquals("Normal tabs count should be unchanged while switching to i ncognito tabs.",
1038 normalTabCount, getLayoutTabInStackCount(false));
1039
1040 // Swipe to regular Tabs.
1041 getInstrumentation().runOnMainSync(new SimulateTabSwipeOnMainThread(layo utManager,
1042 mTabsViewWidthDp / 2, 20,
1043 0, SWIPE_TO_RIGHT_DIRECTION * mTabsViewWidthDp));
1044 UiUtils.settleDownUI(getInstrumentation());
1045 assertEquals("Incognito tabs count should be unchanged while switching b ack to normal "
1046 + "tab stack.", incognitoTabCount, getLayoutTabInStackCount(true ));
1047 assertFalse("Tabs Stack should have been changed to regular tabs.",
1048 getActivity().getCurrentTabModel().isIncognito());
1049 assertEquals("Normal tabs count should be unchanged while switching back to normal tabs.",
1050 normalTabCount, getLayoutTabInStackCount(false));
1051 }
1052
1053 /**
1054 * Test close Incognito tab by swiping in Overview Landscape mode.
1055 */
1056 @MediumTest
1057 @Feature({"Android-TabSwitcher"})
1058 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
1059 public void testCloseIncognitoTabLandscape() throws InterruptedException {
1060 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
1061 newIncognitoTabFromMenu();
1062
1063 showOverviewAndWaitForAnimation();
1064 UiUtils.settleDownUI(getInstrumentation());
1065 swipeToCloseTab(0, true, true, SWIPE_TO_LEFT_DIRECTION);
1066 }
1067
1068 /**
1069 * Test close 5 Incognito tabs by swiping in Overview Landscape mode.
1070 */
1071 @MediumTest
1072 @Feature({"Android-TabSwitcher"})
1073 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
1074 public void testCloseFiveIncognitoTabLandscape() throws InterruptedException {
1075 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
1076 newIncognitoTabsFromMenu(5);
1077
1078 showOverviewAndWaitForAnimation();
1079 UiUtils.settleDownUI(getInstrumentation());
1080 swipeToCloseNTabs(5, true, true, SWIPE_TO_LEFT_DIRECTION);
1081 }
1082
1083 /**
1084 * Test that we can safely close a tab during a fling (http://b/issue?id=536 4043)
1085 */
1086 @SmallTest
1087 @Feature({"Android-TabSwitcher"})
1088 public void testCloseTabDuringFling() throws InterruptedException {
1089 loadUrlInNewTab(TestHttpServerClient.getUrl(
1090 "chrome/test/data/android/tabstest/text_page.html"));
1091 getInstrumentation().runOnMainSync(new Runnable() {
1092 @Override
1093 public void run() {
1094 ContentViewCore view = getActivity().getActivityTab().getContent ViewCore();
1095 view.flingForTest(SystemClock.uptimeMillis(), 0, 0, 0, -2000);
1096 }
1097 });
1098 ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
1099 }
1100
1101 /**
1102 * Flaky on instrumentation-yakju-clankium-ics. See https://crbug.com/431296 .
1103 * @Restriction(RESTRICTION_TYPE_PHONE)
1104 * @MediumTest
1105 * @Feature({"Android-TabSwitcher"})
1106 */
1107 @FlakyTest
1108 public void testQuickSwitchBetweenTabAndSwitcherMode() throws InterruptedExc eption {
1109 final String[] urls = {
1110 TestHttpServerClient.getUrl("chrome/test/data/android/navigate/o ne.html"),
1111 TestHttpServerClient.getUrl("chrome/test/data/android/navigate/t wo.html"),
1112 TestHttpServerClient.getUrl("chrome/test/data/android/navigate/t hree.html")};
1113
1114 for (String url : urls) {
1115 loadUrlInNewTab(url);
1116 }
1117
1118 int lastUrlIndex = urls.length - 1;
1119
1120 View button = getActivity().findViewById(R.id.tab_switcher_button);
1121 assertNotNull("Could not find 'tab_switcher_button'", button);
1122
1123 for (int i = 0; i < 15; i++) {
1124 singleClickView(button, button.getWidth() / 2, button.getHeight() / 2);
1125 // Switch back to the tab view from the tab-switcher mode.
1126 singleClickView(button, button.getWidth() / 2, button.getHeight() / 2);
1127
1128 assertEquals("URL mismatch after switching back to the tab from tab- switch mode",
1129 urls[lastUrlIndex], getActivity().getActivityTab().getUrl()) ;
1130 }
1131 }
1132
1133 /**
1134 * Open an incognito tab from menu and verify its property.
1135 */
1136 @MediumTest
1137 @Feature({"Android-TabSwitcher"})
1138 public void testOpenIncognitoTab() throws InterruptedException {
1139 newIncognitoTabFromMenu();
1140
1141 assertTrue("Current Tab should be an incognito tab.",
1142 getActivity().getActivityTab().isIncognito());
1143 }
1144
1145 /**
1146 * Test NewTab button on the browser toolbar.
1147 * Restricted to phones due crbug.com/429671.
1148 */
1149 @MediumTest
1150 @Feature({"Android-TabSwitcher"})
1151 @Restriction(RESTRICTION_TYPE_PHONE)
1152 public void testNewTabButton() throws InterruptedException {
1153 MenuUtils.invokeCustomMenuActionSync(getInstrumentation(), getActivity() ,
1154 R.id.close_all_tabs_menu_id);
1155 UiUtils.settleDownUI(getInstrumentation());
1156
1157 assertTrue("Should be in overview mode", CriteriaHelper.pollForCriteria( new Criteria() {
1158 @Override
1159 public boolean isSatisfied() {
1160 return getActivity().isInOverviewMode();
1161 }
1162 }));
1163
1164 int initialTabCount = getActivity().getCurrentTabModel().getCount();
1165 assertEquals("Tab count is expected to be 0 after closing all the tabs",
1166 0, initialTabCount);
1167
1168 ChromeTabUtils.clickNewTabButton(this, this);
1169
1170 int newTabCount = getActivity().getCurrentTabModel().getCount();
1171 assertEquals("Tab count is expected to be 1 after clicking Newtab button ",
1172 1, newTabCount);
1173 }
1174
1175 @MediumTest
1176 @Feature({"Android-TabSwitcher"})
1177 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1178 public void testToolbarSwipeOnlyTab() throws InterruptedException {
1179 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1180
1181 assertEquals("Incorrect starting index", 0, tabModel.index());
1182 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, false);
1183 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 0, false);
1184 }
1185
1186 @MediumTest
1187 @Feature({"Android-TabSwitcher"})
1188 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1189 public void testToolbarSwipePrevTab() throws InterruptedException {
1190 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1191 UiUtils.settleDownUI(getInstrumentation());
1192
1193 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1194
1195 assertEquals("Incorrect starting index", 1, tabModel.index());
1196 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, true);
1197 }
1198
1199 @MediumTest
1200 @Feature({"Android-TabSwitcher"})
1201 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1202 public void testToolbarSwipeNextTab() throws InterruptedException {
1203 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1204 ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0);
1205 UiUtils.settleDownUI(getInstrumentation());
1206
1207 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1208
1209 assertEquals("Incorrect starting index", 0, tabModel.index());
1210 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, true);
1211 }
1212
1213 @MediumTest
1214 @Feature({"Android-TabSwitcher"})
1215 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1216 public void testToolbarSwipePrevTabNone() throws InterruptedException {
1217 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1218 ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0);
1219 UiUtils.settleDownUI(getInstrumentation());
1220
1221 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1222
1223 assertEquals("Incorrect starting index", 0, tabModel.index());
1224 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, false);
1225 }
1226
1227 @MediumTest
1228 @Feature({"Android-TabSwitcher"})
1229 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1230 public void testToolbarSwipeNextTabNone() throws InterruptedException {
1231 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1232 UiUtils.settleDownUI(getInstrumentation());
1233
1234 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1235
1236 assertEquals("Incorrect starting index", 1, tabModel.index());
1237 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, false);
1238 }
1239
1240 /**
1241 * Bug: crbug.com/392656
1242 * @MediumTest
1243 * @Feature({"Android-TabSwitcher"})
1244 * @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1245 */
1246 @DisabledTest
1247 public void testToolbarSwipeNextThenPrevTab() throws InterruptedException {
1248 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1249 ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0);
1250 UiUtils.settleDownUI(getInstrumentation());
1251
1252 final TabModel tabModel = getActivity().getTabModelSelector().getModel(f alse);
1253
1254 assertEquals("Incorrect starting index", 0, tabModel.index());
1255 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, true);
1256
1257 assertEquals("Incorrect starting index", 1, tabModel.index());
1258 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, true);
1259 }
1260
1261 /**
1262 * Bug: crbug.com/392656
1263 * @MediumTest
1264 * @Feature({"Android-TabSwitcher"})
1265 * @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1266 */
1267 @DisabledTest
1268 public void testToolbarSwipeNextThenPrevTabIncognito() throws InterruptedExc eption {
1269 newIncognitoTabFromMenu();
1270 newIncognitoTabFromMenu();
1271 ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0);
1272 UiUtils.settleDownUI(getInstrumentation());
1273
1274 final TabModel tabModel = getActivity().getTabModelSelector().getModel(t rue);
1275
1276 assertEquals("Incorrect starting index", 0, tabModel.index());
1277 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, true);
1278
1279 assertEquals("Incorrect starting index", 1, tabModel.index());
1280 runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, true);
1281 }
1282
1283 private void runToolbarSideSwipeTestOnCurrentModel(ScrollDirection direction , int finalIndex,
1284 boolean expectsSelection) throws InterruptedException {
1285 final CallbackHelper selectCallback = new CallbackHelper();
1286 final int id = getActivity().getCurrentTabModel().getTabAt(finalIndex).g etId();
1287 final TabModelObserver observer = new EmptyTabModelObserver() {
1288 @Override
1289 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
1290 if (tab.getId() == id) selectCallback.notifyCalled();
1291 }
1292 };
1293
1294 if (expectsSelection) {
1295 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1296 @Override
1297 public void run() {
1298 TabModelSelector selector = getActivity().getTabModelSelecto r();
1299 for (TabModel tabModel : selector.getModels()) {
1300 tabModel.addObserver(observer);
1301 }
1302 }
1303 });
1304 }
1305
1306 performToolbarSideSwipe(direction);
1307 waitForStaticLayout();
1308 assertEquals("Index after toolbar side swipe is incorrect", finalIndex,
1309 getActivity().getCurrentTabModel().index());
1310
1311 if (expectsSelection) {
1312 try {
1313 selectCallback.waitForCallback(0);
1314 } catch (TimeoutException e) {
1315 Assert.fail("Tab selected event was never received");
1316 }
1317 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1318 @Override
1319 public void run() {
1320 TabModelSelector selector = getActivity().getTabModelSelecto r();
1321 for (TabModel tabModel : selector.getModels()) {
1322 tabModel.removeObserver(observer);
1323 }
1324 }
1325 });
1326 }
1327 }
1328
1329
1330 private void performToolbarSideSwipe(ScrollDirection direction) {
1331 assertTrue("Unexpected direction for side swipe " + direction,
1332 direction == ScrollDirection.LEFT || direction == ScrollDirectio n.RIGHT);
1333 final View toolbar = getActivity().findViewById(R.id.toolbar);
1334 int[] toolbarPos = new int[2];
1335 toolbar.getLocationOnScreen(toolbarPos);
1336 final int width = toolbar.getWidth();
1337 final int height = toolbar.getHeight();
1338
1339 final int fromX = toolbarPos[0] + width / 2;
1340 final int toX = toolbarPos[0] + (direction == ScrollDirection.LEFT ? 0 : width);
1341 final int y = toolbarPos[1] + height / 2;
1342 final int stepCount = 10;
1343
1344 long downTime = SystemClock.uptimeMillis();
1345 dragStart(fromX, y, downTime);
1346 dragTo(fromX, toX, y, y, stepCount, downTime);
1347 dragEnd(toX, y, downTime);
1348 }
1349
1350 private void waitForStaticLayout() throws InterruptedException {
1351 final Callable<Boolean> callable = new Callable<Boolean>() {
1352 @Override
1353 public Boolean call() throws Exception {
1354 CompositorViewHolder compositorViewHolder = (CompositorViewHolde r)
1355 getActivity().findViewById(R.id.compositor_view_holder);
1356 LayoutManager layoutManager = compositorViewHolder.getLayoutMana ger();
1357
1358 return layoutManager.getActiveLayout() instanceof StaticLayout;
1359 }
1360 };
1361
1362 assertTrue("Static Layout never selected after side swipe",
1363 CriteriaHelper.pollForCriteria(new Criteria() {
1364 @Override
1365 public boolean isSatisfied() {
1366 return ThreadUtils.runOnUiThreadBlockingNoException(call able);
1367 }
1368 }));
1369 }
1370
1371 /**
1372 * Test that swipes and tab transitions are not causing URL bar to be focuse d.
1373 */
1374 @MediumTest
1375 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
1376 @Feature({"Android-TabSwitcher"})
1377 public void testOSKIsNotShownDuringSwipe() throws InterruptedException {
1378 final View urlBar = getActivity().findViewById(R.id.url_bar);
1379 final LayoutManagerChrome layoutManager = updateTabsViewSize();
1380 final EdgeSwipeHandler edgeSwipeHandler = layoutManager.getTopSwipeHandl er();
1381
1382 UiUtils.settleDownUI(getInstrumentation());
1383 getInstrumentation().runOnMainSync(
1384 new Runnable() {
1385 @Override
1386 public void run() {
1387 urlBar.requestFocus();
1388 }
1389 });
1390 UiUtils.settleDownUI(getInstrumentation());
1391
1392 getInstrumentation().runOnMainSync(
1393 new Runnable() {
1394 @Override
1395 public void run() {
1396 urlBar.clearFocus();
1397 }
1398 });
1399 UiUtils.settleDownUI(getInstrumentation());
1400 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1401 UiUtils.settleDownUI(getInstrumentation());
1402
1403 assertFalse("Keyboard somehow got shown",
1404 org.chromium.ui.UiUtils.isKeyboardShowing(getActivity(), urlBar) );
1405
1406 ThreadUtils.runOnUiThread(new Runnable() {
1407 @Override
1408 public void run() {
1409 edgeSwipeHandler.swipeStarted(ScrollDirection.RIGHT, 0, 0);
1410 float swipeXChange = mTabsViewWidthDp / 2.f;
1411 edgeSwipeHandler.swipeUpdated(
1412 swipeXChange, 0.f, swipeXChange, 0.f, swipeXChange, 0.f) ;
1413 }
1414 });
1415
1416 assertTrue("Layout still requesting Tab Android view be attached",
1417 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1418 @Override
1419 public boolean isSatisfied() {
1420 LayoutManager driver = getActivity().getLayoutManager();
1421 return !driver.getActiveLayout().shouldDisplayContentOve rlay();
1422 }
1423 }));
1424
1425 ThreadUtils.runOnUiThread(new Runnable() {
1426 @Override
1427 public void run() {
1428 assertFalse("Keyboard should be hidden while swiping",
1429 org.chromium.ui.UiUtils.isKeyboardShowing(getActivity(), urlBar));
1430 edgeSwipeHandler.swipeFinished();
1431 }
1432 });
1433
1434 assertTrue("Layout not requesting Tab Android view be attached",
1435 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1436 @Override
1437 public boolean isSatisfied() {
1438 LayoutManager driver = getActivity().getLayoutManager();
1439 return driver.getActiveLayout().shouldDisplayContentOver lay();
1440 }
1441 }));
1442
1443 assertFalse("Keyboard should not be shown",
1444 org.chromium.ui.UiUtils.isKeyboardShowing(getActivity(), urlBar) );
1445 }
1446
1447 /**
1448 * Test that orientation changes cause the live tab reflow.
1449 */
1450 @MediumTest
1451 @Feature({"Android-TabSwitcher"})
1452 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
1453 public void testOrientationChangeCausesLiveTabReflowInNormalView()
1454 throws InterruptedException, TimeoutException {
1455 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
1456 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1457 loadUrl(RESIZE_TEST_URL);
1458 final WebContents webContents =
1459 getActivity().getActivityTab().getWebContents();
1460
1461 JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
1462 "resizeHappened = fals e;");
1463 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
1464 UiUtils.settleDownUI(getInstrumentation());
1465 assertEquals("onresize event wasn't received by the tab (normal view)",
1466 "true",
1467 JavaScriptUtils.executeJavaScriptAndWaitForResult(
1468 webContents, "resizeHappened",
1469 WAIT_RESIZE_TIMEOUT_MS, TimeUnit.MILLISECONDS));
1470 }
1471
1472 /**
1473 * Test that orientation changes cause the live tab reflow.
1474 */
1475 @MediumTest
1476 @Feature({"Android-TabSwitcher"})
1477 @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
1478 public void testOrientationChangeCausesLiveTabReflowInTabSwitcher()
1479 throws InterruptedException, TimeoutException {
1480 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
1481 ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
1482 loadUrl(RESIZE_TEST_URL);
1483 final WebContents webContents =
1484 getActivity().getActivityTab().getWebContents();
1485
1486 showOverviewAndWaitForAnimation();
1487 JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
1488 "resizeHappened = fals e;");
1489 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LA NDSCAPE);
1490 UiUtils.settleDownUI(getInstrumentation());
1491 assertEquals("onresize event wasn't received by the live tab (tabswitche r, to Landscape)",
1492 "true",
1493 JavaScriptUtils.executeJavaScriptAndWaitForResult(
1494 webContents, "resizeHappened",
1495 WAIT_RESIZE_TIMEOUT_MS, TimeUnit.MILLISECONDS));
1496
1497 JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
1498 "resizeHappened = fals e;");
1499 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PO RTRAIT);
1500 UiUtils.settleDownUI(getInstrumentation());
1501 assertEquals("onresize event wasn't received by the live tab (tabswitche r, to Portrait)",
1502 "true",
1503 JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
1504 "resizeHappened", WAIT_RESIZE_TIMEOUT_MS, TimeUnit.MILLI SECONDS));
1505 }
1506
1507 @MediumTest
1508 @Feature({"Android-TabSwitcher"})
1509 public void testLastClosedUndoableTabGetsHidden() {
1510 final TabModel model = getActivity().getTabModelSelector().getCurrentMod el();
1511 final Tab tab = TabModelUtils.getCurrentTab(model);
1512
1513 assertEquals("Too many tabs at startup", 1, model.getCount());
1514
1515 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1516 @Override
1517 public void run() {
1518 model.closeTab(tab, false, false, true);
1519 }
1520 });
1521
1522 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1523 @Override
1524 public void run() {
1525 assertTrue("Tab close is not undoable", model.isClosurePending(t ab.getId()));
1526 assertTrue("Tab was not hidden", tab.isHidden());
1527 }
1528 });
1529 }
1530
1531 @MediumTest
1532 @Feature({"Android-TabSwitcher"})
1533 public void testLastClosedTabTriggersNotifyChangedCall() {
1534 final TabModel model = getActivity().getTabModelSelector().getCurrentMod el();
1535 final Tab tab = TabModelUtils.getCurrentTab(model);
1536 final TabModelSelector selector = getActivity().getTabModelSelector();
1537 mNotifyChangedCalled = false;
1538
1539 selector.addObserver(new EmptyTabModelSelectorObserver() {
1540 @Override
1541 public void onChange() {
1542 mNotifyChangedCalled = true;
1543 }
1544 });
1545
1546 assertEquals("Too many tabs at startup", 1, model.getCount());
1547
1548 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1549 @Override
1550 public void run() {
1551 model.closeTab(tab, false, false, true);
1552 }
1553 });
1554
1555 assertTrue("notifyChanged() was not called", mNotifyChangedCalled);
1556 }
1557
1558 @Smoke
1559 @Feature({"Android-TabSwitcher"})
1560 public void testTabsAreDestroyedOnModelDestruction() throws InterruptedExcep tion {
1561 startMainActivityOnBlankPage();
1562 final TabModelSelectorImpl selector =
1563 (TabModelSelectorImpl) getActivity().getTabModelSelector();
1564 final Tab tab = getActivity().getActivityTab();
1565
1566 final AtomicBoolean webContentsDestroyCalled = new AtomicBoolean();
1567
1568 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1569 @Override
1570 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
1571 public void run() {
1572 @SuppressWarnings("unused") // Avoid GC of observer
1573 WebContentsObserver observer = new WebContentsObserver(tab.getWe bContents()) {
1574 @Override
1575 public void destroy() {
1576 super.destroy();
1577 webContentsDestroyCalled.set(true);
1578 }
1579 };
1580
1581 assertNotNull("No initial tab at startup", tab);
1582 assertNotNull("Tab does not have a web contents", tab.getWebCont ents());
1583 assertTrue("Tab is destroyed", tab.isInitialized());
1584
1585 selector.destroy();
1586
1587 assertNull("Tab still has a web contents", tab.getWebContents()) ;
1588 assertFalse("Tab was not destroyed", tab.isInitialized());
1589 }
1590 });
1591
1592 assertTrue("WebContentsObserver was never destroyed", webContentsDestroy Called.get());
1593 }
1594
1595 @Override
1596 public void startMainActivity() throws InterruptedException {
1597 float dpToPx = getInstrumentation().getContext().getResources().getDispl ayMetrics().density;
1598 mPxToDp = 1.0f / dpToPx;
1599
1600 // Exclude the tests that can launch directly to a page other than the N TP.
1601 if (getName().equals("testOpenAndCloseNewTabButton")
1602 || getName().equals("testSwitchToTabThatDoesNotHaveThumbnail")
1603 || getName().equals("testCloseTabPortrait")
1604 || getName().equals("testCloseTabLandscape")
1605 || getName().equals("testTabsAreDestroyedOnModelDestruction")) {
1606 return;
1607 }
1608
1609 if (getName().equals("testSpawnPopupOnBackgroundTab")) {
1610 CommandLine.getInstance().appendSwitch(ContentSwitches.DISABLE_POPUP _BLOCKING);
1611 }
1612 startMainActivityFromLauncher();
1613 }
1614 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698