gt:             if (mExpectedValue.equals(mReceivedValue)) return true;
context: /*
   * Copyright (C) 2012 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.webkit.cts;
  
  import android.content.Context;
  import android.cts.util.NullWebViewUtils;
  import android.cts.util.PollingCheck;
  import android.graphics.Bitmap;
  import android.location.Criteria;
  import android.location.Location;
  import android.location.LocationListener;
  import android.location.LocationManager;
  import android.location.LocationProvider;
  import android.os.Bundle;
  import android.os.Looper;
  import android.os.SystemClock;
  import android.test.ActivityInstrumentationTestCase2;
  import android.webkit.CookieManager;
  import android.webkit.CookieSyncManager;
  import android.webkit.GeolocationPermissions;
  import android.webkit.JavascriptInterface;
  import android.webkit.WebChromeClient;
  import android.webkit.WebResourceResponse;
  import android.webkit.WebView;
  import android.webkit.WebViewClient;
  import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
  import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
  
  import java.io.ByteArrayInputStream;
  import java.io.UnsupportedEncodingException;
  import java.util.concurrent.Callable;
  import java.util.Date;
  import java.util.List;
  import java.util.Random;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  import java.util.Set;
  import java.util.TreeSet;
  
  import junit.framework.Assert;
  
  public class GeolocationTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
  
      // TODO Write additional tests to cover:
      // - test that the errors are correct
      // - test that use of gps and network location is correct
  
      // The URLs does not matter since the tests will intercept the load, but it has to be a real
      // url, and different domains.
      private static final String URL_1 = "http://www.example.com";
      private static final String URL_2 = "http://www.example.org";
  
      private static final String JS_INTERFACE_NAME = "Android";
      private static final int POLLING_TIMEOUT = 60 * 1000;
      private static final int LOCATION_THREAD_UPDATE_WAIT_MS = 250;
  
      // static HTML page always injected instead of the url loaded
      private static final String RAW_HTML =
              "<!DOCTYPE html>\n" +
              "<html>\n" +
              "  <head>\n" +
              "    <title>Geolocation</title>\n" +
              "    <script>\n" +
              "      function gotPos(position) {\n" +
              "        " + JS_INTERFACE_NAME + ".gotLocation();\n" +
              "      }\n" +
              "      function initiate_getCurrentPosition() {\n" +
              "        navigator.geolocation.getCurrentPosition(\n" +
              "            gotPos,\n" +
              "            handle_errors,\n" +
              "            {maximumAge:1000});\n" +
              "      }\n" +
              "      function handle_errors(error) {\n" +
              "        switch(error.code) {\n" +
              "          case error.PERMISSION_DENIED:\n" +
              "            " + JS_INTERFACE_NAME + ".errorDenied(); break;\n" +
              "          case error.POSITION_UNAVAILABLE:\n" +
              "            " + JS_INTERFACE_NAME + ".errorUnavailable(); break;\n" +
              "          case error.TIMEOUT:\n" +
              "            " + JS_INTERFACE_NAME + ".errorTimeout(); break;\n" +
              "          default: break;\n" +
              "        }\n" +
              "      }\n" +
              "    </script>\n" +
              "  </head>\n" +
              "  <body onload=\"initiate_getCurrentPosition();\">\n" +
              "  </body>\n" +
              "</html>";
  
      private JavascriptStatusReceiver mJavascriptStatusReceiver;
      private LocationManager mLocationManager;
      private WebViewOnUiThread mOnUiThread;
      private Thread mLocationUpdateThread;
      private volatile boolean mLocationUpdateThreadExitRequested;
      private List<String> mProviders;
  
      public GeolocationTest() throws Exception {
          super("com.android.cts.webkit", WebViewCtsActivity.class);
      }
  
      // Both this test and WebViewOnUiThread need to override some of the methods on WebViewClient,
      // so this test sublclasses the WebViewClient from WebViewOnUiThread
      private static class InterceptClient extends WaitForLoadedClient {
  
          public InterceptClient(WebViewOnUiThread webViewOnUiThread) throws Exception {
              super(webViewOnUiThread);
          }
  
          @Override
          public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
              // Intercept all page loads with the same geolocation enabled page
              try {
                  return new WebResourceResponse("text/html", "utf-8",
                      new ByteArrayInputStream(RAW_HTML.getBytes("UTF-8")));
              } catch(java.io.UnsupportedEncodingException e) {
                  return null;
              }
          }
      }
  
      @Override
      protected void setUp() throws Exception {
          super.setUp();
  
          WebView webview = getActivity().getWebView();
  
          if (webview != null) {
              // Set up a WebView with JavaScript and Geolocation enabled
              final String GEO_DIR = "geo_test";
              mOnUiThread = new WebViewOnUiThread(this, webview);
              mOnUiThread.getSettings().setJavaScriptEnabled(true);
              mOnUiThread.getSettings().setGeolocationEnabled(true);
              mOnUiThread.getSettings().setGeolocationDatabasePath(
                      getActivity().getApplicationContext().getDir(GEO_DIR, 0).getPath());
  
              // Add a JsInterface to report back to the test when a location is received
              mJavascriptStatusReceiver = new JavascriptStatusReceiver();
              mOnUiThread.addJavascriptInterface(mJavascriptStatusReceiver, JS_INTERFACE_NAME);
  
              // Always intercept all loads with the same geolocation test page
              mOnUiThread.setWebViewClient(new InterceptClient(mOnUiThread));
              // Clear all permissions before each test
              GeolocationPermissions.getInstance().clearAll();
              // Cache this mostly because the lookup is two lines of code
              mLocationManager = (LocationManager)getActivity().getApplicationContext()
                      .getSystemService(Context.LOCATION_SERVICE);
              // Add a test provider before each test to inject a location
              mProviders = mLocationManager.getAllProviders();
              for (String provider : mProviders) {
                  // Can't mock passive provider.
                  if (provider.equals(LocationManager.PASSIVE_PROVIDER)) {
                      mProviders.remove(provider);
                      break;
                  }
              }
              mProviders.add(LocationManager.FUSED_PROVIDER);
              addTestProviders();
          }
      }
  
      @Override
      protected void tearDown() throws Exception {
          stopUpdateLocationThread();
          if (mProviders != null) {
              // Remove the test provider after each test
              for (String provider : mProviders) {
                  try {
                      // Work around b/11446702 by clearing the test provider before removing it
                      mLocationManager.clearTestProviderEnabled(provider);
                      mLocationManager.removeTestProvider(provider);
                  } catch (IllegalArgumentException e) {} // Not much to do about this
              }
          }
  
          if (mOnUiThread != null) {
              mOnUiThread.cleanUp();
          }
          // This will null all member and static variables
          super.tearDown();
      }
  
      private void addTestProviders() {
          for (String providerName : mProviders) {
              LocationProvider provider = mLocationManager.getProvider(providerName);
              mLocationManager.addTestProvider(provider.getName(),
                      provider.requiresNetwork(), //requiresNetwork,
                      provider.requiresSatellite(), // requiresSatellite,
                      provider.requiresCell(),  // requiresCell,
                      provider.hasMonetaryCost(), // hasMonetaryCost,
                      provider.supportsAltitude(), // supportsAltitude,
                      provider.supportsSpeed(), // supportsSpeed,
                      provider.supportsBearing(), // supportsBearing,
                      provider.getPowerRequirement(), // powerRequirement
                      provider.getAccuracy()); // accuracy
              mLocationManager.setTestProviderEnabled(provider.getName(), true);
          }
      }
  
      private void startUpdateLocationThread() {
          // Only start the thread once
          if (mLocationUpdateThread == null) {
              mLocationUpdateThreadExitRequested = false;
              mLocationUpdateThread = new Thread() {
                  @Override
                  public void run() {
                      while (!mLocationUpdateThreadExitRequested) {
                          try {
                              Thread.sleep(LOCATION_THREAD_UPDATE_WAIT_MS);
                          } catch(Exception e) {
                              // Do nothing, an extra update is no problem
                          }
                          updateLocation();
                      }
                  }
              };
              mLocationUpdateThread.start();
          }
      }
  
      private void stopUpdateLocationThread() {
          // Only stop the thread if it was started
          if (mLocationUpdateThread != null) {
              mLocationUpdateThreadExitRequested = true;
              try {
                  mLocationUpdateThread.join();
              } catch (InterruptedException e) {
                  // Do nothing
              }
              mLocationUpdateThread = null;
          }
      }
  
      // Update location with a fixed latitude and longtitude, sets the time to the current time.
      private void updateLocation() {
          for (int i = 0; i < mProviders.size(); i++) {
              Location location = new Location(mProviders.get(i));
              location.setLatitude(40);
              location.setLongitude(40);
              location.setAccuracy(1.0f);
              location.setTime(java.lang.System.currentTimeMillis());
              location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
              mLocationManager.setTestProviderLocation(mProviders.get(i), location);
          }
      }
  
      // Need to set the location just after loading the url. Setting it after each load instead of
      // using a maximum age.
      private void loadUrlAndUpdateLocation(String url) {
          mOnUiThread.loadUrlAndWaitForCompletion(url);
          startUpdateLocationThread();
      }
  
      // WebChromeClient that accepts each location for one load. WebChromeClient is used in
      // WebViewOnUiThread to detect when the page is loaded, so subclassing the one used there.
      private static class TestSimpleGeolocationRequestWebChromeClient
                  extends WaitForProgressClient {
          private boolean mReceivedRequest = false;
          private final boolean mAccept;
          private final boolean mRetain;
  
          public TestSimpleGeolocationRequestWebChromeClient(
                  WebViewOnUiThread webViewOnUiThread, boolean accept, boolean retain) {
              super(webViewOnUiThread);
              this.mAccept = accept;
              this.mRetain = retain;
          }
  
          @Override
          public void onGeolocationPermissionsShowPrompt(
                  String origin, GeolocationPermissions.Callback callback) {
              mReceivedRequest = true;
              callback.invoke(origin, mAccept, mRetain);
          }
      }
  
      // Test loading a page and accepting the domain for one load
      public void testSimpleGeolocationRequestAcceptOnce() throws Exception {
          if (!NullWebViewUtils.isWebViewAvailable()) {
              return;
          }
          final TestSimpleGeolocationRequestWebChromeClient chromeClientAcceptOnce =
                  new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, true, false);
          mOnUiThread.setWebChromeClient(chromeClientAcceptOnce);
          loadUrlAndUpdateLocation(URL_1);
          Callable<Boolean> receivedRequest = new Callable<Boolean>() {
              @Override
              public Boolean call() {
                  return chromeClientAcceptOnce.mReceivedRequest;
              }
          };
          PollingCheck.check("Geolocation prompt not called", POLLING_TIMEOUT, receivedRequest);
          Callable<Boolean> receivedLocation = new Callable<Boolean>() {
              @Override
              public Boolean call() {
                  return mJavascriptStatusReceiver.mHasPosition;
              }
          };
          PollingCheck.check("JS didn't get position", POLLING_TIMEOUT, receivedLocation);
          chromeClientAcceptOnce.mReceivedRequest = false;
          // Load URL again, should receive callback again
          loadUrlAndUpdateLocation(URL_1);
          PollingCheck.check("Geolocation prompt not called", POLLING_TIMEOUT, receivedRequest);
          PollingCheck.check("JS didn't get position", POLLING_TIMEOUT, receivedLocation);
      }
  
      private static class OriginCheck extends PollingCheck implements
              android.webkit.ValueCallback<Set<String>> {
  
          private boolean mReceived = false;
          private final Set<String> mExpectedValue;
          private Set<String> mReceivedValue = null;
  
          public OriginCheck(Set<String> val) {
              mExpectedValue = val;
          }
  
          @Override
          protected boolean check() {
              if (!mReceived) return false;
  