/* Copyright (c) 2017 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 LOCATION_API_CLINET_BASE_H #define LOCATION_API_CLINET_BASE_H #include #include #include #include #include #include "LocationAPI.h" #include #include enum SESSION_MODE { SESSION_MODE_NONE = 0, SESSION_MODE_ON_FULL, SESSION_MODE_ON_FIX, SESSION_MODE_ON_TRIP_COMPLETED }; enum REQUEST_TYPE { REQUEST_TRACKING = 0, REQUEST_SESSION, REQUEST_GEOFENCE, REQUEST_NIRESPONSE, REQUEST_MAX, }; enum CTRL_REQUEST_TYPE { CTRL_REQUEST_DELETEAIDINGDATA = 0, CTRL_REQUEST_CONTROL, CTRL_REQUEST_CONFIG, CTRL_REQUEST_MAX, }; class LocationAPIClientBase; class LocationAPIRequest { public: LocationAPIRequest() {} virtual ~LocationAPIRequest() {} virtual void onResponse(LocationError /*error*/, uint32_t /*id*/) {} virtual void onCollectiveResponse( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} }; class RequestQueue { public: RequestQueue(): mSession(0) { } virtual ~RequestQueue() { reset(0); } void inline setSession(uint32_t session) { mSession = session; } void reset(uint32_t session) { LocationAPIRequest* request = nullptr; while (!mQueue.empty()) { request = mQueue.front(); mQueue.pop(); delete request; } mSession = session; } void push(LocationAPIRequest* request) { mQueue.push(request); } LocationAPIRequest* pop() { LocationAPIRequest* request = nullptr; if (!mQueue.empty()) { request = mQueue.front(); mQueue.pop(); } return request; } uint32_t getSession() { return mSession; } private: uint32_t mSession; std::queue mQueue; }; class LocationAPIControlClient { public: LocationAPIControlClient(); virtual ~LocationAPIControlClient(); LocationAPIControlClient(const LocationAPIControlClient&) = delete; LocationAPIControlClient& operator=(const LocationAPIControlClient&) = delete; LocationAPIRequest* getRequestBySession(uint32_t session); // LocationControlAPI uint32_t locAPIGnssDeleteAidingData(GnssAidingData& data); uint32_t locAPIEnable(LocationTechnologyType techType); void locAPIDisable(); uint32_t locAPIGnssUpdateConfig(GnssConfig config); // callbacks void onCtrlResponseCb(LocationError error, uint32_t id); void onCtrlCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids); inline virtual void onGnssDeleteAidingDataCb(LocationError /*error*/) {} inline virtual void onEnableCb(LocationError /*error*/) {} inline virtual void onDisableCb(LocationError /*error*/) {} inline virtual void onGnssUpdateConfigCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} class GnssDeleteAidingDataRequest : public LocationAPIRequest { public: GnssDeleteAidingDataRequest(LocationAPIControlClient& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onGnssDeleteAidingDataCb(error); } LocationAPIControlClient& mAPI; }; class EnableRequest : public LocationAPIRequest { public: EnableRequest(LocationAPIControlClient& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onEnableCb(error); } LocationAPIControlClient& mAPI; }; class DisableRequest : public LocationAPIRequest { public: DisableRequest(LocationAPIControlClient& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onDisableCb(error); } LocationAPIControlClient& mAPI; }; class GnssUpdateConfigRequest : public LocationAPIRequest { public: GnssUpdateConfigRequest(LocationAPIControlClient& API) : mAPI(API) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) { mAPI.onGnssUpdateConfigCb(count, errors, ids); } LocationAPIControlClient& mAPI; }; private: pthread_mutex_t mMutex; LocationControlAPI* mLocationControlAPI; RequestQueue mRequestQueues[CTRL_REQUEST_MAX]; bool mEnabled; GnssConfig mConfig; }; class LocationAPIClientBase { public: LocationAPIClientBase(); virtual ~LocationAPIClientBase(); LocationAPIClientBase(const LocationAPIClientBase&) = delete; LocationAPIClientBase& operator=(const LocationAPIClientBase&) = delete; void locAPISetCallbacks(LocationCallbacks& locationCallbacks); void removeSession(uint32_t session); LocationAPIRequest* getRequestBySession(uint32_t session); // LocationAPI uint32_t locAPIStartTracking(LocationOptions& options); void locAPIStopTracking(); void locAPIUpdateTrackingOptions(LocationOptions& options); int32_t locAPIGetBatchSize(); uint32_t locAPIStartSession(uint32_t id, uint32_t sessionMode, LocationOptions& options); uint32_t locAPIStopSession(uint32_t id); uint32_t locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode, LocationOptions& options); uint32_t locAPIGetBatchedLocations(uint32_t id, size_t count); uint32_t locAPIAddGeofences(size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data); void locAPIRemoveGeofences(size_t count, uint32_t* ids); void locAPIModifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options); void locAPIPauseGeofences(size_t count, uint32_t* ids); void locAPIResumeGeofences(size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask); void locAPIRemoveAllGeofences(); void locAPIGnssNiResponse(uint32_t id, GnssNiResponse response); // callbacks void onResponseCb(LocationError error, uint32_t id); void onCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids); void beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification); inline virtual void onCapabilitiesCb(LocationCapabilitiesMask /*capabilitiesMask*/) {} inline virtual void onGnssNmeaCb(GnssNmeaNotification /*gnssNmeaNotification*/) {} inline virtual void onGnssMeasurementsCb( GnssMeasurementsNotification /*gnssMeasurementsNotification*/) {} inline virtual void onTrackingCb(Location /*location*/) {} inline virtual void onGnssSvCb(GnssSvNotification /*gnssSvNotification*/) {} inline virtual void onStartTrackingCb(LocationError /*error*/) {} inline virtual void onStopTrackingCb(LocationError /*error*/) {} inline virtual void onUpdateTrackingOptionsCb(LocationError /*error*/) {} inline virtual void onGnssLocationInfoCb( GnssLocationInfoNotification /*gnssLocationInfoNotification*/) {} inline virtual void onBatchingCb(size_t /*count*/, Location* /*location*/, BatchingOptions /*batchingOptions*/) {} inline virtual void onBatchingStatusCb(BatchingStatusInfo /*batchingStatus*/, std::list &/*listOfCompletedTrips*/) {} void beforeBatchingStatusCb(BatchingStatusInfo batchStatus, std::list & tripCompletedList); inline virtual void onStartBatchingCb(LocationError /*error*/) {} inline virtual void onStopBatchingCb(LocationError /*error*/) {} inline virtual void onUpdateBatchingOptionsCb(LocationError /*error*/) {} inline virtual void onGetBatchedLocationsCb(LocationError /*error*/) {} inline virtual void onGeofenceBreachCb( GeofenceBreachNotification /*geofenceBreachNotification*/) {} inline virtual void onGeofenceStatusCb( GeofenceStatusNotification /*geofenceStatusNotification*/) {} inline virtual void onAddGeofencesCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} inline virtual void onRemoveGeofencesCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} inline virtual void onModifyGeofencesCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} inline virtual void onPauseGeofencesCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} inline virtual void onResumeGeofencesCb( size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} inline virtual void onGnssNiCb(uint32_t /*id*/, GnssNiNotification /*gnssNiNotification*/) {} inline virtual void onGnssNiResponseCb(LocationError /*error*/) {} private: // private inner classes typedef struct { uint32_t id; uint32_t trackingSession; uint32_t batchingSession; uint32_t sessionMode; } SessionEntity; template class BiDict { public: BiDict() { pthread_mutex_init(&mBiDictMutex, nullptr); } virtual ~BiDict() { pthread_mutex_destroy(&mBiDictMutex); } bool hasId(uint32_t id) { pthread_mutex_lock(&mBiDictMutex); bool ret = (mForwardMap.find(id) != mForwardMap.end()); pthread_mutex_unlock(&mBiDictMutex); return ret; } bool hasSession(uint32_t session) { pthread_mutex_lock(&mBiDictMutex); bool ret = (mBackwardMap.find(session) != mBackwardMap.end()); pthread_mutex_unlock(&mBiDictMutex); return ret; } void set(uint32_t id, uint32_t session, T& ext) { pthread_mutex_lock(&mBiDictMutex); mForwardMap[id] = session; mBackwardMap[session] = id; mExtMap[session] = ext; pthread_mutex_unlock(&mBiDictMutex); } void clear() { pthread_mutex_lock(&mBiDictMutex); mForwardMap.clear(); mBackwardMap.clear(); mExtMap.clear(); pthread_mutex_unlock(&mBiDictMutex); } void rmById(uint32_t id) { pthread_mutex_lock(&mBiDictMutex); mBackwardMap.erase(mForwardMap[id]); mExtMap.erase(mForwardMap[id]); mForwardMap.erase(id); pthread_mutex_unlock(&mBiDictMutex); } void rmBySession(uint32_t session) { pthread_mutex_lock(&mBiDictMutex); mForwardMap.erase(mBackwardMap[session]); mBackwardMap.erase(session); mExtMap.erase(session); pthread_mutex_unlock(&mBiDictMutex); } uint32_t getId(uint32_t session) { pthread_mutex_lock(&mBiDictMutex); uint32_t ret = 0; auto it = mBackwardMap.find(session); if (it != mBackwardMap.end()) { ret = it->second; } pthread_mutex_unlock(&mBiDictMutex); return ret; } uint32_t getSession(uint32_t id) { pthread_mutex_lock(&mBiDictMutex); uint32_t ret = 0; auto it = mForwardMap.find(id); if (it != mForwardMap.end()) { ret = it->second; } pthread_mutex_unlock(&mBiDictMutex); return ret; } T getExtById(uint32_t id) { pthread_mutex_lock(&mBiDictMutex); T ret; memset(&ret, 0, sizeof(T)); uint32_t session = mForwardMap[id]; if (session > 0) { auto it = mExtMap.find(session); if (it != mExtMap.end()) { ret = it->second; } } pthread_mutex_unlock(&mBiDictMutex); return ret; } T getExtBySession(uint32_t session) { pthread_mutex_lock(&mBiDictMutex); T ret; memset(&ret, 0, sizeof(T)); auto it = mExtMap.find(session); if (it != mExtMap.end()) { ret = it->second; } pthread_mutex_unlock(&mBiDictMutex); return ret; } std::vector getAllSessions() { std::vector ret; pthread_mutex_lock(&mBiDictMutex); for (auto it = mBackwardMap.begin(); it != mBackwardMap.end(); it++) { ret.push_back(it->first); } pthread_mutex_unlock(&mBiDictMutex); return ret; } private: pthread_mutex_t mBiDictMutex; // mForwarMap mapping id->session std::map mForwardMap; // mBackwardMap mapping session->id std::map mBackwardMap; // mExtMap mapping session->ext std::map mExtMap; }; class StartTrackingRequest : public LocationAPIRequest { public: StartTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t id) { if (error != LOCATION_ERROR_SUCCESS) { mAPI.removeSession(id); } mAPI.onStartTrackingCb(error); } LocationAPIClientBase& mAPI; }; class StopTrackingRequest : public LocationAPIRequest { public: StopTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t id) { mAPI.onStopTrackingCb(error); if (error == LOCATION_ERROR_SUCCESS) { mAPI.removeSession(id); } } LocationAPIClientBase& mAPI; }; class UpdateTrackingOptionsRequest : public LocationAPIRequest { public: UpdateTrackingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onUpdateTrackingOptionsCb(error); } LocationAPIClientBase& mAPI; }; class StartBatchingRequest : public LocationAPIRequest { public: StartBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t id) { if (error != LOCATION_ERROR_SUCCESS) { mAPI.removeSession(id); } mAPI.onStartBatchingCb(error); } LocationAPIClientBase& mAPI; }; class StopBatchingRequest : public LocationAPIRequest { public: StopBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t id) { mAPI.onStopBatchingCb(error); if (error == LOCATION_ERROR_SUCCESS) { mAPI.removeSession(id); } } LocationAPIClientBase& mAPI; }; class UpdateBatchingOptionsRequest : public LocationAPIRequest { public: UpdateBatchingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onUpdateBatchingOptionsCb(error); } LocationAPIClientBase& mAPI; }; class GetBatchedLocationsRequest : public LocationAPIRequest { public: GetBatchedLocationsRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onGetBatchedLocationsCb(error); } LocationAPIClientBase& mAPI; }; class AddGeofencesRequest : public LocationAPIRequest { public: AddGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); for (size_t i = 0; i < count; i++) { ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); } mAPI.onAddGeofencesCb(count, errors, ids); free(ids); } LocationAPIClientBase& mAPI; }; class RemoveGeofencesRequest : public LocationAPIRequest { public: RemoveGeofencesRequest(LocationAPIClientBase& API, BiDict* removedGeofenceBiDict) : mAPI(API), mRemovedGeofenceBiDict(removedGeofenceBiDict) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { if (nullptr != mRemovedGeofenceBiDict) { uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); for (size_t i = 0; i < count; i++) { ids[i] = mRemovedGeofenceBiDict->getId(sessions[i]); } mAPI.onRemoveGeofencesCb(count, errors, ids); free(ids); delete(mRemovedGeofenceBiDict); } else { LOC_LOGE("%s:%d] Unable to access removed geofences data.", __FUNCTION__, __LINE__); } } LocationAPIClientBase& mAPI; BiDict* mRemovedGeofenceBiDict; }; class ModifyGeofencesRequest : public LocationAPIRequest { public: ModifyGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); for (size_t i = 0; i < count; i++) { ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); } mAPI.onModifyGeofencesCb(count, errors, ids); free(ids); } LocationAPIClientBase& mAPI; }; class PauseGeofencesRequest : public LocationAPIRequest { public: PauseGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); for (size_t i = 0; i < count; i++) { ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); } mAPI.onPauseGeofencesCb(count, errors, ids); free(ids); } LocationAPIClientBase& mAPI; }; class ResumeGeofencesRequest : public LocationAPIRequest { public: ResumeGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); for (size_t i = 0; i < count; i++) { ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); } mAPI.onResumeGeofencesCb(count, errors, ids); free(ids); } LocationAPIClientBase& mAPI; }; class GnssNiResponseRequest : public LocationAPIRequest { public: GnssNiResponseRequest(LocationAPIClientBase& API) : mAPI(API) {} inline void onResponse(LocationError error, uint32_t /*id*/) { mAPI.onGnssNiResponseCb(error); } LocationAPIClientBase& mAPI; }; private: pthread_mutex_t mMutex; geofenceBreachCallback mGeofenceBreachCallback; batchingStatusCallback mBatchingStatusCallback; LocationAPI* mLocationAPI; RequestQueue mRequestQueues[REQUEST_MAX]; BiDict mGeofenceBiDict; BiDict mSessionBiDict; int32_t mBatchSize; bool mTracking; }; #endif /* LOCATION_API_CLINET_BASE_H */