gps: Add support for bringing up a GSM data connection on demand for SUPL.
Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
@@ -31,6 +31,7 @@ static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
|
||||
static jmethodID method_reportLocation;
|
||||
static jmethodID method_reportStatus;
|
||||
static jmethodID method_reportSvStatus;
|
||||
static jmethodID method_reportSuplStatus;
|
||||
static jmethodID method_xtraDownloadRequest;
|
||||
|
||||
static const GpsInterface* sGpsInterface = NULL;
|
||||
@@ -41,19 +42,22 @@ static const GpsSuplInterface* sGpsSuplInterface = NULL;
|
||||
static GpsLocation sGpsLocation;
|
||||
static GpsStatus sGpsStatus;
|
||||
static GpsSvStatus sGpsSvStatus;
|
||||
static GpsSuplStatus sGpsSuplStatus;
|
||||
|
||||
// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
|
||||
// and android_location_GpsLocationProvider_read_status
|
||||
static GpsLocation sGpsLocationCopy;
|
||||
static GpsStatus sGpsStatusCopy;
|
||||
static GpsSvStatus sGpsSvStatusCopy;
|
||||
static GpsSuplStatus sGpsSuplStatusCopy;
|
||||
|
||||
enum CallbackType {
|
||||
kLocation = 1,
|
||||
kStatus = 2,
|
||||
kSvStatus = 4,
|
||||
kXtraDownloadRequest = 8,
|
||||
kDisableRequest = 16,
|
||||
kSuplStatus = 8,
|
||||
kXtraDownloadRequest = 16,
|
||||
kDisableRequest = 32,
|
||||
};
|
||||
static int sPendingCallbacks;
|
||||
|
||||
@@ -92,6 +96,17 @@ static void sv_status_callback(GpsSvStatus* sv_status)
|
||||
pthread_mutex_unlock(&sEventMutex);
|
||||
}
|
||||
|
||||
static void supl_status_callback(GpsSuplStatus* supl_status)
|
||||
{
|
||||
pthread_mutex_lock(&sEventMutex);
|
||||
|
||||
sPendingCallbacks |= kSuplStatus;
|
||||
memcpy(&sGpsSuplStatus, supl_status, sizeof(GpsSuplStatus));
|
||||
|
||||
pthread_cond_signal(&sEventCond);
|
||||
pthread_mutex_unlock(&sEventMutex);
|
||||
}
|
||||
|
||||
GpsCallbacks sGpsCallbacks = {
|
||||
location_callback,
|
||||
status_callback,
|
||||
@@ -111,11 +126,15 @@ GpsXtraCallbacks sGpsXtraCallbacks = {
|
||||
download_request_callback,
|
||||
};
|
||||
|
||||
GpsSuplCallbacks sGpsSuplCallbacks = {
|
||||
supl_status_callback,
|
||||
};
|
||||
|
||||
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
|
||||
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
|
||||
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
|
||||
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
|
||||
method_reportSuplStatus = env->GetMethodID(clazz, "reportSuplStatus", "(I)V");
|
||||
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
|
||||
}
|
||||
|
||||
@@ -129,7 +148,13 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o
|
||||
{
|
||||
if (!sGpsInterface)
|
||||
sGpsInterface = gps_get_interface();
|
||||
return (sGpsInterface && sGpsInterface->init(&sGpsCallbacks) == 0);
|
||||
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
|
||||
return false;
|
||||
|
||||
if (!sGpsSuplInterface)
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
if (sGpsSuplInterface)
|
||||
sGpsSuplInterface->init(&sGpsSuplCallbacks);
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
|
||||
@@ -186,6 +211,7 @@ static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, job
|
||||
memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
|
||||
memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
|
||||
memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
|
||||
memcpy(&sGpsSuplStatusCopy, &sGpsSuplStatus, sizeof(sGpsSuplStatusCopy));
|
||||
pthread_mutex_unlock(&sEventMutex);
|
||||
|
||||
if (pendingCallbacks & kLocation) {
|
||||
@@ -201,6 +227,9 @@ static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, job
|
||||
if (pendingCallbacks & kSvStatus) {
|
||||
env->CallVoidMethod(obj, method_reportSvStatus);
|
||||
}
|
||||
if (pendingCallbacks & kSuplStatus) {
|
||||
env->CallVoidMethod(obj, method_reportSuplStatus, sGpsSuplStatusCopy.status);
|
||||
}
|
||||
if (pendingCallbacks & kXtraDownloadRequest) {
|
||||
env->CallVoidMethod(obj, method_xtraDownloadRequest);
|
||||
}
|
||||
@@ -269,18 +298,7 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j
|
||||
env->ReleaseByteArrayElements(data, bytes, 0);
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj,
|
||||
jint addr, jint port)
|
||||
{
|
||||
if (!sGpsSuplInterface) {
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
}
|
||||
if (sGpsSuplInterface) {
|
||||
sGpsSuplInterface->set_server(addr, port);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobject obj, jstring apn)
|
||||
static void android_location_GpsLocationProvider_supl_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
|
||||
{
|
||||
if (!sGpsSuplInterface) {
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
@@ -291,11 +309,42 @@ static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobje
|
||||
return;
|
||||
}
|
||||
const char *apnStr = env->GetStringUTFChars(apn, NULL);
|
||||
sGpsSuplInterface->set_apn(apnStr);
|
||||
sGpsSuplInterface->data_conn_open(apnStr);
|
||||
env->ReleaseStringUTFChars(apn, apnStr);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_supl_data_conn_closed(JNIEnv* env, jobject obj)
|
||||
{
|
||||
if (!sGpsSuplInterface) {
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
}
|
||||
if (sGpsSuplInterface) {
|
||||
sGpsSuplInterface->data_conn_closed();
|
||||
}
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_supl_data_conn_failed(JNIEnv* env, jobject obj)
|
||||
{
|
||||
if (!sGpsSuplInterface) {
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
}
|
||||
if (sGpsSuplInterface) {
|
||||
sGpsSuplInterface->data_conn_failed();
|
||||
}
|
||||
}
|
||||
|
||||
static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj,
|
||||
jint addr, jint port)
|
||||
{
|
||||
if (!sGpsSuplInterface) {
|
||||
sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
|
||||
}
|
||||
if (sGpsSuplInterface) {
|
||||
sGpsSuplInterface->set_server(addr, port);
|
||||
}
|
||||
}
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
|
||||
@@ -312,8 +361,10 @@ static JNINativeMethod sMethods[] = {
|
||||
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
|
||||
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
|
||||
{"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
|
||||
{"native_supl_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_supl_data_conn_open},
|
||||
{"native_supl_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_supl_data_conn_closed},
|
||||
{"native_supl_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_supl_data_conn_failed},
|
||||
{"native_set_supl_server", "(II)V", (void*)android_location_GpsLocationProvider_set_supl_server},
|
||||
{"native_set_supl_apn", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_set_supl_apn},
|
||||
};
|
||||
|
||||
int register_android_location_GpsLocationProvider(JNIEnv* env)
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.location.LocationProviderImpl;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.SntpClient;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -99,6 +100,14 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
private static final int GPS_STATUS_ENGINE_ON = 3;
|
||||
private static final int GPS_STATUS_ENGINE_OFF = 4;
|
||||
|
||||
// these need to match GpsSuplStatusValue defines in gps.h
|
||||
/** SUPL status event values. */
|
||||
private static final int GPS_REQUEST_SUPL_DATA_CONN = 1;
|
||||
private static final int GPS_RELEASE_SUPL_DATA_CONN = 2;
|
||||
private static final int GPS_SUPL_DATA_CONNECTED = 3;
|
||||
private static final int GPS_SUPL_DATA_CONN_DONE = 4;
|
||||
private static final int GPS_SUPL_DATA_CONN_FAILED = 5;
|
||||
|
||||
// these need to match GpsLocationFlags enum in gps.h
|
||||
private static final int LOCATION_INVALID = 0;
|
||||
private static final int LOCATION_HAS_LAT_LONG = 1;
|
||||
@@ -122,6 +131,11 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
|
||||
private static final int GPS_DELETE_ALL = 0xFFFF;
|
||||
|
||||
// for mSuplDataConnectionState
|
||||
private static final int SUPL_DATA_CONNECTION_CLOSED = 0;
|
||||
private static final int SUPL_DATA_CONNECTION_OPENING = 1;
|
||||
private static final int SUPL_DATA_CONNECTION_OPEN = 2;
|
||||
|
||||
private static final String PROPERTIES_FILE = "/etc/gps.conf";
|
||||
|
||||
private int mLocationFlags = LOCATION_INVALID;
|
||||
@@ -176,6 +190,9 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
private String mSuplHost;
|
||||
private int mSuplPort;
|
||||
private boolean mSetSuplServer;
|
||||
private String mSuplApn;
|
||||
private int mSuplDataConnectionState;
|
||||
private ConnectivityManager mConnMgr;
|
||||
|
||||
// how often to request NTP time, in milliseconds
|
||||
// current setting 4 hours
|
||||
@@ -199,9 +216,11 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
Log.d(TAG, "state: " + state + " apnName: " + apnName + " reason: " + reason);
|
||||
}
|
||||
if ("CONNECTED".equals(state)) {
|
||||
native_set_supl_apn(apnName);
|
||||
} else {
|
||||
native_set_supl_apn("");
|
||||
mSuplApn = apnName;
|
||||
if (mSuplDataConnectionState == SUPL_DATA_CONNECTION_OPENING) {
|
||||
native_supl_data_conn_open(mSuplApn);
|
||||
mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,6 +239,8 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
|
||||
context.registerReceiver(receiver, intentFilter);
|
||||
|
||||
mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
mProperties = new Properties();
|
||||
try {
|
||||
File file = new File(PROPERTIES_FILE);
|
||||
@@ -782,7 +803,44 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* called from native code to update SUPL status
|
||||
*/
|
||||
private void reportSuplStatus(int status) {
|
||||
switch (status) {
|
||||
case GPS_REQUEST_SUPL_DATA_CONN:
|
||||
int result = mConnMgr.startUsingNetworkFeature(
|
||||
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
|
||||
if (result == Phone.APN_ALREADY_ACTIVE) {
|
||||
native_supl_data_conn_open(mSuplApn);
|
||||
mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPEN;
|
||||
} else if (result == Phone.APN_REQUEST_STARTED) {
|
||||
mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPENING;
|
||||
} else {
|
||||
native_supl_data_conn_failed();
|
||||
}
|
||||
break;
|
||||
case GPS_RELEASE_SUPL_DATA_CONN:
|
||||
if (mSuplDataConnectionState != SUPL_DATA_CONNECTION_CLOSED) {
|
||||
mConnMgr.stopUsingNetworkFeature(
|
||||
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
|
||||
native_supl_data_conn_closed();
|
||||
mSuplDataConnectionState = SUPL_DATA_CONNECTION_CLOSED;
|
||||
}
|
||||
break;
|
||||
case GPS_SUPL_DATA_CONNECTED:
|
||||
// Log.d(TAG, "GPS_SUPL_DATA_CONNECTED");
|
||||
break;
|
||||
case GPS_SUPL_DATA_CONN_DONE:
|
||||
// Log.d(TAG, "GPS_SUPL_DATA_CONN_DONE");
|
||||
break;
|
||||
case GPS_SUPL_DATA_CONN_FAILED:
|
||||
// Log.d(TAG, "GPS_SUPL_DATA_CONN_FAILED");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void xtraDownloadRequest() {
|
||||
if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
|
||||
if (mNetworkThread != null) {
|
||||
@@ -1002,6 +1060,8 @@ public class GpsLocationProvider extends LocationProviderImpl {
|
||||
private native void native_inject_xtra_data(byte[] data, int length);
|
||||
|
||||
// SUPL Support
|
||||
private native void native_supl_data_conn_open(String apn);
|
||||
private native void native_supl_data_conn_closed();
|
||||
private native void native_supl_data_conn_failed();
|
||||
private native void native_set_supl_server(int addr, int port);
|
||||
private native void native_set_supl_apn(String apn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user