code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "LocSvc_GnssBatchingInterface"

#include <log_util.h>
#include <BatchingAPIClient.h>
#include "GnssBatching.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
        uint64_t cookie, const wp<IBase>& who) {
    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
    if (mGnssBatching != nullptr) {
        mGnssBatching->stop();
        mGnssBatching->cleanup();
    }
}

GnssBatching::GnssBatching() : mApi(nullptr) {
    mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
}

GnssBatching::~GnssBatching() {
    if (mApi != nullptr) {
        mApi->destroy();
        mApi = nullptr;
    }
}

// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
Return<bool> GnssBatching::init(const sp<V1_0::IGnssBatchingCallback>& callback) {
    if (mApi != nullptr) {
        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
        mApi->destroy();
        mApi = nullptr;
    }

    mApi = new BatchingAPIClient(callback);
    if (mApi == nullptr) {
        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
        return false;
    }

    if (mGnssBatchingCbIface != nullptr) {
        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
    }
    mGnssBatchingCbIface = callback;
    if (mGnssBatchingCbIface != nullptr) {
        mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
    }

    return true;
}

Return<uint16_t> GnssBatching::getBatchSize() {
    uint16_t ret = 0;
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        ret = mApi->getBatchSize();
    }
    return ret;
}

Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
    bool ret = false;
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        ret = mApi->startSession(options);
    }
    return ret;
}

Return<void> GnssBatching::flush() {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        mApi->flushBatchedLocations();
    }
    return Void();
}

Return<bool> GnssBatching::stop() {
    bool ret = false;
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        ret = mApi->stopSession();
    }
    return ret;
}

Return<void> GnssBatching::cleanup() {
    if (mApi != nullptr) {
        mApi->stopSession();
    }
    if (mGnssBatchingCbIface != nullptr) {
        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
        mGnssBatchingCbIface = nullptr;
    }
    if (mGnssBatchingCbIface_2_0 != nullptr) {
        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
        mGnssBatchingCbIface_2_0 = nullptr;
    }
    return Void();
}

// Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
Return<bool> GnssBatching::init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) {
    if (mApi != nullptr) {
        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
        mApi->destroy();
        mApi = nullptr;
    }

    mApi = new BatchingAPIClient(callback);
    if (mApi == nullptr) {
        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
        return false;
    }

    if (mGnssBatchingCbIface_2_0 != nullptr) {
        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
    }
    mGnssBatchingCbIface_2_0 = callback;
    if (mGnssBatchingCbIface_2_0 != nullptr) {
        mGnssBatchingCbIface_2_0->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
    }

    return true;
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
#define ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H

#include <android/hardware/gnss/2.0/IGnssBatching.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V2_0::IGnssBatching;
using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
using ::android::hidl::base::V1_0::IBase;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;

class BatchingAPIClient;
struct GnssBatching : public IGnssBatching {
    GnssBatching();
    ~GnssBatching();

    // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
    Return<bool> init(const sp<V1_0::IGnssBatchingCallback>& callback) override;
    Return<uint16_t> getBatchSize() override;
    Return<bool> start(const IGnssBatching::Options& options ) override;
    Return<void> flush() override;
    Return<bool> stop() override;
    Return<void> cleanup() override;

    // Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
    Return<bool> init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) override;

 private:
    struct GnssBatchingDeathRecipient : hidl_death_recipient {
        GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
            mGnssBatching(gnssBatching) {
        }
        ~GnssBatchingDeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
        sp<GnssBatching> mGnssBatching;
    };

 private:
    sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
    BatchingAPIClient* mApi = nullptr;
    sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0 = nullptr;
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H

license: unknown


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "LocSvc_GnssConfigurationInterface"

#include <log_util.h>
#include "Gnss.h"
#include "GnssConfiguration.h"
#include "ContextBase.h"
#include <android/hardware/gnss/1.0/types.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V2_0::GnssConstellationType;
using namespace loc_core;

GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
}

// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setSuplEs(bool enabled)  {
    // deprecated function. Must return false to pass VTS
    return false;
}

Return<bool> GnssConfiguration::setSuplVersion(uint32_t version)  {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
    switch (version) {
        case 0x00020004:
            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_4;
            break;
        case 0x00020002:
            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
            break;
        case 0x00020000:
            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
            break;
        case 0x00010000:
            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
            break;
        default:
            LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
            return false;
    }

    return mGnss->updateConfiguration(config);
}

Return<bool> GnssConfiguration::setSuplMode(uint8_t mode)  {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
    switch (mode) {
        case 0:
            config.suplModeMask = 0; // STANDALONE ONLY
            break;
        case 1:
            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
            break;
        case 2:
            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
            break;
        case 3:
            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
            break;
        default:
            LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
            return false;
    }

    return mGnss->updateConfiguration(config);
}

Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfileMask) {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config = {};
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
    config.lppProfileMask = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE; //default

    if (lppProfileMask & (1<<0)) {
        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT;
    }
    if (lppProfileMask & (1<<1)) {
        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT;
    }
    if (lppProfileMask & (1<<2)) {
        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT;
    }
    if (lppProfileMask & (1<<3)) {
        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT;
    }

    return mGnss->updateConfiguration(config);
}

Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);

    config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
    if (protocol & (1<<0)) {
        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
    }
    if (protocol & (1<<1)) {
        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
    }
    if (protocol & (1<<2)) {
        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
    }
    if (protocol & (1<<3)) {
        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
    }

    return mGnss->updateConfiguration(config);
}

Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {

    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config = {};
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
    switch (lock) {
    case 0:
        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
        break;
    case 1:
        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
        break;
    case 2:
        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
        break;
    case 3:
        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
        break;
    default:
        LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
        return false;
    }

    mGnss->updateConfiguration(config);
    // Must return false to pass VTS
    return false;
}

Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return false;
    }

    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
    config.emergencyPdnForEmergencySupl = (enabled ?
            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);

    return mGnss->updateConfiguration(config);
}

// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setBlacklist(
            const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) {

    ENTRY_LOG_CALLFLOW();
    if (nullptr == mGnss) {
        LOC_LOGe("mGnss is null");
        return false;
    }

    // blValid is true if blacklist is empty, i.e. clearing the BL;
    // if blacklist is not empty, blValid is initialied to false, and later
    // updated in the for loop to become true only if there is at least
    // one {constellation, svid} in the list that is valid.
    bool blValid = (0 == blacklist.size());
    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
    config.blacklistedSvIds.clear();

    GnssSvIdSource source = {};
    for (int idx = 0; idx < (int)blacklist.size(); idx++) {
        // Set blValid true if any one source is valid
        blValid = setBlacklistedSource(source, (GnssConstellationType)blacklist[idx].constellation,
                blacklist[idx].svid) || blValid;
        config.blacklistedSvIds.push_back(source);
    }

    // Update configuration only if blValid is true
    // i.e. only if atleast one source is valid for blacklisting
    return (blValid && mGnss->updateConfiguration(config));
}

