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