@Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
  @MediumTest
  public void testNewTabLoadLowEnd() throws Exception {
    launchViaLaunchDocumentInstance(false, HREF_LINK, "href link page");

    final AtomicReference<Tab> backgroundTab = new AtomicReference<Tab>();
    final CallbackHelper tabCreatedCallback = new CallbackHelper();
    final CallbackHelper tabLoadStartedCallback = new CallbackHelper();

    final DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
    selector.addObserver(
        new EmptyTabModelSelectorObserver() {
          @Override
          public void onNewTabCreated(final Tab newTab) {
            selector.removeObserver(this);
            backgroundTab.set(newTab);
            tabCreatedCallback.notifyCalled();

            assertFalse(newTab.getWebContents().isLoadingToDifferentDocument());

            newTab.addObserver(
                new EmptyTabObserver() {
                  @Override
                  public void onPageLoadStarted(Tab tab, String url) {
                    newTab.removeObserver(this);
                    tabLoadStartedCallback.notifyCalled();
                  }
                });
          }
        });

    openLinkInBackgroundTab();

    // Tab should be created, but shouldn't start loading until we switch to it.
    assertEquals(1, tabCreatedCallback.getCallCount());
    assertEquals(0, tabLoadStartedCallback.getCallCount());

    switchToTab(backgroundTab.get());

    tabLoadStartedCallback.waitForCallback(0);
  }
  /**
   * Verifies that the .setProcessInForeground() signal is called correctly as the tabs are created
   * and switched.
   */
  @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
  @LargeTest
  @Feature({"ProcessManagement"})
  public void testTabSwitching() throws Exception {
    // Create two tabs and wait until they are loaded, so that their renderers are around.
    final Tab[] tabs = new Tab[2];
    final int[] tabIds = new int[2];
    final DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
    tabIds[0] = launchViaViewIntent(false, URL_1, "Page 1");
    tabIds[1] = launchViaLaunchDocumentInstanceInBackground(false, URL_2, "Page 2");

    final TabModel tabModel = selector.getCurrentModel();
    tabs[0] = selector.getTabById(tabIds[0]);
    tabs[1] = selector.getTabById(tabIds[1]);

    getInstrumentation()
        .runOnMainSync(
            new Runnable() {
              @Override
              public void run() {
                // Make sure that the renderers were spawned.
                assertTrue(tabs[0].getContentViewCore().getCurrentRenderProcessId() > 0);
                assertTrue(tabs[1].getContentViewCore().getCurrentRenderProcessId() > 0);

                // Verify that the renderer of the foreground tab was signalled as visible.
                assertTrue(
                    mBindingManager.isInForeground(
                        tabs[0].getContentViewCore().getCurrentRenderProcessId()));
                // Verify that the renderer of the tab loaded in background was signalled as not
                // visible.
                assertTrue(
                    mBindingManager.isInBackground(
                        tabs[1].getContentViewCore().getCurrentRenderProcessId()));
              }
            });

    // Wait until the activity of tabs[1] is resumed.
    assertTrue(
        "Activity was not resumed.",
        CriteriaHelper.pollForCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                // Switch to the tab that crashed in background.
                // http://crbug.com/509866: TabModelUtils#setIndex() sometimes fails. So we need to
                // call it repeatedly.
                getInstrumentation()
                    .runOnMainSync(
                        new Runnable() {
                          @Override
                          public void run() {
                            TabModelUtils.setIndex(
                                tabModel, TabModelUtils.getTabIndexById(tabModel, tabs[1].getId()));
                          }
                        });

                return ApplicationStatus.getStateForActivity(((DocumentTab) tabs[1]).getActivity())
                    == ActivityState.RESUMED;
              }
            }));

    // Verify that the renderer visibility was flipped.
    assertTrue(
        mBindingManager.isInBackground(tabs[0].getContentViewCore().getCurrentRenderProcessId()));
    assertTrue(
        mBindingManager.isInForeground(tabs[1].getContentViewCore().getCurrentRenderProcessId()));
  }