bool GnssConfiguration::setBlacklistedSource(
            GnssSvIdSource& copyToSource, const GnssConstellationType& constellation,
            const int16_t svid) {

    bool retVal = true;
    uint16_t svIdOffset = 0;
    copyToSource.size = sizeof(GnssSvIdSource);
    copyToSource.svId = svid;

    switch(constellation) {
    case GnssConstellationType::GPS:
        copyToSource.constellation = GNSS_SV_TYPE_GPS;
        LOC_LOGe("GPS SVs can't be blacklisted.");
        retVal = false;
        break;
    case GnssConstellationType::SBAS:
        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
        LOC_LOGe("SBAS SVs can't be blacklisted.");
        retVal = false;
        break;
    case GnssConstellationType::GLONASS:
        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::QZSS:
        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
        svIdOffset = 0;
        break;
    case GnssConstellationType::BEIDOU:
        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::GALILEO:
        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::IRNSS:
        copyToSource.constellation = GNSS_SV_TYPE_NAVIC;
        svIdOffset = 0;
        break;
    default:
        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
        LOC_LOGe("Invalid constellation %hhu", constellation);
        retVal = false;
        break;
    }

    if (copyToSource.svId > 0 && svIdOffset > 0) {
        copyToSource.svId += svIdOffset;
    }

    return retVal;
}

bool GnssConfiguration::setBlacklistedSource(
        GnssSvIdSource& copyToSource,
        const GnssConfiguration::BlacklistedSource& copyFromSource) {

    bool retVal = true;
    uint16_t svIdOffset = 0;
    copyToSource.size = sizeof(GnssSvIdSource);
    copyToSource.svId = copyFromSource.svid;

    switch(copyFromSource.constellation) {
    case GnssConstellationType::GPS:
        copyToSource.constellation = GNSS_SV_TYPE_GPS;
        LOC_LOGe("GPS SVs can't be blacklisted.");
        retVal = false;
        break;
    case GnssConstellationType::SBAS:
        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
        LOC_LOGe("SBAS SVs can't be blacklisted.");
        retVal = false;
        break;
    case GnssConstellationType::GLONASS:
        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::QZSS:
        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
        svIdOffset = GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::BEIDOU:
        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::GALILEO:
        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
        break;
    case GnssConstellationType::IRNSS:
        copyToSource.constellation = GNSS_SV_TYPE_NAVIC;
        svIdOffset = GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID - 1;
        break;
    default:
        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
        LOC_LOGe("Invalid constellation %hhu", copyFromSource.constellation);
        retVal = false;
        break;
    }

    if (copyToSource.svId > 0 && svIdOffset > 0) {
        copyToSource.svId += svIdOffset;
    }

    return retVal;
}

// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
    ENTRY_LOG_CALLFLOW();
    if (mGnss == nullptr) {
        LOC_LOGe("mGnss is nullptr");
        return false;
    }

    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
    config.emergencyExtensionSeconds = emergencyExtensionSeconds;

    return mGnss->updateConfiguration(config);
}

// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setBlacklist_2_1(
        const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) {
    ENTRY_LOG_CALLFLOW();
    if (nullptr == mGnss) {
        LOC_LOGe("mGnss is null");
        return false;
    }

    // blValid is true if blacklist is empty, i.e. clearing the BL;
    // if blacklist is not empty, blValid is initialied to false, and later
    // updated in the for loop to become true only if there is at least
    // one {constellation, svid} in the list that is valid.
    bool blValid = (0 == blacklist.size());
    GnssConfig config;
    memset(&config, 0, sizeof(GnssConfig));
    config.size = sizeof(GnssConfig);
    config.flags = GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
    config.blacklistedSvIds.clear();

    GnssSvIdSource source = {};
    for (int idx = 0; idx < (int)blacklist.size(); idx++) {
        // Set blValid true if any one source is valid
        blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
        config.blacklistedSvIds.push_back(source);
    }

    // Update configuration only if blValid is true
    // i.e. only if atleast one source is valid for blacklisting
    return (blValid && mGnss->updateConfiguration(config));
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */

 /* Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H

#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::hardware::gnss::V2_0::GnssConstellationType;
using ::android::sp;

/*
 * Interface for passing GNSS configuration info from platform to HAL.
 */
struct Gnss;
struct GnssConfiguration : public V2_1::IGnssConfiguration {
    GnssConfiguration(Gnss* gnss);
    ~GnssConfiguration() = default;

    /*
     * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
     * These declarations were generated from IGnssConfiguration.hal.
     */
    Return<bool> setSuplVersion(uint32_t version) override;
    Return<bool> setSuplMode(uint8_t mode) override;
    Return<bool> setSuplEs(bool enabled) override;
    Return<bool> setLppProfile(uint8_t lppProfileMask) override;
    Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
    Return<bool> setEmergencySuplPdn(bool enable) override;
    Return<bool> setGpsLock(uint8_t lock) override;

    // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
    Return<bool> setBlacklist(
            const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;

    // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
    Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
    // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
    Return<bool> setBlacklist_2_1(
            const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;

 private:
    Gnss* mGnss = nullptr;
    bool setBlacklistedSource(
            GnssSvIdSource& copyToSource,
            const GnssConfiguration::BlacklistedSource& copyFromSource);
    bool setBlacklistedSource(
            GnssSvIdSource& copyToSource, const GnssConstellationType& constellation,
            const int16_t svid);
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "LocSvc_GnssDebugInterface"

#include <log/log.h>
#include <log_util.h>
#include "Gnss.h"
#include "GnssDebug.h"
#include "LocationUtil.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::hidl_vec;
using ::android::hardware::gnss::V2_0::IGnssDebug;

#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS   (20000)
#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC     (500)
#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG       (180)

#define GNSS_DEBUG_UNKNOWN_UTC_TIME            (1483228800000LL) // 1/1/2017 00:00 GMT
#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN    (999) // 999 ns
#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX    (1.57783680E17) // 5 years in ns
#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5)  // ppm

GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
{
}

/*
 * This methods requests position, time and satellite ephemeris debug information
 * from the HAL.
 *
 * @return void
*/
Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
{
    LOC_LOGD("%s]: ", __func__);

    V1_0::IGnssDebug::DebugData data = { };

    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
        LOC_LOGE("GnssDebug - Null GNSS interface");
        _hidl_cb(data);
        return Void();
    }

    // get debug report snapshot via hal interface
    GnssDebugReport reports = { };
    mGnss->getGnssInterface()->getDebugReport(reports);

    // location block
    if (reports.mLocation.mValid) {
        data.position.valid = true;
        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;

        data.position.speedMetersPerSec =
            (double)(reports.mLocation.mLocation.speed);
        data.position.bearingDegrees =
            (double)(reports.mLocation.mLocation.bearing);
        data.position.horizontalAccuracyMeters =
            (double)(reports.mLocation.mLocation.accuracy);
        data.position.verticalAccuracyMeters =
            reports.mLocation.verticalAccuracyMeters;
        data.position.speedAccuracyMetersPerSecond =
            reports.mLocation.speedAccuracyMetersPerSecond;
        data.position.bearingAccuracyDegrees =
            reports.mLocation.bearingAccuracyDegrees;

        timeval tv_now, tv_report;
        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
        gettimeofday(&tv_now, NULL);
        data.position.ageSeconds =
            (tv_now.tv_sec - tv_report.tv_sec) +
            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
    }
    else {
        data.position.valid = false;
    }

    if (data.position.horizontalAccuracyMeters <= 0 ||
        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
    }
    if (data.position.verticalAccuracyMeters <= 0 ||
        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
    }
    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
    }
    if (data.position.bearingAccuracyDegrees <= 0 ||
        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
    }

    // time block
    if (reports.mTime.mValid) {
        data.time.timeEstimate = reports.mTime.timeEstimate;
        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
        data.time.frequencyUncertaintyNsPerSec =
            reports.mTime.frequencyUncertaintyNsPerSec;
    }

    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
    }
    if (data.time.timeUncertaintyNs <= 0) {
        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
    } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
    }
    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
    }

    // satellite data block
    V1_0::IGnssDebug::SatelliteData s = { };
    std::vector<V1_0::IGnssDebug::SatelliteData> s_array;

    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
        memset(&s, 0, sizeof(s));
        s.svid = reports.mSatelliteInfo[i].svid;
        convertGnssConstellationType(
            reports.mSatelliteInfo[i].constellation, s.constellation);
        convertGnssEphemerisType(
            reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
        convertGnssEphemerisSource(
            reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
        convertGnssEphemerisHealth(
            reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);

        s.ephemerisAgeSeconds =
            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
        s.serverPredictionIsAvailable =
            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
        s.serverPredictionAgeSeconds =
            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;

        s_array.push_back(s);
    }
    data.satelliteDataArray = s_array;

    // callback HIDL with collected debug data
    _hidl_cb(data);
    return Void();
}

Return<void> GnssDebug::getDebugData_2_0(getDebugData_2_0_cb _hidl_cb)
{
    LOC_LOGD("%s]: ", __func__);

    V2_0::IGnssDebug::DebugData data = { };

    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
        LOC_LOGE("GnssDebug - Null GNSS interface");
        _hidl_cb(data);
        return Void();
    }

    // get debug report snapshot via hal interface
    GnssDebugReport reports = { };
    mGnss->getGnssInterface()->getDebugReport(reports);

    // location block
    if (reports.mLocation.mValid) {
        data.position.valid = true;
        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;

        data.position.speedMetersPerSec =
            (double)(reports.mLocation.mLocation.speed);
        data.position.bearingDegrees =
            (double)(reports.mLocation.mLocation.bearing);
        data.position.horizontalAccuracyMeters =
            (double)(reports.mLocation.mLocation.accuracy);
        data.position.verticalAccuracyMeters =
            reports.mLocation.verticalAccuracyMeters;
        data.position.speedAccuracyMetersPerSecond =
            reports.mLocation.speedAccuracyMetersPerSecond;
        data.position.bearingAccuracyDegrees =
            reports.mLocation.bearingAccuracyDegrees;

        timeval tv_now, tv_report;
        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
        gettimeofday(&tv_now, NULL);
        data.position.ageSeconds =
            (tv_now.tv_sec - tv_report.tv_sec) +
            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
    }
    else {
        data.position.valid = false;
    }

    if (data.position.horizontalAccuracyMeters <= 0 ||
        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
    }
    if (data.position.verticalAccuracyMeters <= 0 ||
        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
    }
    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
    }
    if (data.position.bearingAccuracyDegrees <= 0 ||
        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
    }

    // time block
    if (reports.mTime.mValid) {
        data.time.timeEstimate = reports.mTime.timeEstimate;
        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
        data.time.frequencyUncertaintyNsPerSec =
            reports.mTime.frequencyUncertaintyNsPerSec;
    }

    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
    }
    if (data.time.timeUncertaintyNs <= 0) {
        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
    }
    else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
    }
    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
    }

    // satellite data block
    V2_0::IGnssDebug::SatelliteData s = { };
    std::vector<V2_0::IGnssDebug::SatelliteData> s_array;

    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
        memset(&s, 0, sizeof(s));
        s.v1_0.svid = reports.mSatelliteInfo[i].svid;
        convertGnssConstellationType(
            reports.mSatelliteInfo[i].constellation, s.constellation);
        convertGnssEphemerisType(
            reports.mSatelliteInfo[i].mEphemerisType, s.v1_0.ephemerisType);
        convertGnssEphemerisSource(
            reports.mSatelliteInfo[i].mEphemerisSource, s.v1_0.ephemerisSource);
        convertGnssEphemerisHealth(
            reports.mSatelliteInfo[i].mEphemerisHealth, s.v1_0.ephemerisHealth);

        s.v1_0.ephemerisAgeSeconds =
            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
        s.v1_0.serverPredictionIsAvailable =
            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
        s.v1_0.serverPredictionAgeSeconds =
            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;

        s_array.push_back(s);
    }
    data.satelliteDataArray = s_array;

    // callback HIDL with collected debug data
    _hidl_cb(data);
    return Void();
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
#define ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H

#include <android/hardware/gnss/2.0/IGnssDebug.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V2_0::IGnssDebug;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;

