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/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