1/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation, nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#define LOG_NDEBUG 0
31#define LOG_TAG "LocSvc_GeofenceApiClient"
32
33#include <log_util.h>
34#include <loc_cfg.h>
35
36#include "LocationUtil.h"
37#include "GeofenceAPIClient.h"
38
39namespace android {
40namespace hardware {
41namespace gnss {
42namespace V1_0 {
43namespace implementation {
44
45
46GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
47    LocationAPIClientBase(),
48    mGnssGeofencingCbIface(callback)
49{
50    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
51
52    LocationCallbacks locationCallbacks;
53    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
54    locationCallbacks.size = sizeof(LocationCallbacks);
55
56    locationCallbacks.trackingCb = nullptr;
57    locationCallbacks.batchingCb = nullptr;
58
59    locationCallbacks.geofenceBreachCb = nullptr;
60    if (mGnssGeofencingCbIface != nullptr) {
61        locationCallbacks.geofenceBreachCb =
62            [this](GeofenceBreachNotification geofenceBreachNotification) {
63                onGeofenceBreachCb(geofenceBreachNotification);
64            };
65
66        locationCallbacks.geofenceStatusCb =
67            [this](GeofenceStatusNotification geofenceStatusNotification) {
68                onGeofenceStatusCb(geofenceStatusNotification);
69            };
70    }
71
72    locationCallbacks.gnssLocationInfoCb = nullptr;
73    locationCallbacks.gnssNiCb = nullptr;
74    locationCallbacks.gnssSvCb = nullptr;
75    locationCallbacks.gnssNmeaCb = nullptr;
76    locationCallbacks.gnssMeasurementsCb = nullptr;
77
78    locAPISetCallbacks(locationCallbacks);
79}
80
81void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
82        double radius_meters, int32_t last_transition, int32_t monitor_transitions,
83        uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
84{
85    LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
86            geofence_id, latitude, longitude, radius_meters,
87            last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
88
89    GeofenceOption options;
90    memset(&options, 0, sizeof(GeofenceOption));
91    options.size = sizeof(GeofenceOption);
92    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
93        options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
94    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
95        options.breachTypeMask |=  GEOFENCE_BREACH_EXIT_BIT;
96    options.responsiveness = notification_responsiveness_ms;
97
98    GeofenceInfo data;
99    data.size = sizeof(GeofenceInfo);
100    data.latitude = latitude;
101    data.longitude = longitude;
102    data.radius = radius_meters;
103
104    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
105    if (LOCATION_ERROR_SUCCESS != err) {
106        onAddGeofencesCb(1, &err, &geofence_id);
107    }
108}
109
110void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
111{
112    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
113    locAPIPauseGeofences(1, &geofence_id);
114}
115
116void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
117{
118    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
119    GeofenceBreachTypeMask mask = 0;
120    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
121        mask |= GEOFENCE_BREACH_ENTER_BIT;
122    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
123        mask |=  GEOFENCE_BREACH_EXIT_BIT;
124    locAPIResumeGeofences(1, &geofence_id, &mask);
125}
126
127void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
128{
129    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
130    locAPIRemoveGeofences(1, &geofence_id);
131}
132
133void GeofenceAPIClient::geofenceRemoveAll()
134{
135    LOC_LOGD("%s]", __FUNCTION__);
136    // TODO locAPIRemoveAllGeofences();
137}
138
139// callbacks
140void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
141{
142    LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
143    if (mGnssGeofencingCbIface != nullptr) {
144        for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
145            GnssLocation gnssLocation;
146            convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
147
148            IGnssGeofenceCallback::GeofenceTransition transition;
149            if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
150                transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
151            else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
152                transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
153            else {
154                // continue with other breach if transition is
155                // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
156                continue;
157            }
158
159            auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
160                    geofenceBreachNotification.ids[i], gnssLocation, transition,
161                    static_cast<GnssUtcTime>(geofenceBreachNotification.timestamp));
162            if (!r.isOk()) {
163                LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
164                    __func__, r.description().c_str());
165            }
166        }
167    }
168}
169
170void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
171{
172    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
173    if (mGnssGeofencingCbIface != nullptr) {
174        IGnssGeofenceCallback::GeofenceAvailability status =
175            IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
176        if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
177            status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
178        }
179        GnssLocation gnssLocation;
180        memset(&gnssLocation, 0, sizeof(GnssLocation));
181        auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
182        if (!r.isOk()) {
183            LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
184                __func__, r.description().c_str());
185        }
186    }
187}
188
189void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
190{
191    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
192    if (mGnssGeofencingCbIface != nullptr) {
193        for (size_t i = 0; i < count; i++) {
194            IGnssGeofenceCallback::GeofenceStatus status =
195                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
196            if (errors[i] == LOCATION_ERROR_SUCCESS)
197                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
198            else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
199                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
200            auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
201            if (!r.isOk()) {
202                LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
203                    __func__, r.description().c_str());
204            }
205        }
206    }
207}
208
209void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
210{
211    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
212    if (mGnssGeofencingCbIface != nullptr) {
213        for (size_t i = 0; i < count; i++) {
214            IGnssGeofenceCallback::GeofenceStatus status =
215                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
216            if (errors[i] == LOCATION_ERROR_SUCCESS)
217                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
218            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
219                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
220            auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
221            if (!r.isOk()) {
222                LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
223                    __func__, r.description().c_str());
224            }
225        }
226    }
227}
228
229void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
230{
231    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
232    if (mGnssGeofencingCbIface != nullptr) {
233        for (size_t i = 0; i < count; i++) {
234            IGnssGeofenceCallback::GeofenceStatus status =
235                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
236            if (errors[i] == LOCATION_ERROR_SUCCESS)
237                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
238            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
239                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
240            auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
241            if (!r.isOk()) {
242                LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
243                    __func__, r.description().c_str());
244            }
245        }
246    }
247}
248
249void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
250{
251    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
252    if (mGnssGeofencingCbIface != nullptr) {
253        for (size_t i = 0; i < count; i++) {
254            IGnssGeofenceCallback::GeofenceStatus status =
255                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
256            if (errors[i] == LOCATION_ERROR_SUCCESS)
257                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
258            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
259                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
260            auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
261            if (!r.isOk()) {
262                LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
263                    __func__, r.description().c_str());
264            }
265        }
266    }
267}
268
269}  // namespace implementation
270}  // namespace V1_0
271}  // namespace gnss
272}  // namespace hardware
273}  // namespace android
274