/* Interface for GNSS Debug support. */
struct Gnss;
struct GnssDebug : public IGnssDebug {
    GnssDebug(Gnss* gnss);
    ~GnssDebug() {};

    //  Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow
    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
    //  Methods from ::android::hardware::gnss::V2_0::IGnssDebug follow.
    Return<void> getDebugData_2_0(getDebugData_2_0_cb _hidl_cb) override;

private:
    Gnss* mGnss = nullptr;
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "GnssHal_GnssGeofencing"

#include <log_util.h>
#include <GeofenceAPIClient.h>
#include "GnssGeofencing.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
        uint64_t cookie, const wp<IBase>& who) {
    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
    if (mGnssGeofencing != nullptr) {
        mGnssGeofencing->removeAllGeofences();
    }
}

GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
    mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
}

GnssGeofencing::~GnssGeofencing() {
    if (mApi != nullptr) {
        mApi->destroy();
        mApi = nullptr;
    }
}

// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback)  {
    if (mApi != nullptr) {
        LOC_LOGd("mApi is NOT nullptr");
        return Void();
    }

    mApi = new GeofenceAPIClient(callback);
    if (mApi == nullptr) {
        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
    }

    if (mGnssGeofencingCbIface != nullptr) {
        mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
    }
    mGnssGeofencingCbIface = callback;
    if (mGnssGeofencingCbIface != nullptr) {
        mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
    }

    return Void();
}

Return<void> GnssGeofencing::addGeofence(
        int32_t geofenceId,
        double latitudeDegrees,
        double longitudeDegrees,
        double radiusMeters,
        IGnssGeofenceCallback::GeofenceTransition lastTransition,
        int32_t monitorTransitions,
        uint32_t notificationResponsivenessMs,
        uint32_t unknownTimerMs)  {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        mApi->geofenceAdd(
                geofenceId,
                latitudeDegrees,
                longitudeDegrees,
                radiusMeters,
                static_cast<int32_t>(lastTransition),
                monitorTransitions,
                notificationResponsivenessMs,
                unknownTimerMs);
    }
    return Void();
}

Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId)  {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        mApi->geofencePause(geofenceId);
    }
    return Void();
}

Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        mApi->geofenceResume(geofenceId, monitorTransitions);
    }
    return Void();
}

Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId)  {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
    } else {
        mApi->geofenceRemove(geofenceId);
    }
    return Void();
}

Return<void> GnssGeofencing::removeAllGeofences()  {
    if (mApi == nullptr) {
        LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
    } else {
        mApi->geofenceRemoveAll();
    }
    return Void();
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
#define ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H

#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
using ::android::hardware::gnss::V1_0::IGnssGeofencing;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;

class GeofenceAPIClient;
struct GnssGeofencing : public IGnssGeofencing {
    GnssGeofencing();
    ~GnssGeofencing();

    /*
     * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
     * These declarations were generated from IGnssGeofencing.hal.
     */
    Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback)  override;
    Return<void> addGeofence(int32_t geofenceId,
                             double latitudeDegrees,
                             double longitudeDegrees,
                             double radiusMeters,
                             IGnssGeofenceCallback::GeofenceTransition lastTransition,
                             int32_t monitorTransitions,
                             uint32_t notificationResponsivenessMs,
                             uint32_t unknownTimerMs)  override;

    Return<void> pauseGeofence(int32_t geofenceId)  override;
    Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  override;
    Return<void> removeGeofence(int32_t geofenceId)  override;

 private:
    // This method is not part of the IGnss base class.
    // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
    Return<void> removeAllGeofences();

 private:
    struct GnssGeofencingDeathRecipient : hidl_death_recipient {
        GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
            mGnssGeofencing(gnssGeofencing) {
        }
        ~GnssGeofencingDeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
        sp<GnssGeofencing> mGnssGeofencing;
    };

 private:
    sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
    sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
    GeofenceAPIClient* mApi = nullptr;
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "LocSvc_GnssMeasurementInterface"

#include <log_util.h>
#include "GnssMeasurement.h"
#include "MeasurementAPIClient.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
        uint64_t cookie, const wp<IBase>& who) {
    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
    if (mGnssMeasurement != nullptr) {
        mGnssMeasurement->close();
    }
}

GnssMeasurement::GnssMeasurement() {
    mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
    mApi = new MeasurementAPIClient();
}

GnssMeasurement::~GnssMeasurement() {
    if (mApi) {
        mApi->destroy();
        mApi = nullptr;
    }
}

// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
        const sp<V1_0::IGnssMeasurementCallback>& callback)  {

    Return<GnssMeasurement::GnssMeasurementStatus> ret =
        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
    if (mGnssMeasurementCbIface != nullptr) {
        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
    }

    if (callback == nullptr) {
        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
        return ret;
    }
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
        return ret;
    }

    clearInterfaces();

    mGnssMeasurementCbIface = callback;
    mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);

    return mApi->measurementSetCallback(callback);
}

void GnssMeasurement::clearInterfaces() {
    if (mGnssMeasurementCbIface != nullptr) {
        mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
        mGnssMeasurementCbIface = nullptr;
    }
    if (mGnssMeasurementCbIface_1_1 != nullptr) {
        mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
        mGnssMeasurementCbIface_1_1 = nullptr;
    }
    if (mGnssMeasurementCbIface_2_0 != nullptr) {
        mGnssMeasurementCbIface_2_0->unlinkToDeath(mGnssMeasurementDeathRecipient);
        mGnssMeasurementCbIface_2_0 = nullptr;
    }
    if (mGnssMeasurementCbIface_2_1 != nullptr) {
        mGnssMeasurementCbIface_2_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
        mGnssMeasurementCbIface_2_1 = nullptr;
    }
}

Return<void> GnssMeasurement::close()  {
    if (mApi == nullptr) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
        return Void();
    }

    clearInterfaces();
    mApi->measurementClose();

    return Void();
}

// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
        const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) {

    Return<GnssMeasurement::GnssMeasurementStatus> ret =
        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
    if (mGnssMeasurementCbIface_1_1 != nullptr) {
        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
    }

    if (callback == nullptr) {
        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
        return ret;
    }
    if (nullptr == mApi) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
        return ret;
    }

    clearInterfaces();

    mGnssMeasurementCbIface_1_1 = callback;
    mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);

    GnssPowerMode powerMode = enableFullTracking?
            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;

    return mApi->measurementSetCallback_1_1(callback, powerMode);
}
// Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
        const sp<V2_0::IGnssMeasurementCallback>& callback,
        bool enableFullTracking) {

    Return<GnssMeasurement::GnssMeasurementStatus> ret =
        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
    if (mGnssMeasurementCbIface_2_0 != nullptr) {
        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
    }

    if (callback == nullptr) {
        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
        return ret;
    }
    if (nullptr == mApi) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
        return ret;
    }

    clearInterfaces();

    mGnssMeasurementCbIface_2_0 = callback;
    mGnssMeasurementCbIface_2_0->linkToDeath(mGnssMeasurementDeathRecipient, 0);

    GnssPowerMode powerMode = enableFullTracking ?
        GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;

    return mApi->measurementSetCallback_2_0(callback, powerMode);
}

// Methods from ::android::hardware::gnss::V2_1::IGnssMeasurement follow.
Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_1(
        const sp<::android::hardware::gnss::V2_1::IGnssMeasurementCallback>& callback,
        bool enableFullTracking) {
    Return<GnssMeasurement::GnssMeasurementStatus> ret =
        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
    if (mGnssMeasurementCbIface_2_1 != nullptr) {
        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
    }

    if (callback == nullptr) {
        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
        return ret;
    }
    if (nullptr == mApi) {
        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
        return ret;
    }

    clearInterfaces();

    mGnssMeasurementCbIface_2_1 = callback;
    mGnssMeasurementCbIface_2_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);

    GnssPowerMode powerMode = enableFullTracking ?
            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;

    return mApi->measurementSetCallback_2_1(callback, powerMode);

}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H
#define ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H

#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;

class MeasurementAPIClient;
struct GnssMeasurement : public V2_1::IGnssMeasurement {
    GnssMeasurement();
    ~GnssMeasurement();

    /*
     * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
     * These declarations were generated from IGnssMeasurement.hal.
     */
    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback(
        const sp<V1_0::IGnssMeasurementCallback>& callback) override;
    Return<void> close() override;

    // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
            const sp<V1_1::IGnssMeasurementCallback>& callback,
            bool enableFullTracking) override;

    // Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
            const sp<V2_0::IGnssMeasurementCallback>& callback,
            bool enableFullTracking) override;
    // Methods from ::android::hardware::gnss::V2_1::IGnssMeasurement follow.
    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_1(
            const sp<::android::hardware::gnss::V2_1::IGnssMeasurementCallback>& callback,
            bool enableFullTracking) override;

 private:
    struct GnssMeasurementDeathRecipient : hidl_death_recipient {
        GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
            mGnssMeasurement(gnssMeasurement) {
        }
        ~GnssMeasurementDeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
        sp<GnssMeasurement> mGnssMeasurement;
    };

 private:
    sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
    sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
    sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0 = nullptr;
    sp<V2_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_1 = nullptr;
    MeasurementAPIClient* mApi;
    void clearInterfaces();
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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 "LocSvc_GnssNiInterface"

#include <log_util.h>
#include "Gnss.h"
#include "GnssNi.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
    // we do nothing here
    // Gnss::GnssDeathRecipient will stop the session
}

GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
    mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
}

// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback)  {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return Void();
    }

    mGnss->setGnssNiCb(callback);

    if (mGnssNiCbIface != nullptr) {
        mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
    }
    mGnssNiCbIface = callback;
    if (mGnssNiCbIface != nullptr) {
        mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
    }

    return Void();
}

Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse)  {
    if (mGnss == nullptr) {
        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
        return Void();
    }

    GnssAPIClient* api = mGnss->getApi();
    if (api == nullptr) {
        LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
        return Void();
    }

    api->gnssNiRespond(notifId, userResponse);

    return Void();
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Not a Contribution
 */
/*
 * Copyright (C) 2016 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.
 */

#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
#define ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H

#include <android/hardware/gnss/1.0/IGnssNi.h>
#include <hidl/Status.h>

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V1_0::IGnssNi;
using ::android::hardware::gnss::V1_0::IGnssNiCallback;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;

struct Gnss;
struct GnssNi : public IGnssNi {
    GnssNi(Gnss* gnss);
    ~GnssNi() = default;

    /*
     * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
     * These declarations were generated from IGnssNi.hal.
     */
    Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
    Return<void> respond(int32_t notifId,
                         IGnssNiCallback::GnssUserResponseType userResponse) override;

 private:
    struct GnssNiDeathRecipient : hidl_death_recipient {
        GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
        }
        ~GnssNiDeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
        sp<GnssNi> mGnssNi;
    };

 private:
    sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
    sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
    Gnss* mGnss = nullptr;
};

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H


code:
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include "GnssVisibilityControl.h"
#include <location_interface.h>

namespace android {
namespace hardware {
namespace gnss {
namespace visibility_control {
namespace V1_0 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;

static GnssVisibilityControl* spGnssVisibilityControl = nullptr;

static void convertGnssNfwNotification(GnssNfwNotification& in,
    IGnssVisibilityControlCallback::NfwNotification& out);

GnssVisibilityControl::GnssVisibilityControl(Gnss* gnss) : mGnss(gnss) {
    spGnssVisibilityControl = this;
}
GnssVisibilityControl::~GnssVisibilityControl() {
    spGnssVisibilityControl = nullptr;
}

void GnssVisibilityControl::nfwStatusCb(GnssNfwNotification notification) {
    if (nullptr != spGnssVisibilityControl) {
        spGnssVisibilityControl->statusCb(notification);
    }
}

bool GnssVisibilityControl::isInEmergencySession() {
    if (nullptr != spGnssVisibilityControl) {
        return spGnssVisibilityControl->isE911Session();
    }
    return false;
}

static void convertGnssNfwNotification(GnssNfwNotification& in,
    IGnssVisibilityControlCallback::NfwNotification& out)
{
    memset(&out, 0, sizeof(IGnssVisibilityControlCallback::NfwNotification));
    out.proxyAppPackageName = in.proxyAppPackageName;
    out.protocolStack = (IGnssVisibilityControlCallback::NfwProtocolStack)in.protocolStack;
    out.otherProtocolStackName = in.otherProtocolStackName;
    out.requestor = (IGnssVisibilityControlCallback::NfwRequestor)in.requestor;
    out.requestorId = in.requestorId;
    out.responseType = (IGnssVisibilityControlCallback::NfwResponseType)in.responseType;
    out.inEmergencyMode = in.inEmergencyMode;
    out.isCachedLocation = in.isCachedLocation;
}

void GnssVisibilityControl::statusCb(GnssNfwNotification notification) {

    if (mGnssVisibilityControlCbIface != nullptr) {
        IGnssVisibilityControlCallback::NfwNotification nfwNotification;

        // Convert from one structure to another
        convertGnssNfwNotification(notification, nfwNotification);

        auto r = mGnssVisibilityControlCbIface->nfwNotifyCb(nfwNotification);
        if (!r.isOk()) {
            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
        }
    } else {
        LOC_LOGw("setCallback has not been called yet");
    }
}

bool GnssVisibilityControl::isE911Session() {

    if (mGnssVisibilityControlCbIface != nullptr) {
        auto r = mGnssVisibilityControlCbIface->isInEmergencySession();
        if (!r.isOk()) {
            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
            return false;
        } else {
            return (r);
        }
    } else {
        LOC_LOGw("setCallback has not been called yet");
        return false;
    }
}

// Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
Return<bool> GnssVisibilityControl::enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) {

    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
        LOC_LOGe("Null GNSS interface");
        return false;
    }

