From 2ea296029f115376aaa7f4336d0082bdf47eee29 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 13 Sep 2016 08:38:09 -0700 Subject: [PATCH] Modify GnssLocationProvider to use Treble Gnss HAL Test: GPS functionality tested in binderized and pass-through modes on Angler. All interfaces except AGnssRil, GnssNavigationMessage and GnssNi. AGnssRil and AGnssNavigationMessage are not implemented by conventional GPS HALs in Google devices that would be upgrading to O. Change-Id: Ie4decb4c47892725c8c89bad3f48581550facff7 --- .../location/GpsNetInitiatedHandler.java | 3 - .../server/location/GnssLocationProvider.java | 136 +- services/core/jni/Android.mk | 1 + ...d_server_location_GnssLocationProvider.cpp | 2835 +++++++++-------- 4 files changed, 1491 insertions(+), 1484 deletions(-) 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",