Home | History | Annotate | Download | only in geolocation
      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