    /* If the vector is empty we need to disable all NFW clients
       If there is at least one app in the vector we need to enable
       all NFW clients */
    if (0 == proxyApps.size()) {
        mGnss->getGnssInterface()->enableNfwLocationAccess(false);
    } else {
        mGnss->getGnssInterface()->enableNfwLocationAccess(true);
    }

    return true;
}
/**
 * Registers the callback for HAL implementation to use.
 *
 * @param callback Handle to IGnssVisibilityControlCallback interface.
 */
Return<bool> GnssVisibilityControl::setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) {

    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
        LOC_LOGe("Null GNSS interface");
        return false;
    }
    mGnssVisibilityControlCbIface = callback;

    NfwCbInfo cbInfo = {};
    cbInfo.visibilityControlCb = (void*)nfwStatusCb;
    cbInfo.isInEmergencySession = (void*)isInEmergencySession;

    mGnss->getGnssInterface()->nfwInit(cbInfo);

    return true;
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace visibility_control
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
#define ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H

#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

#include <gps_extended_c.h>
#include <location_interface.h>
#include "Gnss.h"

namespace android {
namespace hardware {
namespace gnss {
namespace visibility_control {
namespace V1_0 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
using ::android::hardware::gnss::V2_1::implementation::Gnss;

struct GnssVisibilityControl : public IGnssVisibilityControl {
    GnssVisibilityControl(Gnss* gnss);
    ~GnssVisibilityControl();

    // Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
    Return<bool> enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) override;
    /**
     * Registers the callback for HAL implementation to use.
     *
     * @param callback Handle to IGnssVisibilityControlCallback interface.
     */
    Return<bool> setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) override;

    void statusCb(GnssNfwNotification notification);
    bool isE911Session();

    /* Data call setup callback passed down to GNSS HAL implementation */
    static void nfwStatusCb(GnssNfwNotification notification);
    static bool isInEmergencySession();

private:
    Gnss* mGnss = nullptr;
    sp<IGnssVisibilityControlCallback> mGnssVisibilityControlCbIface = nullptr;
};

}  // namespace implementation
}  // namespace V1_0
}  // namespace visibility_control
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H


