| Index: content/android/java/org/chromium/content/browser/LocationProvider.java
|
| diff --git a/content/android/java/org/chromium/content/browser/LocationProvider.java b/content/android/java/org/chromium/content/browser/LocationProvider.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..84ffe8dbe165098bd9c790f9a09a97a80146656f
|
| --- /dev/null
|
| +++ b/content/android/java/org/chromium/content/browser/LocationProvider.java
|
| @@ -0,0 +1,231 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.content.browser;
|
| +
|
| +import android.content.Context;
|
| +import android.location.Criteria;
|
| +import android.location.Location;
|
| +import android.location.LocationListener;
|
| +import android.location.LocationManager;
|
| +import android.os.Bundle;
|
| +import android.os.Looper;
|
| +import android.util.Log;
|
| +
|
| +import org.chromium.base.ActivityStatus;
|
| +import org.chromium.base.CalledByNative;
|
| +
|
| +import java.util.concurrent.FutureTask;
|
| +
|
| +/**
|
| + * Implements the Java side of LocationProviderAndroid.
|
| + * Delegates all real functionality to the inner class.
|
| + * See detailed documentation on
|
| + * content/browser/geolocation/android_location_api_adapter.h.
|
| + * Based on android.webkit.GeolocationService.java
|
| + */
|
| +class LocationProvider {
|
| +
|
| + // Log tag
|
| + private static final String TAG = "LocationProvider";
|
| +
|
| + /**
|
| + * This is the core of android location provider. It is a separate class for clarity
|
| + * so that it can manage all processing completely in the UI thread. The container class
|
| + * ensures that the start/stop calls into this class are done in the UI thread.
|
| + */
|
| + private static class LocationProviderImpl
|
| + implements LocationListener, ActivityStatus.Listener {
|
| +
|
| + private Context mContext;
|
| + private LocationManager mLocationManager;
|
| + private boolean mIsRunning;
|
| + private boolean mShouldRunAfterActivityResume;
|
| + private boolean mIsGpsEnabled;
|
| +
|
| + LocationProviderImpl(Context context) {
|
| + mContext = context;
|
| + }
|
| +
|
| + public void onActivityStatusChanged(boolean isPaused) {
|
| + if (isPaused) {
|
| + mShouldRunAfterActivityResume = mIsRunning;
|
| + unregisterFromLocationUpdates();
|
| + } else {
|
| + assert !mIsRunning;
|
| + if (mShouldRunAfterActivityResume) {
|
| + registerForLocationUpdates();
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Start listening for location updates.
|
| + * @param gpsEnabled Whether or not we're interested in high accuracy GPS.
|
| + */
|
| + private void start(boolean gpsEnabled) {
|
| + if (!mIsRunning && !mShouldRunAfterActivityResume) {
|
| + // Currently idle so start listening to activity status changes.
|
| + ActivityStatus.getInstance().registerListener(this);
|
| + }
|
| + mIsGpsEnabled = gpsEnabled;
|
| + if (ActivityStatus.getInstance().isPaused()) {
|
| + mShouldRunAfterActivityResume = true;
|
| + } else {
|
| + unregisterFromLocationUpdates();
|
| + registerForLocationUpdates();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Stop listening for location updates.
|
| + */
|
| + private void stop() {
|
| + unregisterFromLocationUpdates();
|
| + ActivityStatus.getInstance().unregisterListener(this);
|
| + mShouldRunAfterActivityResume = false;
|
| + }
|
| +
|
| + /**
|
| + * Returns true if we are currently listening for location updates, false if not.
|
| + */
|
| + private boolean isRunning() {
|
| + return mIsRunning;
|
| + }
|
| +
|
| + @Override
|
| + public void onLocationChanged(Location location) {
|
| + // Callbacks from the system location sevice are queued to this thread, so it's
|
| + // possible that we receive callbacks after unregistering. At this point, the
|
| + // native object will no longer exist.
|
| + if (mIsRunning) {
|
| + nativeNewLocationAvailable(location.getLatitude(), location.getLongitude(),
|
| + location.getTime(), location.hasAltitude(), location.getAltitude(),
|
| + location.hasAccuracy(), location.getAccuracy(),
|
| + location.hasBearing(), location.getBearing(),
|
| + location.hasSpeed(), location.getSpeed());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void onStatusChanged(String provider, int status, Bundle extras) {
|
| + }
|
| +
|
| + @Override
|
| + public void onProviderEnabled(String provider) {
|
| + }
|
| +
|
| + @Override
|
| + public void onProviderDisabled(String provider) {
|
| + }
|
| +
|
| + private void ensureLocationManagerCreated() {
|
| + if (mLocationManager != null) return;
|
| + mLocationManager = (LocationManager) mContext.getSystemService(
|
| + Context.LOCATION_SERVICE);
|
| + if (mLocationManager == null) {
|
| + Log.e(TAG, "Could not get location manager.");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Registers this object with the location service.
|
| + */
|
| + private void registerForLocationUpdates() {
|
| + ensureLocationManagerCreated();
|
| +
|
| + assert !mIsRunning;
|
| + mIsRunning = true;
|
| +
|
| + // We're running on the main thread. The C++ side is responsible to
|
| + // bounce notifications to the Geolocation thread as they arrive in the mainLooper.
|
| + try {
|
| + Criteria criteria = new Criteria();
|
| + mLocationManager.requestLocationUpdates(0, 0, criteria, this,
|
| + Looper.getMainLooper());
|
| + if (mIsGpsEnabled) {
|
| + criteria.setAccuracy(Criteria.ACCURACY_FINE);
|
| + mLocationManager.requestLocationUpdates(0, 0, criteria, this,
|
| + Looper.getMainLooper());
|
| + }
|
| + } catch(SecurityException e) {
|
| + Log.e(TAG, "Caught security exception registering for location updates from " +
|
| + "system. This should only happen in DumpRenderTree.");
|
| + } catch(IllegalArgumentException e) {
|
| + Log.e(TAG, "Caught IllegalArgumentException registering for location updates.");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Unregisters this object from the location service.
|
| + */
|
| + private void unregisterFromLocationUpdates() {
|
| + if (mIsRunning) {
|
| + mIsRunning = false;
|
| + mLocationManager.removeUpdates(this);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Delegate handling the real work in the main thread.
|
| + private LocationProviderImpl mImpl;
|
| +
|
| + private LocationProvider(Context context) {
|
| + mImpl = new LocationProviderImpl(context);
|
| + }
|
| +
|
| + @CalledByNative
|
| + static LocationProvider create(Context context) {
|
| + return new LocationProvider(context);
|
| + }
|
| +
|
| + /**
|
| + * Start listening for location updates until we're told to quit. May be
|
| + * called in any thread.
|
| + * @param gpsEnabled Whether or not we're interested in high accuracy GPS.
|
| + */
|
| + @CalledByNative
|
| + public boolean start(final boolean gpsEnabled) {
|
| + FutureTask<Void> task = new FutureTask<Void>(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mImpl.start(gpsEnabled);
|
| + }
|
| + }, null);
|
| + ThreadUtils.runOnUiThread(task);
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * Stop listening for location updates. May be called in any thread.
|
| + */
|
| + @CalledByNative
|
| + public void stop() {
|
| + FutureTask<Void> task = new FutureTask<Void>(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mImpl.stop();
|
| + }
|
| + }, null);
|
| + ThreadUtils.runOnUiThread(task);
|
| + }
|
| +
|
| + /**
|
| + * Returns true if we are currently listening for location updates, false if not.
|
| + * Must be called only in the UI thread.
|
| + */
|
| + public boolean isRunning() {
|
| + assert Looper.myLooper() == Looper.getMainLooper();
|
| + return mImpl.isRunning();
|
| + }
|
| +
|
| + // Native functions
|
| + public static native void nativeNewLocationAvailable(
|
| + double latitude, double longitude, long timeStamp,
|
| + boolean hasAltitude, double altitude,
|
| + boolean hasAccuracy, double accuracy,
|
| + boolean hasHeading, double heading,
|
| + boolean hasSpeed, double speed);
|
| + public static native void nativeNewErrorAvailable(String message);
|
| +}
|
|
|