implemented LocationManager C++->Java binding.

This commit is contained in:
rachytski 2011-11-29 20:49:58 +04:00 committed by Alex Zolotarev
parent 61d5fd30b0
commit 5a4bbb5dc9
13 changed files with 400 additions and 74 deletions

View file

@ -41,6 +41,8 @@ LOCAL_SRC_FILES := \
com/mapswithme/maps/Lifecycle.cpp \
com/mapswithme/platform/Platform.cpp \
com/mapswithme/platform/http_thread_android.cpp \
com/mapswithme/jni/jni_thread.cpp \
com/mapswithme/jni/jni_method.cpp \
nv_thread/nv_thread.cpp \
nv_event/nv_event_queue.cpp \
nv_event/nv_event.cpp \

View file

@ -0,0 +1,42 @@
/*
* method_ref.cpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#include "jni_thread.hpp"
#include "jni_method.hpp"
#include "../../../../../base/assert.hpp"
namespace jni
{
Method::Method(jclass klass,
char const * name,
char const * signature)
: m_name(name),
m_signature(signature)
{
JNIEnv * env = GetCurrentThreadJNIEnv();
m_index = env->GetMethodID(klass, m_name, m_signature);
CHECK(m_index, ("Error: No valid function pointer in ", m_name));
}
bool Method::CallBoolean(jobject self)
{
JNIEnv* jniEnv = GetCurrentThreadJNIEnv();
CHECK(jniEnv, ("Error: No valid JNI env in ", m_name));
return jniEnv->CallBooleanMethod(self, m_index);
}
bool Method::CallInt(jobject self)
{
JNIEnv* jniEnv = GetCurrentThreadJNIEnv();
CHECK(jniEnv, ("Error: No valid JNI env in ", m_name));
return (int)jniEnv->CallIntMethod(self, m_index);
}
}

View file

@ -0,0 +1,67 @@
/*
* method_ref.hpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#pragma once
#include <jni.h>
#include "jni_thread.hpp"
namespace jni
{
class Method
{
private:
const char* m_name;
const char* m_signature;
jmethodID m_index;
public:
Method(jclass klass,
const char* name,
const char* signature);
void CallVoid(jobject self)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index);
};
template <typename A1>
void CallVoid(jobject self, A1 a1)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1);
}
template <typename A1, typename A2>
void CallVoid(jobject self, A1 a1, A2 a2)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2);
}
template <typename A1, typename A2, typename A3>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3);
}
template <typename A1, typename A2, typename A3, typename A4>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3, A4 a4)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3, a4);
}
template <typename A1, typename A2, typename A3, typename A4, typename A5>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3, a4, a5);
}
bool CallBoolean(jobject self);
bool CallInt(jobject self);
};
}

View file

@ -0,0 +1,63 @@
/*
* jni_thread.cpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#include "jni_thread.hpp"
#include <pthread.h>
#include "../../../../../base/logging.hpp"
namespace jni
{
JavaVM * s_jvm;
void SetCurrentJVM(JavaVM * jvm)
{
s_jvm = jvm;
}
JavaVM * GetCurrentJVM()
{
return s_jvm;
}
static pthread_key_t s_jniEnvKey = 0;
JNIEnv* GetCurrentThreadJNIEnv()
{
JNIEnv* env = NULL;
if (s_jniEnvKey)
env = (JNIEnv*)pthread_getspecific(s_jniEnvKey);
else
pthread_key_create(&s_jniEnvKey, NULL);
if (!env)
{
if (!GetCurrentJVM())
{
LOG(LINFO, ("Error - could not find JVM!"));
return 0;
}
// Hmm - no env for this thread cached yet
int error = GetCurrentJVM()->AttachCurrentThread(&env, 0);
LOG(LINFO, ("AttachCurrentThread: ", error, ", ", env));
if (error || !env)
{
LOG(LINFO, ("Error - could not attach thread to JVM!"));
return 0;
}
pthread_setspecific(s_jniEnvKey, env);
}
return env;
}
}

View file

@ -0,0 +1,18 @@
/*
* jni_thread.hpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#pragma once
#include <jni.h>
namespace jni
{
void SetCurrentJVM(JavaVM * jvm);
JavaVM * GetCurrentJVM();
JNIEnv * GetCurrentThreadJNIEnv();
}

View file

@ -6,26 +6,89 @@
*/
#include <jni.h>
#include "../jni/jni_thread.hpp"
#include "../maps/Framework.hpp"
#include "LocationService.hpp"
android::LocationService * g_locationService = 0;
namespace android
{
LocationService::LocationService(location::LocationObserver & locationObserver,
jobject observer)
: location::LocationService(locationObserver),
m_javaObserver(observer)
{
jclass k = jni::GetCurrentThreadJNIEnv()->GetObjectClass(m_javaObserver);
m_onLocationChanged.reset(new jni::Method(k, "onLocationChanged", "(JDDF)V"));
m_onStatusChanged.reset(new jni::Method(k, "onStatusChanged", "(J)V"));
}
void LocationService::Start()
{
m_observer.OnLocationStatusChanged(location::EStarted);
m_onStatusChanged->CallVoid(m_javaObserver, location::EStarted);
}
void LocationService::Stop()
{
m_observer.OnLocationStatusChanged(location::EStopped);
m_onStatusChanged->CallVoid(m_javaObserver, location::EStopped);
}
void LocationService::Disable()
{
m_observer.OnLocationStatusChanged(location::EDisabledByUser);
m_onStatusChanged->CallVoid(m_javaObserver, location::EDisabledByUser);
}
void LocationService::OnLocationUpdate(location::GpsInfo const & info)
{
m_observer.OnGpsUpdated(info);
m_onLocationChanged->CallVoid(m_javaObserver, info.m_timestamp, info.m_latitude, info.m_longitude, info.m_horizontalAccuracy);
}
}
///////////////////////////////////////////////////////////////////////////////////
// LocationService
///////////////////////////////////////////////////////////////////////////////////
extern "C"
{
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_location_LocationService_nativeEnableLocationService(JNIEnv * env, jobject thiz,
jboolean enable)
Java_com_mapswithme_maps_location_LocationService_nativeStartUpdate(JNIEnv * env, jobject thiz, jobject observer)
{
g_framework->EnableLocation(enable);
g_locationService = new android::LocationService(*g_framework, observer);
g_locationService->Start();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_location_LocationService_nativeStopUpdate(JNIEnv * env, jobject thiz)
{
g_locationService->Stop();
delete g_locationService;
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_location_LocationService_nativeLocationChanged(JNIEnv * env, jobject thiz,
jlong time, jdouble lat, jdouble lon, jfloat accuracy)
{
g_framework->UpdateLocation(time, lat, lon, accuracy);
location::GpsInfo info;
info.m_horizontalAccuracy = static_cast<double>(accuracy);
info.m_latitude = lat;
info.m_longitude = lon;
info.m_timestamp = time;
info.m_source = location::EAndroidNative;
g_locationService->OnLocationUpdate(info);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_location_LocationService_nativeDisable(JNIEnv * env, jobject thiz)
{
g_locationService->Disable();
}
JNIEXPORT void JNICALL

View file

@ -0,0 +1,32 @@
#pragma once
#include <jni.h>
#include "../../../../../platform/location_service.hpp"
#include "../../../../../std/scoped_ptr.hpp"
#include "../jni/jni_method.hpp"
namespace android
{
class LocationService : public location::LocationService
{
private:
jobject m_javaObserver;
scoped_ptr<jni::Method> m_onLocationChanged;
scoped_ptr<jni::Method> m_onStatusChanged;
public:
LocationService(location::LocationObserver & locationObserver,
jobject observer);
void Start();
void Stop();
void Disable();
void OnLocationUpdate(location::GpsInfo const & info);
};
}
extern android::LocationService * g_locationService;

View file

@ -57,6 +57,16 @@ namespace android
delete m_videoTimer;
}
void Framework::OnLocationStatusChanged(location::TLocationStatus newStatus)
{
m_work.OnLocationStatusChanged(newStatus);
}
void Framework::OnGpsUpdated(location::GpsInfo const & info)
{
m_work.OnGpsUpdate(info);
}
void Framework::DeleteRenderPolicy()
{
LOG(LINFO, ("clearing current render policy."));
@ -241,33 +251,6 @@ namespace android
}
void f()
{
// empty location stub
}
void Framework::EnableLocation(bool enable)
{
// if (enable)
// m_work.StartLocationService(bind(&f));
// else
// m_work.StopLocationService();
}
void Framework::UpdateLocation(uint64_t timestamp, double lat, double lon, float accuracy)
{
location::GpsInfo info;
info.m_timestamp = static_cast<double>(timestamp);
info.m_latitude = lat;
info.m_longitude = lon;
info.m_horizontalAccuracy = accuracy;
// info.m_status = location::EAccurateMode;
// info.m_altitude = 0;
// info.m_course = 0;
// info.m_verticalAccuracy = 0;
m_work.OnGpsUpdate(info);
}
void Framework::UpdateCompass(uint64_t timestamp, double magneticNorth, double trueNorth, float accuracy)
{
location::CompassInfo info;

View file

@ -13,10 +13,11 @@
#include "../../../../../map/window_handle.hpp"
#include "../../../../../map/feature_vec_model.hpp"
#include "../../../nv_event/nv_event.hpp"
#include "../../../../../platform/location_service.hpp"
namespace android
{
class Framework
class Framework : public location::LocationObserver
{
private:
::Framework m_work;
@ -47,6 +48,9 @@ namespace android
storage::Storage & Storage();
void OnLocationStatusChanged(location::TLocationStatus newStatus);
void OnGpsUpdated(location::GpsInfo const & info);
void Invalidate();
bool InitRenderPolicy();

View file

@ -16,6 +16,7 @@
#include "Framework.hpp"
#include "../platform/Platform.hpp"
#include "../../../nv_event/nv_event.hpp"
#include "../jni/jni_thread.hpp"
JavaVM * g_jvm;
@ -24,6 +25,7 @@ extern "C"
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM * jvm, void * reserved)
{
jni::SetCurrentJVM(jvm);
InitNVEvent(jvm);
g_jvm = jvm;
jni::InitSystemLog();
@ -36,6 +38,7 @@ extern "C"
JNI_OnUnload(JavaVM * vm, void * reserved)
{
delete g_framework;
jni::SetCurrentJVM(0);
}
JNIEXPORT void JNICALL

View file

@ -15,14 +15,16 @@ import android.os.Environment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.util.Log;
public class MWMActivity extends NvEventQueueActivity
public class MWMActivity extends NvEventQueueActivity implements LocationService.Observer
{
VideoTimer m_timer;
private static String TAG = "MWMActivity";
private final static String PACKAGE_NAME = "com.mapswithme.maps";
private boolean m_locationEnabled = false;
private LocationService m_locationService = null;
private String getAppBundlePath() throws NameNotFoundException
{
@ -57,6 +59,17 @@ public class MWMActivity extends NvEventQueueActivity
}
m_timer = new VideoTimer();
m_locationService = new LocationService(this);
}
public void onStatusChanged(long status)
{
Log.d(TAG, "onStatusChanged");
}
public void onLocationChanged(long time, double latitude, double longitude, float accuracy)
{
Log.d(TAG, "onLocationChanged");
}
/* @Override
@ -83,7 +96,7 @@ public class MWMActivity extends NvEventQueueActivity
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
// temprorarily disable downloader in the menu
menu.removeItem(R.id.download_maps);
//menu.removeItem(R.id.download_maps);
return true;
}
@ -94,10 +107,10 @@ public class MWMActivity extends NvEventQueueActivity
switch (item.getItemId())
{
case R.id.my_position:
if (m_locationEnabled)
LocationService.stop();
if (m_locationService.isActive())
m_locationService.stopUpdate();
else
LocationService.start(this);
m_locationService.startUpdate(this);
m_locationEnabled = !m_locationEnabled;
return true;
case R.id.download_maps:

View file

@ -16,51 +16,75 @@ import android.view.WindowManager;
public class LocationService implements LocationListener, SensorEventListener
{
public interface Observer
{
public void onLocationChanged(long time, double lat, double lon, float accuracy);
public void onStatusChanged(long status);
};
private boolean m_isActive = false;
private static String TAG = "Location";
private static LocationService m_self;
private LocationManager m_locationManager;
private SensorManager m_sensorManager;
private Sensor m_compassSensor;
// To calculate true north for compass
private GeomagneticField m_field;
public static void start(Context c)
public LocationService(Context c)
{
if (m_self == null)
// Acquire a reference to the system Location Manager
m_locationManager = (LocationManager) c.getSystemService(Context.LOCATION_SERVICE);
m_sensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
m_compassSensor = m_sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
m_field = null;
}
public boolean isActive()
{
return m_isActive;
}
public void startUpdate(Observer observer)
{
m_isActive = false;
/*if (m_locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER))
{
m_self = new LocationService();
// Acquire a reference to the system Location Manager
m_self.m_locationManager = (LocationManager) c.getSystemService(Context.LOCATION_SERVICE);
m_self.m_sensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
m_self.m_compassSensor = m_self.m_sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
// m_self.m_defaultDisplay = ((WindowManager)c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
m_self.m_field = null;
m_locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
m_isActive = true;
}*/
if (m_locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
{
m_locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
m_isActive = true;
}
if (m_locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
m_locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
m_isActive = true;
}
if (m_isActive)
{
m_sensorManager.registerListener(this, m_compassSensor, SensorManager.SENSOR_DELAY_NORMAL);
nativeStartUpdate(observer);
}
else
{
Log.d(TAG, "no locationProviders are found");
// TODO : callback into gui to show the "providers are not enabled" messagebox
}
m_self.startUpdate();
}
public static void stop()
{
if (m_self != null)
m_self.stopUpdate();
}
private void startUpdate()
{
// Register the listener with the Location Manager to receive location updates
m_locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
m_locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
m_locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
m_sensorManager.registerListener(this, m_compassSensor, SensorManager.SENSOR_DELAY_NORMAL);
nativeEnableLocationService(true);
}
private void stopUpdate()
public void stopUpdate()
{
m_locationManager.removeUpdates(this);
m_sensorManager.unregisterListener(this);
nativeEnableLocationService(false);
m_isActive = false;
nativeStopUpdate();
}
//@Override
@ -77,12 +101,26 @@ public class LocationService implements LocationListener, SensorEventListener
public void onProviderDisabled(String provider)
{
Log.d(TAG, "onProviderDisabled " + provider);
if (m_isActive)
{
m_isActive = m_locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
|| m_locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!m_isActive)
{
Log.d(TAG, "to receive a location data please enable some of the location providers");
nativeDisable();
stopUpdate();
/// TODO : callback into GUI to set the button into the "disabled" state
}
}
}
//@Override
public void onProviderEnabled(String provider)
{
Log.d(TAG, "onProviderEnabled " + provider);
if (m_isActive)
m_locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
//@Override
@ -107,12 +145,9 @@ public class LocationService implements LocationListener, SensorEventListener
nativeCompassChanged(event.timestamp, event.values[0], event.values[0] + m_field.getDeclination(), m_field.getDeclination());
}
private native void nativeEnableLocationService(boolean enable);
private native void nativeStartUpdate(Observer observer);
private native void nativeStopUpdate();
private native void nativeDisable();
private native void nativeLocationChanged(long time, double lat, double lon, float accuracy);
// screenOrientation:
// 0 = 0
// 1 = 90
// 2 = 180
// 3 = 270
private native void nativeCompassChanged(long time, double magneticNorth, double trueNorth, float accuracy);
}

View file

@ -11,7 +11,7 @@ namespace location
enum TLocationStatus
{
EStopped,
EStopped = 0,
EStarted,
EFirstEvent, //!< Sent when first valid coorinate is received
ENotSupported,
@ -22,6 +22,7 @@ namespace location
{
EAppleNative,
EWindowsNative,
EAndroidNative,
EGoogle
};