code:
/*
 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define LOG_TAG "LocSvc_MeasurementCorrectionsInterface"

#include <log_util.h>
#include "MeasurementCorrections.h"

namespace android {
namespace hardware {
namespace gnss {
namespace measurement_corrections {
namespace V1_1 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
using MeasurementCorrectionsV1_0 =
        ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using MeasurementCorrectionsV1_1 =
        ::android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;

static MeasurementCorrections* spMeasurementCorrections = nullptr;

void MeasurementCorrections::GnssMeasurementCorrectionsDeathRecipient::serviceDied(uint64_t cookie,
        const wp<IBase>& who) {
    LOC_LOGe("service died. cookie: %llu, who: %p", static_cast<unsigned long long>(cookie), &who);
    // Gnss::GnssDeathrecipient will stop the session
    // we inform the adapter that service has died
    if (nullptr == spMeasurementCorrections) {
        LOC_LOGe("spMeasurementCorrections is nullptr");
        return;
    }
    if (nullptr == spMeasurementCorrections->mGnss ||
        nullptr == spMeasurementCorrections->mGnss->getGnssInterface()) {
        LOC_LOGe("Null GNSS interface");
        return;
    }
    spMeasurementCorrections->mGnss->getGnssInterface()->measCorrClose();
}

MeasurementCorrections::MeasurementCorrections(Gnss* gnss) : mGnss(gnss) {
    mGnssMeasurementCorrectionsDeathRecipient = new GnssMeasurementCorrectionsDeathRecipient(this);
    spMeasurementCorrections = this;
}

MeasurementCorrections::~MeasurementCorrections() {
    spMeasurementCorrections = nullptr;
}

void MeasurementCorrections::measCorrSetCapabilitiesCb(
        GnssMeasurementCorrectionsCapabilitiesMask capabilities) {
    if (nullptr != spMeasurementCorrections) {
        spMeasurementCorrections->setCapabilitiesCb(capabilities);
    }
}

void MeasurementCorrections::setCapabilitiesCb(
    GnssMeasurementCorrectionsCapabilitiesMask capabilities) {

    if (mMeasurementCorrectionsCbIface != nullptr) {
        uint32_t measCorrCapabilities = 0;

        // Convert from one enum to another
        if (capabilities & GNSS_MEAS_CORR_LOS_SATS) {
            measCorrCapabilities |=
                    IMeasurementCorrectionsCallback::Capabilities::LOS_SATS;
        }
        if (capabilities & GNSS_MEAS_CORR_EXCESS_PATH_LENGTH) {
            measCorrCapabilities |=
                    IMeasurementCorrectionsCallback::Capabilities::EXCESS_PATH_LENGTH;
        }
        if (capabilities & GNSS_MEAS_CORR_REFLECTING_PLANE) {
            measCorrCapabilities |=
                    IMeasurementCorrectionsCallback::Capabilities::REFLECTING_PLANE;
        }

        auto r = mMeasurementCorrectionsCbIface->setCapabilitiesCb(measCorrCapabilities);
        if (!r.isOk()) {
            LOC_LOGw("Error invoking setCapabilitiesCb %s", r.description().c_str());
        }
    } else {
        LOC_LOGw("setCallback has not been called yet");
    }
}

Return<bool> MeasurementCorrections::setCorrections(
        const MeasurementCorrectionsV1_0& corrections) {

    GnssMeasurementCorrections gnssMeasurementCorrections = {};

    V2_1::implementation::convertMeasurementCorrections(corrections, gnssMeasurementCorrections);

    return mGnss->getGnssInterface()->measCorrSetCorrections(gnssMeasurementCorrections);
}

Return<bool> MeasurementCorrections::setCorrections_1_1(
        const MeasurementCorrectionsV1_1& corrections) {

    GnssMeasurementCorrections gnssMeasurementCorrections = {};

    V2_1::implementation::convertMeasurementCorrections(
            corrections.v1_0, gnssMeasurementCorrections);

    gnssMeasurementCorrections.hasEnvironmentBearing = corrections.hasEnvironmentBearing;
    gnssMeasurementCorrections.environmentBearingDegrees =
            corrections.environmentBearingDegrees;
    gnssMeasurementCorrections.environmentBearingUncertaintyDegrees =
            corrections.environmentBearingUncertaintyDegrees;

    for (int i = 0; i < corrections.satCorrections.size(); i++) {
        GnssSingleSatCorrection gnssSingleSatCorrection = {};

        V2_1::implementation::convertSingleSatCorrections(
                corrections.satCorrections[i].v1_0, gnssSingleSatCorrection);
        switch (corrections.satCorrections[i].constellation) {
        case (::android::hardware::gnss::V2_0::GnssConstellationType::GPS):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GPS;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::SBAS):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_SBAS;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::GLONASS):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GLONASS;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::QZSS):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_QZSS;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::BEIDOU):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_BEIDOU;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::GALILEO):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GALILEO;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::IRNSS):
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_NAVIC;
            break;
        case (::android::hardware::gnss::V2_0::GnssConstellationType::UNKNOWN):
        default:
            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_UNKNOWN;
            break;
        }
        gnssMeasurementCorrections.satCorrections.push_back(gnssSingleSatCorrection);
    }

    return mGnss->getGnssInterface()->measCorrSetCorrections(gnssMeasurementCorrections);
}

Return<bool> MeasurementCorrections::setCallback(
        const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {

    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
        LOC_LOGe("Null GNSS interface");
        return false;
    }
    mMeasurementCorrectionsCbIface = callback;

    return mGnss->getGnssInterface()->measCorrInit(measCorrSetCapabilitiesCb);
}

}  // namespace implementation
}  // namespace V1_1
}  // namespace measurement_corrections
}  // namespace gnss
}  // namespace hardware
}  // namespace android


code:
/*
 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H
#define ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H

#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

#include <gps_extended_c.h>
#include <location_interface.h>
#include "Gnss.h"
#include <LocationUtil.h>

namespace android {
namespace hardware {
namespace gnss {
namespace measurement_corrections {
namespace V1_1 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
using ::android::hardware::gnss::V1_0::GnssLocation;
using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
using ::android::hardware::gnss::V2_1::implementation::Gnss;
using MeasurementCorrectionsV1_0 =
        ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using MeasurementCorrectionsV1_1 =
        ::android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;

struct MeasurementCorrections : public V1_1::IMeasurementCorrections {
    MeasurementCorrections(Gnss* gnss);
    ~MeasurementCorrections();

    Return<bool> setCorrections(const MeasurementCorrectionsV1_0& corrections) override;

    // Methods from
    // ::android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections follow.
    Return<bool> setCorrections_1_1(const MeasurementCorrectionsV1_1& corrections);

    Return<bool> setCallback(const sp<IMeasurementCorrectionsCallback>& callback) override;

    void setCapabilitiesCb(GnssMeasurementCorrectionsCapabilitiesMask capabilities);

    /* Data call setup callback passed down to GNSS HAL implementation */
    static void measCorrSetCapabilitiesCb(GnssMeasurementCorrectionsCapabilitiesMask capabilities);

private:
    struct GnssMeasurementCorrectionsDeathRecipient : hidl_death_recipient {
        GnssMeasurementCorrectionsDeathRecipient(
            sp<MeasurementCorrections> gnssMeasurementCorrections) :
                    mGnssMeasurementCorrections(gnssMeasurementCorrections) {
        }
        ~GnssMeasurementCorrectionsDeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
        sp<MeasurementCorrections> mGnssMeasurementCorrections;
    };
    Gnss* mGnss = nullptr;
    sp<GnssMeasurementCorrectionsDeathRecipient> mGnssMeasurementCorrectionsDeathRecipient =
            nullptr;
    sp<IMeasurementCorrectionsCallback> mMeasurementCorrectionsCbIface = nullptr;
};

}  // namespace implementation
}  // namespace V1_1
}  // namespace measurement_corrections
}  // namespace gnss
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H


code:
service gnss_service /vendor/bin/hw/android.hardware.gnss@2.1-service-qti
    class hal
    user gps
    group system gps radio vendor_qti_diag


code:
<!-- Copyright (c) 2020, The Linux Foundation. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.
    * Neither the name of The Linux Foundation nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>android.hardware.gnss</name>
        <transport>hwbinder</transport>
        <fqname>@1.1::IGnss/default</fqname>
        <fqname>@2.1::IGnss/default</fqname>
    </hal>
</manifest>


code:
/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#define LOG_NDEBUG 0
#define LOG_TAG "LocSvc_BatchingAPIClient"

#include <inttypes.h>
#include <log_util.h>
#include <loc_cfg.h>
#include <thread>
#include "LocationUtil.h"
#include "BatchingAPIClient.h"

#include "limits.h"

namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {

using ::android::hardware::gnss::V2_0::IGnssBatching;
using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
using ::android::hardware::gnss::V2_0::GnssLocation;

static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
        LocationCapabilitiesMask mask);

BatchingAPIClient::BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback) :
    LocationAPIClientBase(),
    mGnssBatchingCbIface(nullptr),
    mDefaultId(UINT_MAX),
    mLocationCapabilitiesMask(0),
    mGnssBatchingCbIface_2_0(nullptr)
{
    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);

    gnssUpdateCallbacks(callback);
}

BatchingAPIClient::BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback) :
    LocationAPIClientBase(),
    mGnssBatchingCbIface(nullptr),
    mDefaultId(UINT_MAX),
    mLocationCapabilitiesMask(0),
    mGnssBatchingCbIface_2_0(nullptr)
{
    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);

    gnssUpdateCallbacks_2_0(callback);
}

BatchingAPIClient::~BatchingAPIClient()
{
    LOC_LOGD("%s]: ()", __FUNCTION__);
}

