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_GnssAPIClient"
32
33#include <log_util.h>
34#include <loc_cfg.h>
35
36#include "LocationUtil.h"
37#include "GnssAPIClient.h"
38
39namespace android {
40namespace hardware {
41namespace gnss {
42namespace V1_0 {
43namespace implementation {
44
45static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out);
46
47GnssAPIClient::GnssAPIClient(const sp<IGnssCallback>& gpsCb,
48    const sp<IGnssNiCallback>& niCb) :
49    LocationAPIClientBase(),
50    mGnssCbIface(nullptr),
51    mGnssNiCbIface(nullptr),
52    mLocationCapabilitiesMask(0),
53    mLocationCapabilitiesCached(false)
54{
55    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
56
57    // set default LocationOptions.
58    memset(&mLocationOptions, 0, sizeof(LocationOptions));
59    mLocationOptions.size = sizeof(LocationOptions);
60    mLocationOptions.minInterval = 1000;
61    mLocationOptions.minDistance = 0;
62    mLocationOptions.mode = GNSS_SUPL_MODE_STANDALONE;
63
64    gnssUpdateCallbacks(gpsCb, niCb);
65}
66
67GnssAPIClient::~GnssAPIClient()
68{
69    LOC_LOGD("%s]: ()", __FUNCTION__);
70}
71
72// for GpsInterface
73void GnssAPIClient::gnssUpdateCallbacks(const sp<IGnssCallback>& gpsCb,
74    const sp<IGnssNiCallback>& niCb)
75{
76    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
77
78    mGnssCbIface = gpsCb;
79    mGnssNiCbIface = niCb;
80
81    LocationCallbacks locationCallbacks;
82    locationCallbacks.size = sizeof(LocationCallbacks);
83
84    locationCallbacks.trackingCb = nullptr;
85    if (mGnssCbIface != nullptr) {
86        locationCallbacks.trackingCb = [this](Location location) {
87            onTrackingCb(location);
88        };
89    }
90
91    locationCallbacks.batchingCb = nullptr;
92    locationCallbacks.geofenceBreachCb = nullptr;
93    locationCallbacks.geofenceStatusCb = nullptr;
94    locationCallbacks.gnssLocationInfoCb = nullptr;
95
96    locationCallbacks.gnssNiCb = nullptr;
97    if (mGnssNiCbIface != nullptr) {
98        locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotification) {
99            onGnssNiCb(id, gnssNiNotification);
100        };
101    }
102
103    locationCallbacks.gnssSvCb = nullptr;
104    if (mGnssCbIface != nullptr) {
105        locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
106            onGnssSvCb(gnssSvNotification);
107        };
108    }
109
110    locationCallbacks.gnssNmeaCb = nullptr;
111    if (mGnssCbIface != nullptr) {
112        locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
113            onGnssNmeaCb(gnssNmeaNotification);
114        };
115    }
116
117    locationCallbacks.gnssMeasurementsCb = nullptr;
118
119    locAPISetCallbacks(locationCallbacks);
120}
121
122bool GnssAPIClient::gnssStart()
123{
124    LOC_LOGD("%s]: ()", __FUNCTION__);
125    bool retVal = true;
126    locAPIStartTracking(mLocationOptions);
127    return retVal;
128}
129
130bool GnssAPIClient::gnssStop()
131{
132    LOC_LOGD("%s]: ()", __FUNCTION__);
133    bool retVal = true;
134    locAPIStopTracking();
135    return retVal;
136}
137
138void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
139{
140    LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
141    GnssAidingData data;
142    memset(&data, 0, sizeof (GnssAidingData));
143    data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
144        GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
145        GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
146        GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
147        GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
148
149    if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
150        data.deleteAll = true;
151    else {
152        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
153            data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
154        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
155            data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
156        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
157            data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
158        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
159            data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
160        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
161            data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
162        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
163            data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
164        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
165            data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
166        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
167            data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
168        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
169            data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
170        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
171            data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
172        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
173            data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
174        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
175            data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
176    }
177    locAPIGnssDeleteAidingData(data);
178}
179
180bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
181        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
182        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs)
183{
184    LOC_LOGD("%s]: (%d %d %d %d %d)", __FUNCTION__,
185            (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters, preferredTimeMs);
186    bool retVal = true;
187    memset(&mLocationOptions, 0, sizeof(LocationOptions));
188    mLocationOptions.size = sizeof(LocationOptions);
189    mLocationOptions.minInterval = minIntervalMs;
190    mLocationOptions.minDistance = preferredAccuracyMeters;
191    if (mode == IGnss::GnssPositionMode::STANDALONE)
192        mLocationOptions.mode = GNSS_SUPL_MODE_STANDALONE;
193    else if (mode == IGnss::GnssPositionMode::MS_BASED)
194        mLocationOptions.mode = GNSS_SUPL_MODE_MSB;
195    else if (mode ==  IGnss::GnssPositionMode::MS_ASSISTED)
196        mLocationOptions.mode = GNSS_SUPL_MODE_MSA;
197    locAPIUpdateTrackingOptions(mLocationOptions);
198    return retVal;
199}
200
201// for GpsNiInterface
202void GnssAPIClient::gnssNiRespond(int32_t notifId,
203        IGnssNiCallback::GnssUserResponseType userResponse)
204{
205    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
206    GnssNiResponse data = GNSS_NI_RESPONSE_IGNORE;
207    if (userResponse == IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT)
208        data = GNSS_NI_RESPONSE_ACCEPT;
209    else if (userResponse == IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY)
210        data = GNSS_NI_RESPONSE_DENY;
211    else if (userResponse == IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP)
212        data = GNSS_NI_RESPONSE_NO_RESPONSE;
213    locAPIGnssNiResponse(notifId, data);
214}
215
216// for GnssConfigurationInterface
217void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
218{
219    LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
220    locAPIGnssUpdateConfig(gnssConfig);
221}
222
223void GnssAPIClient::requestCapabilities() {
224    // only send capablities if it's already cached, otherwise the first time LocationAPI
225    // is initialized, capabilities will be sent by LocationAPI
226    if (mLocationCapabilitiesCached) {
227        onCapabilitiesCb(mLocationCapabilitiesMask);
228    }
229}
230
231// callbacks
232void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
233{
234    LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
235    mLocationCapabilitiesMask = capabilitiesMask;
236    mLocationCapabilitiesCached = true;
237    if (mGnssCbIface != nullptr) {
238        uint32_t data = 0;
239        if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
240                (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
241                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
242                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
243            data |= IGnssCallback::Capabilities::SCHEDULING;
244        if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
245            data |= IGnssCallback::Capabilities::GEOFENCING;
246        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
247            data |= IGnssCallback::Capabilities::MEASUREMENTS;
248        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
249            data |= IGnssCallback::Capabilities::MSB;
250        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
251            data |= IGnssCallback::Capabilities::MSA;
252        auto r = mGnssCbIface->gnssSetCapabilitesCb(data);
253        if (!r.isOk()) {
254            LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
255                __func__, r.description().c_str());
256        }
257    }
258    if (mGnssCbIface != nullptr) {
259        IGnssCallback::GnssSystemInfo gnssInfo;
260        gnssInfo.yearOfHw = 2015;
261        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
262            gnssInfo.yearOfHw = 2017;
263        }
264        LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
265        auto r = mGnssCbIface->gnssSetSystemInfoCb(gnssInfo);
266        if (!r.isOk()) {
267            LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
268                __func__, r.description().c_str());
269        }
270    }
271}
272
273void GnssAPIClient::onTrackingCb(Location location)
274{
275    LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
276    if (mGnssCbIface != nullptr) {
277        GnssLocation gnssLocation;
278        convertGnssLocation(location, gnssLocation);
279        auto r = mGnssCbIface->gnssLocationCb(gnssLocation);
280        if (!r.isOk()) {
281            LOC_LOGE("%s] Error from gnssLocationCb description=%s",
282                __func__, r.description().c_str());
283        }
284    }
285}
286
287void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
288{
289    LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
290
291    if (mGnssNiCbIface == nullptr) {
292        LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
293        return;
294    }
295
296    IGnssNiCallback::GnssNiNotification notificationGnss = {};
297
298    notificationGnss.notificationId = id;
299
300    if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
301        notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
302    else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
303        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
304    else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
305        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
306    else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
307        notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
308
309    if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
310        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
311    if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
312        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
313    if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
314        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
315
316    notificationGnss.timeoutSec = gnssNiNotification.timeout;
317
318    if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
319        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
320    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
321        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
322    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
323            gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
324        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
325
326    notificationGnss.requestorId = gnssNiNotification.requestor;
327
328    notificationGnss.notificationMessage = gnssNiNotification.message;
329
330    if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
331        notificationGnss.requestorIdEncoding =
332            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
333    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
334        notificationGnss.requestorIdEncoding =
335            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
336    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
337        notificationGnss.requestorIdEncoding =
338            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
339    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
340        notificationGnss.requestorIdEncoding =
341            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
342
343    if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
344        notificationGnss.notificationIdEncoding =
345            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
346    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
347        notificationGnss.notificationIdEncoding =
348            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
349    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
350        notificationGnss.notificationIdEncoding =
351            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
352    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
353        notificationGnss.notificationIdEncoding =
354            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
355
356    mGnssNiCbIface->niNotifyCb(notificationGnss);
357}
358
359void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
360{
361    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
362    if (mGnssCbIface != nullptr) {
363        IGnssCallback::GnssSvStatus svStatus;
364        convertGnssSvStatus(gnssSvNotification, svStatus);
365        auto r = mGnssCbIface->gnssSvStatusCb(svStatus);
366        if (!r.isOk()) {
367            LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
368                __func__, r.description().c_str());
369        }
370    }
371}
372
373void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
374{
375    if (mGnssCbIface != nullptr) {
376        android::hardware::hidl_string nmeaString;
377        nmeaString.setToExternal(gnssNmeaNotification.nmea, gnssNmeaNotification.length);
378        auto r = mGnssCbIface->gnssNmeaCb(
379            static_cast<GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
380        if (!r.isOk()) {
381            LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%u description=%s", __func__,
382                gnssNmeaNotification.nmea, gnssNmeaNotification.length, r.description().c_str());
383        }
384    }
385}
386
387void GnssAPIClient::onStartTrackingCb(LocationError error)
388{
389    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
390    if (error == LOCATION_ERROR_SUCCESS && mGnssCbIface != nullptr) {
391        auto r = mGnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
392        if (!r.isOk()) {
393            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
394                __func__, r.description().c_str());
395        }
396        r = mGnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
397        if (!r.isOk()) {
398            LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
399                __func__, r.description().c_str());
400        }
401    }
402}
403
404void GnssAPIClient::onStopTrackingCb(LocationError error)
405{
406    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
407    if (error == LOCATION_ERROR_SUCCESS && mGnssCbIface != nullptr) {
408        auto r = mGnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
409        if (!r.isOk()) {
410            LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
411                __func__, r.description().c_str());
412        }
413        r = mGnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
414        if (!r.isOk()) {
415            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
416                __func__, r.description().c_str());
417        }
418    }
419}
420
421static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out)
422{
423    memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
424    out.numSvs = in.count;
425    if (out.numSvs > static_cast<uint32_t>(GnssMax::SVS_COUNT)) {
426        LOC_LOGW("%s]: Too many satellites %zd. Clamps to %d.",
427                __FUNCTION__,  out.numSvs, GnssMax::SVS_COUNT);
428        out.numSvs = static_cast<uint32_t>(GnssMax::SVS_COUNT);
429    }
430    for (size_t i = 0; i < out.numSvs; i++) {
431        IGnssCallback::GnssSvInfo& info = out.gnssSvList[i];
432        info.svid = in.gnssSvs[i].svId;
433        convertGnssConstellationType(in.gnssSvs[i].type, info.constellation);
434        info.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
435        info.elevationDegrees = in.gnssSvs[i].elevation;
436        info.azimuthDegrees = in.gnssSvs[i].azimuth;
437        info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
438        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
439            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
440        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
441            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
442        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
443            info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
444    }
445}
446
447}  // namespace implementation
448}  // namespace V1_0
449}  // namespace gnss
450}  // namespace hardware
451}  // namespace android
452