1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/geolocation/location_api_adapter_android.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "content/browser/geolocation/location_provider_android.h"
12 #include "jni/LocationProviderAdapter_jni.h"
13
14 using base::android::AttachCurrentThread;
15 using base::android::CheckException;
16 using base::android::ClearException;
17 using content::AndroidLocationApiAdapter;
18
NewLocationAvailable(JNIEnv * env,jclass,jdouble latitude,jdouble longitude,jdouble time_stamp,jboolean has_altitude,jdouble altitude,jboolean has_accuracy,jdouble accuracy,jboolean has_heading,jdouble heading,jboolean has_speed,jdouble speed)19 static void NewLocationAvailable(JNIEnv* env, jclass,
20 jdouble latitude,
21 jdouble longitude,
22 jdouble time_stamp,
23 jboolean has_altitude, jdouble altitude,
24 jboolean has_accuracy, jdouble accuracy,
25 jboolean has_heading, jdouble heading,
26 jboolean has_speed, jdouble speed) {
27 AndroidLocationApiAdapter::OnNewLocationAvailable(latitude, longitude,
28 time_stamp, has_altitude, altitude, has_accuracy, accuracy,
29 has_heading, heading, has_speed, speed);
30 }
31
NewErrorAvailable(JNIEnv * env,jclass,jstring message)32 static void NewErrorAvailable(JNIEnv* env, jclass, jstring message) {
33 AndroidLocationApiAdapter::OnNewErrorAvailable(env, message);
34 }
35
36 namespace content {
37
AndroidLocationApiAdapter()38 AndroidLocationApiAdapter::AndroidLocationApiAdapter()
39 : location_provider_(NULL) {
40 }
41
~AndroidLocationApiAdapter()42 AndroidLocationApiAdapter::~AndroidLocationApiAdapter() {
43 CHECK(!location_provider_);
44 CHECK(!message_loop_.get());
45 CHECK(java_location_provider_android_object_.is_null());
46 }
47
Start(LocationProviderAndroid * location_provider,bool high_accuracy)48 bool AndroidLocationApiAdapter::Start(
49 LocationProviderAndroid* location_provider, bool high_accuracy) {
50 JNIEnv* env = AttachCurrentThread();
51 if (!location_provider_) {
52 location_provider_ = location_provider;
53 CHECK(java_location_provider_android_object_.is_null());
54 CreateJavaObject(env);
55 {
56 base::AutoLock lock(lock_);
57 CHECK(!message_loop_.get());
58 message_loop_ = base::MessageLoopProxy::current();
59 }
60 }
61 // At this point we should have all our pre-conditions ready, and they'd only
62 // change in Stop() which must be called on the same thread as here.
63 CHECK(location_provider_);
64 CHECK(message_loop_.get());
65 CHECK(!java_location_provider_android_object_.is_null());
66 // We'll start receiving notifications from java in the main thread looper
67 // until Stop() is called.
68 return Java_LocationProviderAdapter_start(env,
69 java_location_provider_android_object_.obj(), high_accuracy);
70 }
71
Stop()72 void AndroidLocationApiAdapter::Stop() {
73 if (!location_provider_) {
74 CHECK(!message_loop_.get());
75 CHECK(java_location_provider_android_object_.is_null());
76 return;
77 }
78
79 {
80 base::AutoLock lock(lock_);
81 message_loop_ = NULL;
82 }
83
84 location_provider_ = NULL;
85
86 JNIEnv* env = AttachCurrentThread();
87 Java_LocationProviderAdapter_stop(
88 env, java_location_provider_android_object_.obj());
89 java_location_provider_android_object_.Reset();
90 }
91
92 // static
NotifyProviderNewGeoposition(const Geoposition & geoposition)93 void AndroidLocationApiAdapter::NotifyProviderNewGeoposition(
94 const Geoposition& geoposition) {
95 // Called on the geolocation thread, safe to access location_provider_ here.
96 if (GetInstance()->location_provider_) {
97 CHECK(GetInstance()->message_loop_->BelongsToCurrentThread());
98 GetInstance()->location_provider_->NotifyNewGeoposition(geoposition);
99 }
100 }
101
102 // static
OnNewLocationAvailable(double latitude,double longitude,double time_stamp,bool has_altitude,double altitude,bool has_accuracy,double accuracy,bool has_heading,double heading,bool has_speed,double speed)103 void AndroidLocationApiAdapter::OnNewLocationAvailable(
104 double latitude, double longitude, double time_stamp,
105 bool has_altitude, double altitude,
106 bool has_accuracy, double accuracy,
107 bool has_heading, double heading,
108 bool has_speed, double speed) {
109 Geoposition position;
110 position.latitude = latitude;
111 position.longitude = longitude;
112 position.timestamp = base::Time::FromDoubleT(time_stamp);
113 if (has_altitude)
114 position.altitude = altitude;
115 if (has_accuracy)
116 position.accuracy = accuracy;
117 if (has_heading)
118 position.heading = heading;
119 if (has_speed)
120 position.speed = speed;
121 GetInstance()->OnNewGeopositionInternal(position);
122 }
123
124 // static
OnNewErrorAvailable(JNIEnv * env,jstring message)125 void AndroidLocationApiAdapter::OnNewErrorAvailable(JNIEnv* env,
126 jstring message) {
127 Geoposition position_error;
128 position_error.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
129 position_error.error_message =
130 base::android::ConvertJavaStringToUTF8(env, message);
131 GetInstance()->OnNewGeopositionInternal(position_error);
132 }
133
134 // static
GetInstance()135 AndroidLocationApiAdapter* AndroidLocationApiAdapter::GetInstance() {
136 return Singleton<AndroidLocationApiAdapter>::get();
137 }
138
139 // static
RegisterGeolocationService(JNIEnv * env)140 bool AndroidLocationApiAdapter::RegisterGeolocationService(JNIEnv* env) {
141 return RegisterNativesImpl(env);
142 }
143
CreateJavaObject(JNIEnv * env)144 void AndroidLocationApiAdapter::CreateJavaObject(JNIEnv* env) {
145 // Create the Java AndroidLocationProvider object.
146 java_location_provider_android_object_.Reset(
147 Java_LocationProviderAdapter_create(env,
148 base::android::GetApplicationContext()));
149 CHECK(!java_location_provider_android_object_.is_null());
150 }
151
OnNewGeopositionInternal(const Geoposition & geoposition)152 void AndroidLocationApiAdapter::OnNewGeopositionInternal(
153 const Geoposition& geoposition) {
154 base::AutoLock lock(lock_);
155 if (!message_loop_.get())
156 return;
157 message_loop_->PostTask(
158 FROM_HERE,
159 base::Bind(
160 &AndroidLocationApiAdapter::NotifyProviderNewGeoposition,
161 geoposition));
162 }
163
164 } // namespace content
165