int BatchingAPIClient::getBatchSize() {
    int batchSize = locAPIGetBatchSize();
    LOC_LOGd("batchSize: %d", batchSize);
    return batchSize;
}

void BatchingAPIClient::setCallbacks()
{
    LocationCallbacks locationCallbacks;
    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
    locationCallbacks.size = sizeof(LocationCallbacks);

    locationCallbacks.trackingCb = nullptr;
    locationCallbacks.batchingCb = nullptr;
    locationCallbacks.batchingCb = [this](size_t count, Location* location,
        BatchingOptions batchOptions) {
        onBatchingCb(count, location, batchOptions);
    };
    locationCallbacks.geofenceBreachCb = nullptr;
    locationCallbacks.geofenceStatusCb = nullptr;
    locationCallbacks.gnssLocationInfoCb = nullptr;
    locationCallbacks.gnssNiCb = nullptr;
    locationCallbacks.gnssSvCb = nullptr;
    locationCallbacks.gnssNmeaCb = nullptr;
    locationCallbacks.gnssMeasurementsCb = nullptr;

    locAPISetCallbacks(locationCallbacks);
}

void BatchingAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback)
{
    mMutex.lock();
    mGnssBatchingCbIface = callback;
    mMutex.unlock();

    if (mGnssBatchingCbIface != nullptr) {
        setCallbacks();
    }
}

void BatchingAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback)
{
    mMutex.lock();
    mGnssBatchingCbIface_2_0 = callback;
    mMutex.unlock();

    if (mGnssBatchingCbIface_2_0 != nullptr) {
        setCallbacks();
    }
}

int BatchingAPIClient::startSession(const IGnssBatching::Options& opts) {
    mMutex.lock();
    mState = STARTED;
    mMutex.unlock();
    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
    int retVal = -1;
    LocationOptions options;
    convertBatchOption(opts, options, mLocationCapabilitiesMask);
    uint32_t mode = 0;
    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
        mode = SESSION_MODE_ON_FULL;
    }
    if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
        retVal = 1;
    }
    return retVal;
}

int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
{
    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
    int retVal = -1;
    LocationOptions options;
    convertBatchOption(opts, options, mLocationCapabilitiesMask);

    uint32_t mode = 0;
    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
        mode = SESSION_MODE_ON_FULL;
    }
    if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
        retVal = 1;
    }
    return retVal;
}

int BatchingAPIClient::stopSession() {
    mMutex.lock();
    mState = STOPPING;
    mMutex.unlock();
    LOC_LOGD("%s]: ", __FUNCTION__);
    int retVal = -1;
    locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
    if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
        retVal = 1;
    }
    return retVal;
}

void BatchingAPIClient::getBatchedLocation(int last_n_locations)
{
    LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
    locAPIGetBatchedLocations(mDefaultId, last_n_locations);
}

void BatchingAPIClient::flushBatchedLocations() {
    LOC_LOGD("%s]: ()", __FUNCTION__);
    uint32_t retVal = locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
    // when flush a stopped session or one doesn't exist, just report an empty batch.
    if (LOCATION_ERROR_ID_UNKNOWN == retVal) {
        BatchingOptions opt = {};
        ::std::thread thd(&BatchingAPIClient::onBatchingCb, this, 0, nullptr, opt);
        thd.detach();
    }
}

void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
{
    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
    mLocationCapabilitiesMask = capabilitiesMask;
}

void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
        BatchingOptions /*batchOptions*/) {
    bool processReport = false;
    LOC_LOGd("(count: %zu)", count);
    mMutex.lock();
    // back to back stop() and flush() could bring twice onBatchingCb(). Each one might come first.
    // Combine them both (the first goes to cache, the second in location*) before report to FW
    switch (mState) {
        case STOPPING:
            mState = STOPPED;
            for (size_t i = 0; i < count; i++) {
                mBatchedLocationInCache.push_back(location[i]);
            }
            break;
        case STARTED:
        case STOPPED: // flush() always trigger report, even on a stopped session
            processReport = true;
            break;
        default:
            break;
    }
    // report location batch when in STARTED state or flush(), combined with cache in last stop()
    if (processReport) {
        auto gnssBatchingCbIface(mGnssBatchingCbIface);
        auto gnssBatchingCbIface_2_0(mGnssBatchingCbIface_2_0);
        size_t batchCacheCnt = mBatchedLocationInCache.size();
        LOC_LOGd("(batchCacheCnt: %zu)", batchCacheCnt);
        if (gnssBatchingCbIface_2_0 != nullptr) {
            hidl_vec<V2_0::GnssLocation> locationVec;
            if (count+batchCacheCnt > 0) {
                locationVec.resize(count+batchCacheCnt);
                for (size_t i = 0; i < batchCacheCnt; ++i) {
                    convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
                }
                for (size_t i = 0; i < count; i++) {
                    convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
                }
            }
            auto r = gnssBatchingCbIface_2_0->gnssLocationBatchCb(locationVec);
            if (!r.isOk()) {
                LOC_LOGE("%s] Error from gnssLocationBatchCb 2_0 description=%s",
                        __func__, r.description().c_str());
            }
        } else if (gnssBatchingCbIface != nullptr) {
            hidl_vec<V1_0::GnssLocation> locationVec;
            if (count+batchCacheCnt > 0) {
                locationVec.resize(count+batchCacheCnt);
                for (size_t i = 0; i < batchCacheCnt; ++i) {
                    convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
                }
                for (size_t i = 0; i < count; i++) {
                    convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
                }
            }
            auto r = gnssBatchingCbIface->gnssLocationBatchCb(locationVec);
            if (!r.isOk()) {
                LOC_LOGE("%s] Error from gnssLocationBatchCb 1.0 description=%s",
                        __func__, r.description().c_str());
            }
        }
        mBatchedLocationInCache.clear();
    }
    mMutex.unlock();
}

static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
        LocationCapabilitiesMask mask)
{
    memset(&out, 0, sizeof(LocationOptions));
    out.size = sizeof(LocationOptions);
    out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
    out.minDistance = 0;
    out.mode = GNSS_SUPL_MODE_STANDALONE;
    if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
        out.mode = GNSS_SUPL_MODE_MSA;
    if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
        out.mode = GNSS_SUPL_MODE_MSB;
}

}  // namespace implementation
}  // namespace V2_1
}  // namespace gnss
}  // namespace hardware
}  // namespace android