diff options
author | Michael Bestas <mkbestas@gmail.com> | 2020-04-18 17:12:06 +0300 |
---|---|---|
committer | Michael Bestas <mkbestas@gmail.com> | 2020-04-18 17:12:39 +0300 |
commit | ddfa99dce7571688697e965b992a35b3f01c1aba (patch) | |
tree | 83e4f6b862bf4752c73e09d7d60496be95a1eda4 /gps/geofence | |
parent | 570a57c7abc1a0f0e48698821e0061dd2e807dc5 (diff) | |
parent | ea8aefcf657335910a97e158e1c4752db9b0a880 (diff) |
sdm660-common: Import GPS HAL from LA.UM.8.2.r1-04300-sdm660.0
Change-Id: I5e93d71bc7df7bb46af8c4b9ff11e8302113cfa9
Diffstat (limited to 'gps/geofence')
-rw-r--r-- | gps/geofence/Android.mk | 36 | ||||
-rw-r--r-- | gps/geofence/GeofenceAdapter.cpp | 870 | ||||
-rw-r--r-- | gps/geofence/GeofenceAdapter.h | 136 | ||||
-rw-r--r-- | gps/geofence/Makefile.am | 50 | ||||
-rw-r--r-- | gps/geofence/configure.ac | 72 | ||||
-rw-r--r-- | gps/geofence/location-geofence.pc.in | 10 | ||||
-rw-r--r-- | gps/geofence/location_geofence.cpp | 145 |
7 files changed, 1319 insertions, 0 deletions
diff --git a/gps/geofence/Android.mk b/gps/geofence/Android.mk new file mode 100644 index 0000000..6e9e870 --- /dev/null +++ b/gps/geofence/Android.mk @@ -0,0 +1,36 @@ +ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),) +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libgeofencing +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES:= \ + GeofenceAdapter.cpp \ + location_geofence.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libgps.utils \ + liblog \ + libloc_core \ + liblbs_core + +LOCAL_HEADER_LIBRARIES := \ + libgps.utils_headers \ + libloc_core_headers \ + libloc_pla_headers \ + liblocation_api_headers + +LOCAL_PRELINK_MODULE := false +LOCAL_CFLAGS += $(GNSS_CFLAGS) +include $(BUILD_SHARED_LIBRARY) + +endif # not BUILD_TINY_ANDROID +endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE + diff --git a/gps/geofence/GeofenceAdapter.cpp b/gps/geofence/GeofenceAdapter.cpp new file mode 100644 index 0000000..e299589 --- /dev/null +++ b/gps/geofence/GeofenceAdapter.cpp @@ -0,0 +1,870 @@ +/* Copyright (c) 2013-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. + * + */ +#define LOG_TAG "LocSvc_GeofenceAdapter" + +#include <GeofenceAdapter.h> +#include "loc_log.h" +#include <log_util.h> +#include <string> + +using namespace loc_core; + +GeofenceAdapter::GeofenceAdapter() : + LocAdapterBase(0, + LocContext::getLocContext( + NULL, + NULL, + LocContext::mLocationHalName, + false), + true /*isMaster*/) +{ + LOC_LOGD("%s]: Constructor", __func__); +} + +void +GeofenceAdapter::stopClientSessions(LocationAPI* client) +{ + LOC_LOGD("%s]: client %p", __func__, client); + + + for (auto it = mGeofenceIds.begin(); it != mGeofenceIds.end();) { + uint32_t hwId = it->second; + GeofenceKey key(it->first); + if (client == key.client) { + it = mGeofenceIds.erase(it); + mLocApi->removeGeofence(hwId, key.id, + new LocApiResponse(*getContext(), + [this, hwId] (LocationError err) { + if (LOCATION_ERROR_SUCCESS == err) { + auto it2 = mGeofences.find(hwId); + if (it2 != mGeofences.end()) { + mGeofences.erase(it2); + } else { + LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId); + } + } + })); + continue; + } + ++it; // increment only when not erasing an iterator + } + +} + +void +GeofenceAdapter::updateClientsEventMask() +{ + LOC_API_ADAPTER_EVENT_MASK_T mask = 0; + for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { + if (it->second.geofenceBreachCb != nullptr) { + mask |= LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT; + mask |= LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL; + } + if (it->second.geofenceStatusCb != nullptr) { + mask |= LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT; + } + } + updateEvtMask(mask, LOC_REGISTRATION_MASK_SET); +} + +LocationError +GeofenceAdapter::getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId) +{ + GeofenceKey key(client, clientId); + auto it = mGeofenceIds.find(key); + if (it != mGeofenceIds.end()) { + hwId = it->second; + return LOCATION_ERROR_SUCCESS; + } + return LOCATION_ERROR_ID_UNKNOWN; +} + +LocationError +GeofenceAdapter::getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key) +{ + auto it = mGeofences.find(hwId); + if (it != mGeofences.end()) { + key = it->second.key; + return LOCATION_ERROR_SUCCESS; + } + return LOCATION_ERROR_ID_UNKNOWN; +} + +void +GeofenceAdapter::handleEngineUpEvent() +{ + struct MsgSSREvent : public LocMsg { + GeofenceAdapter& mAdapter; + inline MsgSSREvent(GeofenceAdapter& adapter) : + LocMsg(), + mAdapter(adapter) {} + virtual void proc() const { + mAdapter.setEngineCapabilitiesKnown(true); + mAdapter.broadcastCapabilities(mAdapter.getCapabilities()); + mAdapter.restartGeofences(); + for (auto msg: mAdapter.mPendingMsgs) { + mAdapter.sendMsg(msg); + } + mAdapter.mPendingMsgs.clear(); + } + }; + + sendMsg(new MsgSSREvent(*this)); +} + +void +GeofenceAdapter::restartGeofences() +{ + if (mGeofences.empty()) { + return; + } + + GeofencesMap oldGeofences(mGeofences); + mGeofences.clear(); + mGeofenceIds.clear(); + + for (auto it = oldGeofences.begin(); it != oldGeofences.end(); it++) { + GeofenceObject object = it->second; + GeofenceOption options = {sizeof(GeofenceOption), + object.breachMask, + object.responsiveness, + object.dwellTime}; + GeofenceInfo info = {sizeof(GeofenceInfo), + object.latitude, + object.longitude, + object.radius}; + mLocApi->addGeofence(object.key.id, + options, + info, + new LocApiResponseData<LocApiGeofenceData>(*getContext(), + [this, object, options, info] (LocationError err, LocApiGeofenceData data) { + if (LOCATION_ERROR_SUCCESS == err) { + if (true == object.paused) { + mLocApi->pauseGeofence(data.hwId, object.key.id, + new LocApiResponse(*getContext(), [] (LocationError err ) {})); + } + saveGeofenceItem(object.key.client, object.key.id, data.hwId, options, info); + } + })); + } +} + +void +GeofenceAdapter::reportResponse(LocationAPI* client, size_t count, LocationError* errs, + uint32_t* ids) +{ + IF_LOC_LOGD { + std::string idsString = "["; + std::string errsString = "["; + if (NULL != ids && NULL != errs) { + for (size_t i=0; i < count; ++i) { + idsString += std::to_string(ids[i]) + " "; + errsString += std::to_string(errs[i]) + " "; + } + } + idsString += "]"; + errsString += "]"; + + LOC_LOGD("%s]: client %p ids %s errs %s", + __func__, client, idsString.c_str(), errsString.c_str()); + } + + auto it = mClientData.find(client); + if (it != mClientData.end() && it->second.collectiveResponseCb != nullptr) { + it->second.collectiveResponseCb(count, errs, ids); + } else { + LOC_LOGE("%s]: client %p response not found in info", __func__, client); + } +} + +uint32_t* +GeofenceAdapter::addGeofencesCommand(LocationAPI* client, size_t count, GeofenceOption* options, + GeofenceInfo* infos) +{ + LOC_LOGD("%s]: client %p count %zu", __func__, client, count); + + struct MsgAddGeofences : public LocMsg { + GeofenceAdapter& mAdapter; + LocApiBase& mApi; + LocationAPI* mClient; + size_t mCount; + uint32_t* mIds; + GeofenceOption* mOptions; + GeofenceInfo* mInfos; + inline MsgAddGeofences(GeofenceAdapter& adapter, + LocApiBase& api, + LocationAPI* client, + size_t count, + uint32_t* ids, + GeofenceOption* options, + GeofenceInfo* infos) : + LocMsg(), + mAdapter(adapter), + mApi(api), + mClient(client), + mCount(count), + mIds(ids), + mOptions(options), + mInfos(infos) {} + inline virtual void proc() const { + LocationError* errs = new LocationError[mCount]; + if (nullptr == errs) { + LOC_LOGE("%s]: new failed to allocate errs", __func__); + return; + } + for (size_t i=0; i < mCount; ++i) { + if (NULL == mIds || NULL == mOptions || NULL == mInfos) { + errs[i] = LOCATION_ERROR_INVALID_PARAMETER; + } else { + mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, + mOptions = mOptions, mInfos = mInfos, mIds = mIds, &mApi = mApi, + errs, i] (LocationError err ) { + mApi.addGeofence(mIds[i], mOptions[i], mInfos[i], + new LocApiResponseData<LocApiGeofenceData>(*mAdapter.getContext(), + [&mAdapter = mAdapter, mOptions = mOptions, mClient = mClient, + mCount = mCount, mIds = mIds, mInfos = mInfos, errs, i] + (LocationError err, LocApiGeofenceData data) { + if (LOCATION_ERROR_SUCCESS == err) { + mAdapter.saveGeofenceItem(mClient, + mIds[i], + data.hwId, + mOptions[i], + mInfos[i]); + } + errs[i] = err; + + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + delete[] mOptions; + delete[] mInfos; + } + })); + })); + } + } + } + }; + + if (0 == count) { + return NULL; + } + uint32_t* ids = new uint32_t[count]; + if (nullptr == ids) { + LOC_LOGE("%s]: new failed to allocate ids", __func__); + return NULL; + } + if (NULL != ids) { + for (size_t i=0; i < count; ++i) { + ids[i] = generateSessionId(); + } + } + GeofenceOption* optionsCopy; + if (options == NULL) { + optionsCopy = NULL; + } else { + optionsCopy = new GeofenceOption[count]; + if (nullptr == optionsCopy) { + LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__); + return NULL; + } + COPY_IF_NOT_NULL(optionsCopy, options, count); + } + GeofenceInfo* infosCopy; + if (infos == NULL) { + infosCopy = NULL; + } else { + infosCopy = new GeofenceInfo[count]; + if (nullptr == infosCopy) { + LOC_LOGE("%s]: new failed to allocate infosCopy", __func__); + return NULL; + } + COPY_IF_NOT_NULL(infosCopy, infos, count); + } + + sendMsg(new MsgAddGeofences(*this, *mLocApi, client, count, ids, optionsCopy, infosCopy)); + return ids; +} + +void +GeofenceAdapter::removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids) +{ + LOC_LOGD("%s]: client %p count %zu", __func__, client, count); + + struct MsgRemoveGeofences : public LocMsg { + GeofenceAdapter& mAdapter; + LocApiBase& mApi; + LocationAPI* mClient; + size_t mCount; + uint32_t* mIds; + inline MsgRemoveGeofences(GeofenceAdapter& adapter, + LocApiBase& api, + LocationAPI* client, + size_t count, + uint32_t* ids) : + LocMsg(), + mAdapter(adapter), + mApi(api), + mClient(client), + mCount(count), + mIds(ids) {} + inline virtual void proc() const { + LocationError* errs = new LocationError[mCount]; + if (nullptr == errs) { + LOC_LOGE("%s]: new failed to allocate errs", __func__); + return; + } + for (size_t i=0; i < mCount; ++i) { + mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + &mApi = mApi, errs, i] (LocationError err ) { + uint32_t hwId = 0; + errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId); + if (LOCATION_ERROR_SUCCESS == errs[i]) { + mApi.removeGeofence(hwId, mIds[i], + new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + hwId, errs, i] (LocationError err ) { + if (LOCATION_ERROR_SUCCESS == err) { + mAdapter.removeGeofenceItem(hwId); + } + errs[i] = err; + + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + })); + } else { + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + } + })); + } + } + }; + + if (0 == count) { + return; + } + uint32_t* idsCopy = new uint32_t[count]; + if (nullptr == idsCopy) { + LOC_LOGE("%s]: new failed to allocate idsCopy", __func__); + return; + } + COPY_IF_NOT_NULL(idsCopy, ids, count); + sendMsg(new MsgRemoveGeofences(*this, *mLocApi, client, count, idsCopy)); +} + +void +GeofenceAdapter::pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids) +{ + LOC_LOGD("%s]: client %p count %zu", __func__, client, count); + + struct MsgPauseGeofences : public LocMsg { + GeofenceAdapter& mAdapter; + LocApiBase& mApi; + LocationAPI* mClient; + size_t mCount; + uint32_t* mIds; + inline MsgPauseGeofences(GeofenceAdapter& adapter, + LocApiBase& api, + LocationAPI* client, + size_t count, + uint32_t* ids) : + LocMsg(), + mAdapter(adapter), + mApi(api), + mClient(client), + mCount(count), + mIds(ids) {} + inline virtual void proc() const { + LocationError* errs = new LocationError[mCount]; + if (nullptr == errs) { + LOC_LOGE("%s]: new failed to allocate errs", __func__); + return; + } + for (size_t i=0; i < mCount; ++i) { + mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + &mApi = mApi, errs, i] (LocationError err ) { + uint32_t hwId = 0; + errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId); + if (LOCATION_ERROR_SUCCESS == errs[i]) { + mApi.pauseGeofence(hwId, mIds[i], new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + hwId, errs, i] (LocationError err ) { + if (LOCATION_ERROR_SUCCESS == err) { + mAdapter.pauseGeofenceItem(hwId); + } + errs[i] = err; + + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + })); + } else { + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + } + })); + } + } + }; + + if (0 == count) { + return; + } + uint32_t* idsCopy = new uint32_t[count]; + if (nullptr == idsCopy) { + LOC_LOGE("%s]: new failed to allocate idsCopy", __func__); + return; + } + COPY_IF_NOT_NULL(idsCopy, ids, count); + sendMsg(new MsgPauseGeofences(*this, *mLocApi, client, count, idsCopy)); +} + +void +GeofenceAdapter::resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids) +{ + LOC_LOGD("%s]: client %p count %zu", __func__, client, count); + + struct MsgResumeGeofences : public LocMsg { + GeofenceAdapter& mAdapter; + LocApiBase& mApi; + LocationAPI* mClient; + size_t mCount; + uint32_t* mIds; + inline MsgResumeGeofences(GeofenceAdapter& adapter, + LocApiBase& api, + LocationAPI* client, + size_t count, + uint32_t* ids) : + LocMsg(), + mAdapter(adapter), + mApi(api), + mClient(client), + mCount(count), + mIds(ids) {} + inline virtual void proc() const { + LocationError* errs = new LocationError[mCount]; + if (nullptr == errs) { + LOC_LOGE("%s]: new failed to allocate errs", __func__); + return; + } + for (size_t i=0; i < mCount; ++i) { + mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + &mApi = mApi, errs, i] (LocationError err ) { + uint32_t hwId = 0; + errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId); + if (LOCATION_ERROR_SUCCESS == errs[i]) { + mApi.resumeGeofence(hwId, mIds[i], + new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, hwId, + errs, mIds = mIds, i] (LocationError err ) { + if (LOCATION_ERROR_SUCCESS == err) { + errs[i] = err; + + mAdapter.resumeGeofenceItem(hwId); + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + } + })); + } else { + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + } + } + })); + } + } + }; + + if (0 == count) { + return; + } + uint32_t* idsCopy = new uint32_t[count]; + if (nullptr == idsCopy) { + LOC_LOGE("%s]: new failed to allocate idsCopy", __func__); + return; + } + COPY_IF_NOT_NULL(idsCopy, ids, count); + sendMsg(new MsgResumeGeofences(*this, *mLocApi, client, count, idsCopy)); +} + +void +GeofenceAdapter::modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids, + GeofenceOption* options) +{ + LOC_LOGD("%s]: client %p count %zu", __func__, client, count); + + struct MsgModifyGeofences : public LocMsg { + GeofenceAdapter& mAdapter; + LocApiBase& mApi; + LocationAPI* mClient; + size_t mCount; + uint32_t* mIds; + GeofenceOption* mOptions; + inline MsgModifyGeofences(GeofenceAdapter& adapter, + LocApiBase& api, + LocationAPI* client, + size_t count, + uint32_t* ids, + GeofenceOption* options) : + LocMsg(), + mAdapter(adapter), + mApi(api), + mClient(client), + mCount(count), + mIds(ids), + mOptions(options) {} + inline virtual void proc() const { + LocationError* errs = new LocationError[mCount]; + if (nullptr == errs) { + LOC_LOGE("%s]: new failed to allocate errs", __func__); + return; + } + for (size_t i=0; i < mCount; ++i) { + if (NULL == mIds || NULL == mOptions) { + errs[i] = LOCATION_ERROR_INVALID_PARAMETER; + } else { + mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds, + &mApi = mApi, mOptions = mOptions, errs, i] (LocationError err ) { + uint32_t hwId = 0; + errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId); + if (LOCATION_ERROR_SUCCESS == errs[i]) { + mApi.modifyGeofence(hwId, mIds[i], mOptions[i], + new LocApiResponse(*mAdapter.getContext(), + [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, + mIds = mIds, mOptions = mOptions, hwId, errs, i] + (LocationError err ) { + if (LOCATION_ERROR_SUCCESS == err) { + errs[i] = err; + + mAdapter.modifyGeofenceItem(hwId, mOptions[i]); + } + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + delete[] mOptions; + } + })); + } else { + // Send aggregated response on last item and cleanup + if (i == mCount-1) { + mAdapter.reportResponse(mClient, mCount, errs, mIds); + delete[] errs; + delete[] mIds; + delete[] mOptions; + } + } + })); + } + } + } + }; + + if (0 == count) { + return; + } + uint32_t* idsCopy = new uint32_t[count]; + if (nullptr == idsCopy) { + LOC_LOGE("%s]: new failed to allocate idsCopy", __func__); + return; + } + COPY_IF_NOT_NULL(idsCopy, ids, count); + GeofenceOption* optionsCopy; + if (options == NULL) { + optionsCopy = NULL; + } else { + optionsCopy = new GeofenceOption[count]; + if (nullptr == optionsCopy) { + LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__); + return; + } + COPY_IF_NOT_NULL(optionsCopy, options, count); + } + + sendMsg(new MsgModifyGeofences(*this, *mLocApi, client, count, idsCopy, optionsCopy)); +} + +void +GeofenceAdapter::saveGeofenceItem(LocationAPI* client, uint32_t clientId, uint32_t hwId, + const GeofenceOption& options, const GeofenceInfo& info) +{ + LOC_LOGD("%s]: hwId %u client %p clientId %u", __func__, hwId, client, clientId); + GeofenceKey key(client, clientId); + GeofenceObject object = {key, + options.breachTypeMask, + options.responsiveness, + options.dwellTime, + info.latitude, + info.longitude, + info.radius, + false}; + mGeofences[hwId] = object; + mGeofenceIds[key] = hwId; + dump(); +} + +void +GeofenceAdapter::removeGeofenceItem(uint32_t hwId) +{ + GeofenceKey key; + LocationError err = getGeofenceKeyFromHwId(hwId, key); + if (LOCATION_ERROR_SUCCESS != err) { + LOC_LOGE("%s]: can not find the key for hwId %u", __func__, hwId); + } else { + auto it1 = mGeofenceIds.find(key); + if (it1 != mGeofenceIds.end()) { + mGeofenceIds.erase(it1); + + auto it2 = mGeofences.find(hwId); + if (it2 != mGeofences.end()) { + mGeofences.erase(it2); + dump(); + } else { + LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId); + } + } else { + LOC_LOGE("%s]: geofence item to erase not found. hwId %u", __func__, hwId); + } + } +} + +void +GeofenceAdapter::pauseGeofenceItem(uint32_t hwId) +{ + auto it = mGeofences.find(hwId); + if (it != mGeofences.end()) { + it->second.paused = true; + dump(); + } else { + LOC_LOGE("%s]: geofence item to pause not found. hwId %u", __func__, hwId); + } +} + +void +GeofenceAdapter::resumeGeofenceItem(uint32_t hwId) +{ + auto it = mGeofences.find(hwId); + if (it != mGeofences.end()) { + it->second.paused = false; + dump(); + } else { + LOC_LOGE("%s]: geofence item to resume not found. hwId %u", __func__, hwId); + } +} + +void +GeofenceAdapter::modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options) +{ + auto it = mGeofences.find(hwId); + if (it != mGeofences.end()) { + it->second.breachMask = options.breachTypeMask; + it->second.responsiveness = options.responsiveness; + it->second.dwellTime = options.dwellTime; + dump(); + } else { + LOC_LOGE("%s]: geofence item to modify not found. hwId %u", __func__, hwId); + } +} + + +void +GeofenceAdapter::geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location, + GeofenceBreachType breachType, uint64_t timestamp) +{ + + IF_LOC_LOGD { + std::string idsString = "["; + if (NULL != hwIds) { + for (size_t i=0; i < count; ++i) { + idsString += std::to_string(hwIds[i]) + " "; + } + } + idsString += "]"; + LOC_LOGD("%s]: breachType %u count %zu ids %s", + __func__, breachType, count, idsString.c_str()); + } + + if (0 == count || NULL == hwIds) + return; + + struct MsgGeofenceBreach : public LocMsg { + GeofenceAdapter& mAdapter; + size_t mCount; + uint32_t* mHwIds; + Location mLocation; + GeofenceBreachType mBreachType; + uint64_t mTimestamp; + inline MsgGeofenceBreach(GeofenceAdapter& adapter, + size_t count, + uint32_t* hwIds, + Location& location, + GeofenceBreachType breachType, + uint64_t timestamp) : + LocMsg(), + mAdapter(adapter), + mCount(count), + mHwIds(new uint32_t[count]), + mLocation(location), + mBreachType(breachType), + mTimestamp(timestamp) + { + if (nullptr == mHwIds) { + LOC_LOGE("%s]: new failed to allocate mHwIds", __func__); + return; + } + COPY_IF_NOT_NULL(mHwIds, hwIds, mCount); + } + inline virtual ~MsgGeofenceBreach() { + delete[] mHwIds; + } + inline virtual void proc() const { + mAdapter.geofenceBreach(mCount, mHwIds, mLocation, mBreachType, mTimestamp); + } + }; + + sendMsg(new MsgGeofenceBreach(*this, count, hwIds, location, breachType, timestamp)); + +} + +void +GeofenceAdapter::geofenceBreach(size_t count, uint32_t* hwIds, const Location& location, + GeofenceBreachType breachType, uint64_t timestamp) +{ + + for (auto it = mClientData.begin(); it != mClientData.end(); ++it) { + uint32_t* clientIds = new uint32_t[count]; + if (nullptr == clientIds) { + return; + } + uint32_t index = 0; + for (size_t i=0; i < count; ++i) { + GeofenceKey key; + LocationError err = getGeofenceKeyFromHwId(hwIds[i], key); + if (LOCATION_ERROR_SUCCESS == err) { + if (key.client == it->first) { + clientIds[index++] = key.id; + } + } + } + if (index > 0 && it->second.geofenceBreachCb != nullptr) { + GeofenceBreachNotification notify = {sizeof(GeofenceBreachNotification), + index, + clientIds, + location, + breachType, + timestamp}; + + it->second.geofenceBreachCb(notify); + } + delete[] clientIds; + } +} + +void +GeofenceAdapter::geofenceStatusEvent(GeofenceStatusAvailable available) +{ + LOC_LOGD("%s]: available %u ", __func__, available); + + struct MsgGeofenceStatus : public LocMsg { + GeofenceAdapter& mAdapter; + GeofenceStatusAvailable mAvailable; + inline MsgGeofenceStatus(GeofenceAdapter& adapter, + GeofenceStatusAvailable available) : + LocMsg(), + mAdapter(adapter), + mAvailable(available) {} + inline virtual void proc() const { + mAdapter.geofenceStatus(mAvailable); + } + }; + + sendMsg(new MsgGeofenceStatus(*this, available)); +} + +void +GeofenceAdapter::geofenceStatus(GeofenceStatusAvailable available) +{ + for (auto it = mClientData.begin(); it != mClientData.end(); ++it) { + if (it->second.geofenceStatusCb != nullptr) { + GeofenceStatusNotification notify = {sizeof(GeofenceStatusNotification), + available, + LOCATION_TECHNOLOGY_TYPE_GNSS}; + it->second.geofenceStatusCb(notify); + } + } +} + +void +GeofenceAdapter::dump() +{ + IF_LOC_LOGV { + LOC_LOGV( + "HAL | hwId | mask | respon | latitude | longitude | radius | paused | Id | client"); + for (auto it = mGeofences.begin(); it != mGeofences.end(); ++it) { + uint32_t hwId = it->first; + GeofenceObject object = it->second; + LOC_LOGV(" | %5u | %4u | %6u | %8.2f | %9.2f | %6.2f | %6u | %04x | %p ", + hwId, object.breachMask, object.responsiveness, + object.latitude, object.longitude, object.radius, + object.paused, object.key.id, object.key.client); + } + } +} + diff --git a/gps/geofence/GeofenceAdapter.h b/gps/geofence/GeofenceAdapter.h new file mode 100644 index 0000000..38f4823 --- /dev/null +++ b/gps/geofence/GeofenceAdapter.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2013-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 GEOFENCE_ADAPTER_H +#define GEOFENCE_ADAPTER_H + +#include <LocAdapterBase.h> +#include <LocContext.h> +#include <LocationAPI.h> +#include <map> + +using namespace loc_core; + +#define COPY_IF_NOT_NULL(dest, src, len) do { \ + if (NULL!=dest && NULL!=src) { \ + for (size_t i=0; i<len; ++i) { \ + dest[i] = src[i]; \ + } \ + } \ +} while (0) + +typedef struct GeofenceKey { + LocationAPI* client; + uint32_t id; + inline GeofenceKey() : + client(NULL), id(0) {} + inline GeofenceKey(LocationAPI* _client, uint32_t _id) : + client(_client), id(_id) {} +} GeofenceKey; +inline bool operator <(GeofenceKey const& left, GeofenceKey const& right) { + return left.id < right.id || (left.id == right.id && left.client < right.client); +} +inline bool operator ==(GeofenceKey const& left, GeofenceKey const& right) { + return left.id == right.id && left.client == right.client; +} +inline bool operator !=(GeofenceKey const& left, GeofenceKey const& right) { + return left.id != right.id || left.client != right.client; +} +typedef struct { + GeofenceKey key; + GeofenceBreachTypeMask breachMask; + uint32_t responsiveness; + uint32_t dwellTime; + double latitude; + double longitude; + double radius; + bool paused; +} GeofenceObject; +typedef std::map<uint32_t, GeofenceObject> GeofencesMap; //map of hwId to GeofenceObject +typedef std::map<GeofenceKey, uint32_t> GeofenceIdMap; //map of GeofenceKey to hwId + +class GeofenceAdapter : public LocAdapterBase { + + /* ==== GEOFENCES ====================================================================== */ + GeofencesMap mGeofences; //map hwId to GeofenceObject + GeofenceIdMap mGeofenceIds; //map of GeofenceKey to hwId + +protected: + + /* ==== CLIENT ========================================================================= */ + virtual void updateClientsEventMask(); + virtual void stopClientSessions(LocationAPI* client); + +public: + + GeofenceAdapter(); + virtual ~GeofenceAdapter() {} + + /* ==== SSR ============================================================================ */ + /* ======== EVENTS ====(Called from QMI Thread)========================================= */ + virtual void handleEngineUpEvent(); + /* ======== UTILITIES ================================================================== */ + void restartGeofences(); + + /* ==== GEOFENCES ====================================================================== */ + /* ======== COMMANDS ====(Called from Client Thread)==================================== */ + uint32_t* addGeofencesCommand(LocationAPI* client, size_t count, + GeofenceOption* options, GeofenceInfo* info); + void removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids); + void pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids); + void resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids); + void modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids, + GeofenceOption* options); + /* ======== RESPONSES ================================================================== */ + void reportResponse(LocationAPI* client, size_t count, LocationError* errs, uint32_t* ids); + /* ======== UTILITIES ================================================================== */ + void saveGeofenceItem(LocationAPI* client, + uint32_t clientId, + uint32_t hwId, + const GeofenceOption& options, + const GeofenceInfo& info); + void removeGeofenceItem(uint32_t hwId); + void pauseGeofenceItem(uint32_t hwId); + void resumeGeofenceItem(uint32_t hwId); + void modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options); + LocationError getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId); + LocationError getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key); + void dump(); + + /* ==== REPORTS ======================================================================== */ + /* ======== EVENTS ====(Called from QMI Thread)========================================= */ + void geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location, + GeofenceBreachType breachType, uint64_t timestamp); + void geofenceStatusEvent(GeofenceStatusAvailable available); + /* ======== UTILITIES ================================================================== */ + void geofenceBreach(size_t count, uint32_t* hwIds, const Location& location, + GeofenceBreachType breachType, uint64_t timestamp); + void geofenceStatus(GeofenceStatusAvailable available); +}; + +#endif /* GEOFENCE_ADAPTER_H */ diff --git a/gps/geofence/Makefile.am b/gps/geofence/Makefile.am new file mode 100644 index 0000000..61883ff --- /dev/null +++ b/gps/geofence/Makefile.am @@ -0,0 +1,50 @@ +AM_CFLAGS = -Wundef \ + -Wno-trigraphs \ + -g -O0 \ + -fno-inline \ + -fno-short-enums \ + -fpic \ + ${GPSUTILS_CFLAGS} \ + ${LOCCORE_CFLAGS} \ + $(LOCPLA_CFLAGS) \ + -D__func__=__PRETTY_FUNCTION__ \ + -std=c++1y + +AM_CPPFLAGS = $(AM_CFLAGS) + +ACLOCAL_AMFLAGS = -I m4 + +requiredlibs = \ + ${LOCCORE_LIBS} \ + $(GPSUTILS_LIBS) \ + -llog + +h_sources = \ + GeofenceAdapter.h + +c_sources = \ + GeofenceAdapter.cpp \ + location_geofence.cpp + +libgeofencing_la_SOURCES = $(c_sources) +if USE_GLIB +libgeofencing_la_CFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS) +libgeofencing_la_CPPFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS) $(AM_CPPFLAGS) +libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs @GLIB_LIBS@ $(requiredlibs) -shared -version-info 1:0:0 +libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++ @GLIB_LIBS@ +else +libgeofencing_la_CFLAGS = $(AM_CFLAGS) +libgeofencing_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) +libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs $(requiredlibs) -shared -version-info 1:0:0 +libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++ +endif + +library_include_HEADERS = $(h_sources) + +library_includedir = $(pkgincludedir) + +lib_LTLIBRARIES = libgeofencing.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = location-geofence.pc +EXTRA_DIST = $(pkgconfig_DATA) diff --git a/gps/geofence/configure.ac b/gps/geofence/configure.ac new file mode 100644 index 0000000..8e3cd81 --- /dev/null +++ b/gps/geofence/configure.ac @@ -0,0 +1,72 @@ +AC_PREREQ(2.61) +AC_INIT([location-geofence], 1.0.0) +AM_INIT_AUTOMAKE([foreign]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# Check for programs +AC_PROG_LIBTOOL +AC_PROG_CXX +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_AWK +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +PKG_PROG_PKG_CONFIG + +# Check for libraries +PKG_CHECK_MODULES([GPSUTILS], [gps-utils]) +AC_SUBST([GPSUTILS_CFLAGS]) +AC_SUBST([GPSUTILS_LIBS]) + +PKG_CHECK_MODULES([LOCCORE], [loc-core]) +AC_SUBST([LOCCORE_CFLAGS]) +AC_SUBST([LOCCORE_LIBS]) + +AS_CASE([$host], + [arm*], [ARM=yes], + [ARM=no] +) + +AC_ARG_WITH([locpla_includes], + AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@], + [specify the path to locpla-includes in loc-pla_git.bb]), + [locpla_incdir=$withval], + with_locpla_includes=no) + +if test "x$with_locpla_includes" != "xno"; then + AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}") +fi + +AC_ARG_WITH([glib], + AC_HELP_STRING([--with-glib], + [enable glib, building HLOS systems which use glib])) + +if (test "x${with_glib}" = "xyes"); then + AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib]) + PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GThread >= 2.16 is required)) + PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GLib >= 2.16 is required)) + GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS" + GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS" + + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) +fi + +AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes") + +AC_SUBST([CFLAGS]) +AC_SUBST([CPPFLAGS]) +AC_SUBST([LIBS]) + +AC_CONFIG_FILES([ \ + Makefile \ + location-geofence.pc + ]) + +AC_OUTPUT diff --git a/gps/geofence/location-geofence.pc.in b/gps/geofence/location-geofence.pc.in new file mode 100644 index 0000000..6a0781f --- /dev/null +++ b/gps/geofence/location-geofence.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: location-geofence +Description: QTI GPS Geofence +Version: @VERSION +Libs: -L${libdir} -lgeofencing +Cflags: -I${includedir}/location-geofence diff --git a/gps/geofence/location_geofence.cpp b/gps/geofence/location_geofence.cpp new file mode 100644 index 0000000..66729f4 --- /dev/null +++ b/gps/geofence/location_geofence.cpp @@ -0,0 +1,145 @@ +/* Copyright (c) 2017-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 "GeofenceAdapter.h" +#include "location_interface.h" + +static GeofenceAdapter* gGeofenceAdapter = NULL; + +static void initialize(); +static void deinitialize(); + +static void addClient(LocationAPI* client, const LocationCallbacks& callbacks); +static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb); +static void requestCapabilities(LocationAPI* client); + +static uint32_t* addGeofences(LocationAPI* client, size_t count, GeofenceOption*, GeofenceInfo*); +static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids); +static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids, + GeofenceOption* options); +static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids); +static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids); + +static const GeofenceInterface gGeofenceInterface = { + sizeof(GeofenceInterface), + initialize, + deinitialize, + addClient, + removeClient, + requestCapabilities, + addGeofences, + removeGeofences, + modifyGeofences, + pauseGeofences, + resumeGeofences +}; + +#ifndef DEBUG_X86 +extern "C" const GeofenceInterface* getGeofenceInterface() +#else +const GeofenceInterface* getGeofenceInterface() +#endif // DEBUG_X86 +{ + return &gGeofenceInterface; +} + +static void initialize() +{ + if (NULL == gGeofenceAdapter) { + gGeofenceAdapter = new GeofenceAdapter(); + } +} + +static void deinitialize() +{ + if (NULL != gGeofenceAdapter) { + delete gGeofenceAdapter; + gGeofenceAdapter = NULL; + } +} + +static void addClient(LocationAPI* client, const LocationCallbacks& callbacks) +{ + if (NULL != gGeofenceAdapter) { + gGeofenceAdapter->addClientCommand(client, callbacks); + } +} + +static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb) +{ + if (NULL != gGeofenceAdapter) { + gGeofenceAdapter->removeClientCommand(client, rmClientCb); + } +} + +static void requestCapabilities(LocationAPI* client) +{ + if (NULL != gGeofenceAdapter) { + gGeofenceAdapter->requestCapabilitiesCommand(client); + } +} + +static uint32_t* addGeofences(LocationAPI* client, size_t count, + GeofenceOption* options, GeofenceInfo* info) +{ + if (NULL != gGeofenceAdapter) { + return gGeofenceAdapter->addGeofencesCommand(client, count, options, info); + } else { + return NULL; + } +} + +static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids) +{ + if (NULL != gGeofenceAdapter) { + return gGeofenceAdapter->removeGeofencesCommand(client, count, ids); + } +} + +static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids, + GeofenceOption* options) +{ + if (NULL != gGeofenceAdapter) { + return gGeofenceAdapter->modifyGeofencesCommand(client, count, ids, options); + } +} + +static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids) +{ + if (NULL != gGeofenceAdapter) { + return gGeofenceAdapter->pauseGeofencesCommand(client, count, ids); + } +} + +static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids) +{ + if (NULL != gGeofenceAdapter) { + return gGeofenceAdapter->resumeGeofencesCommand(client, count, ids); + } +} + |