summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/android/java/org/chromium/base/ThreadUtils.java134
-rw-r--r--content/browser/DEPS1
-rw-r--r--content/browser/geolocation/arbitrator_dependency_factory.cc5
-rw-r--r--content/browser/geolocation/location_api_adapter_android.cc160
-rw-r--r--content/browser/geolocation/location_api_adapter_android.h83
-rw-r--r--content/browser/geolocation/location_provider.cc4
-rw-r--r--content/browser/geolocation/location_provider_android.cc48
-rw-r--r--content/browser/geolocation/location_provider_android.h35
-rw-r--r--content/content.gyp16
-rw-r--r--content/content_browser.gypi15
-rw-r--r--content/content_tests.gypi9
-rw-r--r--content/public/android/OWNERS4
-rw-r--r--content/public/android/java/content.xml1
-rw-r--r--content/public/android/java/org/chromium/content/browser/LocationProvider.java232
14 files changed, 745 insertions, 2 deletions
diff --git a/base/android/java/org/chromium/base/ThreadUtils.java b/base/android/java/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..ca31c3d
--- /dev/null
+++ b/base/android/java/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,134 @@
+// 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.base;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Helper methods to deal with threading related tasks.
+ */
+public class ThreadUtils {
+
+ /**
+ * Run the supplied Runnable on the main thread. The method will block until
+ * the Runnable completes.
+ *
+ * @param r The Runnable to run.
+ */
+ public static void runOnUiThreadBlocking(final Runnable r) {
+ if (runningOnUiThread()) {
+ r.run();
+ } else {
+ FutureTask<Void> task = new FutureTask<Void>(r, null);
+ postOnUiThread(task);
+ try {
+ task.get();
+ } catch (Exception e) {
+ throw new RuntimeException("Exception occured while waiting for runnable", e);
+ }
+ }
+ }
+
+ /**
+ * Run the supplied Callable on the main thread, wrapping any exceptions in
+ * a RuntimeException. The method will block until the Callable completes.
+ *
+ * @param c The Callable to run
+ * @return The result of the callable
+ */
+ public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
+ try {
+ return runOnUiThreadBlocking(c);
+ } catch (ExecutionException e) {
+ throw new RuntimeException("Error occured waiting for callable", e);
+ }
+ }
+
+ /**
+ * Run the supplied Callable on the main thread, The method will block until
+ * the Callable completes.
+ *
+ * @param c The Callable to run
+ * @return The result of the callable
+ * @throws ExecutionException c's exception
+ */
+ public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
+ FutureTask<T> task = new FutureTask<T>(c);
+ runOnUiThread(task);
+ try {
+ return task.get();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for callable", e);
+ }
+ }
+
+ /**
+ * Run the supplied FutureTask on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param task The FutureTask to run
+ * @return The queried task (to aid inline construction)
+ */
+ public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
+ if (runningOnUiThread()) {
+ task.run();
+ } else {
+ postOnUiThread(task);
+ }
+ return task;
+ }
+
+ /**
+ * Run the supplied Callable on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param c The Callable to run
+ * @return A FutureTask wrapping the callable to retrieve results
+ */
+ public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
+ return runOnUiThread(new FutureTask<T>(c));
+ }
+
+ /**
+ * Run the supplied Runnable on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param r The Runnable to run
+ */
+ public static void runOnUiThread(Runnable r) {
+ runOnUiThread(new FutureTask<Void>(r, null));
+ }
+
+ /**
+ * Post the supplied FutureTask to run on the main thread. The method will
+ * not block, even if called on the UI thread.
+ *
+ * @param task The FutureTask to run
+ * @return The queried task (to aid inline construction)
+ */
+ public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
+ new Handler(Looper.getMainLooper()).post(task);
+ return task;
+ }
+
+ /**
+ * Asserts that the current thread is running on the main thread.
+ */
+ public static void assertOnUiThread() {
+ assert runningOnUiThread();
+ }
+
+ /**
+ * @return true iff the current thread is the main (UI) thread.
+ */
+ public static boolean runningOnUiThread() {
+ return Looper.getMainLooper() == Looper.myLooper();
+ }
+}
diff --git a/content/browser/DEPS b/content/browser/DEPS
index d937ab9..9d94e0d 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+content/gpu", # For gpu_info_collector.h and in-process GPU
"+content/port/browser",
"+content/public/browser",
+ "+jni", # For generated JNI includes
"+media/audio", # For audio input for speech input feature.
"+media/base/android", # For Android JNI registration.
diff --git a/content/browser/geolocation/arbitrator_dependency_factory.cc b/content/browser/geolocation/arbitrator_dependency_factory.cc
index 60225b6..170f6d3 100644
--- a/content/browser/geolocation/arbitrator_dependency_factory.cc
+++ b/content/browser/geolocation/arbitrator_dependency_factory.cc
@@ -33,8 +33,13 @@ DefaultGeolocationArbitratorDependencyFactory::NewNetworkLocationProvider(
net::URLRequestContextGetter* context,
const GURL& url,
const string16& access_token) {
+#if defined(OS_ANDROID)
+ // Android uses its own SystemLocationProvider.
+ return NULL;
+#else
return ::NewNetworkLocationProvider(access_token_store, context,
url, access_token);
+#endif
}
LocationProviderBase*
diff --git a/content/browser/geolocation/location_api_adapter_android.cc b/content/browser/geolocation/location_api_adapter_android.cc
new file mode 100644
index 0000000..f1c8948
--- /dev/null
+++ b/content/browser/geolocation/location_api_adapter_android.cc
@@ -0,0 +1,160 @@
+// 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.
+
+#include "content/browser/geolocation/location_api_adapter_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/browser/geolocation/location_provider_android.h"
+#include "jni/location_provider_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+using base::android::ClearException;
+using base::android::GetMethodID;
+
+static void NewLocationAvailable(JNIEnv* env, jclass,
+ jdouble latitude,
+ jdouble longitude,
+ jlong time_stamp,
+ jboolean has_altitude, jdouble altitude,
+ jboolean has_accuracy, jdouble accuracy,
+ jboolean has_heading, jdouble heading,
+ jboolean has_speed, jdouble speed) {
+ AndroidLocationApiAdapter::OnNewLocationAvailable(latitude, longitude,
+ time_stamp, has_altitude, altitude, has_accuracy, accuracy,
+ has_heading, heading, has_speed, speed);
+}
+
+static void NewErrorAvailable(JNIEnv* env, jclass, jstring message) {
+ AndroidLocationApiAdapter::OnNewErrorAvailable(env, message);
+}
+
+AndroidLocationApiAdapter::AndroidLocationApiAdapter()
+ : location_provider_(NULL) {
+}
+
+AndroidLocationApiAdapter::~AndroidLocationApiAdapter() {
+ CHECK(!location_provider_);
+ CHECK(!message_loop_);
+ CHECK(java_location_provider_android_object_.is_null());
+}
+
+bool AndroidLocationApiAdapter::Start(
+ LocationProviderAndroid* location_provider, bool high_accuracy) {
+ JNIEnv* env = AttachCurrentThread();
+ if (!location_provider_) {
+ location_provider_ = location_provider;
+ CHECK(java_location_provider_android_object_.is_null());
+ CreateJavaObject(env);
+ {
+ base::AutoLock lock(lock_);
+ CHECK(!message_loop_.get());
+ message_loop_ = base::MessageLoopProxy::current();
+ }
+ }
+ // At this point we should have all our pre-conditions ready, and they'd only
+ // change in Stop() which must be called on the same thread as here.
+ CHECK(location_provider_);
+ CHECK(message_loop_.get());
+ CHECK(!java_location_provider_android_object_.is_null());
+ // We'll start receiving notifications from java in the main thread looper
+ // until Stop() is called.
+ return Java_LocationProvider_start(env,
+ java_location_provider_android_object_.obj(), high_accuracy);
+}
+
+void AndroidLocationApiAdapter::Stop() {
+ if (!location_provider_) {
+ CHECK(!message_loop_.get());
+ CHECK(java_location_provider_android_object_.is_null());
+ return;
+ }
+
+ {
+ base::AutoLock lock(lock_);
+ message_loop_ = NULL;
+ }
+
+ location_provider_ = NULL;
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_LocationProvider_stop(env, java_location_provider_android_object_.obj());
+ java_location_provider_android_object_.Reset();
+}
+
+// static
+void AndroidLocationApiAdapter::NotifyProviderNewGeoposition(
+ const content::Geoposition& geoposition) {
+ // Called on the geolocation thread, safe to access location_provider_ here.
+ if (GetInstance()->location_provider_) {
+ CHECK(GetInstance()->message_loop_->BelongsToCurrentThread());
+ GetInstance()->location_provider_->NotifyNewGeoposition(geoposition);
+ }
+}
+
+// static
+void AndroidLocationApiAdapter::OnNewLocationAvailable(
+ double latitude, double longitude, long time_stamp,
+ bool has_altitude, double altitude,
+ bool has_accuracy, double accuracy,
+ bool has_heading, double heading,
+ bool has_speed, double speed) {
+ content::Geoposition position;
+ position.latitude = latitude;
+ position.longitude = longitude;
+ position.timestamp = base::Time::FromDoubleT(time_stamp / 1000.0);
+ if (has_altitude)
+ position.altitude = altitude;
+ if (has_accuracy)
+ position.accuracy = accuracy;
+ if (has_heading)
+ position.heading = heading;
+ if (has_speed)
+ position.speed = speed;
+ GetInstance()->OnNewGeopositionInternal(position);
+}
+
+// static
+void AndroidLocationApiAdapter::OnNewErrorAvailable(JNIEnv* env,
+ jstring message) {
+ content::Geoposition position_error;
+ position_error.error_code =
+ content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ position_error.error_message =
+ base::android::ConvertJavaStringToUTF8(env, message);
+ GetInstance()->OnNewGeopositionInternal(position_error);
+}
+
+// static
+AndroidLocationApiAdapter* AndroidLocationApiAdapter::GetInstance() {
+ return Singleton<AndroidLocationApiAdapter>::get();
+}
+
+// static
+bool AndroidLocationApiAdapter::RegisterGeolocationService(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void AndroidLocationApiAdapter::CreateJavaObject(JNIEnv* env) {
+ // Create the Java AndroidLocationProvider object.
+ java_location_provider_android_object_.Reset(
+ Java_LocationProvider_create(env,
+ base::android::GetApplicationContext()));
+ CHECK(!java_location_provider_android_object_.is_null());
+}
+
+void AndroidLocationApiAdapter::OnNewGeopositionInternal(
+ const content::Geoposition& geoposition) {
+ base::AutoLock lock(lock_);
+ if (!message_loop_)
+ return;
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &AndroidLocationApiAdapter::NotifyProviderNewGeoposition,
+ geoposition));
+}
diff --git a/content/browser/geolocation/location_api_adapter_android.h b/content/browser/geolocation/location_api_adapter_android.h
new file mode 100644
index 0000000..c2b4f85
--- /dev/null
+++ b/content/browser/geolocation/location_api_adapter_android.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_GEOLOCATION_ANDROID_LOCATION_API_ADAPTER_H_
+#define CONTENT_BROWSER_GEOLOCATION_ANDROID_LOCATION_API_ADAPTER_H_
+#pragma once
+
+#include "base/android/scoped_java_ref.h"
+#include "base/synchronization/lock.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop_proxy.h"
+#include "base/android/jni_helper.h"
+
+namespace content {
+struct Geoposition;
+}
+
+class LocationProviderAndroid;
+
+// Interacts with JNI and reports back to AndroidLocationProvider.
+// This class creates a LocationProvider java object and listens for
+// updates.
+// The simplified flow is:
+// GeolocationProvider runs in a Geolocation Thread and fetches geolocation data
+// from a LocationProvider.
+// AndroidLocationProvider access a singleton AndroidLocationApiAdapter
+// AndroidLocationApiAdapter calls via JNI and uses the main thread Looper
+// in the java side to listen for location updates. We then bounce these updates
+// to the Geolocation thread.
+// Note that AndroidLocationApiAdapter is a singleton and there's at most only
+// one AndroidLocationProvider that has called Start().
+class AndroidLocationApiAdapter {
+ public:
+ // Starts the underlying location provider, returns true if successful.
+ // Called on the Geolocation thread.
+ bool Start(LocationProviderAndroid* location_provider, bool high_accuracy);
+ // Stops the underlying location provider.
+ // Called on the Geolocation thread.
+ void Stop();
+
+ // Returns our singleton.
+ static AndroidLocationApiAdapter* GetInstance();
+
+ // Called when initializing chrome_view to obtain a pointer to the java class.
+ static bool RegisterGeolocationService(JNIEnv* env);
+
+ // Called by JNI on main thread looper.
+ static void OnNewLocationAvailable(double latitude,
+ double longitude,
+ long time_stamp,
+ bool has_altitude, double altitude,
+ bool has_accuracy, double accuracy,
+ bool has_heading, double heading,
+ bool has_speed, double speed);
+ static void OnNewErrorAvailable(JNIEnv* env, jstring message);
+
+ private:
+ friend struct DefaultSingletonTraits<AndroidLocationApiAdapter>;
+ AndroidLocationApiAdapter();
+ ~AndroidLocationApiAdapter();
+
+ void CreateJavaObject(JNIEnv* env);
+
+ // Called on the JNI main thread looper.
+ void OnNewGeopositionInternal(const content::Geoposition& geoposition);
+
+ /// Called on the Geolocation thread.
+ static void NotifyProviderNewGeoposition(
+ const content::Geoposition& geoposition);
+
+ base::android::ScopedJavaGlobalRef<jobject>
+ java_location_provider_android_object_;
+ LocationProviderAndroid* location_provider_;
+
+ // Guards against the following member which is accessed on Geolocation
+ // thread and the JNI main thread looper.
+ base::Lock lock_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
+};
+
+#endif // CONTENT_BROWSER_GEOLOCATION_ANDROID_LOCATION_API_ADAPTER_H_
diff --git a/content/browser/geolocation/location_provider.cc b/content/browser/geolocation/location_provider.cc
index c58bf6b..d587b55 100644
--- a/content/browser/geolocation/location_provider.cc
+++ b/content/browser/geolocation/location_provider.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -56,7 +56,7 @@ void LocationProviderBase::UpdateListeners() {
}
}
-#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN)
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN) && !defined OS_ANDROID
LocationProviderBase* NewSystemLocationProvider() {
return NULL;
}
diff --git a/content/browser/geolocation/location_provider_android.cc b/content/browser/geolocation/location_provider_android.cc
new file mode 100644
index 0000000..8628679
--- /dev/null
+++ b/content/browser/geolocation/location_provider_android.cc
@@ -0,0 +1,48 @@
+// 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.
+
+#include "content/browser/geolocation/location_provider_android.h"
+
+#include "base/time.h"
+#include "content/browser/geolocation/location_api_adapter_android.h"
+#include "content/public/common/geoposition.h"
+
+// LocationProviderAndroid
+LocationProviderAndroid::LocationProviderAndroid() {
+}
+
+LocationProviderAndroid::~LocationProviderAndroid() {
+ StopProvider();
+}
+
+void LocationProviderAndroid::NotifyNewGeoposition(
+ const content::Geoposition& position) {
+ last_position_ = position;
+ UpdateListeners();
+}
+
+bool LocationProviderAndroid::StartProvider(bool high_accuracy) {
+ return AndroidLocationApiAdapter::GetInstance()->Start(this, high_accuracy);
+}
+
+void LocationProviderAndroid::StopProvider() {
+ AndroidLocationApiAdapter::GetInstance()->Stop();
+}
+
+void LocationProviderAndroid::GetPosition(content::Geoposition* position) {
+ *position = last_position_;
+}
+
+void LocationProviderAndroid::UpdatePosition() {
+ // Nothing to do here, android framework will call us back on new position.
+}
+
+void LocationProviderAndroid::OnPermissionGranted(
+ const GURL& requesting_frame) {
+ // Nothing to do here.
+}
+
+LocationProviderBase* NewSystemLocationProvider() {
+ return new LocationProviderAndroid;
+}
diff --git a/content/browser/geolocation/location_provider_android.h b/content/browser/geolocation/location_provider_android.h
new file mode 100644
index 0000000..748bca1
--- /dev/null
+++ b/content/browser/geolocation/location_provider_android.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_ANDROID_H_
+#define CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_ANDROID_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/geolocation/location_provider.h"
+#include "content/public/common/geoposition.h"
+
+class AndroidLocationApiAdapter;
+struct Geoposition;
+
+// Location provider for Android using the platform provider over JNI.
+class LocationProviderAndroid : public LocationProviderBase {
+ public:
+ LocationProviderAndroid();
+ virtual ~LocationProviderAndroid();
+
+ // Called by the AndroidLocationApiAdapter.
+ void NotifyNewGeoposition(const content::Geoposition& position);
+
+ // LocationProviderBase.
+ virtual bool StartProvider(bool high_accuracy) OVERRIDE;
+ virtual void StopProvider() OVERRIDE;
+ virtual void GetPosition(content::Geoposition* position) OVERRIDE;
+ virtual void UpdatePosition() OVERRIDE;
+ virtual void OnPermissionGranted(const GURL& requesting_frame) OVERRIDE;
+
+ private:
+ content::Geoposition last_position_;
+};
+
+#endif // CONTENT_BROWSER_GEOLOCATION_LOCATION_PROVIDER_ANDROID_H_
diff --git a/content/content.gyp b/content/content.gyp
index 6632f6d..b05a6e7 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -200,12 +200,28 @@
['OS == "android"', {
'targets': [
{
+ 'target_name': 'content_jni_headers',
+ 'type': 'none',
+ 'variables': {
+ 'java_sources': [
+ '../content/public/android/java/org/chromium/content/browser/LocationProvider.java',
+ ],
+ 'jni_headers': [
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/location_provider_jni.h',
+ ],
+ },
+ 'includes': [ '../build/jni_generator.gypi' ],
+ },
+ {
'target_name': 'content_java',
'type': 'none',
'variables': {
'package_name': 'content',
'java_in_dir': '../content/public/android/java',
},
+ 'dependencies': [
+ '../base/base.gyp:base_java',
+ ],
'includes': [ '../build/java.gypi' ],
},
],
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 558fa5e..bc44c69 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -337,10 +337,14 @@
'browser/geolocation/gps_location_provider_linux.h',
'browser/geolocation/libgps_wrapper_linux.cc',
'browser/geolocation/libgps_wrapper_linux.h',
+ 'browser/geolocation/location_api_adapter_android.cc',
+ 'browser/geolocation/location_api_adapter_android.h',
'browser/geolocation/location_arbitrator.cc',
'browser/geolocation/location_arbitrator.h',
'browser/geolocation/location_provider.cc',
'browser/geolocation/location_provider.h',
+ 'browser/geolocation/location_provider_android.cc',
+ 'browser/geolocation/location_provider_android.h',
'browser/geolocation/network_location_provider.cc',
'browser/geolocation/network_location_provider.h',
'browser/geolocation/network_location_request.cc',
@@ -814,6 +818,17 @@
],
'dependencies': [
'../media/media.gyp:media',
+ 'content.gyp:content_jni_headers',
+ 'content.gyp:content_java',
+ ],
+ 'sources!': [
+ 'browser/geolocation/network_location_provider.cc',
+ 'browser/geolocation/network_location_provider.h',
+ 'browser/geolocation/network_location_request.cc',
+ 'browser/geolocation/network_location_request.h',
+ ],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/content',
],
}],
['OS=="mac"', {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 5b828fd..aea6d7d 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -380,6 +380,15 @@
'browser/accessibility/browser_accessibility_win_unittest.cc',
],
}],
+ ['OS == "android"', {
+ 'sources!': [
+ 'browser/geolocation/device_data_provider_unittest.cc',
+ 'browser/geolocation/gps_location_provider_unittest_linux.cc',
+ 'browser/geolocation/network_location_provider_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_common_unittest.cc',
+ 'browser/geolocation/wifi_data_provider_linux_unittest.cc',
+ ],
+ }],
],
},
{
diff --git a/content/public/android/OWNERS b/content/public/android/OWNERS
new file mode 100644
index 0000000..a35ceee
--- /dev/null
+++ b/content/public/android/OWNERS
@@ -0,0 +1,4 @@
+satish@chromium.org
+bulach@chromium.org
+jrg@chromium.org
+yfriedman@chromium.org
diff --git a/content/public/android/java/content.xml b/content/public/android/java/content.xml
index a00a4e5..435cbab 100644
--- a/content/public/android/java/content.xml
+++ b/content/public/android/java/content.xml
@@ -40,6 +40,7 @@
<javac srcdir="${src}" destdir="${classes.dir}">
<classpath>
<path location="${location.base}/android.jar"/>
+ <path location="${PRODUCT_DIR}/chromium_base.jar"/>
</classpath>
</javac>
</target>
diff --git a/content/public/android/java/org/chromium/content/browser/LocationProvider.java b/content/public/android/java/org/chromium/content/browser/LocationProvider.java
new file mode 100644
index 0000000..6a89eef
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/LocationProvider.java
@@ -0,0 +1,232 @@
+// 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 org.chromium.base.ThreadUtils;
+
+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);
+}