diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 93e86afe2589c..4c39c308ef872 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -131,14 +131,11 @@ public class GpsNetInitiatedHandler { public String text; public int requestorIdEncoding; public int textEncoding; - public Bundle extras; }; public static class GpsNiResponse { /* User response, one of the values in GpsUserResponseType */ int userResponse; - /* Optional extra data to pass with the user response */ - Bundle extras; }; private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 45f54a9f88284..54366e6c587c3 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -95,7 +95,8 @@ import java.util.Arrays; import java.util.Date; import java.util.Map.Entry; import java.util.Properties; - +import java.util.Map; +import java.util.HashMap; import libcore.io.IoUtils; /** @@ -211,24 +212,18 @@ public class GnssLocationProvider implements LocationProviderInterface { private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; - // Request ref location - private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1; - private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2; + //TODO(b/33112647): Create gps_debug.conf with commented career parameters. + private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf"; // ref. location info private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; - private static final int AGPS_REG_LOCATION_TYPE_MAC = 3; // set id info private static final int AGPS_SETID_TYPE_NONE = 0; private static final int AGPS_SETID_TYPE_IMSI = 1; private static final int AGPS_SETID_TYPE_MSISDN = 2; - private static final String PROPERTIES_FILE_PREFIX = "/etc/gps"; - private static final String PROPERTIES_FILE_SUFFIX = ".conf"; - private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX; - private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; @@ -501,10 +496,6 @@ public class GnssLocationProvider implements LocationProviderInterface { startNavigating(false); } else if (action.equals(ALARM_TIMEOUT)) { hibernate(); - } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { - checkSmsSuplInit(intent); - } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { - checkWapSuplInit(intent); } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action) || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) || Intent.ACTION_SCREEN_OFF.equals(action) @@ -557,31 +548,6 @@ public class GnssLocationProvider implements LocationProviderInterface { } } - private void checkSmsSuplInit(Intent intent) { - SmsMessage[] messages = Intents.getMessagesFromIntent(intent); - if (messages == null) { - Log.e(TAG, "Message does not exist in the intent."); - return; - } - - for (SmsMessage message : messages) { - if (message != null && message.mWrappedSmsMessage != null) { - byte[] suplInit = message.getUserData(); - if (suplInit != null) { - native_agps_ni_message(suplInit, suplInit.length); - } - } - } - } - - private void checkWapSuplInit(Intent intent) { - byte[] suplInit = intent.getByteArrayExtra("data"); - if (suplInit == null) { - return; - } - native_agps_ni_message(suplInit,suplInit.length); - } - private void updateLowPowerMode() { // Disable GPS if we are in device idle mode. boolean disableGps = mPowerManager.isDeviceIdleMode(); @@ -602,23 +568,14 @@ public class GnssLocationProvider implements LocationProviderInterface { return native_is_supported(); } + interface SetCarrierProperty { + public boolean set(int value); + } + private void reloadGpsProperties(Context context, Properties properties) { if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size()); loadPropertiesFromResource(context, properties); - boolean isPropertiesLoadedFromFile = false; - final String gpsHardware = SystemProperties.get("ro.hardware.gps"); - - if (!TextUtils.isEmpty(gpsHardware)) { - final String propFilename = - PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX; - isPropertiesLoadedFromFile = - loadPropertiesFromFile(propFilename, properties); - } - if (!isPropertiesLoadedFromFile) { - loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties); - } - if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size()); String lpp_prof = SystemProperties.get(LPP_PROFILE); if (!TextUtils.isEmpty(lpp_prof)) { // override default value of this if lpp_prof is not empty @@ -636,16 +593,37 @@ public class GnssLocationProvider implements LocationProviderInterface { Log.e(TAG, "unable to parse C2K_PORT: " + portString); } } - + /* + * Allow carrier properties to be loaded from a debug configuration file. + */ + loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties); if (native_is_gnss_configuration_supported()) { - try { - // Convert properties to string contents and send it to HAL. - ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); - properties.store(baos, null); - native_configuration_update(baos.toString()); - if (DEBUG) Log.d(TAG, "final config = " + baos.toString()); - } catch (IOException ex) { - Log.e(TAG, "failed to dump properties contents"); + Map map = new HashMap() { + { + put("SUPL_VER", (val) -> native_set_supl_version(val)); + put("SUPL_MODE", (val) -> native_set_supl_mode(val)); + put("SUPL_ES", (val) -> native_set_supl_es(val)); + put("LPP_PROFILE", (val) -> native_set_lpp_profile(val)); + put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val)); + put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val)); + put("GPS_LOCK", (val) -> native_set_gps_lock(val)); + } + }; + + for(Entry entry : map.entrySet()) { + String propertyName = entry.getKey(); + String propertyValueString = properties.getProperty(propertyName); + if (propertyValueString != null) { + try { + int propertyValueInt = Integer.decode(propertyValueString); + boolean result = entry.getValue().set(propertyValueInt); + if (result == false) { + Log.e(TAG, "Unable to set " + propertyName); + } + } catch (NumberFormatException e) { + Log.e(TAG, "unable to parse propertyName: " + propertyValueString); + } + } } } else if (DEBUG) { Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" @@ -692,7 +670,7 @@ public class GnssLocationProvider implements LocationProviderInterface { } } catch (IOException e) { - Log.w(TAG, "Could not open GPS configuration file " + filename); + Log.v(TAG, "Could not open GPS configuration file " + filename); return false; } return true; @@ -1973,8 +1951,7 @@ public class GnssLocationProvider implements LocationProviderInterface { String requestorId, String text, int requestorIdEncoding, - int textEncoding, - String extras // Encoded extra data + int textEncoding ) { Log.i(TAG, "reportNiNotification: entered"); @@ -2003,28 +1980,6 @@ public class GnssLocationProvider implements LocationProviderInterface { notification.requestorIdEncoding = requestorIdEncoding; notification.textEncoding = textEncoding; - // Process extras, assuming the format is - // one of more lines of "key = value" - Bundle bundle = new Bundle(); - - if (extras == null) extras = ""; - Properties extraProp = new Properties(); - - try { - extraProp.load(new StringReader(extras)); - } - catch (IOException e) - { - Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); - } - - for (Entry ent : extraProp.entrySet()) - { - bundle.putString((String) ent.getKey(), (String) ent.getValue()); - } - - notification.extras = bundle; - mNIHandler.handleNiNotification(notification); } @@ -2075,7 +2030,7 @@ public class GnssLocationProvider implements LocationProviderInterface { * Called from native code to request reference location info */ - private void requestRefLocation(int flags) { + private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); final int phoneType = phone.getPhoneType(); @@ -2547,5 +2502,12 @@ public class GnssLocationProvider implements LocationProviderInterface { private native boolean native_stop_navigation_message_collection(); // GNSS Configuration - private static native void native_configuration_update(String configData); + private static native boolean native_set_supl_version(int version); + private static native boolean native_set_supl_mode(int mode); + private static native boolean native_set_supl_es(int es); + private static native boolean native_set_lpp_profile(int lppProfile); + private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect); + private static native boolean native_set_gps_lock(int gpsLock); + private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); + } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 4d43e8e9c3686..0006860ea437a 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -72,6 +72,7 @@ LOCAL_SHARED_LIBRARIES += \ libhwbinder \ libutils \ android.hardware.audio.common@2.0 \ + android.hardware.gnss@1.0 \ android.hardware.light@2.0 \ android.hardware.power@1.0 \ android.hardware.thermal@1.0 \ diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 25e819c2c1dcb..b0a4297da86e5 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -18,10 +18,13 @@ #define LOG_NDEBUG 0 +#include + +#include +#include + #include "JNIHelp.h" #include "jni.h" -#include "hardware/hardware.h" -#include "hardware/gps_internal.h" #include "hardware_legacy/power.h" #include "utils/Log.h" #include "utils/misc.h" @@ -34,6 +37,7 @@ #include #include #include +#include static jobject mCallbacksObj = NULL; @@ -58,978 +62,65 @@ static jmethodID method_reportGeofenceResumeStatus; static jmethodID method_reportMeasurementData; static jmethodID method_reportNavigationMessages; -static const GpsInterface* sGpsInterface = NULL; -static const GpsXtraInterface* sGpsXtraInterface = NULL; -static const AGpsInterface* sAGpsInterface = NULL; -static const GpsNiInterface* sGpsNiInterface = NULL; -static const GpsDebugInterface* sGpsDebugInterface = NULL; -static const AGpsRilInterface* sAGpsRilInterface = NULL; -static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL; -static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL; -static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL; -static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL; +using android::OK; +using android::sp; +using android::status_t; +using android::String16; -#define GPS_MAX_SATELLITE_COUNT 32 -#define GNSS_MAX_SATELLITE_COUNT 64 +using android::hardware::IPCThreadState; +using android::hardware::ProcessState; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::hidl_vec; -// Let these through, with ID remapped down to 1, 2... by offset -#define GLONASS_SVID_OFFSET 64 -#define GLONASS_SVID_COUNT 24 -#define BEIDOU_SVID_OFFSET 200 -#define BEIDOU_SVID_COUNT 35 +using android::hardware::gnss::V1_0::IAGnss; +using android::hardware::gnss::V1_0::IAGnssCallback; +using android::hardware::gnss::V1_0::IAGnssCallback; +using android::hardware::gnss::V1_0::IAGnssRil; +using android::hardware::gnss::V1_0::IAGnssRilCallback; +using android::hardware::gnss::V1_0::IGnss; +using android::hardware::gnss::V1_0::IGnssCallback; +using android::hardware::gnss::V1_0::IGnssConfiguration; +using android::hardware::gnss::V1_0::IGnssDebug; +using android::hardware::gnss::V1_0::IGnssGeofenceCallback; +using android::hardware::gnss::V1_0::IGnssGeofencing; +using android::hardware::gnss::V1_0::IGnssMeasurement; +using android::hardware::gnss::V1_0::IGnssMeasurementCallback; +using android::hardware::gnss::V1_0::IGnssNavigationMessage; +using android::hardware::gnss::V1_0::IGnssNavigationMessageCallback; +using android::hardware::gnss::V1_0::IGnssNi; +using android::hardware::gnss::V1_0::IGnssNiCallback; +using android::hardware::gnss::V1_0::IGnssXtra; +using android::hardware::gnss::V1_0::IGnssXtraCallback; -// Let these through, with ID remapped up (33->120 ... 64->151, etc.) -#define SBAS_SVID_MIN 33 -#define SBAS_SVID_MAX 64 -#define SBAS_SVID_ADD 87 -// Let these through, with no ID remapping -#define QZSS_SVID_MIN 193 -#define QZSS_SVID_MAX 200 - -#define SVID_SHIFT_WIDTH 7 -#define CONSTELLATION_TYPE_SHIFT_WIDTH 3 - -// temporary storage for GPS callbacks -static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT]; -static size_t sGnssSvListSize; -static const char* sNmeaString; -static int sNmeaStringLength; +sp gnssHal = nullptr; +sp gnssXtraIface = nullptr; +sp agnssRilIface = nullptr; +sp gnssGeofencingIface = nullptr; +sp agnssIface = nullptr; +sp gnssDebugIface = nullptr; +sp gnssConfigurationIface = nullptr; +sp gnssNiIface = nullptr; +sp gnssMeasurementIface = nullptr; +sp gnssNavigationMessageIface = nullptr; #define WAKE_LOCK_NAME "GPS" namespace android { -static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { - if (env->ExceptionCheck()) { - ALOGE("An exception was thrown by callback '%s'.", methodName); - LOGE_EX(env); - env->ExceptionClear(); - } -} - -static void location_callback(GpsLocation* location) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags, - (jdouble)location->latitude, (jdouble)location->longitude, - (jdouble)location->altitude, - (jfloat)location->speed, (jfloat)location->bearing, - (jfloat)location->accuracy, (jlong)location->timestamp); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void status_callback(GpsStatus* status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void sv_status_callback(GpsSvStatus* sv_status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - size_t status_size = sv_status->size; - // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1 - // if it doesn't provide a valid size. - if (status_size == 0) { - ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size); - } - sGnssSvListSize = sv_status->num_svs; - // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list. - if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) { - ALOGW("Too many satellites %zd. Clamps to %d.", - sGnssSvListSize, - GPS_MAX_SATELLITE_COUNT); - sGnssSvListSize = GPS_MAX_SATELLITE_COUNT; - } - uint32_t ephemeris_mask = sv_status->ephemeris_mask; - uint32_t almanac_mask = sv_status->almanac_mask; - uint32_t used_in_fix_mask = sv_status->used_in_fix_mask; - for (size_t i = 0; i < sGnssSvListSize; i++) { - GnssSvInfo& info = sGnssSvList[i]; - info.svid = sv_status->sv_list[i].prn; - // Defacto mapping from the overused API that was designed for GPS-only - if (info.svid >=1 && info.svid <= 32) { - info.constellation = GNSS_CONSTELLATION_GPS; - } else if (info.svid > GLONASS_SVID_OFFSET && - info.svid <= GLONASS_SVID_OFFSET + GLONASS_SVID_COUNT) { - info.constellation = GNSS_CONSTELLATION_GLONASS; - info.svid -= GLONASS_SVID_OFFSET; - } else if (info.svid > BEIDOU_SVID_OFFSET && - info.svid <= BEIDOU_SVID_OFFSET + BEIDOU_SVID_COUNT) { - info.constellation = GNSS_CONSTELLATION_BEIDOU; - info.svid -= BEIDOU_SVID_OFFSET; - } else if (info.svid >= SBAS_SVID_MIN && info.svid <= SBAS_SVID_MAX) { - info.constellation = GNSS_CONSTELLATION_SBAS; - info.svid += SBAS_SVID_ADD; - } else if (info.svid >= QZSS_SVID_MIN && info.svid <= QZSS_SVID_MAX) { - info.constellation = GNSS_CONSTELLATION_QZSS; - } else { - ALOGD("Unknown constellation type with Svid = %d.", info.svid); - info.constellation = GNSS_CONSTELLATION_UNKNOWN; - } - info.c_n0_dbhz = sv_status->sv_list[i].snr; - info.elevation = sv_status->sv_list[i].elevation; - info.azimuth = sv_status->sv_list[i].azimuth; - info.flags = GNSS_SV_FLAGS_NONE; - // Only GPS info is valid for these fields, as these masks are just 32 bits, by GPS prn - if (info.constellation == GNSS_CONSTELLATION_GPS) { - int32_t this_svid_mask = (1 << (info.svid - 1)); - if ((ephemeris_mask & this_svid_mask) != 0) { - info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA; - } - if ((almanac_mask & this_svid_mask) != 0) { - info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA; - } - if ((used_in_fix_mask & this_svid_mask) != 0) { - info.flags |= GNSS_SV_FLAGS_USED_IN_FIX; - } - } - } - env->CallVoidMethod(mCallbacksObj, method_reportSvStatus); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void gnss_sv_status_callback(GnssSvStatus* sv_status) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - size_t status_size = sv_status->size; - // Check the size, and reject the object that has invalid size. - if (status_size != sizeof(GnssSvStatus)) { - ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size); - return; - } - sGnssSvListSize = sv_status->num_svs; - // Clamp the list size - if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) { - ALOGD("Too many satellites %zd. Clamps to %d.", - sGnssSvListSize, - GNSS_MAX_SATELLITE_COUNT); - sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT; - } - // Copy GNSS SV info into sGnssSvList, if any. - if (sGnssSvListSize > 0) { - memcpy(sGnssSvList, - sv_status->gnss_sv_list, - sizeof(GnssSvInfo) * sGnssSvListSize); - } - env->CallVoidMethod(mCallbacksObj, method_reportSvStatus); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - // The Java code will call back to read these values - // We do this to avoid creating unnecessary String objects - sNmeaString = nmea; - sNmeaStringLength = length; - env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void set_system_info_callback(const GnssSystemInfo* info) { - ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw); - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, - info->year_of_hw); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void set_capabilities_callback(uint32_t capabilities) -{ - ALOGD("set_capabilities_callback: %du\n", capabilities); - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void acquire_wakelock_callback() -{ - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); -} - -static void release_wakelock_callback() -{ - release_wake_lock(WAKE_LOCK_NAME); -} - -static void request_utc_time_callback() -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_requestUtcTime); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) -{ - return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); -} - -GpsCallbacks sGpsCallbacks = { - sizeof(GpsCallbacks), - location_callback, - status_callback, - sv_status_callback, - nmea_callback, - set_capabilities_callback, - acquire_wakelock_callback, - release_wakelock_callback, - create_thread_callback, - request_utc_time_callback, - set_system_info_callback, - gnss_sv_status_callback, -}; - -static void xtra_download_request_callback() -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -GpsXtraCallbacks sGpsXtraCallbacks = { - xtra_download_request_callback, - create_thread_callback, -}; - -static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order) -{ - if (INADDR_NONE == ip) { - return NULL; - } - - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jbyteArray byteArray = env->NewByteArray(4); - if (byteArray == NULL) { - ALOGE("Unable to allocate byte array for IPv4 address"); - return NULL; - } - - jbyte ipv4[4]; - if (net_order) { - ALOGV("Converting IPv4 address(net_order) %x", ip); - memcpy(ipv4, &ip, sizeof(ipv4)); - } else { - ALOGV("Converting IPv4 address(host_order) %x", ip); - //endianess transparent conversion from int to char[] - ipv4[0] = (jbyte) (ip & 0xFF); - ipv4[1] = (jbyte)((ip>>8) & 0xFF); - ipv4[2] = (jbyte)((ip>>16) & 0xFF); - ipv4[3] = (jbyte) (ip>>24); - } - - env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4); - return byteArray; -} - -static void agps_status_callback(AGpsStatus* agps_status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jbyteArray byteArray = NULL; - bool isSupported = false; - - size_t status_size = agps_status->size; - if (status_size == sizeof(AGpsStatus)) { - ALOGV("AGpsStatus is V3: %zd", status_size); - switch (agps_status->addr.ss_family) - { - case AF_INET: - { - struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr); - uint32_t ipAddr = *(uint32_t*)&(in->sin_addr); - byteArray = convert_to_ipv4(ipAddr, true /* net_order */); - if (ipAddr == INADDR_NONE || byteArray != NULL) { - isSupported = true; - } - IF_ALOGD() { - // log the IP for reference in case there is a bogus value pushed by HAL - char str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN); - ALOGD("AGPS IP is v4: %s", str); - } - } - break; - case AF_INET6: - { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr); - byteArray = env->NewByteArray(16); - if (byteArray != NULL) { - env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr)); - isSupported = true; - } else { - ALOGE("Unable to allocate byte array for IPv6 address."); - } - IF_ALOGD() { - // log the IP for reference in case there is a bogus value pushed by HAL - char str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN); - ALOGD("AGPS IP is v6: %s", str); - } - } - break; - default: - ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family); - break; - } - } else if (status_size >= sizeof(AGpsStatus_v2)) { - ALOGV("AGpsStatus is V2+: %zd", status_size); - // for back-compatibility reasons we check in v2 that the data structure size is greater or - // equal to the declared size in gps.h - uint32_t ipaddr = agps_status->ipaddr; - ALOGV("AGPS IP is v4: %x", ipaddr); - byteArray = convert_to_ipv4(ipaddr, false /* net_order */); - if (ipaddr == INADDR_NONE || byteArray != NULL) { - isSupported = true; - } - } else if (status_size >= sizeof(AGpsStatus_v1)) { - ALOGV("AGpsStatus is V1+: %zd", status_size); - // because we have to check for >= with regards to v2, we also need to relax the check here - // and only make sure that the size is at least what we expect - isSupported = true; - } else { - ALOGE("Invalid size of AGpsStatus found: %zd.", status_size); - } - - if (isSupported) { - jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0; - ALOGV("Passing AGPS IP addr: size %d", byteArrayLength); - env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type, - agps_status->status, byteArray); - - checkAndClearExceptionFromCallback(env, __FUNCTION__); - } else { - ALOGD("Skipping calling method_reportAGpsStatus."); - } - - if (byteArray) { - env->DeleteLocalRef(byteArray); - } -} - -AGpsCallbacks sAGpsCallbacks = { - agps_status_callback, - create_thread_callback, -}; - -static void gps_ni_notify_callback(GpsNiNotification *notification) -{ - ALOGD("gps_ni_notify_callback\n"); - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jstring requestor_id = env->NewStringUTF(notification->requestor_id); - jstring text = env->NewStringUTF(notification->text); - jstring extras = env->NewStringUTF(notification->extras); - - if (requestor_id && text && extras) { - env->CallVoidMethod(mCallbacksObj, method_reportNiNotification, - notification->notification_id, notification->ni_type, - notification->notify_flags, notification->timeout, - notification->default_response, requestor_id, text, - notification->requestor_id_encoding, - notification->text_encoding, extras); - } else { - ALOGE("out of memory in gps_ni_notify_callback\n"); - } - - if (requestor_id) - env->DeleteLocalRef(requestor_id); - if (text) - env->DeleteLocalRef(text); - if (extras) - env->DeleteLocalRef(extras); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -GpsNiCallbacks sGpsNiCallbacks = { - gps_ni_notify_callback, - create_thread_callback, -}; - -static void agps_request_set_id(uint32_t flags) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -static void agps_request_ref_location(uint32_t flags) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} - -AGpsRilCallbacks sAGpsRilCallbacks = { - agps_request_set_id, - agps_request_ref_location, - create_thread_callback, -}; - -static void gps_geofence_transition_callback(int32_t geofence_id, GpsLocation* location, - int32_t transition, GpsUtcTime timestamp) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - - env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id, - location->flags, (jdouble)location->latitude, (jdouble)location->longitude, - (jdouble)location->altitude, - (jfloat)location->speed, (jfloat)location->bearing, - (jfloat)location->accuracy, (jlong)location->timestamp, - transition, timestamp); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -static void gps_geofence_status_callback(int32_t status, GpsLocation* location) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jint flags = 0; - jdouble latitude = 0; - jdouble longitude = 0; - jdouble altitude = 0; - jfloat speed = 0; - jfloat bearing = 0; - jfloat accuracy = 0; - jlong timestamp = 0; - if (location != NULL) { - flags = location->flags; - latitude = location->latitude; - longitude = location->longitude; - altitude = location->altitude; - speed = location->speed; - bearing = location->bearing; - accuracy = location->accuracy; - timestamp = location->timestamp; - } - - env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status, - flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -static void gps_geofence_add_callback(int32_t geofence_id, int32_t status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (status != GPS_GEOFENCE_OPERATION_SUCCESS) { - ALOGE("Error in geofence_add_callback: %d\n", status); - } - env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (status != GPS_GEOFENCE_OPERATION_SUCCESS) { - ALOGE("Error in geofence_remove_callback: %d\n", status); - } - env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (status != GPS_GEOFENCE_OPERATION_SUCCESS) { - ALOGE("Error in geofence_resume_callback: %d\n", status); - } - env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status) -{ - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (status != GPS_GEOFENCE_OPERATION_SUCCESS) { - ALOGE("Error in geofence_pause_callback: %d\n", status); - } - env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status); - checkAndClearExceptionFromCallback(env, __FUNCTION__); -}; - -GpsGeofenceCallbacks sGpsGeofenceCallbacks = { - gps_geofence_transition_callback, - gps_geofence_status_callback, - gps_geofence_add_callback, - gps_geofence_remove_callback, - gps_geofence_pause_callback, - gps_geofence_resume_callback, - create_thread_callback, -}; - -static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { - int err; - hw_module_t* module; - - method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); - method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); - method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); - method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V"); - method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); - method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); - method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V"); - method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); - method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", - "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); - method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V"); - method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V"); - method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V"); - method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition", - "(IIDDDFFFJIJ)V"); - method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus", - "(IIDDDFFFJ)V"); - method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus", - "(II)V"); - method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus", - "(II)V"); - method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus", - "(II)V"); - method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus", - "(II)V"); - method_reportMeasurementData = env->GetMethodID( - clazz, - "reportMeasurementData", - "(Landroid/location/GnssMeasurementsEvent;)V"); - method_reportNavigationMessages = env->GetMethodID( - clazz, - "reportNavigationMessage", - "(Landroid/location/GnssNavigationMessage;)V"); - - err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); - if (err == 0) { - hw_device_t* device; - err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); - if (err == 0) { - gps_device_t* gps_device = (gps_device_t *)device; - sGpsInterface = gps_device->get_gps_interface(gps_device); - } - } - if (sGpsInterface) { - sGpsXtraInterface = - (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE); - sAGpsInterface = - (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - sGpsNiInterface = - (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); - sGpsDebugInterface = - (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE); - sAGpsRilInterface = - (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE); - sGpsGeofencingInterface = - (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE); - sGpsMeasurementInterface = - (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE); - sGpsNavigationMessageInterface = - (const GpsNavigationMessageInterface*)sGpsInterface->get_extension( - GPS_NAVIGATION_MESSAGE_INTERFACE); - sGnssConfigurationInterface = - (const GnssConfigurationInterface*)sGpsInterface->get_extension( - GNSS_CONFIGURATION_INTERFACE); - } -} - -static jboolean android_location_GnssLocationProvider_is_supported( - JNIEnv* /* env */, jclass /* clazz */) -{ - return (sGpsInterface != NULL) ? JNI_TRUE : JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_is_agps_ril_supported( - JNIEnv* /* env */, jclass /* clazz */) -{ - return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE; -} - -static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported( - JNIEnv* /* env */, jclass /* jclazz */) -{ - return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) -{ - // this must be set before calling into the HAL library - if (!mCallbacksObj) - mCallbacksObj = env->NewGlobalRef(obj); - - // fail if the main interface fails to initialize - if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) - return JNI_FALSE; - - // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL, - // but continue to allow the rest of the GPS interface to work. - if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0) - sGpsXtraInterface = NULL; - if (sAGpsInterface) - sAGpsInterface->init(&sAGpsCallbacks); - if (sGpsNiInterface) - sGpsNiInterface->init(&sGpsNiCallbacks); - if (sAGpsRilInterface) - sAGpsRilInterface->init(&sAGpsRilCallbacks); - if (sGpsGeofencingInterface) - sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks); - - return JNI_TRUE; -} - -static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) -{ - if (sGpsInterface) - sGpsInterface->cleanup(); -} - -static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */, - jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, - jint preferred_time) -{ - if (sGpsInterface) { - if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, - preferred_time) == 0) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } - } - else - return JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) -{ - if (sGpsInterface) { - if (sGpsInterface->start() == 0) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } - } - else - return JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) -{ - if (sGpsInterface) { - if (sGpsInterface->stop() == 0) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } - } - else - return JNI_FALSE; -} - -static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */, - jobject /* obj */, - jint flags) -{ - if (sGpsInterface) - sGpsInterface->delete_aiding_data(flags); -} - -static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */, - jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray, - jfloatArray azumArray) -{ - // this should only be called from within a call to reportSvStatus - jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0); - jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0); - jfloat* elev = env->GetFloatArrayElements(elevArray, 0); - jfloat* azim = env->GetFloatArrayElements(azumArray, 0); - - // GNSS SV info. - for (size_t i = 0; i < sGnssSvListSize; ++i) { - const GnssSvInfo& info = sGnssSvList[i]; - svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) | - (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) | - info.flags; - cn0s[i] = info.c_n0_dbhz; - elev[i] = info.elevation; - azim[i] = info.azimuth; - } - - env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0); - env->ReleaseFloatArrayElements(cn0Array, cn0s, 0); - env->ReleaseFloatArrayElements(elevArray, elev, 0); - env->ReleaseFloatArrayElements(azumArray, azim, 0); - return (jint) sGnssSvListSize; -} - -static void android_location_GnssLocationProvider_agps_set_reference_location_cellid( - JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) -{ - AGpsRefLocation location; - - if (!sAGpsRilInterface) { - ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid"); - return; - } - - switch(type) { - case AGPS_REF_LOCATION_TYPE_GSM_CELLID: - case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: - location.type = type; - location.u.cellID.mcc = mcc; - location.u.cellID.mnc = mnc; - location.u.cellID.lac = lac; - location.u.cellID.cid = cid; - break; - default: - ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__); - return; - break; - } - sAGpsRilInterface->set_ref_location(&location, sizeof(location)); -} - -static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env, - jobject /* obj */, jbyteArray ni_msg, jint size) -{ - size_t sz; - - if (!sAGpsRilInterface) { - ALOGE("no AGPS RIL interface in send_ni_message"); - return; - } - if (size < 0) - return; - sz = (size_t)size; - jbyte* b = env->GetByteArrayElements(ni_msg, 0); - sAGpsRilInterface->ni_message((uint8_t *)b,sz); - env->ReleaseByteArrayElements(ni_msg,b,0); -} - -static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */, - jint type, jstring setid_string) -{ - if (!sAGpsRilInterface) { - ALOGE("no AGPS RIL interface in agps_set_id"); - return; - } - - const char *setid = env->GetStringUTFChars(setid_string, NULL); - sAGpsRilInterface->set_set_id(type, setid); - env->ReleaseStringUTFChars(setid_string, setid); -} - -static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */, - jbyteArray nmeaArray, jint buffer_size) -{ - // this should only be called from within a call to reportNmea - jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0); - int length = sNmeaStringLength; - if (length > buffer_size) - length = buffer_size; - memcpy(nmea, sNmeaString, length); - env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT); - return (jint) length; -} - -static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */, - jlong time, jlong timeReference, jint uncertainty) -{ - if (sGpsInterface) - sGpsInterface->inject_time(time, timeReference, uncertainty); -} - -static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, - jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) -{ - if (sGpsInterface) - sGpsInterface->inject_location(latitude, longitude, accuracy); -} - -static jboolean android_location_GnssLocationProvider_supports_xtra( - JNIEnv* /* env */, jobject /* obj */) -{ - return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE; -} - -static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */, - jbyteArray data, jint length) -{ - if (!sGpsXtraInterface) { - ALOGE("no XTRA interface in inject_xtra_data"); - return; - } - - jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0); - sGpsXtraInterface->inject_xtra_data((char *)bytes, length); - env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); -} - -static void android_location_GnssLocationProvider_agps_data_conn_open( - JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType) -{ - if (!sAGpsInterface) { - ALOGE("no AGPS interface in agps_data_conn_open"); - return; - } - if (apn == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return; - } - - const char *apnStr = env->GetStringUTFChars(apn, NULL); - - size_t interface_size = sAGpsInterface->size; - if (interface_size == sizeof(AGpsInterface)) { - sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType); - } else if (interface_size == sizeof(AGpsInterface_v1)) { - sAGpsInterface->data_conn_open(apnStr); - } else { - ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size); - } - - env->ReleaseStringUTFChars(apn, apnStr); -} - -static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */, - jobject /* obj */) -{ - if (!sAGpsInterface) { - ALOGE("no AGPS interface in agps_data_conn_closed"); - return; - } - sAGpsInterface->data_conn_closed(); -} - -static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */, - jobject /* obj */) -{ - if (!sAGpsInterface) { - ALOGE("no AGPS interface in agps_data_conn_failed"); - return; - } - sAGpsInterface->data_conn_failed(); -} - -static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */, - jint type, jstring hostname, jint port) -{ - if (!sAGpsInterface) { - ALOGE("no AGPS interface in set_agps_server"); - return; - } - const char *c_hostname = env->GetStringUTFChars(hostname, NULL); - sAGpsInterface->set_server(type, c_hostname, port); - env->ReleaseStringUTFChars(hostname, c_hostname); -} - -static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */, - jobject /* obj */, jint notifId, jint response) -{ - if (!sGpsNiInterface) { - ALOGE("no NI interface in send_ni_response"); - return; - } - - sGpsNiInterface->respond(notifId, response); -} - -static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, - jobject /* obj */) { - jstring result = NULL; - if (sGpsDebugInterface) { - const size_t maxLength = 2047; - char buffer[maxLength+1]; - size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength); - if (length > maxLength) length = maxLength; - buffer[length] = 0; - result = env->NewStringUTF(buffer); - } - return result; -} - -static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */, - jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn) -{ - - if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) { - if (extraInfo) { - const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL); - sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr); - env->ReleaseStringUTFChars(extraInfo, extraInfoStr); - } else { - sAGpsRilInterface->update_network_state(connected, type, roaming, NULL); - } - - // update_network_availability callback was not included in original AGpsRilInterface - if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface) - && sAGpsRilInterface->update_network_availability) { - const char *c_apn = env->GetStringUTFChars(apn, NULL); - sAGpsRilInterface->update_network_availability(available, c_apn); - env->ReleaseStringUTFChars(apn, c_apn); - } - } -} - -static jboolean android_location_GnssLocationProvider_is_geofence_supported( - JNIEnv* /* env */, jobject /* obj */) -{ - return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius, - jint last_transition, jint monitor_transition, jint notification_responsiveness, - jint unknown_timer) { - if (sGpsGeofencingInterface != NULL) { - sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude, - radius, last_transition, monitor_transition, notification_responsiveness, - unknown_timer); - return JNI_TRUE; - } else { - ALOGE("Geofence interface not available"); - } - return JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofence_id) { - if (sGpsGeofencingInterface != NULL) { - sGpsGeofencingInterface->remove_geofence_area(geofence_id); - return JNI_TRUE; - } else { - ALOGE("Geofence interface not available"); - } - return JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofence_id) { - if (sGpsGeofencingInterface != NULL) { - sGpsGeofencingInterface->pause_geofence(geofence_id); - return JNI_TRUE; - } else { - ALOGE("Geofence interface not available"); - } - return JNI_FALSE; -} - -static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofence_id, jint monitor_transition) { - if (sGpsGeofencingInterface != NULL) { - sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition); - return JNI_TRUE; - } else { - ALOGE("Geofence interface not available"); - } - return JNI_FALSE; -} - template class JavaMethodHelper { - public: - // Helper function to call setter on a Java object. - static void callJavaMethod( + public: + // Helper function to call setter on a Java object. + static void callJavaMethod( JNIEnv* env, jclass clazz, jobject object, const char* method_name, T value); - private: + private: static const char *const signature_; }; @@ -1045,20 +136,20 @@ void JavaMethodHelper::callJavaMethod( } class JavaObject { - public: - JavaObject(JNIEnv* env, const char* class_name); - virtual ~JavaObject(); + public: + JavaObject(JNIEnv* env, const char* class_name); + virtual ~JavaObject(); - template - void callSetter(const char* method_name, T value); - template - void callSetter(const char* method_name, T* value, size_t size); - jobject get(); + template + void callSetter(const char* method_name, T value); + template + void callSetter(const char* method_name, T* value, size_t size); + jobject get(); - private: - JNIEnv* env_; - jclass clazz_; - jobject object_; + private: + JNIEnv* env_; + jclass clazz_; + jobject object_; }; JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) { @@ -1081,7 +172,7 @@ template<> void JavaObject::callSetter( const char* method_name, uint8_t* value, size_t size) { jbyteArray array = env_->NewByteArray(size); - env_->SetByteArrayRegion(array, 0, size, (jbyte*) value); + env_->SetByteArrayRegion(array, 0, size, reinterpret_cast(value)); jmethodID method = env_->GetMethodID( clazz_, method_name, @@ -1095,7 +186,6 @@ jobject JavaObject::get() { } // Define Java method signatures for all known types. - template<> const char *const JavaMethodHelper::signature_ = "(B)V"; template<> @@ -1119,209 +209,460 @@ const char *const JavaMethodHelper::signature_ = "(Z)V"; #define SET(setter, value) object.callSetter("set" # setter, (value)) -// If you want to check if a flag is not set, use SET_IF_NOT(FLAG, setter, -// value) to do that. SET_IF(!FLAG, setter, value) won't compile. -// -// This macros generates compilation error if the provided 'flag' is not a -// single token. For example, 'GNSS_CLOCK_HAS_BIAS' can be accepted, but -// '!GNSS_CLOCK_HAS_DRIFT' will fail to compile. -#define SET_IF(flag, setter, value) do { \ - if (flags & flag) { \ - JavaObject& name_check_##flag = object; \ - name_check_##flag.callSetter("set" # setter, (value)); \ - } \ - } while (false) -#define SET_IF_NOT(flag, setter, value) do { \ - if (!(flags & flag)) { \ - JavaObject& name_check_##flag = object; \ - name_check_##flag.callSetter("set" # setter, (value)); \ - } \ - } while (false) +static inline jboolean boolToJbool(bool value) { + return value ? JNI_TRUE : JNI_FALSE; +} -static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) { - static uint32_t discontinuity_count_to_handle_old_clock_type = 0; - JavaObject object(env, "android/location/GnssClock"); - GpsClockFlags flags = clock->flags; +static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + ALOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + } +} - SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, - LeapSecond, - static_cast(clock->leap_second)); +/* + * GnssCallback class implements the callback methods for IGnss interface. + */ +struct GnssCallback : public IGnssCallback { + Return gnssLocationCb( + const android::hardware::gnss::V1_0::GnssLocation& location) override; + Return gnssStatusCb(const IGnssCallback::GnssStatusValue status) override; + Return gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; + Return gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override; + Return gnssSetCapabilitesCb(uint32_t capabilities) override; + Return gnssAcquireWakelockCb() override; + Return gnssReleaseWakelockCb() override; + Return gnssRequestTimeCb() override; + Return gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override; - // GnssClock only supports the more effective HW_CLOCK type, so type - // handling and documentation complexity has been removed. To convert the - // old GPS_CLOCK types (active only in a limited number of older devices), - // the GPS time information is handled as an always discontinuous HW clock, - // with the GPS time information put into the full_bias_ns instead - so that - // time_ns - full_bias_ns = local estimate of GPS time. Additionally, the - // sign of full_bias_ns and bias_ns has flipped between GpsClock & - // GnssClock, so that is also handled below. - switch (clock->type) { - case GPS_CLOCK_TYPE_UNKNOWN: - // Clock type unsupported. - ALOGE("Unknown clock type provided."); - break; - case GPS_CLOCK_TYPE_LOCAL_HW_TIME: - // Already local hardware time. No need to do anything. - break; - case GPS_CLOCK_TYPE_GPS_TIME: - // GPS time, need to convert. - flags |= GPS_CLOCK_HAS_FULL_BIAS; - clock->full_bias_ns = clock->time_ns; - clock->time_ns = 0; - SET(HardwareClockDiscontinuityCount, - discontinuity_count_to_handle_old_clock_type++); - break; + static GnssSvInfo sGnssSvList[static_cast( + android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)]; + static size_t sGnssSvListSize; + + static const char* sNmeaString; + static size_t sNmeaStringLength; +}; + +IGnssCallback::GnssSvInfo GnssCallback::sGnssSvList[static_cast( + android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)]; +const char* GnssCallback::sNmeaString = nullptr; +size_t GnssCallback::sNmeaStringLength = 0; +size_t GnssCallback::sGnssSvListSize = 0; + +Return GnssCallback::gnssLocationCb( + const ::android::hardware::gnss::V1_0::GnssLocation& location) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, + method_reportLocation, + location.gnssLocationFlags, + static_cast(location.latitudeDegrees), + static_cast(location.longitudeDegrees), + static_cast(location.altitudeMeters), + static_cast(location.speedMetersPerSec), + static_cast(location.bearingDegrees), + static_cast(location.accuracyMeters), + static_cast(location.timestamp)); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_reportStatus, status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + sGnssSvListSize = svStatus.numSvs; + if (sGnssSvListSize > static_cast( + android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) { + ALOGD("Too many satellites %zd. Clamps to %u.", sGnssSvListSize, + static_cast(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)); + sGnssSvListSize = static_cast(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT); } - SET(TimeNanos, clock->time_ns); - SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY, - TimeUncertaintyNanos, - clock->time_uncertainty_ns); - - // Definition of sign for full_bias_ns & bias_ns has been changed since N, - // so flip signs here. - SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, -(clock->full_bias_ns)); - SET_IF(GPS_CLOCK_HAS_BIAS, BiasNanos, -(clock->bias_ns)); - - SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY, - BiasUncertaintyNanos, - clock->bias_uncertainty_ns); - SET_IF(GPS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps); - SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY, - DriftUncertaintyNanosPerSecond, - clock->drift_uncertainty_nsps); - - return object.get(); -} - -static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) { - JavaObject object(env, "android/location/GnssClock"); - GnssClockFlags flags = clock->flags; - - SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, - LeapSecond, - static_cast(clock->leap_second)); - SET(TimeNanos, clock->time_ns); - SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY, - TimeUncertaintyNanos, - clock->time_uncertainty_ns); - SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns); - SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns); - SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY, - BiasUncertaintyNanos, - clock->bias_uncertainty_ns); - SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps); - SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY, - DriftUncertaintyNanosPerSecond, - clock->drift_uncertainty_nsps); - - SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count); - - return object.get(); -} - -static jobject translate_gps_measurement(JNIEnv* env, - GpsMeasurement* measurement) { - JavaObject object(env, "android/location/GnssMeasurement"); - GpsMeasurementFlags flags = measurement->flags; - SET(Svid, static_cast(measurement->prn)); - if (measurement->prn >= 1 && measurement->prn <= 32) { - SET(ConstellationType, static_cast(GNSS_CONSTELLATION_GPS)); - } else { - ALOGD("Unknown constellation type with Svid = %d.", measurement->prn); - SET(ConstellationType, - static_cast(GNSS_CONSTELLATION_UNKNOWN)); + // Copy GNSS SV info into sGnssSvList, if any. + if (svStatus.numSvs > 0) { + memcpy(sGnssSvList, svStatus.gnssSvList.data(), sizeof(GnssSvInfo) * sGnssSvListSize); } - SET(TimeOffsetNanos, measurement->time_offset_ns); - SET(State, static_cast(measurement->state)); - SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns); - SET(ReceivedSvTimeUncertaintyNanos, - measurement->received_gps_tow_uncertainty_ns); - SET(Cn0DbHz, measurement->c_n0_dbhz); - SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps); - SET(PseudorangeRateUncertaintyMetersPerSecond, - measurement->pseudorange_rate_uncertainty_mps); - SET(AccumulatedDeltaRangeState, - static_cast(measurement->accumulated_delta_range_state)); - SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m); - SET(AccumulatedDeltaRangeUncertaintyMeters, - measurement->accumulated_delta_range_uncertainty_m); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY, - CarrierFrequencyHz, - measurement->carrier_frequency_hz); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES, - CarrierCycles, - measurement->carrier_cycles); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE, - CarrierPhase, - measurement->carrier_phase); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY, - CarrierPhaseUncertainty, - measurement->carrier_phase_uncertainty); - SET(MultipathIndicator, - static_cast(measurement->multipath_indicator)); - SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db); - return object.get(); + env->CallVoidMethod(mCallbacksObj, method_reportSvStatus); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); } -static jobject translate_gnss_measurement(JNIEnv* env, - GnssMeasurement* measurement) { +Return GnssCallback::gnssNmeaCb( + int64_t timestamp, const ::android::hardware::hidl_string& nmea) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + /* + * The Java code will call back to read these values. + * We do this to avoid creating unnecessary String objects. + */ + sNmeaString = nmea.c_str(); + sNmeaStringLength = nmea.size(); + + env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { + ALOGD("%s: %du\n", __func__, capabilities); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssCallback::gnssAcquireWakelockCb() { + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); + return Void(); +} + +Return GnssCallback::gnssReleaseWakelockCb() { + release_wake_lock(WAKE_LOCK_NAME); + return Void(); +} + +Return GnssCallback::gnssRequestTimeCb() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestUtcTime); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) { + ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, + info.yearOfHw); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +class GnssXtraCallback : public IGnssXtraCallback { + Return downloadRequestCb() override; +}; + +/* + * GnssXtraCallback class implements the callback methods for the IGnssXtra + * interface. + */ +Return GnssXtraCallback::downloadRequestCb() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +/* + * GnssGeofenceCallback class implements the callback methods for the + * IGnssGeofence interface. + */ +struct GnssGeofenceCallback : public IGnssGeofenceCallback { + // Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow. + Return gnssGeofenceTransitionCb( + int32_t geofenceId, + const android::hardware::gnss::V1_0::GnssLocation& location, + GeofenceTransition transition, + hardware::gnss::V1_0::GnssUtcTime timestamp) override; + Return gnssGeofenceStatusCb( + GeofenceAvailability status, + const android::hardware::gnss::V1_0::GnssLocation& location) override; + Return gnssGeofenceAddCb(int32_t geofenceId, + GeofenceStatus status) override; + Return gnssGeofenceRemoveCb(int32_t geofenceId, + GeofenceStatus status) override; + Return gnssGeofencePauseCb(int32_t geofenceId, + GeofenceStatus status) override; + Return gnssGeofenceResumeCb(int32_t geofenceId, + GeofenceStatus status) override; +}; + +Return GnssGeofenceCallback::gnssGeofenceTransitionCb( + int32_t geofenceId, + const android::hardware::gnss::V1_0::GnssLocation& location, + GeofenceTransition transition, + hardware::gnss::V1_0::GnssUtcTime timestamp) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + env->CallVoidMethod(mCallbacksObj, + method_reportGeofenceTransition, + geofenceId, + location.gnssLocationFlags, + static_cast(location.latitudeDegrees), + static_cast(location.longitudeDegrees), + static_cast(location.altitudeMeters), + static_cast(location.speedMetersPerSec), + static_cast(location.bearingDegrees), + static_cast(location.accuracyMeters), + static_cast(location.timestamp), + transition, + timestamp); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssGeofenceCallback::gnssGeofenceStatusCb( + GeofenceAvailability status, + const android::hardware::gnss::V1_0::GnssLocation& location) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, + method_reportGeofenceStatus, + status, + location.gnssLocationFlags, + static_cast(location.latitudeDegrees), + static_cast(location.longitudeDegrees), + static_cast(location.altitudeMeters), + static_cast(location.speedMetersPerSec), + static_cast(location.bearingDegrees), + static_cast(location.accuracyMeters), + static_cast(location.timestamp)); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId, + GeofenceStatus status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) { + ALOGE("%s: Error in adding a Geofence: %d\n", __func__, status); + } + + env->CallVoidMethod(mCallbacksObj, + method_reportGeofenceAddStatus, + geofenceId, + status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId, + GeofenceStatus status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) { + ALOGE("%s: Error in removing a Geofence: %d\n", __func__, status); + } + + env->CallVoidMethod(mCallbacksObj, + method_reportGeofenceRemoveStatus, + geofenceId, status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId, + GeofenceStatus status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) { + ALOGE("%s: Error in pausing Geofence: %d\n", __func__, status); + } + + env->CallVoidMethod(mCallbacksObj, + method_reportGeofencePauseStatus, + geofenceId, status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId, + GeofenceStatus status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) { + ALOGE("%s: Error in resuming Geofence: %d\n", __func__, status); + } + + env->CallVoidMethod(mCallbacksObj, + method_reportGeofenceResumeStatus, + geofenceId, status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +/* + * GnssNavigationMessageCallback interface implements the callback methods + * required by the IGnssNavigationMessage interface. + */ +struct GnssNavigationMessageCallback : public IGnssNavigationMessageCallback { + /* + * Methods from ::android::hardware::gps::V1_0::IGnssNavigationMessageCallback + * follow. + */ + Return gnssNavigationMessageCb( + const IGnssNavigationMessageCallback::GnssNavigationMessage& message) override; +}; + +Return GnssNavigationMessageCallback::gnssNavigationMessageCb( + const IGnssNavigationMessageCallback::GnssNavigationMessage& message) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + size_t dataLength = message.data.size(); + + std::vector navigationData = message.data; + uint8_t* data = &(navigationData[0]); + if (dataLength == 0 || data == NULL) { + ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, + dataLength); + return Void(); + } + + JavaObject object(env, "android/location/GnssNavigationMessage"); + SET(Type, static_cast(message.type)); + SET(Svid, static_cast(message.svid)); + SET(MessageId, static_cast(message.messageId)); + SET(SubmessageId, static_cast(message.submessageId)); + object.callSetter("setData", data, dataLength); + SET(Status, static_cast(message.status)); + + jobject navigationMessage = object.get(); + env->CallVoidMethod(mCallbacksObj, + method_reportNavigationMessages, + navigationMessage); + env->DeleteLocalRef(navigationMessage); + return Void(); +} + +/* + * GnssMeasurementCallback implements the callback methods required for the + * GnssMeasurement interface. + */ +struct GnssMeasurementCallback : public IGnssMeasurementCallback { + Return GnssMeasurementCb(const IGnssMeasurementCallback::GnssData& data); + private: + jobject translateGnssMeasurement( + JNIEnv* env, const IGnssMeasurementCallback::GnssMeasurement* measurement); + jobject translateGnssClock( + JNIEnv* env, const IGnssMeasurementCallback::GnssClock* clock); + jobjectArray translateGnssMeasurements( + JNIEnv* env, + const IGnssMeasurementCallback::GnssMeasurement* measurements, + size_t count); + void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray); +}; + + +Return GnssMeasurementCallback::GnssMeasurementCb( + const IGnssMeasurementCallback::GnssData& data) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + jobject clock; + jobjectArray measurementArray; + + clock = translateGnssClock(env, &data.clock); + measurementArray = translateGnssMeasurements( + env, data.measurements.data(), data.measurementCount); + setMeasurementData(env, clock, measurementArray); + + env->DeleteLocalRef(clock); + env->DeleteLocalRef(measurementArray); + return Void(); +} + +jobject GnssMeasurementCallback::translateGnssMeasurement( + JNIEnv* env, const IGnssMeasurementCallback::GnssMeasurement* measurement) { JavaObject object(env, "android/location/GnssMeasurement"); - GnssMeasurementFlags flags = measurement->flags; + uint32_t flags = static_cast(measurement->flags); SET(Svid, static_cast(measurement->svid)); SET(ConstellationType, static_cast(measurement->constellation)); - SET(TimeOffsetNanos, measurement->time_offset_ns); + SET(TimeOffsetNanos, measurement->timeOffsetNs); SET(State, static_cast(measurement->state)); - SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns); + SET(ReceivedSvTimeNanos, measurement->receivedSvTimeInNs); SET(ReceivedSvTimeUncertaintyNanos, - measurement->received_sv_time_uncertainty_in_ns); - SET(Cn0DbHz, measurement->c_n0_dbhz); - SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps); + measurement->receivedSvTimeUncertaintyInNs); + SET(Cn0DbHz, measurement->cN0DbHz); + SET(PseudorangeRateMetersPerSecond, measurement->pseudorangeRateMps); SET(PseudorangeRateUncertaintyMetersPerSecond, - measurement->pseudorange_rate_uncertainty_mps); + measurement->pseudorangeRateUncertaintyMps); SET(AccumulatedDeltaRangeState, - static_cast(measurement->accumulated_delta_range_state)); - SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m); + (static_cast(measurement->accumulatedDeltaRangeState))); + SET(AccumulatedDeltaRangeMeters, measurement->accumulatedDeltaRangeM); SET(AccumulatedDeltaRangeUncertaintyMeters, - measurement->accumulated_delta_range_uncertainty_m); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY, - CarrierFrequencyHz, - measurement->carrier_frequency_hz); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES, - CarrierCycles, - measurement->carrier_cycles); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE, - CarrierPhase, - measurement->carrier_phase); - SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY, - CarrierPhaseUncertainty, - measurement->carrier_phase_uncertainty); - SET(MultipathIndicator, - static_cast(measurement->multipath_indicator)); - SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db); + measurement->accumulatedDeltaRangeUncertaintyM); + + if (flags & static_cast(GnssMeasurementFlags::HAS_CARRIER_FREQUENCY)) { + SET(CarrierFrequencyHz, measurement->carrierFrequencyHz); + } + + if (flags & static_cast(GnssMeasurementFlags::HAS_CARRIER_PHASE)) { + SET(CarrierPhase, measurement->carrierPhase); + } + + if (flags & static_cast(GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY)) { + SET(CarrierPhaseUncertainty, measurement->carrierPhaseUncertainty); + } + + SET(MultipathIndicator, static_cast(measurement->multipathIndicator)); + + if (flags & static_cast(GnssMeasurementFlags::HAS_SNR)) { + SET(SnrInDb, measurement->snrDb); + } return object.get(); } -static jobjectArray translate_gps_measurements(JNIEnv* env, - GpsMeasurement* measurements, - size_t count) { +jobject GnssMeasurementCallback::translateGnssClock( + JNIEnv* env, const IGnssMeasurementCallback::GnssClock* clock) { + JavaObject object(env, "android/location/GnssClock"); + + uint32_t flags = static_cast(clock->gnssClockFlags); + if (flags & static_cast(GnssClockFlags::HAS_LEAP_SECOND)) { + SET(LeapSecond, static_cast(clock->leapSecond)); + } + + if (flags & static_cast(GnssClockFlags::HAS_TIME_UNCERTAINTY)) { + SET(TimeUncertaintyNanos, clock->timeUncertaintyNs); + } + + if (flags & static_cast(GnssClockFlags::HAS_FULL_BIAS)) { + SET(FullBiasNanos, clock->fullBiasNs); + } + + if (flags & static_cast(GnssClockFlags::HAS_BIAS)) { + SET(BiasNanos, clock->biasNs); + } + + if (flags & static_cast(GnssClockFlags::HAS_BIAS_UNCERTAINTY)) { + SET(BiasUncertaintyNanos, clock->biasUncertaintyNs); + } + + if (flags & static_cast(GnssClockFlags::HAS_DRIFT)) { + SET(DriftNanosPerSecond, clock->driftNsps); + } + + if (flags & static_cast(GnssClockFlags::HAS_DRIFT_UNCERTAINTY)) { + SET(DriftUncertaintyNanosPerSecond, clock->driftUncertaintyNsps); + } + + SET(TimeNanos, clock->timeNs); + SET(HardwareClockDiscontinuityCount, clock->hwClockDiscontinuityCount); + + return object.get(); +} + +jobjectArray GnssMeasurementCallback::translateGnssMeasurements(JNIEnv* env, + const IGnssMeasurementCallback::GnssMeasurement* + measurements, size_t count) { if (count == 0) { return NULL; } - jclass gnssMeasurementClass = env->FindClass( - "android/location/GnssMeasurement"); + jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement"); jobjectArray gnssMeasurementArray = env->NewObjectArray( count, gnssMeasurementClass, NULL /* initialElement */); for (uint16_t i = 0; i < count; ++i) { - jobject gnssMeasurement = translate_gps_measurement( + jobject gnssMeasurement = translateGnssMeasurement( env, &measurements[i]); env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement); @@ -1332,130 +673,789 @@ static jobjectArray translate_gps_measurements(JNIEnv* env, return gnssMeasurementArray; } -static jobjectArray translate_gnss_measurements(JNIEnv* env, - GnssMeasurement* measurements, - size_t count) { - if (count == 0) { - return NULL; - } +void GnssMeasurementCallback::setMeasurementData(JNIEnv* env, jobject clock, + jobjectArray measurementArray) { + jclass gnssMeasurementsEventClass = + env->FindClass("android/location/GnssMeasurementsEvent"); + jmethodID gnssMeasurementsEventCtor = + env->GetMethodID( + gnssMeasurementsEventClass, + "", + "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V"); - jclass gnssMeasurementClass = env->FindClass( - "android/location/GnssMeasurement"); - jobjectArray gnssMeasurementArray = env->NewObjectArray( - count, - gnssMeasurementClass, - NULL /* initialElement */); + jobject gnssMeasurementsEvent = env->NewObject(gnssMeasurementsEventClass, + gnssMeasurementsEventCtor, + clock, + measurementArray); - for (uint16_t i = 0; i < count; ++i) { - jobject gnssMeasurement = translate_gnss_measurement( - env, - &measurements[i]); - env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement); - env->DeleteLocalRef(gnssMeasurement); - } - - env->DeleteLocalRef(gnssMeasurementClass); - return gnssMeasurementArray; -} - -static void set_measurement_data(JNIEnv *env, - jobject clock, - jobjectArray measurementArray) { - jclass gnssMeasurementsEventClass = env->FindClass( - "android/location/GnssMeasurementsEvent"); - jmethodID gnssMeasurementsEventCtor = env->GetMethodID( - gnssMeasurementsEventClass, - "", - "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V"); - - jobject gnssMeasurementsEvent = env->NewObject( - gnssMeasurementsEventClass, - gnssMeasurementsEventCtor, - clock, - measurementArray); - env->CallVoidMethod(mCallbacksObj, - method_reportMeasurementData, - gnssMeasurementsEvent); + env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, + gnssMeasurementsEvent); checkAndClearExceptionFromCallback(env, __FUNCTION__); env->DeleteLocalRef(gnssMeasurementsEventClass); env->DeleteLocalRef(gnssMeasurementsEvent); } -static void measurement_callback(GpsData* data) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (data == NULL) { - ALOGE("Invalid data provided to gps_measurement_callback"); - return; - } - if (data->size != sizeof(GpsData)) { - ALOGE("Invalid GpsData size found in gps_measurement_callback, " - "size=%zd", - data->size); - return; - } - - jobject clock; - jobjectArray measurementArray; - clock = translate_gps_clock(env, &data->clock); - measurementArray = translate_gps_measurements( - env, data->measurements, data->measurement_count); - set_measurement_data(env, clock, measurementArray); - - env->DeleteLocalRef(clock); - env->DeleteLocalRef(measurementArray); -} - -static void gnss_measurement_callback(GnssData* data) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (data == NULL) { - ALOGE("Invalid data provided to gps_measurement_callback"); - return; - } - if (data->size != sizeof(GnssData)) { - ALOGE("Invalid GnssData size found in gnss_measurement_callback, " - "size=%zd", - data->size); - return; - } - - jobject clock; - jobjectArray measurementArray; - clock = translate_gnss_clock(env, &data->clock); - measurementArray = translate_gnss_measurements( - env, data->measurements, data->measurement_count); - set_measurement_data(env, clock, measurementArray); - - env->DeleteLocalRef(clock); - env->DeleteLocalRef(measurementArray); -} - -GpsMeasurementCallbacks sGpsMeasurementCallbacks = { - sizeof(GpsMeasurementCallbacks), - measurement_callback, - gnss_measurement_callback, +/* + * GnssNiCallback implements callback methods required by the IGnssNi interface. + */ +struct GnssNiCallback : public IGnssNiCallback { + Return niNotifyCb(const IGnssNiCallback::GnssNiNotification& notification) + override; }; +Return GnssNiCallback::niNotifyCb( + const IGnssNiCallback::GnssNiNotification& notification) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jstring requestorId = env->NewStringUTF(notification.requestorId.c_str()); + jstring text = env->NewStringUTF(notification.notificationMessage.c_str()); + + if (requestorId && text) { + env->CallVoidMethod(mCallbacksObj, method_reportNiNotification, + notification.notificationId, notification.niType, + notification.notifyFlags, notification.timeoutSec, + notification.defaultResponse, requestorId, text, + notification.requestorIdEncoding, + notification.notificationIdEncoding); + } else { + ALOGE("%s: OOM Error\n", __func__); + } + + if (requestorId) { + env->DeleteLocalRef(requestorId); + } + + if (text) { + env->DeleteLocalRef(text); + } + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +/* + * AGnssCallback implements callback methods required by the IAGnss interface. + */ +struct AGnssCallback : public IAGnssCallback { + // Methods from ::android::hardware::gps::V1_0::IAGnssCallback follow. + Return agnssStatusIpV6Cb( + const IAGnssCallback::AGnssStatusIpV6& agps_status) override; + + Return agnssStatusIpV4Cb( + const IAGnssCallback::AGnssStatusIpV4& agps_status) override; + private: + jbyteArray convertToIpV4(uint32_t ip); +}; + +Return AGnssCallback::agnssStatusIpV6Cb( + const IAGnssCallback::AGnssStatusIpV6& agps_status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jbyteArray byteArray = NULL; + bool isSupported = false; + + byteArray = env->NewByteArray(16); + if (byteArray != NULL) { + env->SetByteArrayRegion(byteArray, 0, 16, + (const jbyte*)(agps_status.ipV6Addr.data())); + isSupported = true; + } else { + ALOGE("Unable to allocate byte array for IPv6 address."); + } + + IF_ALOGD() { + // log the IP for reference in case there is a bogus value pushed by HAL + char str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, agps_status.ipV6Addr.data(), str, INET6_ADDRSTRLEN); + ALOGD("AGPS IP is v6: %s", str); + } + + jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0; + ALOGV("Passing AGPS IP addr: size %d", byteArrayLength); + env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, + agps_status.type, agps_status.status, byteArray); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + + if (byteArray) { + env->DeleteLocalRef(byteArray); + } + + return Void(); +} + +Return AGnssCallback::agnssStatusIpV4Cb( + const IAGnssCallback::AGnssStatusIpV4& agps_status) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jbyteArray byteArray = NULL; + + uint32_t ipAddr = agps_status.ipV4Addr; + byteArray = convertToIpV4(ipAddr); + + IF_ALOGD() { + /* + * log the IP for reference in case there is a bogus value pushed by + * HAL. + */ + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &ipAddr, str, INET_ADDRSTRLEN); + ALOGD("AGPS IP is v4: %s", str); + } + + jsize byteArrayLength = + byteArray != NULL ? env->GetArrayLength(byteArray) : 0; + ALOGV("Passing AGPS IP addr: size %d", byteArrayLength); + env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, + agps_status.type, agps_status.status, byteArray); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + + if (byteArray) { + env->DeleteLocalRef(byteArray); + } + return Void(); +} + +jbyteArray AGnssCallback::convertToIpV4(uint32_t ip) { + if (INADDR_NONE == ip) { + return NULL; + } + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jbyteArray byteArray = env->NewByteArray(4); + if (byteArray == NULL) { + ALOGE("Unable to allocate byte array for IPv4 address"); + return NULL; + } + + jbyte ipv4[4]; + ALOGV("Converting IPv4 address byte array (net_order) %x", ip); + memcpy(ipv4, &ip, sizeof(ipv4)); + env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*)ipv4); + return byteArray; +} + +/* + * AGnssRilCallback implements the callback methods required by the AGnssRil + * interface. + */ +struct AGnssRilCallback : IAGnssRilCallback { + Return requestSetIdCb(IAGnssRilCallback::ID setIdFlag) override; + Return requestRefLocCb() override; +}; + +Return AGnssRilCallback::requestSetIdCb(IAGnssRilCallback::ID setIdFlag) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestSetID, setIdFlag); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +Return AGnssRilCallback::requestRefLocCb() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestRefLocation); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +static void android_location_GnssLocationProvider_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_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V"); + method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); + method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); + method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V"); + method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); + method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", + "(IIIIILjava/lang/String;Ljava/lang/String;II)V"); + method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V"); + method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V"); + method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V"); + method_reportGeofenceTransition = env->GetMethodID(clazz, "reportGeofenceTransition", + "(IIDDDFFFJIJ)V"); + method_reportGeofenceStatus = env->GetMethodID(clazz, "reportGeofenceStatus", + "(IIDDDFFFJ)V"); + method_reportGeofenceAddStatus = env->GetMethodID(clazz, "reportGeofenceAddStatus", + "(II)V"); + method_reportGeofenceRemoveStatus = env->GetMethodID(clazz, "reportGeofenceRemoveStatus", + "(II)V"); + method_reportGeofenceResumeStatus = env->GetMethodID(clazz, "reportGeofenceResumeStatus", + "(II)V"); + method_reportGeofencePauseStatus = env->GetMethodID(clazz, "reportGeofencePauseStatus", + "(II)V"); + method_reportMeasurementData = env->GetMethodID( + clazz, + "reportMeasurementData", + "(Landroid/location/GnssMeasurementsEvent;)V"); + method_reportNavigationMessages = env->GetMethodID( + clazz, + "reportNavigationMessage", + "(Landroid/location/GnssNavigationMessage;)V"); + + // TODO(b/31632518) + gnssHal = IGnss::getService("gnss"); + if (gnssHal != nullptr) { + auto result = gnssHal->getExtensionXtra([](const sp& xtraIface) { + gnssXtraIface = xtraIface; + }); + + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to Xtra"); + } + + result = gnssHal->getExtensionAGnssRil([](const sp& rilIface) { + agnssRilIface = rilIface; + }); + + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to AGnssRil"); + } + + result = gnssHal->getExtensionAGnss([](const sp& assistedGnssIface) { + agnssIface = assistedGnssIface; + }); + + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to AGnss"); + } + + result = gnssHal->getExtensionGnssNavigationMessage( + [](const sp& navigationMessageIface) { + gnssNavigationMessageIface = navigationMessageIface; + }); + + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssNavigationMessage"); + } + + result = gnssHal->getExtensionGnssMeasurement([]( + const sp& measurementIface) { + gnssMeasurementIface = measurementIface; + }); + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssMeasurement"); + } + + result = gnssHal->getExtensionGnssDebug([](const sp& debugIface) { + gnssDebugIface = debugIface; + }); + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssDebug"); + } + + result = gnssHal->getExtensionGnssNi([](const sp& niIface) { + gnssNiIface = niIface; + }); + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssNi"); + } + + result = gnssHal->getExtensionGnssConfiguration([](const sp& configIface) { + gnssConfigurationIface = configIface; + }); + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssConfiguration"); + } + + result = gnssHal->getExtensionGnssGeofencing([](const sp& geofenceIface) { + gnssGeofencingIface = geofenceIface; + }); + if (!result.getStatus().isOk()) { + ALOGD("Unable to get a handle to GnssGeofencing"); + } + + } else { + ALOGE("Unable to get GPS service\n"); + } + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->startThreadPool(); +} + +static jboolean android_location_GnssLocationProvider_is_supported( + JNIEnv* /* env */, jclass /* clazz */) { + return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_is_agps_ril_supported( + JNIEnv* /* env */, jclass /* clazz */) { + return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported( + JNIEnv* /* env */, jclass /* jclazz */) { + return (gnssConfigurationIface != nullptr) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) { + /* + * This must be set before calling into the HAL library. + */ + if (!mCallbacksObj) + mCallbacksObj = env->NewGlobalRef(obj); + + sp gnssCbIface = new GnssCallback(); + /* + * Fail if the main interface fails to initialize + */ + if (gnssHal == nullptr) { + ALOGE("Unable to Initialize GNSS HAL\n"); + return JNI_FALSE; + } + + auto result = gnssHal->setCallback(gnssCbIface); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("SetCallback for Gnss Interface fails\n"); + return JNI_FALSE; + } + + sp gnssXtraCbIface = new GnssXtraCallback(); + if (gnssXtraIface == nullptr) { + ALOGE("Unable to initialize GNSS Xtra interface\n"); + } + + result = gnssXtraIface->setCallback(gnssXtraCbIface); + if ((!result) || (!result.getStatus().isOk())) { + gnssXtraIface = nullptr; + ALOGE("SetCallback for Gnss Xtra Interface fails\n"); + } + + sp aGnssCbIface = new AGnssCallback(); + if (agnssIface != nullptr) { + agnssIface->setCallback(aGnssCbIface); + } else { + ALOGE("Unable to Initialize AGnss interface\n"); + } + + sp gnssGeofencingCbIface = new GnssGeofenceCallback(); + if (gnssGeofencingIface != nullptr) { + gnssGeofencingIface->setCallback(gnssGeofencingCbIface); + } else { + ALOGE("Unable to initialize GNSS Geofencing interface\n"); + } + + sp gnssNiCbIface = new GnssNiCallback(); + if (gnssNiCbIface != nullptr) { + gnssNiIface->setCallback(gnssNiCbIface); + } else { + ALOGE("Unable to initialize GNSS NI interface\n"); + } + + return JNI_TRUE; +} + +static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) { + if (gnssHal != nullptr) { + gnssHal->cleanup(); + } +} + +static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */, + jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, + jint preferred_time) { + if (gnssHal != nullptr) { + auto result = gnssHal->setPositionMode(static_cast(mode), + static_cast(recurrence), + min_interval, + preferred_accuracy, + preferred_time); + if (!result.getStatus().isOk()) { + ALOGE("%s: GNSS setPositionMode failed\n", __func__); + return JNI_FALSE; + } else { + return result; + } + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) { + if (gnssHal != nullptr) { + auto result = gnssHal->start(); + if (!result.getStatus().isOk()) { + return JNI_FALSE; + } else { + return result; + } + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) { + if (gnssHal != nullptr) { + auto result = gnssHal->stop(); + if (!result.getStatus().isOk()) { + return JNI_FALSE; + } else { + return result; + } + } else { + return JNI_FALSE; + } +} +static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */, + jobject /* obj */, + jint flags) { + if (gnssHal != nullptr) { + auto result = gnssHal->deleteAidingData(static_cast(flags)); + if (!result.getStatus().isOk()) { + ALOGE("Error in deleting aiding data"); + } + } +} + +/* + * This enum is used by the read_sv_status method to combine the svid, + * constellation and svFlag fields. + */ +enum ShiftWidth: uint8_t { + SVID_SHIFT_WIDTH = 7, + CONSTELLATION_TYPE_SHIFT_WIDTH = 3 +}; + +static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */, + jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray, + jfloatArray azumArray) { + /* + * This method should only be called from within a call to reportSvStatus. + */ + jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0); + jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0); + jfloat* elev = env->GetFloatArrayElements(elevArray, 0); + jfloat* azim = env->GetFloatArrayElements(azumArray, 0); + + /* + * Read GNSS SV info. + */ + for (size_t i = 0; i < GnssCallback::sGnssSvListSize; ++i) { + const IGnssCallback::GnssSvInfo& info = GnssCallback::sGnssSvList[i]; + svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) | + (static_cast(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) | + static_cast(info.svFlag); + cn0s[i] = info.cN0Dbhz; + elev[i] = info.elevationDegrees; + azim[i] = info.azimuthDegrees; + } + + env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0); + env->ReleaseFloatArrayElements(cn0Array, cn0s, 0); + env->ReleaseFloatArrayElements(elevArray, elev, 0); + env->ReleaseFloatArrayElements(azumArray, azim, 0); + return static_cast(GnssCallback::sGnssSvListSize); +} + +static void android_location_GnssLocationProvider_agps_set_reference_location_cellid( + JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) { + IAGnssRil::AGnssRefLocation location; + + if (agnssRilIface == nullptr) { + ALOGE("No AGPS RIL interface in agps_set_reference_location_cellid"); + return; + } + + switch (static_cast(type)) { + case IAGnssRil::AGnssRefLocationType::GSM_CELLID: + case IAGnssRil::AGnssRefLocationType::UMTS_CELLID: + location.type = static_cast(type); + location.cellID.mcc = mcc; + location.cellID.mnc = mnc; + location.cellID.lac = lac; + location.cellID.cid = cid; + break; + default: + ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).", __FUNCTION__, __LINE__); + return; + break; + } + + agnssRilIface->setRefLocation(location); +} + +static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */, + jint type, jstring setid_string) { + if (agnssRilIface == nullptr) { + ALOGE("no AGPS RIL interface in agps_set_id"); + return; + } + + const char *setid = env->GetStringUTFChars(setid_string, NULL); + agnssRilIface->setSetId((IAGnssRil::SetIDType)type, setid); + env->ReleaseStringUTFChars(setid_string, setid); +} + +static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */, + jbyteArray nmeaArray, jint buffer_size) { + // this should only be called from within a call to reportNmea + jbyte* nmea = reinterpret_cast(env->GetPrimitiveArrayCritical(nmeaArray, 0)); + int length = GnssCallback::sNmeaStringLength; + if (length > buffer_size) + length = buffer_size; + memcpy(nmea, GnssCallback::sNmeaString, length); + env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT); + return (jint) length; +} + +static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */, + jlong time, jlong timeReference, jint uncertainty) { + if (gnssHal != nullptr) { + auto result = gnssHal->injectTime(time, timeReference, uncertainty); + if (!result || !result.getStatus().isOk()) { + ALOGE("%s: Gnss injectTime() failed", __func__); + } + } +} + +static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, + jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) { + if (gnssHal != nullptr) { + auto result = gnssHal->injectLocation(latitude, longitude, accuracy); + if (!result || !result.getStatus().isOk()) { + ALOGE("%s: Gnss injectLocation() failed", __func__); + } + } +} + +static jboolean android_location_GnssLocationProvider_supports_xtra( + JNIEnv* /* env */, jobject /* obj */) { + return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE; +} + +static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */, + jbyteArray data, jint length) { + if (gnssXtraIface == nullptr) { + ALOGE("XTRA Interface not supported"); + return; + } + + jbyte* bytes = reinterpret_cast(env->GetPrimitiveArrayCritical(data, 0)); + gnssXtraIface->injectXtraData(std::string((const char*)bytes, length)); + env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); +} + +static void android_location_GnssLocationProvider_agps_data_conn_open( + JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType) { + if (agnssIface == nullptr) { + ALOGE("no AGPS interface in agps_data_conn_open"); + return; + } + if (apn == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + const char *apnStr = env->GetStringUTFChars(apn, NULL); + + auto result = agnssIface->dataConnOpen(apnStr, static_cast(apnIpType)); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("%s: Failed to set APN and its IP type", __func__); + } + env->ReleaseStringUTFChars(apn, apnStr); +} + +static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */, + jobject /* obj */) { + if (agnssIface == nullptr) { + ALOGE("%s: AGPS interface not supported", __func__); + return; + } + + auto result = agnssIface->dataConnClosed(); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("%s: Failed to close AGnss data connection", __func__); + } +} + +static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */, + jobject /* obj */) { + if (agnssIface == nullptr) { + ALOGE("%s: AGPS interface not supported", __func__); + return; + } + + auto result = agnssIface->dataConnFailed(); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__); + } +} + +static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */, + jint type, jstring hostname, jint port) { + if (agnssIface == nullptr) { + ALOGE("no AGPS interface in set_agps_server"); + return; + } + + const char *c_hostname = env->GetStringUTFChars(hostname, NULL); + auto result = agnssIface->setServer(static_cast(type), + c_hostname, + port); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("%s: Failed to set AGnss host name and port", __func__); + } + + env->ReleaseStringUTFChars(hostname, c_hostname); +} + +static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */, + jobject /* obj */, jint notifId, jint response) { + if (gnssNiIface == nullptr) { + ALOGE("no NI interface in send_ni_response"); + return; + } + + gnssNiIface->respond(notifId, static_cast(response)); +} + +static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, + jobject /* obj */) { + jstring result = NULL; + /* + * TODO(b/33089503) : Create a jobject to represent GnssDebug. + */ + if (gnssDebugIface != nullptr) { + IGnssDebug::DebugData data; + gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) { + data = debugData; + }); + + std::stringstream internalState; + if (data.position.valid) { + internalState << "Gnss Location Data:: LatitudeDegrees: " << data.position.latitudeDegrees + << ", LongitudeDegrees: " << data.position.longitudeDegrees + << ", altitudeMeters: " << data.position.altitudeMeters + << ", accuracyMeters: " << data.position.accuracyMeters + << ", ageSeconds: " << data.position.ageSeconds << std::endl; + } + + if (data.time.valid) { + internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate + << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs << std::endl; + } + + if (data.satelliteDataArray.size() != 0) { + internalState << "Satellite Data:: "; + } + + for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { + internalState << "svid: " << data.satelliteDataArray[i].svid + << ", constellation: " + << static_cast(data.satelliteDataArray[i].constellation) + << ", ephemerisType: " + << static_cast(data.satelliteDataArray[i].ephemerisType) + << ", ephemerisAgeSeconds: " + << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl; + } + result = env->NewStringUTF(internalState.str().c_str()); + } + return result; +} + +static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, + jobject /* obj */, + jboolean connected, + jint type, + jboolean roaming, + jboolean available, + jstring extraInfo, + jstring apn) { + if (agnssRilIface != nullptr) { + auto result = agnssRilIface->updateNetworkState(connected, + static_cast(type), + roaming); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("updateNetworkState failed"); + } + + const char *c_apn = env->GetStringUTFChars(apn, NULL); + result = agnssRilIface->updateNetworkAvailability(available, c_apn); + if ((!result) || (!result.getStatus().isOk())) { + ALOGE("updateNetworkAvailability failed"); + } + + env->ReleaseStringUTFChars(apn, c_apn); + } else { + ALOGE("AGnssRilInterface does not exist"); + } +} + +static jboolean android_location_GnssLocationProvider_is_geofence_supported( + JNIEnv* /* env */, jobject /* obj */) { + return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */, + jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius, + jint last_transition, jint monitor_transition, jint notification_responsiveness, + jint unknown_timer) { + if (gnssGeofencingIface != nullptr) { + auto result = gnssGeofencingIface->addGeofence( + geofenceId, latitude, longitude, radius, + static_cast(last_transition), + monitor_transition, notification_responsiveness, unknown_timer); + return boolToJbool(result.getStatus().isOk()); + } else { + ALOGE("Geofence Interface not available"); + } + return JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */, + jobject /* obj */, jint geofenceId) { + if (gnssGeofencingIface != nullptr) { + auto result = gnssGeofencingIface->removeGeofence(geofenceId); + return boolToJbool(result.getStatus().isOk()); + } else { + ALOGE("Geofence interface not available"); + } + return JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */, + jobject /* obj */, jint geofenceId) { + if (gnssGeofencingIface != nullptr) { + auto result = gnssGeofencingIface->pauseGeofence(geofenceId); + return boolToJbool(result.getStatus().isOk()); + } else { + ALOGE("Geofence interface not available"); + } + return JNI_FALSE; +} + +static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */, + jobject /* obj */, jint geofenceId, jint monitor_transition) { + if (gnssGeofencingIface != nullptr) { + auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition); + return boolToJbool(result.getStatus().isOk()); + } else { + ALOGE("Geofence interface not available"); + } + return JNI_FALSE; +} + static jboolean android_location_GnssLocationProvider_is_measurement_supported( - JNIEnv* env, - jclass clazz) { - if (sGpsMeasurementInterface != NULL) { + JNIEnv* env, jclass clazz) { + if (gnssMeasurementIface != nullptr) { return JNI_TRUE; } + return JNI_FALSE; } static jboolean android_location_GnssLocationProvider_start_measurement_collection( JNIEnv* env, jobject obj) { - if (sGpsMeasurementInterface == NULL) { - ALOGE("Measurement interface is not available."); + if (gnssMeasurementIface == nullptr) { + ALOGE("GNSS Measurement interface is not available."); return JNI_FALSE; } - int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks); - if (result != GPS_GEOFENCE_OPERATION_SUCCESS) { - ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result); + sp cbIface = new GnssMeasurementCallback(); + IGnssMeasurement::GnssMeasurementStatus result = gnssMeasurementIface->setCallback(cbIface); + if (result != IGnssMeasurement::GnssMeasurementStatus::SUCCESS) { + ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d", + static_cast(result)); return JNI_FALSE; + } else { + ALOGD("gnss measurement infc has been enabled"); } return JNI_TRUE; @@ -1464,104 +1464,19 @@ static jboolean android_location_GnssLocationProvider_start_measurement_collecti static jboolean android_location_GnssLocationProvider_stop_measurement_collection( JNIEnv* env, jobject obj) { - if (sGpsMeasurementInterface == NULL) { + if (gnssMeasurementIface == nullptr) { ALOGE("Measurement interface not available"); return JNI_FALSE; } - sGpsMeasurementInterface->close(); - return JNI_TRUE; + auto result = gnssMeasurementIface->close(); + return boolToJbool(result.getStatus().isOk()); } -static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) { - size_t dataLength = message->data_length; - uint8_t* data = message->data; - if (dataLength == 0 || data == NULL) { - ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength); - return NULL; - } - JavaObject object(env, "android/location/GnssNavigationMessage"); - SET(Svid, static_cast(message->prn)); - if (message->prn >=1 && message->prn <= 32) { - SET(ConstellationType, static_cast(GNSS_CONSTELLATION_GPS)); - // Legacy driver doesn't set the higher byte to constellation type - // correctly. Set the higher byte to 'GPS'. - SET(Type, static_cast(message->type | 0x0100)); - } else { - ALOGD("Unknown constellation type with Svid = %d.", message->prn); - SET(ConstellationType, - static_cast(GNSS_CONSTELLATION_UNKNOWN)); - SET(Type, static_cast(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN)); - } - SET(MessageId, static_cast(message->message_id)); - SET(SubmessageId, static_cast(message->submessage_id)); - object.callSetter("setData", data, dataLength); - SET(Status, static_cast(message->status)); - return object.get(); -} - -static jobject translate_gnss_navigation_message( - JNIEnv* env, GnssNavigationMessage* message) { - size_t dataLength = message->data_length; - uint8_t* data = message->data; - if (dataLength == 0 || data == NULL) { - ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength); - return NULL; - } - JavaObject object(env, "android/location/GnssNavigationMessage"); - SET(Type, static_cast(message->type)); - SET(Svid, static_cast(message->svid)); - SET(MessageId, static_cast(message->message_id)); - SET(SubmessageId, static_cast(message->submessage_id)); - object.callSetter("setData", data, dataLength); - SET(Status, static_cast(message->status)); - return object.get(); -} - -static void navigation_message_callback(GpsNavigationMessage* message) { - if (message == NULL) { - ALOGE("Invalid Navigation Message provided to callback"); - return; - } - if (message->size != sizeof(GpsNavigationMessage)) { - ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size); - return; - } - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jobject navigationMessage = translate_gps_navigation_message(env, message); - env->CallVoidMethod(mCallbacksObj, - method_reportNavigationMessages, - navigationMessage); - env->DeleteLocalRef(navigationMessage); -} - -static void gnss_navigation_message_callback(GnssNavigationMessage* message) { - if (message == NULL) { - ALOGE("Invalid Navigation Message provided to callback"); - return; - } - if (message->size != sizeof(GnssNavigationMessage)) { - ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size); - return; - } - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jobject navigationMessage = translate_gnss_navigation_message(env, message); - env->CallVoidMethod(mCallbacksObj, - method_reportNavigationMessages, - navigationMessage); - env->DeleteLocalRef(navigationMessage); -} - -GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = { - sizeof(GpsNavigationMessageCallbacks), - navigation_message_callback, - gnss_navigation_message_callback, -}; - static jboolean android_location_GnssLocationProvider_is_navigation_message_supported( JNIEnv* env, jclass clazz) { - if(sGpsNavigationMessageInterface != NULL) { + if (gnssNavigationMessageIface != nullptr) { return JNI_TRUE; } return JNI_FALSE; @@ -1570,14 +1485,18 @@ static jboolean android_location_GnssLocationProvider_is_navigation_message_supp static jboolean android_location_GnssLocationProvider_start_navigation_message_collection( JNIEnv* env, jobject obj) { - if (sGpsNavigationMessageInterface == NULL) { + if (gnssNavigationMessageIface == nullptr) { ALOGE("Navigation Message interface is not available."); return JNI_FALSE; } - int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks); - if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) { - ALOGE("An error has been found in %s: %d", __FUNCTION__, result); + sp gnssNavigationMessageCbIface = + new GnssNavigationMessageCallback(); + IGnssNavigationMessage::GnssNavigationMessageStatus result = + gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface); + + if (result != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) { + ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast(result)); return JNI_FALSE; } @@ -1587,127 +1506,255 @@ static jboolean android_location_GnssLocationProvider_start_navigation_message_c static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection( JNIEnv* env, jobject obj) { - if (sGpsNavigationMessageInterface == NULL) { + if (gnssNavigationMessageIface == nullptr) { ALOGE("Navigation Message interface is not available."); return JNI_FALSE; } - sGpsNavigationMessageInterface->close(); - return JNI_TRUE; + auto result = gnssNavigationMessageIface->close(); + return boolToJbool(result.getStatus().isOk()); } -static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj, - jstring config_content) -{ - if (!sGnssConfigurationInterface) { - ALOGE("no GPS configuration interface in configuraiton_update"); - return; +static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*, + jobject, + jint emergencySuplPdn) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setEmergencySuplPdn(emergencySuplPdn); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*, + jobject, + jint version) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + auto result = gnssConfigurationIface->setSuplVersion(version); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*, + jobject, + jint suplEs) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setSuplEs(suplEs); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*, + jobject, + jint mode) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setSuplMode(mode); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*, + jobject, + jint gpsLock) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setGpsLock(gpsLock); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*, + jobject, + jint lppProfile) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setLppProfile(lppProfile); + + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + +static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_select(JNIEnv*, + jobject, + jint gnssPosProtocol) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol); + if (result.getStatus().isOk()) { + return result; + } else { + return JNI_FALSE; } - const char *data = env->GetStringUTFChars(config_content, NULL); - ALOGD("GPS configuration:\n %s", data); - sGnssConfigurationInterface->configuration_update( - data, env->GetStringUTFLength(config_content)); - env->ReleaseStringUTFChars(config_content, data); } static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native}, - {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported}, + {"class_init_native", "()V", reinterpret_cast( + android_location_GnssLocationProvider_class_init_native)}, + {"native_is_supported", "()Z", reinterpret_cast( + android_location_GnssLocationProvider_is_supported)}, {"native_is_agps_ril_supported", "()Z", - (void*)android_location_GnssLocationProvider_is_agps_ril_supported}, + reinterpret_cast(android_location_GnssLocationProvider_is_agps_ril_supported)}, {"native_is_gnss_configuration_supported", "()Z", - (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported}, - {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init}, - {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup}, + reinterpret_cast( + android_location_gpsLocationProvider_is_gnss_configuration_supported)}, + {"native_init", "()Z", reinterpret_cast(android_location_GnssLocationProvider_init)}, + {"native_cleanup", "()V", reinterpret_cast( + android_location_GnssLocationProvider_cleanup)}, {"native_set_position_mode", "(IIIII)Z", - (void*)android_location_GnssLocationProvider_set_position_mode}, - {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start}, - {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop}, + reinterpret_cast(android_location_GnssLocationProvider_set_position_mode)}, + {"native_start", "()Z", reinterpret_cast(android_location_GnssLocationProvider_start)}, + {"native_stop", "()Z", reinterpret_cast(android_location_GnssLocationProvider_stop)}, {"native_delete_aiding_data", "(I)V", - (void*)android_location_GnssLocationProvider_delete_aiding_data}, + reinterpret_cast(android_location_GnssLocationProvider_delete_aiding_data)}, {"native_read_sv_status", "([I[F[F[F)I", - (void*)android_location_GnssLocationProvider_read_sv_status}, - {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea}, - {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time}, + reinterpret_cast(android_location_GnssLocationProvider_read_sv_status)}, + {"native_read_nmea", "([BI)I", reinterpret_cast( + android_location_GnssLocationProvider_read_nmea)}, + {"native_inject_time", "(JJI)V", reinterpret_cast( + android_location_GnssLocationProvider_inject_time)}, {"native_inject_location", "(DDF)V", - (void*)android_location_GnssLocationProvider_inject_location}, - {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra}, + reinterpret_cast(android_location_GnssLocationProvider_inject_location)}, + {"native_supports_xtra", "()Z", reinterpret_cast( + android_location_GnssLocationProvider_supports_xtra)}, {"native_inject_xtra_data", "([BI)V", - (void*)android_location_GnssLocationProvider_inject_xtra_data}, + reinterpret_cast(android_location_GnssLocationProvider_inject_xtra_data)}, {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", - (void*)android_location_GnssLocationProvider_agps_data_conn_open}, + reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_open)}, {"native_agps_data_conn_closed", "()V", - (void*)android_location_GnssLocationProvider_agps_data_conn_closed}, + reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_closed)}, {"native_agps_data_conn_failed", "()V", - (void*)android_location_GnssLocationProvider_agps_data_conn_failed}, + reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_failed)}, {"native_agps_set_id", "(ILjava/lang/String;)V", - (void*)android_location_GnssLocationProvider_agps_set_id}, + reinterpret_cast(android_location_GnssLocationProvider_agps_set_id)}, {"native_agps_set_ref_location_cellid", "(IIIII)V", - (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid}, + reinterpret_cast( + android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, {"native_set_agps_server", "(ILjava/lang/String;I)V", - (void*)android_location_GnssLocationProvider_set_agps_server}, + reinterpret_cast(android_location_GnssLocationProvider_set_agps_server)}, {"native_send_ni_response", "(II)V", - (void*)android_location_GnssLocationProvider_send_ni_response}, - {"native_agps_ni_message", - "([BI)V", - (void *)android_location_GnssLocationProvider_agps_send_ni_message}, + reinterpret_cast(android_location_GnssLocationProvider_send_ni_response)}, {"native_get_internal_state", "()Ljava/lang/String;", - (void*)android_location_GnssLocationProvider_get_internal_state}, + reinterpret_cast(android_location_GnssLocationProvider_get_internal_state)}, {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", - (void*)android_location_GnssLocationProvider_update_network_state }, + reinterpret_cast(android_location_GnssLocationProvider_update_network_state)}, {"native_is_geofence_supported", "()Z", - (void*) android_location_GnssLocationProvider_is_geofence_supported}, + reinterpret_cast(android_location_GnssLocationProvider_is_geofence_supported)}, {"native_add_geofence", "(IDDDIIII)Z", - (void *)android_location_GnssLocationProvider_add_geofence}, + reinterpret_cast(android_location_GnssLocationProvider_add_geofence)}, {"native_remove_geofence", "(I)Z", - (void *)android_location_GnssLocationProvider_remove_geofence}, - {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence}, + reinterpret_cast(android_location_GnssLocationProvider_remove_geofence)}, + {"native_pause_geofence", "(I)Z", reinterpret_cast( + android_location_GnssLocationProvider_pause_geofence)}, {"native_resume_geofence", "(II)Z", - (void *)android_location_GnssLocationProvider_resume_geofence}, + reinterpret_cast(android_location_GnssLocationProvider_resume_geofence)}, {"native_is_measurement_supported", "()Z", - (void*) android_location_GnssLocationProvider_is_measurement_supported}, + reinterpret_cast( + android_location_GnssLocationProvider_is_measurement_supported)}, {"native_start_measurement_collection", "()Z", - (void*) android_location_GnssLocationProvider_start_measurement_collection}, + reinterpret_cast( + android_location_GnssLocationProvider_start_measurement_collection)}, {"native_stop_measurement_collection", "()Z", - (void*) android_location_GnssLocationProvider_stop_measurement_collection}, + reinterpret_cast( + android_location_GnssLocationProvider_stop_measurement_collection)}, {"native_is_navigation_message_supported", "()Z", - (void*) android_location_GnssLocationProvider_is_navigation_message_supported}, + reinterpret_cast( + android_location_GnssLocationProvider_is_navigation_message_supported)}, {"native_start_navigation_message_collection", "()Z", - (void*) android_location_GnssLocationProvider_start_navigation_message_collection}, + reinterpret_cast( + android_location_GnssLocationProvider_start_navigation_message_collection)}, {"native_stop_navigation_message_collection", "()Z", - (void*) android_location_GnssLocationProvider_stop_navigation_message_collection}, - {"native_configuration_update", - "(Ljava/lang/String;)V", - (void*)android_location_GnssLocationProvider_configuration_update}, + reinterpret_cast( + android_location_GnssLocationProvider_stop_navigation_message_collection)}, + {"native_set_supl_es", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_supl_es)}, + {"native_set_supl_version", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_supl_version)}, + {"native_set_supl_mode", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_supl_mode)}, + {"native_set_lpp_profile", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_lpp_profile)}, + {"native_set_gnss_pos_protocol_select", + "(I)Z", + reinterpret_cast( + android_location_GnssLocationProvider_set_gnss_pos_protocol_select)}, + {"native_set_gps_lock", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_gps_lock)}, + {"native_set_emergency_supl_pdn", + "(I)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_emergency_supl_pdn)}, }; -int register_android_server_location_GnssLocationProvider(JNIEnv* env) -{ +int register_android_server_location_GnssLocationProvider(JNIEnv* env) { return jniRegisterNativeMethods( env, "com/android/server/location/GnssLocationProvider",