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/LocationProvider_jni.h" 13 14 using base::android::AttachCurrentThread; 15 using base::android::CheckException; 16 using base::android::ClearException; 17 using content::AndroidLocationApiAdapter; 18 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 32 static void NewErrorAvailable(JNIEnv* env, jclass, jstring message) { 33 AndroidLocationApiAdapter::OnNewErrorAvailable(env, message); 34 } 35 36 namespace content { 37 38 AndroidLocationApiAdapter::AndroidLocationApiAdapter() 39 : location_provider_(NULL) { 40 } 41 42 AndroidLocationApiAdapter::~AndroidLocationApiAdapter() { 43 CHECK(!location_provider_); 44 CHECK(!message_loop_.get()); 45 CHECK(java_location_provider_android_object_.is_null()); 46 } 47 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_LocationProvider_start(env, 69 java_location_provider_android_object_.obj(), high_accuracy); 70 } 71 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_LocationProvider_stop(env, java_location_provider_android_object_.obj()); 88 java_location_provider_android_object_.Reset(); 89 } 90 91 // static 92 void AndroidLocationApiAdapter::NotifyProviderNewGeoposition( 93 const Geoposition& geoposition) { 94 // Called on the geolocation thread, safe to access location_provider_ here. 95 if (GetInstance()->location_provider_) { 96 CHECK(GetInstance()->message_loop_->BelongsToCurrentThread()); 97 GetInstance()->location_provider_->NotifyNewGeoposition(geoposition); 98 } 99 } 100 101 // static 102 void AndroidLocationApiAdapter::OnNewLocationAvailable( 103 double latitude, double longitude, double time_stamp, 104 bool has_altitude, double altitude, 105 bool has_accuracy, double accuracy, 106 bool has_heading, double heading, 107 bool has_speed, double speed) { 108 Geoposition position; 109 position.latitude = latitude; 110 position.longitude = longitude; 111 position.timestamp = base::Time::FromDoubleT(time_stamp); 112 if (has_altitude) 113 position.altitude = altitude; 114 if (has_accuracy) 115 position.accuracy = accuracy; 116 if (has_heading) 117 position.heading = heading; 118 if (has_speed) 119 position.speed = speed; 120 GetInstance()->OnNewGeopositionInternal(position); 121 } 122 123 // static 124 void AndroidLocationApiAdapter::OnNewErrorAvailable(JNIEnv* env, 125 jstring message) { 126 Geoposition position_error; 127 position_error.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; 128 position_error.error_message = 129 base::android::ConvertJavaStringToUTF8(env, message); 130 GetInstance()->OnNewGeopositionInternal(position_error); 131 } 132 133 // static 134 AndroidLocationApiAdapter* AndroidLocationApiAdapter::GetInstance() { 135 return Singleton<AndroidLocationApiAdapter>::get(); 136 } 137 138 // static 139 bool AndroidLocationApiAdapter::RegisterGeolocationService(JNIEnv* env) { 140 return RegisterNativesImpl(env); 141 } 142 143 void AndroidLocationApiAdapter::CreateJavaObject(JNIEnv* env) { 144 // Create the Java AndroidLocationProvider object. 145 java_location_provider_android_object_.Reset( 146 Java_LocationProvider_create(env, 147 base::android::GetApplicationContext())); 148 CHECK(!java_location_provider_android_object_.is_null()); 149 } 150 151 void AndroidLocationApiAdapter::OnNewGeopositionInternal( 152 const Geoposition& geoposition) { 153 base::AutoLock lock(lock_); 154 if (!message_loop_.get()) 155 return; 156 message_loop_->PostTask( 157 FROM_HERE, 158 base::Bind( 159 &AndroidLocationApiAdapter::NotifyProviderNewGeoposition, 160 geoposition)); 161 } 162 163 } // namespace content 164