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:
Mike Lockwood
2009-04-14 16:25:07 -04:00
parent 42ad56ead4
commit 58bda98766
2 changed files with 133 additions and 22 deletions

View File

@@ -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)

View File

@@ -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);
}