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 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_LocationProviderAdapter_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_LocationProviderAdapter_stop( 88 env, java_location_provider_android_object_.obj()); 89 java_location_provider_android_object_.Reset(); 90 } 91 92 // static 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 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 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 135 AndroidLocationApiAdapter* AndroidLocationApiAdapter::GetInstance() { 136 return Singleton<AndroidLocationApiAdapter>::get(); 137 } 138 139 // static 140 bool AndroidLocationApiAdapter::RegisterGeolocationService(JNIEnv* env) { 141 return RegisterNativesImpl(env); 142 } 143 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 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