@SmallTest
  @Feature({"AndroidWebView"})
  public void testNullContentsClientClickableContent() throws Throwable {
    try {
      // The test will fire real intents through the test activity.
      // Need to temporarily suppress startActivity otherwise there will be a
      // handler selection window and the test can't dismiss that.
      getActivity().setIgnoreStartActivity(true);
      setupWithProvidedContentsClient(
          new NullContentsClient() {
            @Override
            public boolean hasWebViewClient() {
              return false;
            }
          });
      final String pageTitle = "Click Title";
      final String testEmail = "*****@*****.**";
      final String testUrl =
          mWebServer.setResponse(
              "/email_test.html",
              "<html><head><title>"
                  + pageTitle
                  + "</title></head>"
                  + "<body><span id='email'>"
                  + testEmail
                  + "</span></body>",
              null);

      // JS is required for the click simulator.
      mAwContents.getSettings().setJavaScriptEnabled(true);
      loadUrlAsync(mAwContents, testUrl);
      pollOnUiThread(
          new Callable<Boolean>() {
            @Override
            public Boolean call() {
              return mAwContents.getTitle().equals(pageTitle);
            }
          });

      // Clicking on an email should create an intent.
      DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "email");
      pollOnUiThread(
          new Callable<Boolean>() {
            @Override
            public Boolean call() {
              return getActivity().getLastSentIntent() != null;
            }
          });
      assertEquals(
          "mailto:" + testEmail.replace("@", "%40"),
          getActivity().getLastSentIntent().getData().toString());
    } finally {
      getActivity().setIgnoreStartActivity(false);
    }
  }
  @SmallTest
  @Feature({"AndroidWebView"})
  public void testClickableContentInIframe() throws Throwable {
    standardSetup();

    final String pageTitle = "Click Title";
    final String testEmail = "*****@*****.**";
    final String testUrl =
        mWebServer.setResponse(
            "/email_test.html",
            "<html><head><title>"
                + pageTitle
                + "</title></head>"
                + "<body style='margin:0;'>"
                + " <iframe style='border:none;' srcdoc=\""
                + "   <body style='margin:0;'><span id='email'>"
                + testEmail
                + "</span></body>"
                + "\" src='iframe.html'></iframe>"
                + "</body>",
            null);

    // JS is required for the click simulator.
    mAwContents.getSettings().setJavaScriptEnabled(true);
    loadUrlAsync(mAwContents, testUrl);
    pollOnUiThread(
        new Callable<Boolean>() {
          @Override
          public Boolean call() {
            return mAwContents.getTitle().equals(pageTitle);
          }
        });

    int callCount = mShouldOverrideUrlLoadingHelper.getCallCount();
    DOMUtils.clickNodeByJs(
        this,
        mAwContents.getContentViewCore(),
        "window.frames[0].document.getElementById('email')");
    mShouldOverrideUrlLoadingHelper.waitForCallback(callCount);
    assertEquals(
        "mailto:" + testEmail.replace("@", "%40"),
        mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertFalse(mShouldOverrideUrlLoadingHelper.isRedirect());
    assertTrue(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertFalse(mShouldOverrideUrlLoadingHelper.isMainFrame());
  }
 public ContentViewCore getContentViewCore() {
   return mAwContents.getContentViewCore();
 }
  @SmallTest
  @Feature({"AndroidWebView"})
  public void testNullContentsClientOpenLink() throws Throwable {
    try {
      // The test will fire real intents through the test activity.
      // Need to temporarily suppress startActivity otherwise there will be a
      // handler selection window and the test can't dismiss that.
      getActivity().setIgnoreStartActivity(true);
      final String testUrl =
          mWebServer.setResponse(
              "/" + CommonResources.ABOUT_FILENAME,
              CommonResources.ABOUT_HTML,
              CommonResources.getTextHtmlHeaders(true));
      setupWithProvidedContentsClient(
          new NullContentsClient() {
            @Override
            public boolean hasWebViewClient() {
              return false;
            }
          });
      mAwContents.getSettings().setJavaScriptEnabled(true);
      final String pageTitle = "Click Title";
      final String htmlWithLink =
          "<html><title>"
              + pageTitle
              + "</title>"
              + "<body><a id='link' href='"
              + testUrl
              + "'>Click this!</a></body></html>";
      final String urlWithLink =
          mWebServer.setResponse(
              "/html_with_link.html", htmlWithLink, CommonResources.getTextHtmlHeaders(true));

      loadUrlAsync(mAwContents, urlWithLink);
      pollOnUiThread(
          new Callable<Boolean>() {
            @Override
            public Boolean call() {
              return mAwContents.getTitle().equals(pageTitle);
            }
          });
      // Executing JS code that tries to navigate somewhere should not create an intent.
      assertEquals(
          "\"" + testUrl + "\"",
          JSUtils.executeJavaScriptAndWaitForResult(
              this,
              mAwContents,
              new OnEvaluateJavaScriptResultHelper(),
              "document.location.href='" + testUrl + "'"));
      assertNull(getActivity().getLastSentIntent());

      // Clicking on a link should create an intent.
      DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "link");
      pollOnUiThread(
          new Callable<Boolean>() {
            @Override
            public Boolean call() {
              return getActivity().getLastSentIntent() != null;
            }
          });
      assertEquals(testUrl, getActivity().getLastSentIntent().getData().toString());
    } finally {
      getActivity().setIgnoreStartActivity(false);
    }
  }
  /**
   * Worker method for the various redirect tests.
   *
   * <p>Calling this will first load the redirect URL built from redirectFilePath, query and
   * locationFilePath and assert that we get a override callback for the destination. The second
   * part of the test loads a page that contains a link which points at the redirect URL. We expect
   * two callbacks - one for the redirect link and another for the destination.
   */
  private void doTestCalledOnRedirect(
      String redirectUrl, String redirectTarget, boolean serverSideRedirect) throws Throwable {
    standardSetup();
    final String pageTitle = "doTestCalledOnRedirect page";
    final String pageWithLinkToRedirectUrl =
        addPageToTestServer(
            "/page_with_link_to_redirect.html",
            CommonResources.makeHtmlPageWithSimpleLinkTo(
                "<title>" + pageTitle + "</title>", redirectUrl));
    enableJavaScriptOnUiThread(mAwContents);

    // There is a slight difference between navigations caused by calling load and navigations
    // caused by clicking on a link:
    //
    //  * when using load the navigation is treated as if it came from the URL bar (has the
    //    navigation type TYPED, doesn't have the has_user_gesture flag); thus the navigation
    //    itself is not reported via shouldOverrideUrlLoading, but then if it has caused a
    //    redirect, the redirect itself is reported;
    //
    //  * when clicking on a link the navigation has the LINK type and has_user_gesture depends
    //    on whether it was a real click done by the user, or has it been done by JS; on click,
    //    both the initial navigation and the redirect are reported via
    //    shouldOverrideUrlLoading.
    int directLoadCallCount = mShouldOverrideUrlLoadingHelper.getCallCount();
    loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), redirectUrl);

    mShouldOverrideUrlLoadingHelper.waitForCallback(directLoadCallCount, 1);
    assertEquals(redirectTarget, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertEquals(serverSideRedirect, mShouldOverrideUrlLoadingHelper.isRedirect());
    assertFalse(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());

    // Test clicking with JS, hasUserGesture must be false.
    int indirectLoadCallCount = mShouldOverrideUrlLoadingHelper.getCallCount();
    loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithLinkToRedirectUrl);
    assertEquals(indirectLoadCallCount, mShouldOverrideUrlLoadingHelper.getCallCount());

    clickOnLinkUsingJs();

    mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 1);
    assertEquals(redirectUrl, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertFalse(mShouldOverrideUrlLoadingHelper.isRedirect());
    assertFalse(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());
    mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount + 1, 1);
    assertEquals(redirectTarget, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertEquals(serverSideRedirect, mShouldOverrideUrlLoadingHelper.isRedirect());
    assertFalse(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());

    // Make sure the redirect target page has finished loading.
    pollOnUiThread(
        new Callable<Boolean>() {
          @Override
          public Boolean call() {
            return !mAwContents.getTitle().equals(pageTitle);
          }
        });
    indirectLoadCallCount = mShouldOverrideUrlLoadingHelper.getCallCount();
    loadUrlAsync(mAwContents, pageWithLinkToRedirectUrl);
    pollOnUiThread(
        new Callable<Boolean>() {
          @Override
          public Boolean call() {
            return mAwContents.getTitle().equals(pageTitle);
          }
        });
    assertEquals(indirectLoadCallCount, mShouldOverrideUrlLoadingHelper.getCallCount());

    // Simulate touch, hasUserGesture must be true only on the first call.
    DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "link");

    mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 1);
    assertEquals(redirectUrl, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertFalse(mShouldOverrideUrlLoadingHelper.isRedirect());
    assertTrue(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());
    mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount + 1, 1);
    assertEquals(redirectTarget, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
    assertEquals(serverSideRedirect, mShouldOverrideUrlLoadingHelper.isRedirect());
    assertFalse(mShouldOverrideUrlLoadingHelper.hasUserGesture());
    assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());
  }