@MediumTest
  @Feature({"AppBanners"})
  public void testBannerAppearsThenDoesNotAppearAgainForMonths() throws Exception {
    // Visit a site that requests a banner.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(1));
    assertTrue(waitUntilNoInfoBarsExist());

    // Indicate a day has passed, then revisit the page.
    AppBannerManager.setTimeDeltaForTesting(1);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(2));
    assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));

    // Revisit the page to make the banner go away, but don't explicitly dismiss it.
    // This hides the banner for a few months.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(3));
    assertTrue(waitUntilNoInfoBarsExist());

    // Wait a month until revisiting the page.
    AppBannerManager.setTimeDeltaForTesting(31);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(4));
    assertTrue(waitUntilNoInfoBarsExist());

    AppBannerManager.setTimeDeltaForTesting(32);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(5));
    assertTrue(waitUntilNoInfoBarsExist());

    // Wait two months until revisiting the page, which should pop up the banner.
    AppBannerManager.setTimeDeltaForTesting(61);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(6));
    assertTrue(waitUntilNoInfoBarsExist());

    AppBannerManager.setTimeDeltaForTesting(62);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(7));
    assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
  }
  @Override
  protected void setUp() throws Exception {
    mPackageManager = new TestPackageManager();
    AppBannerManager.setIsEnabledForTesting(true);
    AppBannerInfoBarDelegateAndroid.setPackageManagerForTesting(mPackageManager);

    super.setUp();

    // Must be set after native has loaded.
    mDetailsDelegate = new MockAppDetailsDelegate();
    ThreadUtils.runOnUiThreadBlocking(
        new Runnable() {
          @Override
          public void run() {
            AppBannerManager.setAppDetailsDelegate(mDetailsDelegate);
          }
        });

    AppBannerManager.disableSecureSchemeCheckForTesting();

    // Navigations in this test are all of type ui::PAGE_TRANSITION_LINK, i.e. indirect.
    // Force indirect navigations to be worth the same as direct for testing.
    AppBannerManager.forceEngagementWeightsForTesting(1, 1);
  }
  @SmallTest
  @Feature({"AppBanners"})
  public void testWebAppBannerAppears() throws Exception {
    // Create a Tab that doesn't have the AppBannerManager enabled.  This prevents race
    // conditions between service worker activation and AppBannerManager getting triggered.
    // This race condition is a known problem, which is why the specs include wiggle room for
    // how many times a site must be visited.
    AppBannerManager.setIsEnabledForTesting(false);
    loadUrlInNewTab("about:blank");

    // Visit a site that can have a banner, then wait until the service worker is activated.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL)));
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                String url = getActivity().getActivityTab().getUrl();
                Uri uri = Uri.parse(url);
                return TextUtils.equals(uri.getFragment(), "sw_activated");
              }
            }));
    AppBannerManager.setIsEnabledForTesting(true);

    // Revisit the site in a new tab, which will have the AppBannerManager enabled.
    loadUrlInNewTab("about:blank");
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL)));

    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                AppBannerManager manager =
                    getActivity().getActivityTab().getAppBannerManagerForTesting();
                return !manager.isFetcherActiveForTesting();
              }
            }));
    assertTrue(waitUntilNoInfoBarsExist());

    // Indicate a day has passed, then revisit the page to show the banner.
    AppBannerManager.setTimeDeltaForTesting(1);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL)));
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                AppBannerManager manager =
                    getActivity().getActivityTab().getAppBannerManagerForTesting();
                return !manager.isFetcherActiveForTesting();
              }
            }));
    assertTrue(waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE));
  }
  @MediumTest
  @Feature({"AppBanners"})
  public void testBlockedBannerDoesNotAppearAgainForMonths() throws Exception {
    // Visit a site that requests a banner.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(1));
    assertTrue(waitUntilNoInfoBarsExist());

    // Indicate a day has passed, then revisit the page.
    InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
    final InfobarListener listener = new InfobarListener();
    container.setAnimationListener(listener);
    AppBannerManager.setTimeDeltaForTesting(1);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(2));
    assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));

    // Explicitly dismiss the banner.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                return listener.mDoneAnimating;
              }
            }));
    ArrayList<InfoBar> infobars = container.getInfoBars();
    View close = infobars.get(0).getContentWrapper().findViewById(R.id.infobar_close_button);
    TouchCommon.singleClickView(close);
    assertTrue(waitUntilNoInfoBarsExist());

    // Waiting two months shouldn't be long enough.
    AppBannerManager.setTimeDeltaForTesting(61);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(3));
    assertTrue(waitUntilNoInfoBarsExist());

    AppBannerManager.setTimeDeltaForTesting(62);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(4));
    assertTrue(waitUntilNoInfoBarsExist());

    // Waiting three months should allow banners to reappear.
    AppBannerManager.setTimeDeltaForTesting(91);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(5));
    assertTrue(waitUntilNoInfoBarsExist());

    AppBannerManager.setTimeDeltaForTesting(92);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL)));
    assertTrue(waitUntilAppDetailsRetrieved(6));
    assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
  }
  private void runFullNativeInstallPathway(String url, String expectedReferrer) throws Exception {
    // Visit a site that requests a banner.
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), url)));
    assertTrue(waitUntilAppDetailsRetrieved(1));
    assertEquals(mDetailsDelegate.mReferrer, expectedReferrer);
    assertTrue(waitUntilNoInfoBarsExist());

    // Indicate a day has passed, then revisit the page to get the banner to appear.
    InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
    final InfobarListener listener = new InfobarListener();
    container.setAnimationListener(listener);
    AppBannerManager.setTimeDeltaForTesting(1);
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new TabLoadObserver(getActivity().getActivityTab(), url)));
    assertTrue(waitUntilAppDetailsRetrieved(2));
    assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
    assertTrue(
        CriteriaHelper.pollForUIThreadCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                return listener.mDoneAnimating;
              }
            }));

    // Check that the button asks if the user wants to install the app.
    InfoBar infobar = container.getInfoBars().get(0);
    final Button button = (Button) infobar.getContentWrapper().findViewById(R.id.button_primary);
    assertEquals(NATIVE_APP_INSTALL_TEXT, button.getText());

    // Click the button to trigger the install.
    final ActivityMonitor activityMonitor =
        new ActivityMonitor(
            new IntentFilter(INSTALL_ACTION), new ActivityResult(Activity.RESULT_OK, null), true);
    getInstrumentation().addMonitor(activityMonitor);
    TouchCommon.singleClickView(button);

    // Wait for the infobar to register that the app is installing.
    final String installingText =
        getInstrumentation().getTargetContext().getString(R.string.app_banner_installing);
    assertTrue(
        CriteriaHelper.pollForCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                return getInstrumentation().checkMonitorHit(activityMonitor, 1)
                    && TextUtils.equals(button.getText(), installingText);
              }
            }));

    // Say that the package is installed.  Infobar should say that the app is ready to open.
    mPackageManager.isInstalled = true;
    final String openText =
        getInstrumentation().getTargetContext().getString(R.string.app_banner_open);
    assertTrue(
        CriteriaHelper.pollForCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                return TextUtils.equals(button.getText(), openText);
              }
            }));
  }