| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "GnssLocationProvider" |
| |
| #define LOG_NDEBUG 0 |
| |
| #include <android/hardware/gnss/1.0/IGnss.h> |
| #include <android/hardware/gnss/1.1/IGnss.h> |
| |
| #include <android/hardware/gnss/1.0/IGnssMeasurement.h> |
| #include <android/hardware/gnss/1.1/IGnssMeasurement.h> |
| #include <nativehelper/JNIHelp.h> |
| #include "jni.h" |
| #include "hardware_legacy/power.h" |
| #include "utils/Log.h" |
| #include "utils/misc.h" |
| #include "android_runtime/AndroidRuntime.h" |
| #include "android_runtime/Log.h" |
| |
| #include <arpa/inet.h> |
| #include <limits> |
| #include <linux/in.h> |
| #include <linux/in6.h> |
| #include <pthread.h> |
| #include <string.h> |
| #include <cinttypes> |
| |
| static jobject mCallbacksObj = NULL; |
| |
| static jmethodID method_reportLocation; |
| static jmethodID method_reportStatus; |
| static jmethodID method_reportSvStatus; |
| static jmethodID method_reportAGpsStatus; |
| static jmethodID method_reportNmea; |
| static jmethodID method_setEngineCapabilities; |
| static jmethodID method_setGnssYearOfHardware; |
| static jmethodID method_setGnssHardwareModelName; |
| static jmethodID method_xtraDownloadRequest; |
| static jmethodID method_reportNiNotification; |
| static jmethodID method_requestLocation; |
| static jmethodID method_requestRefLocation; |
| static jmethodID method_requestSetID; |
| static jmethodID method_requestUtcTime; |
| static jmethodID method_reportGeofenceTransition; |
| static jmethodID method_reportGeofenceStatus; |
| static jmethodID method_reportGeofenceAddStatus; |
| static jmethodID method_reportGeofenceRemoveStatus; |
| static jmethodID method_reportGeofencePauseStatus; |
| static jmethodID method_reportGeofenceResumeStatus; |
| static jmethodID method_reportMeasurementData; |
| static jmethodID method_reportNavigationMessages; |
| static jmethodID method_reportLocationBatch; |
| |
| /* |
| * Save a pointer to JavaVm to attach/detach threads executing |
| * callback methods that need to make JNI calls. |
| */ |
| static JavaVM* sJvm; |
| |
| using android::OK; |
| using android::sp; |
| using android::wp; |
| using android::status_t; |
| using android::String16; |
| |
| using android::hardware::Return; |
| using android::hardware::Void; |
| using android::hardware::hidl_vec; |
| using android::hardware::hidl_death_recipient; |
| using android::hardware::gnss::V1_0::GnssLocation; |
| using android::hardware::gnss::V1_0::GnssLocationFlags; |
| |
| 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::IGnssBatching; |
| using android::hardware::gnss::V1_0::IGnssBatchingCallback; |
| 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::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; |
| |
| using android::hardware::gnss::V1_1::IGnssCallback; |
| |
| using android::hidl::base::V1_0::IBase; |
| |
| using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss; |
| using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss; |
| using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; |
| using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; |
| using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback; |
| using IGnssMeasurementCallback_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback; |
| |
| |
| struct GnssDeathRecipient : virtual public hidl_death_recipient |
| { |
| // hidl_death_recipient interface |
| virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override { |
| // TODO(b/37460011): implement a better death recovery mechanism without |
| // crashing system server process as described in go//treble-gnss-death |
| LOG_ALWAYS_FATAL("Abort due to IGNSS hidl service failure," |
| " restarting system server"); |
| } |
| }; |
| |
| sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr; |
| sp<IGnss_V1_0> gnssHal = nullptr; |
| sp<IGnss_V1_1> gnssHal_V1_1 = nullptr; |
| sp<IGnssXtra> gnssXtraIface = nullptr; |
| sp<IAGnssRil> agnssRilIface = nullptr; |
| sp<IGnssGeofencing> gnssGeofencingIface = nullptr; |
| sp<IAGnss> agnssIface = nullptr; |
| sp<IGnssBatching> gnssBatchingIface = nullptr; |
| sp<IGnssDebug> gnssDebugIface = nullptr; |
| sp<IGnssConfiguration> gnssConfigurationIface = nullptr; |
| sp<IGnssNi> gnssNiIface = nullptr; |
| sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr; |
| sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr; |
| sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr; |
| |
| #define WAKE_LOCK_NAME "GPS" |
| |
| namespace android { |
| |
| template<class T> |
| class JavaMethodHelper { |
| 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: |
| static const char *const signature_; |
| }; |
| |
| template<class T> |
| void JavaMethodHelper<T>::callJavaMethod( |
| JNIEnv* env, |
| jclass clazz, |
| jobject object, |
| const char* method_name, |
| T value) { |
| jmethodID method = env->GetMethodID(clazz, method_name, signature_); |
| env->CallVoidMethod(object, method, value); |
| } |
| |
| class JavaObject { |
| public: |
| JavaObject(JNIEnv* env, const char* class_name); |
| JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1); |
| virtual ~JavaObject(); |
| |
| template<class T> |
| void callSetter(const char* method_name, T value); |
| template<class T> |
| void callSetter(const char* method_name, T* value, size_t size); |
| jobject get(); |
| |
| private: |
| JNIEnv* env_; |
| jclass clazz_; |
| jobject object_; |
| }; |
| |
| JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) { |
| clazz_ = env_->FindClass(class_name); |
| jmethodID ctor = env->GetMethodID(clazz_, "<init>", "()V"); |
| object_ = env_->NewObject(clazz_, ctor); |
| } |
| |
| JavaObject::JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1) : env_(env) { |
| clazz_ = env_->FindClass(class_name); |
| jmethodID ctor = env->GetMethodID(clazz_, "<init>", "(Ljava/lang/String;)V"); |
| object_ = env_->NewObject(clazz_, ctor, env->NewStringUTF(sz_arg_1)); |
| } |
| |
| JavaObject::~JavaObject() { |
| env_->DeleteLocalRef(clazz_); |
| } |
| |
| template<class T> |
| void JavaObject::callSetter(const char* method_name, T value) { |
| JavaMethodHelper<T>::callJavaMethod( |
| env_, clazz_, object_, method_name, value); |
| } |
| |
| template<> |
| void JavaObject::callSetter( |
| const char* method_name, uint8_t* value, size_t size) { |
| jbyteArray array = env_->NewByteArray(size); |
| env_->SetByteArrayRegion(array, 0, size, reinterpret_cast<jbyte*>(value)); |
| jmethodID method = env_->GetMethodID( |
| clazz_, |
| method_name, |
| "([B)V"); |
| env_->CallVoidMethod(object_, method, array); |
| env_->DeleteLocalRef(array); |
| } |
| |
| jobject JavaObject::get() { |
| return object_; |
| } |
| |
| // Define Java method signatures for all known types. |
| template<> |
| const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V"; |
| template<> |
| const char *const JavaMethodHelper<int8_t>::signature_ = "(B)V"; |
| template<> |
| const char *const JavaMethodHelper<int16_t>::signature_ = "(S)V"; |
| template<> |
| const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V"; |
| template<> |
| const char *const JavaMethodHelper<int32_t>::signature_ = "(I)V"; |
| template<> |
| const char *const JavaMethodHelper<uint32_t>::signature_ = "(I)V"; |
| template<> |
| const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V"; |
| template<> |
| const char *const JavaMethodHelper<float>::signature_ = "(F)V"; |
| template<> |
| const char *const JavaMethodHelper<double>::signature_ = "(D)V"; |
| template<> |
| const char *const JavaMethodHelper<bool>::signature_ = "(Z)V"; |
| |
| #define SET(setter, value) object.callSetter("set" # setter, (value)) |
| |
| static inline jboolean boolToJbool(bool value) { |
| return value ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| 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(); |
| } |
| } |
| |
| class ScopedJniThreadAttach { |
| public: |
| ScopedJniThreadAttach() { |
| /* |
| * attachResult will also be JNI_OK if the thead was already attached to |
| * JNI before the call to AttachCurrentThread(). |
| */ |
| jint attachResult = sJvm->AttachCurrentThread(&mEnv, nullptr); |
| LOG_ALWAYS_FATAL_IF(attachResult != JNI_OK, "Unable to attach thread. Error %d", |
| attachResult); |
| } |
| |
| ~ScopedJniThreadAttach() { |
| jint detachResult = sJvm->DetachCurrentThread(); |
| /* |
| * Return if the thread was already detached. Log error for any other |
| * failure. |
| */ |
| if (detachResult == JNI_EDETACHED) { |
| return; |
| } |
| |
| LOG_ALWAYS_FATAL_IF(detachResult != JNI_OK, "Unable to detach thread. Error %d", |
| detachResult); |
| } |
| |
| JNIEnv* getEnv() { |
| /* |
| * Checking validity of mEnv in case the thread was detached elsewhere. |
| */ |
| LOG_ALWAYS_FATAL_IF(AndroidRuntime::getJNIEnv() != mEnv); |
| return mEnv; |
| } |
| |
| private: |
| JNIEnv* mEnv = nullptr; |
| }; |
| |
| thread_local std::unique_ptr<ScopedJniThreadAttach> tJniThreadAttacher; |
| |
| static JNIEnv* getJniEnv() { |
| JNIEnv* env = AndroidRuntime::getJNIEnv(); |
| |
| /* |
| * If env is nullptr, the thread is not already attached to |
| * JNI. It is attached below and the destructor for ScopedJniThreadAttach |
| * will detach it on thread exit. |
| */ |
| if (env == nullptr) { |
| tJniThreadAttacher.reset(new ScopedJniThreadAttach()); |
| env = tJniThreadAttacher->getEnv(); |
| } |
| |
| return env; |
| } |
| |
| static jobject translateLocation(JNIEnv* env, const GnssLocation& location) { |
| JavaObject object(env, "android/location/Location", "gps"); |
| |
| uint16_t flags = static_cast<uint32_t>(location.gnssLocationFlags); |
| if (flags & GnssLocationFlags::HAS_LAT_LONG) { |
| SET(Latitude, location.latitudeDegrees); |
| SET(Longitude, location.longitudeDegrees); |
| } |
| if (flags & GnssLocationFlags::HAS_ALTITUDE) { |
| SET(Altitude, location.altitudeMeters); |
| } |
| if (flags & GnssLocationFlags::HAS_SPEED) { |
| SET(Speed, location.speedMetersPerSec); |
| } |
| if (flags & GnssLocationFlags::HAS_BEARING) { |
| SET(Bearing, location.bearingDegrees); |
| } |
| if (flags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) { |
| SET(Accuracy, location.horizontalAccuracyMeters); |
| } |
| if (flags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) { |
| SET(VerticalAccuracyMeters, location.verticalAccuracyMeters); |
| } |
| if (flags & GnssLocationFlags::HAS_SPEED_ACCURACY) { |
| SET(SpeedAccuracyMetersPerSecond, location.speedAccuracyMetersPerSecond); |
| } |
| if (flags & GnssLocationFlags::HAS_BEARING_ACCURACY) { |
| SET(BearingAccuracyDegrees, location.bearingAccuracyDegrees); |
| } |
| SET(Time, location.timestamp); |
| |
| return object.get(); |
| } |
| |
| static GnssLocation createGnssLocation( |
| jint gnssLocationFlags, |
| jdouble latitudeDegrees, |
| jdouble longitudeDegrees, |
| jdouble altitudeMeters, |
| jfloat speedMetersPerSec, |
| jfloat bearingDegrees, |
| jfloat horizontalAccuracyMeters, |
| jfloat verticalAccuracyMeters, |
| jfloat speedAccuracyMetersPerSecond, |
| jfloat bearingAccuracyDegrees, |
| jlong timestamp) { |
| GnssLocation location; |
| location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags); |
| location.latitudeDegrees = static_cast<double>(latitudeDegrees); |
| location.longitudeDegrees = static_cast<double>(longitudeDegrees); |
| location.altitudeMeters = static_cast<double>(altitudeMeters); |
| location.speedMetersPerSec = static_cast<float>(speedMetersPerSec); |
| location.bearingDegrees = static_cast<float>(bearingDegrees); |
| location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters); |
| location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters); |
| location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond); |
| location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees); |
| location.timestamp = static_cast<uint64_t>(timestamp); |
| |
| return location; |
| } |
| |
| /* |
| * GnssCallback class implements the callback methods for IGnss interface. |
| */ |
| struct GnssCallback : public IGnssCallback { |
| Return<void> gnssLocationCb(const GnssLocation& location) override; |
| Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override; |
| Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; |
| Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override; |
| Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override; |
| Return<void> gnssAcquireWakelockCb() override; |
| Return<void> gnssReleaseWakelockCb() override; |
| Return<void> gnssRequestTimeCb() override; |
| Return<void> gnssRequestLocationCb(const bool independentFromGnss) override; |
| Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override; |
| |
| // New in 1.1 |
| Return<void> gnssNameCb(const android::hardware::hidl_string& name) override; |
| |
| // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics |
| static const char* sNmeaString; |
| static size_t sNmeaStringLength; |
| }; |
| |
| Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { |
| ALOGD("%s: name=%s\n", __func__, name.c_str()); |
| |
| JNIEnv* env = getJniEnv(); |
| jstring jstringName = env->NewStringUTF(name.c_str()); |
| env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| |
| return Void(); |
| } |
| |
| const char* GnssCallback::sNmeaString = nullptr; |
| size_t GnssCallback::sNmeaStringLength = 0; |
| |
| Return<void> GnssCallback::gnssLocationCb(const GnssLocation& location) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobject jLocation = translateLocation(env, location); |
| bool hasLatLong = (static_cast<uint32_t>(location.gnssLocationFlags) & |
| GnssLocationFlags::HAS_LAT_LONG) != 0; |
| |
| env->CallVoidMethod(mCallbacksObj, |
| method_reportLocation, |
| boolToJbool(hasLatLong), |
| jLocation); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| env->DeleteLocalRef(jLocation); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) { |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_reportStatus, status); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) { |
| JNIEnv* env = getJniEnv(); |
| |
| uint32_t listSize = svStatus.numSvs; |
| if (listSize > static_cast<uint32_t>( |
| android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) { |
| ALOGD("Too many satellites %u. Clamps to %u.", listSize, |
| static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)); |
| listSize = static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT); |
| } |
| |
| jintArray svidWithFlagArray = env->NewIntArray(listSize); |
| jfloatArray cn0Array = env->NewFloatArray(listSize); |
| jfloatArray elevArray = env->NewFloatArray(listSize); |
| jfloatArray azimArray = env->NewFloatArray(listSize); |
| jfloatArray carrierFreqArray = env->NewFloatArray(listSize); |
| |
| jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0); |
| jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0); |
| jfloat* elev = env->GetFloatArrayElements(elevArray, 0); |
| jfloat* azim = env->GetFloatArrayElements(azimArray, 0); |
| jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0); |
| |
| /* |
| * Read GNSS SV info. |
| */ |
| for (size_t i = 0; i < listSize; ++i) { |
| enum ShiftWidth: uint8_t { |
| SVID_SHIFT_WIDTH = 8, |
| CONSTELLATION_TYPE_SHIFT_WIDTH = 4 |
| }; |
| |
| const IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList.data()[i]; |
| svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) | |
| (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) | |
| static_cast<uint32_t>(info.svFlag); |
| cn0s[i] = info.cN0Dbhz; |
| elev[i] = info.elevationDegrees; |
| azim[i] = info.azimuthDegrees; |
| carrierFreq[i] = info.carrierFrequencyHz; |
| } |
| |
| env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0); |
| env->ReleaseFloatArrayElements(cn0Array, cn0s, 0); |
| env->ReleaseFloatArrayElements(elevArray, elev, 0); |
| env->ReleaseFloatArrayElements(azimArray, azim, 0); |
| env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0); |
| |
| env->CallVoidMethod(mCallbacksObj, method_reportSvStatus, |
| static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray, |
| carrierFreqArray); |
| |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssNmeaCb( |
| int64_t timestamp, const ::android::hardware::hidl_string& nmea) { |
| JNIEnv* env = 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<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { |
| ALOGD("%s: %du\n", __func__, capabilities); |
| |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssAcquireWakelockCb() { |
| acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssReleaseWakelockCb() { |
| release_wake_lock(WAKE_LOCK_NAME); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssRequestTimeCb() { |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_requestUtcTime); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) { |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss)); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) { |
| ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw); |
| |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, |
| info.yearOfHw); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| class GnssXtraCallback : public IGnssXtraCallback { |
| Return<void> downloadRequestCb() override; |
| }; |
| |
| /* |
| * GnssXtraCallback class implements the callback methods for the IGnssXtra |
| * interface. |
| */ |
| Return<void> GnssXtraCallback::downloadRequestCb() { |
| JNIEnv* env = 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<void> gnssGeofenceTransitionCb( |
| int32_t geofenceId, |
| const GnssLocation& location, |
| GeofenceTransition transition, |
| hardware::gnss::V1_0::GnssUtcTime timestamp) override; |
| Return<void> gnssGeofenceStatusCb( |
| GeofenceAvailability status, |
| const GnssLocation& location) override; |
| Return<void> gnssGeofenceAddCb(int32_t geofenceId, |
| GeofenceStatus status) override; |
| Return<void> gnssGeofenceRemoveCb(int32_t geofenceId, |
| GeofenceStatus status) override; |
| Return<void> gnssGeofencePauseCb(int32_t geofenceId, |
| GeofenceStatus status) override; |
| Return<void> gnssGeofenceResumeCb(int32_t geofenceId, |
| GeofenceStatus status) override; |
| }; |
| |
| Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb( |
| int32_t geofenceId, |
| const GnssLocation& location, |
| GeofenceTransition transition, |
| hardware::gnss::V1_0::GnssUtcTime timestamp) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobject jLocation = translateLocation(env, location); |
| |
| env->CallVoidMethod(mCallbacksObj, |
| method_reportGeofenceTransition, |
| geofenceId, |
| jLocation, |
| transition, |
| timestamp); |
| |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| env->DeleteLocalRef(jLocation); |
| return Void(); |
| } |
| |
| Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb( |
| GeofenceAvailability status, |
| const GnssLocation& location) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobject jLocation = translateLocation(env, location); |
| |
| env->CallVoidMethod(mCallbacksObj, |
| method_reportGeofenceStatus, |
| status, |
| jLocation); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| env->DeleteLocalRef(jLocation); |
| return Void(); |
| } |
| |
| Return<void> GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId, |
| GeofenceStatus status) { |
| JNIEnv* env = 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<void> GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId, |
| GeofenceStatus status) { |
| JNIEnv* env = 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<void> GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId, |
| GeofenceStatus status) { |
| JNIEnv* env = 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<void> GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId, |
| GeofenceStatus status) { |
| JNIEnv* env = 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<void> gnssNavigationMessageCb( |
| const IGnssNavigationMessageCallback::GnssNavigationMessage& message) override; |
| }; |
| |
| Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb( |
| const IGnssNavigationMessageCallback::GnssNavigationMessage& message) { |
| JNIEnv* env = getJniEnv(); |
| |
| size_t dataLength = message.data.size(); |
| |
| std::vector<uint8_t> 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<int32_t>(message.type)); |
| SET(Svid, static_cast<int32_t>(message.svid)); |
| SET(MessageId, static_cast<int32_t>(message.messageId)); |
| SET(SubmessageId, static_cast<int32_t>(message.submessageId)); |
| object.callSetter("setData", data, dataLength); |
| SET(Status, static_cast<int32_t>(message.status)); |
| |
| jobject navigationMessage = object.get(); |
| env->CallVoidMethod(mCallbacksObj, |
| method_reportNavigationMessages, |
| navigationMessage); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| env->DeleteLocalRef(navigationMessage); |
| return Void(); |
| } |
| |
| /* |
| * GnssMeasurementCallback implements the callback methods required for the |
| * GnssMeasurement interface. |
| */ |
| struct GnssMeasurementCallback : public IGnssMeasurementCallback_V1_1 { |
| Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_V1_1::GnssData& data) override; |
| Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_V1_0::GnssData& data) override; |
| private: |
| void translateGnssMeasurement_V1_0( |
| JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurement, |
| JavaObject& object); |
| jobjectArray translateGnssMeasurements( |
| JNIEnv* env, |
| const IGnssMeasurementCallback_V1_1::GnssMeasurement* measurements_v1_1, |
| const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurements_v1_0, |
| size_t count); |
| jobject translateGnssClock( |
| JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock); |
| void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray); |
| }; |
| |
| |
| Return<void> GnssMeasurementCallback::gnssMeasurementCb( |
| const IGnssMeasurementCallback_V1_1::GnssData& data) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobject clock; |
| jobjectArray measurementArray; |
| |
| clock = translateGnssClock(env, &data.clock); |
| |
| measurementArray = translateGnssMeasurements( |
| env, data.measurements.data(), NULL, data.measurements.size()); |
| setMeasurementData(env, clock, measurementArray); |
| |
| env->DeleteLocalRef(clock); |
| env->DeleteLocalRef(measurementArray); |
| return Void(); |
| } |
| |
| Return<void> GnssMeasurementCallback::GnssMeasurementCb( |
| const IGnssMeasurementCallback_V1_0::GnssData& data) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobject clock; |
| jobjectArray measurementArray; |
| |
| clock = translateGnssClock(env, &data.clock); |
| measurementArray = translateGnssMeasurements( |
| env, NULL, data.measurements.data(), data.measurementCount); |
| setMeasurementData(env, clock, measurementArray); |
| |
| env->DeleteLocalRef(clock); |
| env->DeleteLocalRef(measurementArray); |
| return Void(); |
| } |
| |
| // preallocate object as: JavaObject object(env, "android/location/GnssMeasurement"); |
| void GnssMeasurementCallback::translateGnssMeasurement_V1_0( |
| JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurement, |
| JavaObject& object) { |
| uint32_t flags = static_cast<uint32_t>(measurement->flags); |
| |
| SET(Svid, static_cast<int32_t>(measurement->svid)); |
| SET(ConstellationType, static_cast<int32_t>(measurement->constellation)); |
| SET(TimeOffsetNanos, measurement->timeOffsetNs); |
| SET(State, static_cast<int32_t>(measurement->state)); |
| SET(ReceivedSvTimeNanos, measurement->receivedSvTimeInNs); |
| SET(ReceivedSvTimeUncertaintyNanos, |
| measurement->receivedSvTimeUncertaintyInNs); |
| SET(Cn0DbHz, measurement->cN0DbHz); |
| SET(PseudorangeRateMetersPerSecond, measurement->pseudorangeRateMps); |
| SET(PseudorangeRateUncertaintyMetersPerSecond, |
| measurement->pseudorangeRateUncertaintyMps); |
| SET(AccumulatedDeltaRangeState, |
| (static_cast<int32_t>(measurement->accumulatedDeltaRangeState))); |
| SET(AccumulatedDeltaRangeMeters, measurement->accumulatedDeltaRangeM); |
| SET(AccumulatedDeltaRangeUncertaintyMeters, |
| measurement->accumulatedDeltaRangeUncertaintyM); |
| |
| if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_CARRIER_FREQUENCY)) { |
| SET(CarrierFrequencyHz, measurement->carrierFrequencyHz); |
| } |
| |
| // Intentionally not copying deprecated fields of carrierCycles, |
| // carrierPhase, carrierPhaseUncertainty |
| |
| SET(MultipathIndicator, static_cast<int32_t>(measurement->multipathIndicator)); |
| |
| if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_SNR)) { |
| SET(SnrInDb, measurement->snrDb); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL)) { |
| SET(AutomaticGainControlLevelInDb, measurement->agcLevelDb); |
| } |
| } |
| |
| jobject GnssMeasurementCallback::translateGnssClock( |
| JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) { |
| JavaObject object(env, "android/location/GnssClock"); |
| |
| uint32_t flags = static_cast<uint32_t>(clock->gnssClockFlags); |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_LEAP_SECOND)) { |
| SET(LeapSecond, static_cast<int32_t>(clock->leapSecond)); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_TIME_UNCERTAINTY)) { |
| SET(TimeUncertaintyNanos, clock->timeUncertaintyNs); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_FULL_BIAS)) { |
| SET(FullBiasNanos, clock->fullBiasNs); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS)) { |
| SET(BiasNanos, clock->biasNs); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS_UNCERTAINTY)) { |
| SET(BiasUncertaintyNanos, clock->biasUncertaintyNs); |
| } |
| |
| if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_DRIFT)) { |
| SET(DriftNanosPerSecond, clock->driftNsps); |
| } |
| |
| if (flags & static_cast<uint32_t>(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_V1_1::GnssMeasurement* measurements_v1_1, |
| const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurements_v1_0, |
| size_t count) { |
| if (count == 0) { |
| return NULL; |
| } |
| |
| jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement"); |
| jobjectArray gnssMeasurementArray = env->NewObjectArray( |
| count, |
| gnssMeasurementClass, |
| NULL /* initialElement */); |
| |
| for (uint16_t i = 0; i < count; ++i) { |
| JavaObject object(env, "android/location/GnssMeasurement"); |
| if (measurements_v1_1 != NULL) { |
| translateGnssMeasurement_V1_0(env, &(measurements_v1_1[i].v1_0), object); |
| |
| // Set the V1_1 flag |
| SET(AccumulatedDeltaRangeState, |
| static_cast<int32_t>(measurements_v1_1[i].accumulatedDeltaRangeState)); |
| } else { |
| translateGnssMeasurement_V1_0(env, &(measurements_v1_0[i]), object); |
| } |
| |
| env->SetObjectArrayElement(gnssMeasurementArray, i, object.get()); |
| } |
| |
| env->DeleteLocalRef(gnssMeasurementClass); |
| return gnssMeasurementArray; |
| } |
| |
| void GnssMeasurementCallback::setMeasurementData(JNIEnv* env, jobject clock, |
| jobjectArray measurementArray) { |
| jclass gnssMeasurementsEventClass = |
| env->FindClass("android/location/GnssMeasurementsEvent"); |
| jmethodID gnssMeasurementsEventCtor = |
| env->GetMethodID( |
| gnssMeasurementsEventClass, |
| "<init>", |
| "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V"); |
| |
| jobject gnssMeasurementsEvent = env->NewObject(gnssMeasurementsEventClass, |
| gnssMeasurementsEventCtor, |
| clock, |
| measurementArray); |
| |
| env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, |
| gnssMeasurementsEvent); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| env->DeleteLocalRef(gnssMeasurementsEventClass); |
| env->DeleteLocalRef(gnssMeasurementsEvent); |
| } |
| |
| /* |
| * GnssNiCallback implements callback methods required by the IGnssNi interface. |
| */ |
| struct GnssNiCallback : public IGnssNiCallback { |
| Return<void> niNotifyCb(const IGnssNiCallback::GnssNiNotification& notification) |
| override; |
| }; |
| |
| Return<void> GnssNiCallback::niNotifyCb( |
| const IGnssNiCallback::GnssNiNotification& notification) { |
| JNIEnv* env = 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<void> agnssStatusIpV6Cb( |
| const IAGnssCallback::AGnssStatusIpV6& agps_status) override; |
| |
| Return<void> agnssStatusIpV4Cb( |
| const IAGnssCallback::AGnssStatusIpV4& agps_status) override; |
| private: |
| jbyteArray convertToIpV4(uint32_t ip); |
| }; |
| |
| Return<void> AGnssCallback::agnssStatusIpV6Cb( |
| const IAGnssCallback::AGnssStatusIpV6& agps_status) { |
| JNIEnv* env = 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<void> AGnssCallback::agnssStatusIpV4Cb( |
| const IAGnssCallback::AGnssStatusIpV4& agps_status) { |
| JNIEnv* env = 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 = 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<void> requestSetIdCb(uint32_t setIdFlag) override; |
| Return<void> requestRefLocCb() override; |
| }; |
| |
| Return<void> AGnssRilCallback::requestSetIdCb(uint32_t setIdFlag) { |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_requestSetID, setIdFlag); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| Return<void> AGnssRilCallback::requestRefLocCb() { |
| JNIEnv* env = getJniEnv(); |
| env->CallVoidMethod(mCallbacksObj, method_requestRefLocation); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| return Void(); |
| } |
| |
| /* |
| * GnssBatchingCallback interface implements the callback methods |
| * required by the IGnssBatching interface. |
| */ |
| struct GnssBatchingCallback : public IGnssBatchingCallback { |
| /* |
| * Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback |
| * follow. |
| */ |
| Return<void> gnssLocationBatchCb( |
| const ::android::hardware::hidl_vec<GnssLocation> & locations) |
| override; |
| }; |
| |
| Return<void> GnssBatchingCallback::gnssLocationBatchCb( |
| const ::android::hardware::hidl_vec<GnssLocation> & locations) { |
| JNIEnv* env = getJniEnv(); |
| |
| jobjectArray jLocations = env->NewObjectArray(locations.size(), |
| env->FindClass("android/location/Location"), nullptr); |
| |
| for (uint16_t i = 0; i < locations.size(); ++i) { |
| jobject jLocation = translateLocation(env, locations[i]); |
| env->SetObjectArrayElement(jLocations, i, jLocation); |
| env->DeleteLocalRef(jLocation); |
| } |
| |
| env->CallVoidMethod(mCallbacksObj, method_reportLocationBatch, jLocations); |
| checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| |
| env->DeleteLocalRef(jLocations); |
| |
| return Void(); |
| } |
| |
| static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { |
| method_reportLocation = env->GetMethodID(clazz, "reportLocation", |
| "(ZLandroid/location/Location;)V"); |
| method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); |
| method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)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_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName", |
| "(Ljava/lang/String;)V"); |
| method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); |
| method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", |
| "(IIIIILjava/lang/String;Ljava/lang/String;II)V"); |
| method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(Z)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", |
| "(ILandroid/location/Location;IJ)V"); |
| method_reportGeofenceStatus = env->GetMethodID(clazz, "reportGeofenceStatus", |
| "(ILandroid/location/Location;)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"); |
| method_reportLocationBatch = env->GetMethodID( |
| clazz, |
| "reportLocationBatch", |
| "([Landroid/location/Location;)V"); |
| |
| /* |
| * Save a pointer to JVM. |
| */ |
| jint jvmStatus = env->GetJavaVM(&sJvm); |
| if (jvmStatus != JNI_OK) { |
| LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus); |
| } |
| |
| // TODO(b/31632518) |
| gnssHal_V1_1 = IGnss_V1_1::getService(); |
| if (gnssHal_V1_1 == nullptr) { |
| ALOGD("gnssHal 1.1 was null, trying 1.0"); |
| gnssHal = IGnss_V1_0::getService(); |
| } else { |
| gnssHal = gnssHal_V1_1; |
| } |
| |
| if (gnssHal != nullptr) { |
| gnssHalDeathRecipient = new GnssDeathRecipient(); |
| hardware::Return<bool> linked = gnssHal->linkToDeath( |
| gnssHalDeathRecipient, /*cookie*/ 0); |
| if (!linked.isOk()) { |
| ALOGE("Transaction error in linking to GnssHAL death: %s", |
| linked.description().c_str()); |
| } else if (!linked) { |
| ALOGW("Unable to link to GnssHal death notifications"); |
| } else { |
| ALOGD("Link to death notification successful"); |
| } |
| |
| auto gnssXtra = gnssHal->getExtensionXtra(); |
| if (!gnssXtra.isOk()) { |
| ALOGD("Unable to get a handle to Xtra"); |
| } else { |
| gnssXtraIface = gnssXtra; |
| } |
| |
| auto gnssRil = gnssHal->getExtensionAGnssRil(); |
| if (!gnssRil.isOk()) { |
| ALOGD("Unable to get a handle to AGnssRil"); |
| } else { |
| agnssRilIface = gnssRil; |
| } |
| |
| auto gnssAgnss = gnssHal->getExtensionAGnss(); |
| if (!gnssAgnss.isOk()) { |
| ALOGD("Unable to get a handle to AGnss"); |
| } else { |
| agnssIface = gnssAgnss; |
| } |
| |
| auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage(); |
| if (!gnssNavigationMessage.isOk()) { |
| ALOGD("Unable to get a handle to GnssNavigationMessage"); |
| } else { |
| gnssNavigationMessageIface = gnssNavigationMessage; |
| } |
| |
| if (gnssHal_V1_1 != nullptr) { |
| auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1(); |
| if (!gnssMeasurement.isOk()) { |
| ALOGD("Unable to get a handle to GnssMeasurement"); |
| } else { |
| gnssMeasurementIface_V1_1 = gnssMeasurement; |
| gnssMeasurementIface = gnssMeasurementIface_V1_1; |
| } |
| } else { |
| auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement(); |
| if (!gnssMeasurement_V1_0.isOk()) { |
| ALOGD("Unable to get a handle to GnssMeasurement"); |
| } else { |
| gnssMeasurementIface = gnssMeasurement_V1_0; |
| } |
| } |
| |
| auto gnssDebug = gnssHal->getExtensionGnssDebug(); |
| if (!gnssDebug.isOk()) { |
| ALOGD("Unable to get a handle to GnssDebug"); |
| } else { |
| gnssDebugIface = gnssDebug; |
| } |
| |
| auto gnssNi = gnssHal->getExtensionGnssNi(); |
| if (!gnssNi.isOk()) { |
| ALOGD("Unable to get a handle to GnssNi"); |
| } else { |
| gnssNiIface = gnssNi; |
| } |
| |
| auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration(); |
| if (!gnssConfiguration.isOk()) { |
| ALOGD("Unable to get a handle to GnssConfiguration"); |
| } else { |
| gnssConfigurationIface = gnssConfiguration; |
| } |
| |
| auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing(); |
| if (!gnssGeofencing.isOk()) { |
| ALOGD("Unable to get a handle to GnssGeofencing"); |
| } else { |
| gnssGeofencingIface = gnssGeofencing; |
| } |
| |
| auto gnssBatching = gnssHal->getExtensionGnssBatching(); |
| if (!gnssBatching.isOk()) { |
| ALOGD("Unable to get a handle to gnssBatching"); |
| } else { |
| gnssBatchingIface = gnssBatching; |
| } |
| } else { |
| ALOGE("Unable to get GPS service\n"); |
| } |
| } |
| |
| 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); |
| |
| /* |
| * Fail if the main interface fails to initialize |
| */ |
| if (gnssHal == nullptr) { |
| ALOGE("Unable to Initialize GNSS HAL\n"); |
| return JNI_FALSE; |
| } |
| |
| sp<IGnssCallback> gnssCbIface = new GnssCallback(); |
| |
| Return<bool> result = false; |
| if (gnssHal_V1_1 != nullptr) { |
| result = gnssHal_V1_1->setCallback_1_1(gnssCbIface); |
| } else { |
| result = gnssHal->setCallback(gnssCbIface); |
| } |
| if (!result.isOk() || !result) { |
| ALOGE("SetCallback for Gnss Interface fails\n"); |
| return JNI_FALSE; |
| } |
| |
| sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback(); |
| if (gnssXtraIface == nullptr) { |
| ALOGE("Unable to initialize GNSS Xtra interface\n"); |
| } else { |
| result = gnssXtraIface->setCallback(gnssXtraCbIface); |
| if (!result.isOk() || !result) { |
| gnssXtraIface = nullptr; |
| ALOGI("SetCallback for Gnss Xtra Interface fails\n"); |
| } |
| } |
| |
| sp<IAGnssCallback> aGnssCbIface = new AGnssCallback(); |
| if (agnssIface != nullptr) { |
| agnssIface->setCallback(aGnssCbIface); |
| } else { |
| ALOGI("Unable to Initialize AGnss interface\n"); |
| } |
| |
| sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback(); |
| if (gnssGeofencingIface != nullptr) { |
| gnssGeofencingIface->setCallback(gnssGeofencingCbIface); |
| } else { |
| ALOGI("Unable to initialize GNSS Geofencing interface\n"); |
| } |
| |
| sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback(); |
| if (gnssNiIface != nullptr) { |
| gnssNiIface->setCallback(gnssNiCbIface); |
| } else { |
| ALOGI("Unable to initialize GNSS NI interface\n"); |
| } |
| |
| sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback(); |
| if (agnssRilIface != nullptr) { |
| agnssRilIface->setCallback(aGnssRilCbIface); |
| } else { |
| ALOGI("Unable to Initialize AGnss Ril 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, jboolean low_power_mode) { |
| Return<bool> result = false; |
| if (gnssHal_V1_1 != nullptr) { |
| result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode), |
| static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence), |
| min_interval, |
| preferred_accuracy, |
| preferred_time, |
| low_power_mode); |
| } else if (gnssHal != nullptr) { |
| result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode), |
| static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence), |
| min_interval, |
| preferred_accuracy, |
| preferred_time); |
| } |
| if (!result.isOk()) { |
| ALOGE("%s: GNSS setPositionMode failed\n", __func__); |
| return JNI_FALSE; |
| } else { |
| return result; |
| } |
| } |
| |
| static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) { |
| if (gnssHal != nullptr) { |
| auto result = gnssHal->start(); |
| if (!result.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.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<IGnss_V1_0::GnssAidingData>(flags)); |
| if (!result.isOk()) { |
| ALOGE("Error in deleting aiding data"); |
| } |
| } |
| } |
| |
| 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<IAGnssRil::AGnssRefLocationType>(type)) { |
| case IAGnssRil::AGnssRefLocationType::GSM_CELLID: |
| case IAGnssRil::AGnssRefLocationType::UMTS_CELLID: |
| location.type = static_cast<IAGnssRil::AGnssRefLocationType>(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<jbyte *>(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.isOk() || !result) { |
| ALOGE("%s: Gnss injectTime() failed", __func__); |
| } |
| } |
| } |
| |
| static void android_location_GnssLocationProvider_inject_best_location( |
| JNIEnv*, |
| jobject, |
| jint gnssLocationFlags, |
| jdouble latitudeDegrees, |
| jdouble longitudeDegrees, |
| jdouble altitudeMeters, |
| jfloat speedMetersPerSec, |
| jfloat bearingDegrees, |
| jfloat horizontalAccuracyMeters, |
| jfloat verticalAccuracyMeters, |
| jfloat speedAccuracyMetersPerSecond, |
| jfloat bearingAccuracyDegrees, |
| jlong timestamp) { |
| if (gnssHal_V1_1 != nullptr) { |
| GnssLocation location = createGnssLocation( |
| gnssLocationFlags, |
| latitudeDegrees, |
| longitudeDegrees, |
| altitudeMeters, |
| speedMetersPerSec, |
| bearingDegrees, |
| horizontalAccuracyMeters, |
| verticalAccuracyMeters, |
| speedAccuracyMetersPerSecond, |
| bearingAccuracyDegrees, |
| timestamp); |
| auto result = gnssHal_V1_1->injectBestLocation(location); |
| if (!result.isOk() || !result) { |
| ALOGE("%s: Gnss injectBestLocation() failed.", __func__); |
| } |
| } else { |
| ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __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.isOk() || !result) { |
| 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<jbyte *>(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<IAGnss::ApnIpType>(apnIpType)); |
| if (!result.isOk() || !result){ |
| 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.isOk() || !result) { |
| 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.isOk() || !result) { |
| 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<IAGnssCallback::AGnssType>(type), |
| c_hostname, |
| port); |
| if (!result.isOk() || !result) { |
| 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<IGnssNiCallback::GnssUserResponseType>(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. |
| */ |
| |
| std::stringstream internalState; |
| |
| if (gnssDebugIface == nullptr) { |
| internalState << "Gnss Debug Interface not available" << std::endl; |
| } else { |
| IGnssDebug::DebugData data; |
| gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) { |
| data = debugData; |
| }); |
| |
| internalState << "Gnss Location Data:: "; |
| if (!data.position.valid) { |
| internalState << "not valid"; |
| } else { |
| internalState << "LatitudeDegrees: " << data.position.latitudeDegrees |
| << ", LongitudeDegrees: " << data.position.longitudeDegrees |
| << ", altitudeMeters: " << data.position.altitudeMeters |
| << ", speedMetersPerSecond: " << data.position.speedMetersPerSec |
| << ", bearingDegrees: " << data.position.bearingDegrees |
| << ", horizontalAccuracyMeters: " |
| << data.position.horizontalAccuracyMeters |
| << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters |
| << ", speedAccuracyMetersPerSecond: " |
| << data.position.speedAccuracyMetersPerSecond |
| << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees |
| << ", ageSeconds: " << data.position.ageSeconds; |
| } |
| internalState << std::endl; |
| |
| internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate |
| << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs |
| << ", frequencyUncertaintyNsPerSec: " |
| << data.time.frequencyUncertaintyNsPerSec << std::endl; |
| |
| if (data.satelliteDataArray.size() != 0) { |
| internalState << "Satellite Data for " << data.satelliteDataArray.size() |
| << " satellites:: " << std::endl; |
| } |
| |
| internalState << "constellation: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; " |
| << "ephemerisType: 0=Eph, 1=Alm, 2=?; " |
| << "ephemerisSource: 0=Demod, 1=Supl, 2=Server, 3=?; " |
| << "ephemerisHealth: 0=Good, 1=Bad, 2=?" << std::endl; |
| for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { |
| internalState << "svid: " << data.satelliteDataArray[i].svid |
| << ", constellation: " |
| << static_cast<uint32_t>(data.satelliteDataArray[i].constellation) |
| << ", ephemerisType: " |
| << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType) |
| << ", ephemerisSource: " |
| << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisSource) |
| << ", ephemerisHealth: " |
| << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisHealth) |
| << ", serverPredictionIsAvailable: " |
| << data.satelliteDataArray[i].serverPredictionIsAvailable |
| << ", serverPredictionAgeSeconds: " |
| << data.satelliteDataArray[i].serverPredictionAgeSeconds |
| << ", 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<IAGnssRil::NetworkType>(type), |
| roaming); |
| if (!result.isOk() || !result) { |
| ALOGE("updateNetworkState failed"); |
| } |
| |
| const char *c_apn = env->GetStringUTFChars(apn, NULL); |
| result = agnssRilIface->updateNetworkAvailability(available, c_apn); |
| if (!result.isOk() || !result) { |
| 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<IGnssGeofenceCallback::GeofenceTransition>(last_transition), |
| monitor_transition, notification_responsiveness, unknown_timer); |
| return boolToJbool(result.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.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.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.isOk()); |
| } else { |
| ALOGE("Geofence interface not available"); |
| } |
| return JNI_FALSE; |
| } |
| |
| static jboolean android_location_GnssLocationProvider_is_measurement_supported( |
| 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 */, |
| jboolean enableFullTracking) { |
| if (gnssMeasurementIface == nullptr) { |
| ALOGE("GNSS Measurement interface is not available."); |
| return JNI_FALSE; |
| } |
| |
| sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback(); |
| IGnssMeasurement_V1_0::GnssMeasurementStatus result = |
| IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;; |
| if (gnssMeasurementIface_V1_1 != nullptr) { |
| result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface, |
| enableFullTracking); |
| } else { |
| if (enableFullTracking == JNI_TRUE) { |
| // full tracking mode not supported in 1.0 HAL |
| return JNI_FALSE; |
| } |
| result = gnssMeasurementIface->setCallback(cbIface); |
| } |
| |
| if (result != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) { |
| ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d", |
| static_cast<int32_t>(result)); |
| return JNI_FALSE; |
| } else { |
| ALOGD("gnss measurement infc has been enabled"); |
| } |
| |
| return JNI_TRUE; |
| } |
| |
| static jboolean android_location_GnssLocationProvider_stop_measurement_collection( |
| JNIEnv* env, |
| jobject obj) { |
| if (gnssMeasurementIface == nullptr) { |
| ALOGE("Measurement interface not available"); |
| return JNI_FALSE; |
| } |
| |
| auto result = gnssMeasurementIface->close(); |
| return boolToJbool(result.isOk()); |
| } |
| |
| static jboolean android_location_GnssLocationProvider_is_navigation_message_supported( |
| JNIEnv* env, |
| jclass clazz) { |
| if (gnssNavigationMessageIface != nullptr) { |
| return JNI_TRUE; |
| } |
| return JNI_FALSE; |
| } |
| |
| static jboolean android_location_GnssLocationProvider_start_navigation_message_collection( |
| JNIEnv* env, |
| jobject obj) { |
| if (gnssNavigationMessageIface == nullptr) { |
| ALOGE("Navigation Message interface is not available."); |
| return JNI_FALSE; |
| } |
| |
| sp<IGnssNavigationMessageCallback> 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<int32_t>(result)); |
| return JNI_FALSE; |
| } |
| |
| return JNI_TRUE; |
| } |
| |
| static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection( |
| JNIEnv* env, |
| jobject obj) { |
| if (gnssNavigationMessageIface == nullptr) { |
| ALOGE("Navigation Message interface is not available."); |
| return JNI_FALSE; |
| } |
| |
| auto result = gnssNavigationMessageIface->close(); |
| return boolToJbool(result.isOk()); |
| } |
| |
| 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.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.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.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.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.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.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.isOk()) { |
| return result; |
| } else { |
| return JNI_FALSE; |
| } |
| } |
| |
| static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) { |
| if (gnssBatchingIface == nullptr) { |
| return 0; // batching not supported, size = 0 |
| } |
| auto result = gnssBatchingIface->getBatchSize(); |
| if (result.isOk()) { |
| return static_cast<jint>(result); |
| } else { |
| return 0; // failure in binder, don't support batching |
| } |
| } |
| |
| static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) { |
| if (gnssBatchingIface == nullptr) { |
| return JNI_FALSE; // batching not supported |
| } |
| sp<IGnssBatchingCallback> gnssBatchingCbIface = new GnssBatchingCallback(); |
| |
| return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface)); |
| } |
| |
| static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) { |
| if (gnssBatchingIface == nullptr) { |
| return; // batching not supported |
| } |
| gnssBatchingIface->cleanup(); |
| } |
| |
| static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass, |
| jlong periodNanos, jboolean wakeOnFifoFull) { |
| if (gnssBatchingIface == nullptr) { |
| return JNI_FALSE; // batching not supported |
| } |
| |
| IGnssBatching::Options options; |
| options.periodNanos = periodNanos; |
| if (wakeOnFifoFull) { |
| options.flags = static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL); |
| } else { |
| options.flags = 0; |
| } |
| |
| return static_cast<jboolean>(gnssBatchingIface->start(options)); |
| } |
| |
| static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { |
| if (gnssBatchingIface == nullptr) { |
| return; // batching not supported |
| } |
| |
| gnssBatchingIface->flush(); |
| } |
| |
| static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) { |
| if (gnssBatchingIface == nullptr) { |
| return JNI_FALSE; // batching not supported |
| } |
| |
| return gnssBatchingIface->stop(); |
| } |
| |
| static const JNINativeMethod sMethods[] = { |
| /* name, signature, funcPtr */ |
| {"class_init_native", "()V", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_class_init_native)}, |
| {"native_is_supported", "()Z", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_is_supported)}, |
| {"native_is_agps_ril_supported", "()Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_is_agps_ril_supported)}, |
| {"native_is_gnss_configuration_supported", "()Z", |
| reinterpret_cast<void *>( |
| android_location_gpsLocationProvider_is_gnss_configuration_supported)}, |
| {"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)}, |
| {"native_cleanup", "()V", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_cleanup)}, |
| {"native_set_position_mode", |
| "(IIIIIZ)Z", |
| reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)}, |
| {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)}, |
| {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)}, |
| {"native_delete_aiding_data", |
| "(I)V", |
| reinterpret_cast<void*>(android_location_GnssLocationProvider_delete_aiding_data)}, |
| {"native_read_nmea", "([BI)I", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_read_nmea)}, |
| {"native_inject_time", "(JJI)V", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_inject_time)}, |
| {"native_inject_best_location", |
| "(IDDDFFFFFFJ)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)}, |
| {"native_inject_location", |
| "(DDF)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)}, |
| {"native_supports_xtra", "()Z", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_supports_xtra)}, |
| {"native_inject_xtra_data", |
| "([BI)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_xtra_data)}, |
| {"native_agps_data_conn_open", |
| "(Ljava/lang/String;I)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_open)}, |
| {"native_agps_data_conn_closed", |
| "()V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_closed)}, |
| {"native_agps_data_conn_failed", |
| "()V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_failed)}, |
| {"native_agps_set_id", |
| "(ILjava/lang/String;)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_set_id)}, |
| {"native_agps_set_ref_location_cellid", |
| "(IIIII)V", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, |
| {"native_set_agps_server", |
| "(ILjava/lang/String;I)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_agps_server)}, |
| {"native_send_ni_response", |
| "(II)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_send_ni_response)}, |
| {"native_get_internal_state", |
| "()Ljava/lang/String;", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)}, |
| {"native_update_network_state", |
| "(ZIZZLjava/lang/String;Ljava/lang/String;)V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_update_network_state)}, |
| {"native_is_geofence_supported", |
| "()Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_is_geofence_supported)}, |
| {"native_add_geofence", |
| "(IDDDIIII)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_add_geofence)}, |
| {"native_remove_geofence", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_remove_geofence)}, |
| {"native_pause_geofence", "(I)Z", reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_pause_geofence)}, |
| {"native_resume_geofence", |
| "(II)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_resume_geofence)}, |
| {"native_is_measurement_supported", |
| "()Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_is_measurement_supported)}, |
| {"native_start_measurement_collection", |
| "(Z)Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_start_measurement_collection)}, |
| {"native_stop_measurement_collection", |
| "()Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_stop_measurement_collection)}, |
| {"native_is_navigation_message_supported", |
| "()Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_is_navigation_message_supported)}, |
| {"native_start_navigation_message_collection", |
| "()Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_start_navigation_message_collection)}, |
| {"native_stop_navigation_message_collection", |
| "()Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_stop_navigation_message_collection)}, |
| {"native_set_supl_es", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)}, |
| {"native_set_supl_version", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_version)}, |
| {"native_set_supl_mode", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_mode)}, |
| {"native_set_lpp_profile", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_lpp_profile)}, |
| {"native_set_gnss_pos_protocol_select", |
| "(I)Z", |
| reinterpret_cast<void *>( |
| android_location_GnssLocationProvider_set_gnss_pos_protocol_select)}, |
| {"native_set_gps_lock", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_gps_lock)}, |
| {"native_set_emergency_supl_pdn", |
| "(I)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)}, |
| {"native_get_batch_size", |
| "()I", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)}, |
| {"native_init_batching", |
| "()Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)}, |
| {"native_start_batch", |
| "(JZ)Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_start_batch)}, |
| {"native_flush_batch", |
| "()V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_flush_batch)}, |
| {"native_stop_batch", |
| "()Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_stop_batch)}, |
| {"native_init_batching", |
| "()Z", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)}, |
| {"native_cleanup_batching", |
| "()V", |
| reinterpret_cast<void *>(android_location_GnssLocationProvider_cleanup_batching)}, |
| }; |
| |
| int register_android_server_location_GnssLocationProvider(JNIEnv* env) { |
| return jniRegisterNativeMethods( |
| env, |
| "com/android/server/location/GnssLocationProvider", |
| sMethods, |
| NELEM(sMethods)); |
| } |
| |
| } /* namespace android */ |