/* 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 <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <queue>
#include <map>
#include "LocationAPI.h"
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<LocationAPIRequest*> 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);
void 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<uint32_t> &/*listOfCompletedTrips*/) {}
void beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
std::list<uint32_t> & 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<typename T>
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<uint32_t> getAllSessions() {
std::vector<uint32_t> 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<uint32_t, uint32_t> mForwardMap;
// mBackwardMap mapping session->id
std::map<uint32_t, uint32_t> mBackwardMap;
// mExtMap mapping session->ext
std::map<uint32_t, T> mExtMap;
};
class StartTrackingRequest : public LocationAPIRequest {
public:
StartTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {}
inline void onResponse(LocationError error, uint32_t /*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*/) {
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) : 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.mGeofenceBiDict.rmBySession(sessions[i]);
}
mAPI.onRemoveGeofencesCb(count, errors, ids);
free(ids);
}
LocationAPIClientBase& mAPI;
};
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<GeofenceBreachTypeMask> mGeofenceBiDict;
BiDict<SessionEntity> mSessionBiDict;
int32_t mBatchSize;
bool mTracking;
};
#endif /* LOCATION_API_CLINET_BASE_H */