1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.compatibility.common.deviceinfo;
18 
19 import android.content.Context;
20 import android.location.GnssCapabilities;
21 import android.location.GnssMeasurement;
22 import android.location.GnssMeasurementsEvent;
23 import android.location.LocationManager;
24 import android.os.Build;
25 
26 import com.android.compatibility.common.util.DeviceInfoStore;
27 
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 
34 /**
35  * Gnss device info collector.
36  */
37 public final class GnssDeviceInfo extends DeviceInfo {
38 
39     private static final String LOG_TAG = "GnssDeviceInfo";
40     private static final String UNKNOWN_GNSS_NAME = "unknown";
41     private static final String NO_GNSS_HARDWARE = "no_gnss_hardware";
42     public static final int ADR_STATE_VALID = (1 << 0);
43 
44     @Override
collectDeviceInfo(DeviceInfoStore store)45     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
46         LocationManager locationManager =
47                 (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
48 
49         if (locationManager == null) {
50             store.addResult("gnss_hardware_model_name", UNKNOWN_GNSS_NAME);
51             return;
52         }
53         collectGnssHardwareModelName(store, locationManager);
54         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
55             collectGnssCapabilities(store, locationManager.getGnssCapabilities());
56         }
57         collectAccumulatedDeltaRangeMeasurements(store, locationManager);
58     }
59 
60     /**
61      * collect info for gnss hardware model name. If there is no GNSS hardware, the function stores
62      * "unknown". If there is no name available, the function stores "no_gnss_hardware".
63      */
collectGnssHardwareModelName( DeviceInfoStore store, LocationManager locationManager)64     private void collectGnssHardwareModelName(
65             DeviceInfoStore store, LocationManager locationManager) throws IOException {
66         if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
67             store.addResult("gnss_hardware_model_name", NO_GNSS_HARDWARE);
68             return;
69         }
70         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
71             return;
72         }
73         String gnssHardwareModelName = locationManager.getGnssHardwareModelName();
74         if (gnssHardwareModelName == null) {
75             store.addResult("gnss_hardware_model_name", UNKNOWN_GNSS_NAME);
76             return;
77         }
78         store.addResult("gnss_hardware_model_name", gnssHardwareModelName);
79     }
80 
81     /** collect info for gnss capabilities into a group */
collectGnssCapabilities(DeviceInfoStore store, GnssCapabilities gnssCapabilities)82     private void collectGnssCapabilities(DeviceInfoStore store, GnssCapabilities gnssCapabilities)
83             throws IOException {
84         store.startGroup("gnss_capabilities");
85 
86         store.addResult("has_low_power_mode", gnssCapabilities.hasLowPowerMode());
87         store.addResult("has_geofencing", gnssCapabilities.hasGeofencing());
88         store.addResult("has_measurements", gnssCapabilities.hasMeasurements());
89         store.addResult(
90                 "has_measurement_corrections", gnssCapabilities.hasMeasurementCorrections());
91         store.addResult(
92                 "has_measurement_corrections_los_sats",
93                 gnssCapabilities.hasMeasurementCorrectionsLosSats());
94         store.addResult(
95                 "has_measurement_corrections_excess_path_length",
96                 gnssCapabilities.hasMeasurementCorrectionsExcessPathLength());
97 
98         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
99             store.addResult("has_satellite_blocklist", gnssCapabilities.hasSatelliteBlacklist());
100             store.addResult("has_navigation_messages", gnssCapabilities.hasNavMessages());
101             store.addResult(
102                     "has_measurement_corrections_reflecting_plane",
103                     gnssCapabilities.hasMeasurementCorrectionsReflectingPane());
104         } else {
105             store.addResult("has_satellite_blocklist", gnssCapabilities.hasSatelliteBlocklist());
106             store.addResult("has_navigation_messages", gnssCapabilities.hasNavigationMessages());
107             store.addResult(
108                     "has_measurement_corrections_reflecting_plane",
109                     gnssCapabilities.hasMeasurementCorrectionsReflectingPlane());
110         }
111 
112         if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
113             store.addResult("has_antenna_info", gnssCapabilities.hasGnssAntennaInfo());
114         }
115 
116         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
117             store.addResult("has_antenna_info", gnssCapabilities.hasAntennaInfo());
118             store.addResult("has_satellite_pvt", gnssCapabilities.hasSatellitePvt());
119             store.addResult(
120                     "has_measurement_correlation_vectors",
121                     gnssCapabilities.hasMeasurementCorrelationVectors());
122             store.addResult(
123                     "has_measurement_corrections_for_driving",
124                     gnssCapabilities.hasMeasurementCorrectionsForDriving());
125         }
126         store.endGroup();
127     }
128 
129     /**
130      * Collect Accumulated Delta Range info:
131      * 1. Start measurement with 1s interval and wait for up to 10 measurement events.
132      * 2. Set as true if a measurement has a valid AccumulatedDeltaRange state, false otherwise
133      */
collectAccumulatedDeltaRangeMeasurements(DeviceInfoStore store, LocationManager locationManager)134     private void collectAccumulatedDeltaRangeMeasurements(DeviceInfoStore store,
135             LocationManager locationManager) throws InterruptedException, IOException {
136         final int gnssMeasurementsEventsToCollect = 10;
137         TestGnssMeasurementListener mMeasurementListener = new TestGnssMeasurementListener(
138                 gnssMeasurementsEventsToCollect);
139         locationManager.registerGnssMeasurementsCallback(mMeasurementListener);
140         mMeasurementListener.waitFor();
141         boolean hasAccumulatedDeltaRange = false;
142         for (GnssMeasurementsEvent event : mMeasurementListener.getEvents()) {
143             for (GnssMeasurement measurement : event.getMeasurements()) {
144                 if ((measurement.getAccumulatedDeltaRangeState() & ADR_STATE_VALID)
145                         == ADR_STATE_VALID) {
146                     hasAccumulatedDeltaRange = true;
147                     break;
148                 }
149                 if (hasAccumulatedDeltaRange) break;
150             }
151         }
152         locationManager.unregisterGnssMeasurementsCallback(mMeasurementListener);
153         store.addResult("has_valid_accumulated_delta_range", hasAccumulatedDeltaRange);
154     }
155 
156     private class TestGnssMeasurementListener extends GnssMeasurementsEvent.Callback {
157         public static final int MEAS_TIMEOUT_IN_SEC = 5;
158         private final List<GnssMeasurementsEvent> mMeasurementsEvents;
159         private final CountDownLatch mCountDownLatch;
160         private static final long STANDARD_WAIT_TIME_MS = 50;
161         private static final long STANDARD_SLEEP_TIME_MS = 50;
162 
163         /**
164          * Constructor for TestGnssMeasurementListener
165          *
166          * @param eventsToCollect wait until this number of events collected.
167          */
TestGnssMeasurementListener(int eventsToCollect)168         TestGnssMeasurementListener(int eventsToCollect) {
169             mCountDownLatch = new CountDownLatch(eventsToCollect);
170             mMeasurementsEvents = new ArrayList<>(eventsToCollect);
171         }
172 
173         @Override
onGnssMeasurementsReceived(GnssMeasurementsEvent event)174         public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) {
175             if (event.getMeasurements().size() > 0) {
176                 synchronized (mMeasurementsEvents) {
177                     mMeasurementsEvents.add(event);
178                 }
179                 mCountDownLatch.countDown();
180             }
181         }
182 
183         /**
184          * Get the current list of GPS Measurements Events.
185          *
186          * @return the current list of GPS Measurements Events
187          */
getEvents()188         public List<GnssMeasurementsEvent> getEvents() {
189             synchronized (mMeasurementsEvents) {
190                 List<GnssMeasurementsEvent> clone = new ArrayList<>();
191                 clone.addAll(mMeasurementsEvents);
192                 return clone;
193             }
194         }
195 
waitFor()196         public boolean waitFor() throws InterruptedException {
197             long waitTimeRounds = (TimeUnit.SECONDS.toMillis(MEAS_TIMEOUT_IN_SEC))
198                     / (STANDARD_WAIT_TIME_MS + STANDARD_SLEEP_TIME_MS);
199             for (int i = 0; i < waitTimeRounds; ++i) {
200                 Thread.sleep(STANDARD_SLEEP_TIME_MS);
201                 if (mCountDownLatch.await(STANDARD_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
202                     return true;
203                 }
204             }
205             return false;
206         }
207     }
208 }
209