Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58bda987 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

gps: Add support for bringing up a GSM data connection on demand for SUPL.

parent 42ad56ea
Loading
Loading
Loading
Loading
+66 −15
Original line number Diff line number Diff line
@@ -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,30 +298,50 @@ 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)
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);
    }
    if (sGpsSuplInterface) {
        sGpsSuplInterface->set_server(addr, port);
        if (apn == NULL) {
            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
            return;
        }
        const char *apnStr = env->GetStringUTFChars(apn, NULL);
        sGpsSuplInterface->data_conn_open(apnStr);
        env->ReleaseStringUTFChars(apn, apnStr);
    }
}

static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobject obj, jstring apn)
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) {
        if (apn == NULL) {
            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
            return;
        sGpsSuplInterface->data_conn_closed();
    }
        const char *apnStr = env->GetStringUTFChars(apn, NULL);
        sGpsSuplInterface->set_apn(apnStr);
        env->ReleaseStringUTFChars(apn, apnStr);
}

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

@@ -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)
+65 −5
Original line number Diff line number Diff line
@@ -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);
@@ -783,6 +804,43 @@ public class GpsLocationProvider extends LocationProviderImpl {
        }
    }

    /**
     * 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);
}