diff options
author | jknotten@chromium.org <jknotten@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-09 12:12:09 +0000 |
---|---|---|
committer | jknotten@chromium.org <jknotten@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-09 12:12:09 +0000 |
commit | 5aab223f965826e7752d0f22487ed85ca2bcaa05 (patch) | |
tree | 588677002e89d620bce8359f831b426d49722ec9 /content/browser | |
parent | 61c9e8f83177bc9c4270c2d9f205e673f0f73b0f (diff) | |
download | chromium_src-5aab223f965826e7752d0f22487ed85ca2bcaa05.zip chromium_src-5aab223f965826e7752d0f22487ed85ca2bcaa05.tar.gz chromium_src-5aab223f965826e7752d0f22487ed85ca2bcaa05.tar.bz2 |
Upstream Geolocation for Android.
TEST=content_unittests: GeolocationProvider.* LocationArbitrator.*
There are also some integration tests downstream for the Java specific part.
Review URL: https://chromiumcodereview.appspot.com/10209003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@136019 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
7 files changed, 334 insertions, 2 deletions
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_ |