• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 android.location.cts.fine;
18 
19 import static android.Manifest.permission.LOCATION_BYPASS;
20 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
21 import static android.app.AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION;
22 import static android.app.AppOpsManager.OPSTR_MONITOR_LOCATION;
23 import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
24 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
25 import static android.content.pm.PackageManager.FEATURE_WATCH;
26 import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
27 import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
28 import static android.location.LocationManager.FUSED_PROVIDER;
29 import static android.location.LocationManager.GPS_PROVIDER;
30 import static android.location.LocationManager.NETWORK_PROVIDER;
31 import static android.location.LocationManager.PASSIVE_PROVIDER;
32 import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
33 import static android.location.LocationRequest.PASSIVE_INTERVAL;
34 import static android.location.LocationRequest.QUALITY_HIGH_ACCURACY;
35 import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
36 import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
37 import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
38 
39 import static androidx.test.ext.truth.content.IntentSubject.assertThat;
40 import static androidx.test.ext.truth.location.LocationSubject.assertThat;
41 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
42 
43 import static com.android.compatibility.common.util.LocationUtils.createLocation;
44 
45 import static com.google.common.truth.Truth.assertThat;
46 
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertTrue;
49 import static org.junit.Assert.fail;
50 import static org.junit.Assume.assumeFalse;
51 import static org.junit.Assume.assumeTrue;
52 
53 import android.Manifest;
54 import android.annotation.NonNull;
55 import android.app.AppOpsManager;
56 import android.app.PendingIntent;
57 import android.app.UiAutomation;
58 import android.content.Context;
59 import android.content.Intent;
60 import android.location.Criteria;
61 import android.location.GnssMeasurementsEvent;
62 import android.location.GnssNavigationMessage;
63 import android.location.GnssStatus;
64 import android.location.LastLocationRequest;
65 import android.location.Location;
66 import android.location.LocationListener;
67 import android.location.LocationManager;
68 import android.location.LocationProvider;
69 import android.location.LocationRequest;
70 import android.location.OnNmeaMessageListener;
71 import android.location.cts.common.BroadcastCapture;
72 import android.location.cts.common.GetCurrentLocationCapture;
73 import android.location.cts.common.LocationListenerCapture;
74 import android.location.cts.common.LocationPendingIntentCapture;
75 import android.location.cts.common.OpActiveChangedCapture;
76 import android.location.cts.common.ProviderRequestChangedListenerCapture;
77 import android.location.cts.common.gnss.GnssAntennaInfoCapture;
78 import android.location.cts.common.gnss.GnssMeasurementsCapture;
79 import android.location.cts.common.gnss.GnssNavigationMessageCapture;
80 import android.location.provider.ProviderProperties;
81 import android.os.Build;
82 import android.os.HandlerThread;
83 import android.os.Looper;
84 import android.os.PowerManager;
85 import android.os.SystemClock;
86 import android.os.SystemProperties;
87 import android.platform.test.annotations.AppModeFull;
88 import android.provider.DeviceConfig;
89 import android.util.ArraySet;
90 import android.util.Log;
91 
92 import androidx.test.core.app.ApplicationProvider;
93 import androidx.test.ext.junit.runners.AndroidJUnit4;
94 import androidx.test.platform.app.InstrumentationRegistry;
95 
96 import com.android.compatibility.common.util.BatteryUtils;
97 import com.android.compatibility.common.util.DeviceConfigStateHelper;
98 import com.android.compatibility.common.util.LocationUtils;
99 import com.android.compatibility.common.util.ScreenUtils;
100 import com.android.compatibility.common.util.ScreenUtils.ScreenResetter;
101 
102 import org.junit.After;
103 import org.junit.Before;
104 import org.junit.Ignore;
105 import org.junit.Test;
106 import org.junit.runner.RunWith;
107 
108 import java.util.Collections;
109 import java.util.HashSet;
110 import java.util.List;
111 import java.util.Objects;
112 import java.util.Random;
113 import java.util.concurrent.Executors;
114 
115 @RunWith(AndroidJUnit4.class)
116 public class LocationManagerFineTest {
117 
118     private static final String TAG = "LocationManagerFineTest";
119 
120     private static final long TIMEOUT_MS = 5000;
121     private static final long FAILURE_TIMEOUT_MS = 200;
122 
123     private static final String TEST_PROVIDER = "test_provider";
124 
125     private static final String VALID_LOCATION_ATTRIBUTION_TAG = "valid_location_attribution_tag";
126     private static final String ANOTHER_VALID_LOCATION_ATTRIBUTION_TAG =
127             "another_valid_location_attribution_tag";
128     private static final String INVALID_LOCATION_ATTRIBUTION_TAG =
129             "invalid_location_attribution_tag";
130 
131     private static final String IGNORE_SETTINGS_ALLOWLIST = "ignore_settings_allowlist";
132     private static final String ADAS_SETTINGS_ALLOWLIST = "adas_settings_allowlist";
133 
134     private Random mRandom;
135     private Context mContext;
136     private LocationManager mManager;
137 
138     @Before
setUp()139     public void setUp() throws Exception {
140         LocationUtils.registerMockLocationProvider(getInstrumentation(),
141                 true);
142 
143         long seed = System.currentTimeMillis();
144         Log.i(TAG, "location random seed: " + seed);
145 
146         mRandom = new Random(seed);
147         mContext = ApplicationProvider.getApplicationContext();
148         mManager = Objects.requireNonNull(mContext.getSystemService(LocationManager.class));
149 
150         for (String provider : mManager.getAllProviders()) {
151             mManager.removeTestProvider(provider);
152         }
153 
154         mManager.addTestProvider(TEST_PROVIDER,
155                 new ProviderProperties.Builder()
156                         .setHasNetworkRequirement(true)
157                         .setHasCellRequirement(true)
158                         .setPowerUsage(ProviderProperties.POWER_USAGE_HIGH)
159                         .setAccuracy(ProviderProperties.ACCURACY_FINE).build());
160         mManager.setTestProviderEnabled(TEST_PROVIDER, true);
161     }
162 
163     @After
tearDown()164     public void tearDown() throws Exception {
165         if (mManager != null) {
166             for (String provider : mManager.getAllProviders()) {
167                 mManager.removeTestProvider(provider);
168             }
169             mManager.removeTestProvider(FUSED_PROVIDER);
170         }
171 
172         LocationUtils.registerMockLocationProvider(getInstrumentation(),
173                 false);
174     }
175 
176     @Test
testIsLocationEnabled()177     public void testIsLocationEnabled() {
178         assertThat(mManager.isLocationEnabled()).isTrue();
179     }
180 
181     @Test
testIsProviderEnabled()182     public void testIsProviderEnabled() {
183         assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isTrue();
184 
185         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
186         assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isFalse();
187 
188         mManager.setTestProviderEnabled(TEST_PROVIDER, true);
189         assertThat(mManager.isProviderEnabled(TEST_PROVIDER)).isTrue();
190 
191         for (String provider : mManager.getAllProviders()) {
192             mManager.isProviderEnabled(provider);
193         }
194 
195         try {
196             mManager.isProviderEnabled(null);
197             fail("Should throw IllegalArgumentException if provider is null!");
198         } catch (IllegalArgumentException e) {
199             // expected
200         }
201     }
202 
203     @Test
testGetLastKnownLocation()204     public void testGetLastKnownLocation() {
205         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
206         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
207 
208         mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
209         assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isEqualTo(loc1);
210 
211         mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
212         assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isEqualTo(loc2);
213 
214         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
215         assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isNull();
216 
217         try {
218             mManager.getLastKnownLocation(null);
219             fail("Should throw IllegalArgumentException if provider is null!");
220         } catch (IllegalArgumentException e) {
221             // expected
222         }
223     }
224 
225     @Test
testGetLastKnownLocation_AdasLocationSettings_ReturnsLocation()226     public void testGetLastKnownLocation_AdasLocationSettings_ReturnsLocation() throws Exception {
227         assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
228 
229         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
230              DeviceConfigStateHelper locationDeviceConfigStateHelper =
231                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_LOCATION)) {
232 
233             locationDeviceConfigStateHelper.set(ADAS_SETTINGS_ALLOWLIST,
234                     mContext.getPackageName());
235 
236             mManager.addTestProvider(
237                     GPS_PROVIDER,
238                     false,
239                     true,
240                     false,
241                     false,
242                     true,
243                     true,
244                     true,
245                     Criteria.POWER_HIGH,
246                     Criteria.ACCURACY_FINE);
247 
248             Location loc = createLocation(GPS_PROVIDER, mRandom);
249             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
250 
251             mManager.setTestProviderEnabled(GPS_PROVIDER, true);
252 
253             getInstrumentation()
254                     .getUiAutomation()
255                     .adoptShellPermissionIdentity(LOCATION_BYPASS, WRITE_SECURE_SETTINGS);
256 
257             try {
258                 // Returns loc when ADAS toggle is on.
259                 mManager.setLocationEnabledForUser(false, mContext.getUser());
260                 mManager.setAdasGnssLocationEnabled(true);
261                 assertThat(
262                         mManager.getLastKnownLocation(
263                                 GPS_PROVIDER,
264                                 new LastLocationRequest.Builder()
265                                         .setAdasGnssBypass(true)
266                                         .build()))
267                         .isEqualTo(loc);
268 
269             } finally {
270                 mManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
271                 getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
272             }
273         }
274     }
275 
276     @Test
testGetLastKnownLocation_AdasLocationSettings_ReturnsNull()277     public void testGetLastKnownLocation_AdasLocationSettings_ReturnsNull() throws Exception {
278         assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
279 
280         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
281              DeviceConfigStateHelper locationDeviceConfigStateHelper =
282                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_LOCATION)) {
283 
284             locationDeviceConfigStateHelper.set(ADAS_SETTINGS_ALLOWLIST,
285                     mContext.getPackageName());
286 
287             mManager.addTestProvider(
288                     GPS_PROVIDER,
289                     false,
290                     true,
291                     false,
292                     false,
293                     true,
294                     true,
295                     true,
296                     Criteria.POWER_HIGH,
297                     Criteria.ACCURACY_FINE);
298 
299             Location loc = createLocation(GPS_PROVIDER, mRandom);
300             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
301 
302             mManager.setTestProviderEnabled(GPS_PROVIDER, true);
303 
304             getInstrumentation()
305                     .getUiAutomation()
306                     .adoptShellPermissionIdentity(LOCATION_BYPASS, WRITE_SECURE_SETTINGS);
307 
308             try {
309                 // Returns null when ADAS toggle is off
310                 mManager.setAdasGnssLocationEnabled(false);
311                 mManager.setLocationEnabledForUser(false, mContext.getUser());
312 
313                 assertThat(
314                         mManager.getLastKnownLocation(
315                                 GPS_PROVIDER,
316                                 new LastLocationRequest.Builder()
317                                         .setAdasGnssBypass(true)
318                                         .build()))
319                         .isNull();
320 
321             } finally {
322                 mManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
323                 mManager.setAdasGnssLocationEnabled(true);
324                 getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
325             }
326         }
327     }
328 
329     @Test
testGetLastKnownLocation_RemoveProvider()330     public void testGetLastKnownLocation_RemoveProvider() {
331         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
332 
333         mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
334         mManager.removeTestProvider(TEST_PROVIDER);
335         assertThat(mManager.getLastKnownLocation(TEST_PROVIDER)).isNull();
336     }
337 
338     @Test
testGetCurrentLocation()339     public void testGetCurrentLocation() throws Exception {
340         Location loc = createLocation(TEST_PROVIDER, mRandom);
341 
342         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
343             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
344                     Executors.newSingleThreadExecutor(), capture);
345             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
346             assertThat(capture.getLocation(TIMEOUT_MS)).isEqualTo(loc);
347         }
348 
349         try {
350             mManager.getCurrentLocation((String) null, null, Executors.newSingleThreadExecutor(),
351                     (location) -> {});
352             fail("Should throw IllegalArgumentException if provider is null!");
353         } catch (IllegalArgumentException e) {
354             // expected
355         }
356     }
357 
358     @Test
testGetCurrentLocation_Timeout()359     public void testGetCurrentLocation_Timeout() throws Exception {
360         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
361             mManager.getCurrentLocation(
362                     TEST_PROVIDER,
363                     new LocationRequest.Builder(0).setDurationMillis(500).build(),
364                     capture.getCancellationSignal(),
365                     Executors.newSingleThreadExecutor(),
366                     capture);
367             assertThat(capture.getLocation(1000)).isNull();
368         }
369 
370         try {
371             mManager.getCurrentLocation((String) null, null, Executors.newSingleThreadExecutor(),
372                     (location) -> {});
373             fail("Should throw IllegalArgumentException if provider is null!");
374         } catch (IllegalArgumentException e) {
375             // expected
376         }
377     }
378 
379     @Test
testGetCurrentLocation_FreshOldLocation()380     public void testGetCurrentLocation_FreshOldLocation() throws Exception {
381         Location loc = createLocation(TEST_PROVIDER, mRandom);
382 
383         mManager.setTestProviderLocation(TEST_PROVIDER, loc);
384         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
385             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
386                     Executors.newSingleThreadExecutor(), capture);
387             assertThat(capture.getLocation(TIMEOUT_MS)).isEqualTo(loc);
388         }
389     }
390 
391     @Test
testGetCurrentLocation_DirectExecutor()392     public void testGetCurrentLocation_DirectExecutor() throws Exception {
393         Location loc = createLocation(TEST_PROVIDER, mRandom);
394 
395         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
396             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
397                     Runnable::run, capture);
398             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
399             assertThat(capture.getLocation(TIMEOUT_MS)).isEqualTo(loc);
400         }
401     }
402 
403     @Test
testGetCurrentLocation_Cancellation()404     public void testGetCurrentLocation_Cancellation() throws Exception {
405         Location loc = createLocation(TEST_PROVIDER, mRandom);
406 
407         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
408             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
409                     Executors.newSingleThreadExecutor(), capture);
410             capture.getCancellationSignal().cancel();
411             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
412             assertThat(capture.hasLocation(FAILURE_TIMEOUT_MS)).isFalse();
413         }
414     }
415 
416     @Test
testGetCurrentLocation_ProviderDisabled()417     public void testGetCurrentLocation_ProviderDisabled() throws Exception {
418         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
419             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
420             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
421                     Executors.newSingleThreadExecutor(), capture);
422             assertThat(capture.getLocation(FAILURE_TIMEOUT_MS)).isNull();
423         }
424 
425         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
426             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
427                     Executors.newSingleThreadExecutor(), capture);
428             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
429             assertThat(capture.getLocation(FAILURE_TIMEOUT_MS)).isNull();
430         }
431     }
432 
433     @Test
testRequestLocationUpdates()434     public void testRequestLocationUpdates() throws Exception {
435         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
436         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
437 
438         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
439             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
440                     Executors.newSingleThreadExecutor(), capture);
441 
442             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
443             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
444             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
445             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
446             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
447             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.FALSE);
448             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
449             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.TRUE);
450 
451             mManager.removeUpdates(capture);
452 
453             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
454             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
455             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
456             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
457             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
458             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
459         }
460 
461         try {
462             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, null, Looper.getMainLooper());
463             fail("Should throw IllegalArgumentException if listener is null!");
464         } catch (IllegalArgumentException e) {
465             // expected
466         }
467 
468         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
469             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, null, capture);
470             fail("Should throw IllegalArgumentException if executor is null!");
471         } catch (IllegalArgumentException e) {
472             // expected
473         }
474 
475         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
476             mManager.requestLocationUpdates(null, 0, 0, capture, Looper.getMainLooper());
477             fail("Should throw IllegalArgumentException if provider is null!");
478         } catch (IllegalArgumentException e) {
479             // expected
480         }
481 
482         try {
483             mManager.removeUpdates((LocationListener) null);
484             fail("Should throw IllegalArgumentException if listener is null!");
485         } catch (IllegalArgumentException e) {
486             // expected
487         }
488     }
489 
490     @Test
testRequestLocationUpdates_Passive()491     public void testRequestLocationUpdates_Passive() throws Exception {
492         Location loc = createLocation(TEST_PROVIDER, mRandom);
493 
494         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
495             mManager.requestLocationUpdates(
496                     TEST_PROVIDER,
497                     new LocationRequest.Builder(PASSIVE_INTERVAL)
498                             .setMinUpdateIntervalMillis(0)
499                             .build(),
500                     Runnable::run,
501                     capture);
502             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
503             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
504         }
505     }
506 
507     @Test
testRequestLocationUpdates_PendingIntent()508     public void testRequestLocationUpdates_PendingIntent() throws Exception {
509         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
510         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
511 
512         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
513             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
514 
515             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
516             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
517             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
518             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
519             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
520             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.FALSE);
521             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
522             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.TRUE);
523 
524             mManager.removeUpdates(capture.getPendingIntent());
525 
526             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
527             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
528             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
529             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
530             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
531             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
532         }
533 
534         try {
535             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, (PendingIntent) null);
536             fail("Should throw IllegalArgumentException if pending intent is null!");
537         } catch (IllegalArgumentException e) {
538             // expected
539         }
540 
541         PendingIntent immutablePI = PendingIntent.getBroadcast(mContext, 0,
542                 new Intent("IMMUTABLE_TEST_ACTION")
543                         .setPackage(mContext.getPackageName())
544                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
545                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
546         try {
547             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, immutablePI);
548             fail("Should throw IllegalArgumentException if pending intent is immutable!");
549         } catch (IllegalArgumentException e) {
550             // expected
551         } finally {
552             immutablePI.cancel();
553         }
554 
555         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
556             mManager.requestLocationUpdates(null, 0, 0, capture.getPendingIntent());
557             fail("Should throw IllegalArgumentException if provider is null!");
558         } catch (IllegalArgumentException e) {
559             // expected
560         }
561 
562         try {
563             mManager.removeUpdates((PendingIntent) null);
564             fail("Should throw IllegalArgumentException if pending intent is null!");
565         } catch (IllegalArgumentException e) {
566             // expected
567         }
568     }
569 
570     @Test
testRequestLocationUpdates_DirectExecutor()571     public void testRequestLocationUpdates_DirectExecutor() throws Exception {
572         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
573         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
574 
575         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
576             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Runnable::run, capture);
577 
578             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
579             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
580             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
581             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
582             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
583             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.FALSE);
584             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
585             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.TRUE);
586         }
587     }
588 
589     @Test
testRequestLocationUpdates_Looper()590     public void testRequestLocationUpdates_Looper() throws Exception {
591         HandlerThread thread = new HandlerThread("locationTestThread");
592         thread.start();
593         Looper looper = thread.getLooper();
594         try {
595 
596             Location loc1 = createLocation(TEST_PROVIDER, mRandom);
597             Location loc2 = createLocation(TEST_PROVIDER, mRandom);
598 
599             try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
600                 mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture, looper);
601 
602                 mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
603                 assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
604                 mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
605                 assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
606                 mManager.setTestProviderEnabled(TEST_PROVIDER, false);
607                 assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.FALSE);
608                 mManager.setTestProviderEnabled(TEST_PROVIDER, true);
609                 assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.TRUE);
610             }
611 
612         } finally {
613             looper.quit();
614         }
615     }
616 
617     @Test
testRequestLocationUpdates_Criteria()618     public void testRequestLocationUpdates_Criteria() throws Exception {
619         // criteria API will always use the fused provider...
620         mManager.addTestProvider(FUSED_PROVIDER,
621                 false,
622                 false,
623                 false,
624                 false,
625                 true,
626                 true,
627                 true,
628                 Criteria.POWER_LOW,
629                 Criteria.ACCURACY_FINE);
630         mManager.setTestProviderEnabled(FUSED_PROVIDER, true);
631 
632         Criteria criteria = new Criteria();
633         criteria.setAccuracy(Criteria.ACCURACY_FINE);
634         criteria.setPowerRequirement(Criteria.POWER_LOW);
635 
636         Location loc1 = createLocation(FUSED_PROVIDER, mRandom);
637         Location loc2 = createLocation(FUSED_PROVIDER, mRandom);
638 
639         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
640             mManager.requestLocationUpdates(0, 0, criteria, Executors.newSingleThreadExecutor(), capture);
641 
642             mManager.setTestProviderLocation(FUSED_PROVIDER, loc1);
643             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
644             mManager.setTestProviderLocation(FUSED_PROVIDER, loc2);
645             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
646             mManager.setTestProviderEnabled(FUSED_PROVIDER, false);
647             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.FALSE);
648             mManager.setTestProviderEnabled(FUSED_PROVIDER, true);
649             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(Boolean.TRUE);
650 
651             mManager.removeUpdates(capture);
652 
653             mManager.setTestProviderLocation(FUSED_PROVIDER, loc1);
654             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
655             mManager.setTestProviderEnabled(FUSED_PROVIDER, false);
656             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
657             mManager.setTestProviderEnabled(FUSED_PROVIDER, true);
658             assertThat(capture.getNextProviderChange(FAILURE_TIMEOUT_MS)).isNull();
659         }
660 
661 
662         try {
663             mManager.requestLocationUpdates(0, 0, criteria, null, Looper.getMainLooper());
664             fail("Should throw IllegalArgumentException if listener is null!");
665         } catch (IllegalArgumentException e) {
666             // expected
667         }
668 
669         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
670             mManager.requestLocationUpdates(0, 0, criteria, null, capture);
671             fail("Should throw IllegalArgumentException if executor is null!");
672         } catch (IllegalArgumentException e) {
673             // expected
674         }
675 
676         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
677             mManager.requestLocationUpdates(0, 0, null, Executors.newSingleThreadExecutor(), capture);
678             fail("Should throw IllegalArgumentException if criteria is null!");
679         } catch (IllegalArgumentException e) {
680             // expected
681         }
682     }
683 
684     @Test
testRequestLocationUpdates_ReplaceRequest()685     public void testRequestLocationUpdates_ReplaceRequest() throws Exception {
686         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
687         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
688 
689         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
690             mManager.requestLocationUpdates(TEST_PROVIDER, 1000, 1000, (runnable) -> {}, capture);
691             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Executors.newSingleThreadExecutor(), capture);
692 
693             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
694             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
695             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
696             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc2);
697         }
698     }
699 
700     @Test
testRequestLocationUpdates_NumUpdates()701     public void testRequestLocationUpdates_NumUpdates() throws Exception {
702         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
703         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
704 
705         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
706             mManager.requestLocationUpdates(
707                     TEST_PROVIDER,
708                     new LocationRequest.Builder(0).setMaxUpdates(1).build(),
709                     Executors.newSingleThreadExecutor(),
710                     capture);
711 
712             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
713             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
714             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
715             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
716         }
717     }
718 
719     @Test
testRequestLocationUpdates_MinUpdateInterval()720     public void testRequestLocationUpdates_MinUpdateInterval() throws Exception {
721         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
722         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
723 
724         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
725             mManager.requestLocationUpdates(
726                     TEST_PROVIDER,
727                     new LocationRequest.Builder(5000).build(),
728                     Executors.newSingleThreadExecutor(),
729                     capture);
730 
731             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
732             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
733             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
734             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
735         }
736     }
737 
738     @Test
testRequestLocationUpdates_MinUpdateDistance()739     public void testRequestLocationUpdates_MinUpdateDistance() throws Exception {
740         Location loc1 = createLocation(TEST_PROVIDER, 0, 0, 10);
741         Location loc2 = createLocation(TEST_PROVIDER, 0, 1, 10);
742 
743         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
744             mManager.requestLocationUpdates(
745                     TEST_PROVIDER,
746                     new LocationRequest.Builder(0).setMinUpdateDistanceMeters(200000).build(),
747                     Executors.newSingleThreadExecutor(),
748                     capture);
749 
750             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
751             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
752             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
753             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
754         }
755     }
756 
757     @Test
758     @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
testRequestLocationUpdates_BatterySaver_GpsDisabledScreenOff()759     public void testRequestLocationUpdates_BatterySaver_GpsDisabledScreenOff() throws Exception {
760         // battery saver is unsupported on auto, tv and watch
761         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
762         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
763         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
764         assumeTrue(BatteryUtils.isBatterySaverSupported());
765 
766         PowerManager powerManager = Objects.requireNonNull(
767                 mContext.getSystemService(PowerManager.class));
768 
769         mManager.addTestProvider(GPS_PROVIDER,
770                 false,
771                 true,
772                 false,
773                 false,
774                 true,
775                 true,
776                 true,
777                 Criteria.POWER_HIGH,
778                 Criteria.ACCURACY_FINE);
779         mManager.setTestProviderEnabled(GPS_PROVIDER, true);
780 
781         LocationRequest request = new LocationRequest.Builder(0).build();
782 
783         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
784              ScreenResetter ignored = new ScreenResetter();
785              DeviceConfigStateHelper batterySaverDeviceConfigStateHelper =
786                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_BATTERY_SAVER)) {
787             mManager.requestLocationUpdates(GPS_PROVIDER, request,
788                     Executors.newSingleThreadExecutor(), capture);
789             mManager.requestLocationUpdates(TEST_PROVIDER, request,
790                     Executors.newSingleThreadExecutor(), capture);
791 
792             batterySaverDeviceConfigStateHelper.set("location_mode", "1");
793             BatteryUtils.runDumpsysBatteryUnplug();
794             BatteryUtils.enableBatterySaver(true);
795             assertThat(powerManager.getLocationPowerSaveMode()).isEqualTo(
796                     LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF);
797 
798             // check screen off behavior
799             ScreenUtils.setScreenOn(false);
800             assertFalse(powerManager.isInteractive());
801             Location loc = createLocation(TEST_PROVIDER, mRandom);
802             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
803             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
804             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
805             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
806 
807             // check screen on behavior
808             ScreenUtils.setScreenOn(true);
809             assertTrue(powerManager.isInteractive());
810             loc = createLocation(TEST_PROVIDER, mRandom);
811             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
812             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
813             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
814             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
815         } finally {
816             BatteryUtils.enableBatterySaver(false);
817             BatteryUtils.runDumpsysBatteryReset();
818         }
819     }
820 
821     @Test
822     @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
testRequestLocationUpdates_BatterySaver_AllDisabledScreenOff()823     public void testRequestLocationUpdates_BatterySaver_AllDisabledScreenOff() throws Exception {
824         // battery saver is unsupported on auto, tv and watch
825         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
826         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
827         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
828         assumeTrue(BatteryUtils.isBatterySaverSupported());
829 
830         PowerManager powerManager = Objects.requireNonNull(
831                 mContext.getSystemService(PowerManager.class));
832 
833         LocationRequest request = new LocationRequest.Builder(0).build();
834 
835         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
836              ScreenResetter ignored = new ScreenResetter();
837              DeviceConfigStateHelper batterySaverDeviceConfigStateHelper =
838                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_BATTERY_SAVER)) {
839             mManager.requestLocationUpdates(TEST_PROVIDER, request,
840                     Executors.newSingleThreadExecutor(), capture);
841 
842             batterySaverDeviceConfigStateHelper.set("location_mode", "2");
843             BatteryUtils.runDumpsysBatteryUnplug();
844             BatteryUtils.enableBatterySaver(true);
845             assertThat(powerManager.getLocationPowerSaveMode()).isEqualTo(
846                     LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
847 
848             // check screen off behavior
849             ScreenUtils.setScreenOn(false);
850             assertFalse(powerManager.isInteractive());
851             mManager.setTestProviderLocation(TEST_PROVIDER, createLocation(TEST_PROVIDER, mRandom));
852             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
853 
854             // check screen on behavior
855             ScreenUtils.setScreenOn(true);
856             assertTrue(powerManager.isInteractive());
857             Location loc = createLocation(TEST_PROVIDER, mRandom);
858             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
859             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
860         } finally {
861             BatteryUtils.enableBatterySaver(false);
862             BatteryUtils.runDumpsysBatteryReset();
863         }
864     }
865 
866     @Test
867     @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
testRequestLocationUpdates_BatterySaver_ThrottleScreenOff()868     public void testRequestLocationUpdates_BatterySaver_ThrottleScreenOff() throws Exception {
869         // battery saver is unsupported on auto, tv and watch
870         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
871         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
872         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
873         assumeTrue(BatteryUtils.isBatterySaverSupported());
874 
875         PowerManager powerManager = Objects.requireNonNull(
876                 mContext.getSystemService(PowerManager.class));
877 
878         LocationRequest request = new LocationRequest.Builder(0).build();
879 
880         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
881              ScreenResetter ignored = new ScreenResetter();
882              DeviceConfigStateHelper batterySaverDeviceConfigStateHelper =
883                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_BATTERY_SAVER)) {
884             mManager.requestLocationUpdates(TEST_PROVIDER, request,
885                     Executors.newSingleThreadExecutor(), capture);
886 
887             batterySaverDeviceConfigStateHelper.set("location_mode", "4");
888             BatteryUtils.runDumpsysBatteryUnplug();
889             BatteryUtils.enableBatterySaver(true);
890             assertThat(powerManager.getLocationPowerSaveMode()).isEqualTo(
891                     LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
892 
893             // check screen off behavior
894             ScreenUtils.setScreenOn(false);
895             assertFalse(powerManager.isInteractive());
896             mManager.setTestProviderLocation(TEST_PROVIDER, createLocation(TEST_PROVIDER, mRandom));
897             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
898 
899             // check screen on behavior
900             ScreenUtils.setScreenOn(true);
901             assertTrue(powerManager.isInteractive());
902             Location loc = createLocation(TEST_PROVIDER, mRandom);
903             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
904             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc);
905         } finally {
906             BatteryUtils.enableBatterySaver(false);
907             BatteryUtils.runDumpsysBatteryReset();
908         }
909     }
910 
911     @Test
testRequestLocationUpdates_LocationSettingsIgnored()912     public void testRequestLocationUpdates_LocationSettingsIgnored() throws Exception {
913         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
914              DeviceConfigStateHelper locationDeviceConfigStateHelper =
915                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_LOCATION)) {
916 
917             locationDeviceConfigStateHelper.set(IGNORE_SETTINGS_ALLOWLIST,
918                     mContext.getPackageName());
919 
920             getInstrumentation().getUiAutomation()
921                     .adoptShellPermissionIdentity(LOCATION_BYPASS);
922             try {
923                 mManager.requestLocationUpdates(
924                         TEST_PROVIDER,
925                         new LocationRequest.Builder(0)
926                                 .setLocationSettingsIgnored(true)
927                                 .build(),
928                         Executors.newSingleThreadExecutor(),
929                         capture);
930             } finally {
931                 getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
932             }
933 
934             // turn off provider
935             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
936 
937             // test that all restrictions are bypassed
938             Location loc = createLocation(TEST_PROVIDER, mRandom);
939             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
940             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isEqualTo(loc);
941             loc = createLocation(TEST_PROVIDER, mRandom);
942             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
943             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isEqualTo(loc);
944         }
945     }
946 
947     @Test
testRequestLocationUpdates_AdasGnssBypass()948     public void testRequestLocationUpdates_AdasGnssBypass() throws Exception {
949         assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
950 
951         try (LocationListenerCapture capture = new LocationListenerCapture(mContext);
952              DeviceConfigStateHelper locationDeviceConfigStateHelper =
953                      new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_LOCATION)) {
954 
955             locationDeviceConfigStateHelper.set(ADAS_SETTINGS_ALLOWLIST,
956                     mContext.getPackageName());
957 
958             mManager.addTestProvider(
959                     GPS_PROVIDER,
960                     false,
961                     true,
962                     false,
963                     false,
964                     true,
965                     true,
966                     true,
967                     Criteria.POWER_HIGH,
968                     Criteria.ACCURACY_FINE);
969 
970             getInstrumentation().getUiAutomation()
971                     .adoptShellPermissionIdentity(LOCATION_BYPASS);
972             try {
973                 mManager.requestLocationUpdates(
974                         GPS_PROVIDER,
975                         new LocationRequest.Builder(0)
976                                 .setAdasGnssBypass(true)
977                                 .build(),
978                         Executors.newSingleThreadExecutor(),
979                         capture);
980             } finally {
981                 getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
982             }
983 
984             // turn off provider
985             mManager.setTestProviderEnabled(GPS_PROVIDER, false);
986 
987             // test that all restrictions are bypassed
988             Location loc = createLocation(GPS_PROVIDER, mRandom);
989             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
990             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isEqualTo(loc);
991             loc = createLocation(GPS_PROVIDER, mRandom);
992             mManager.setTestProviderLocation(GPS_PROVIDER, loc);
993             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isEqualTo(loc);
994         }
995     }
996 
997     @Test
testMonitoring()998     public void testMonitoring() throws Exception {
999         AppOpsManager appOps = Objects.requireNonNull(
1000                 mContext.getSystemService(AppOpsManager.class));
1001 
1002         try (OpActiveChangedCapture opCapture = new OpActiveChangedCapture(appOps,
1003                 OPSTR_MONITOR_LOCATION);
1004              OpActiveChangedCapture opHighPowerCapture = new OpActiveChangedCapture(appOps,
1005                      OPSTR_MONITOR_HIGH_POWER_LOCATION);
1006              LocationListenerCapture capture1 = new LocationListenerCapture(mContext);
1007              LocationListenerCapture capture2 = new LocationListenerCapture(mContext);
1008              LocationListenerCapture capture3 = new LocationListenerCapture(mContext)) {
1009             appOps.startWatchingActive(new String[]{OPSTR_MONITOR_LOCATION}, Runnable::run,
1010                     opCapture);
1011             appOps.startWatchingActive(new String[]{OPSTR_MONITOR_HIGH_POWER_LOCATION},
1012                     Runnable::run, opHighPowerCapture);
1013 
1014             mManager.requestLocationUpdates(TEST_PROVIDER,
1015                     new LocationRequest.Builder(Long.MAX_VALUE - 1).build(),
1016                     Executors.newSingleThreadExecutor(), capture1);
1017             assertThat(opCapture.getNextActive(TIMEOUT_MS)).isTrue();
1018             assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1019 
1020             mManager.requestLocationUpdates(TEST_PROVIDER, new LocationRequest.Builder(
1021                             0).setQuality(
1022                             QUALITY_HIGH_ACCURACY).build(),
1023                     Executors.newSingleThreadExecutor(), capture2);
1024             assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1025             assertThat(opHighPowerCapture.getNextActive(TIMEOUT_MS)).isTrue();
1026 
1027             mManager.requestLocationUpdates(TEST_PROVIDER, new LocationRequest.Builder(
1028                             0).setQuality(
1029                             QUALITY_HIGH_ACCURACY).build(),
1030                     Executors.newSingleThreadExecutor(), capture3);
1031             assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1032             assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1033 
1034             mManager.removeUpdates(capture2);
1035             assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1036             assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1037 
1038             mManager.removeUpdates(capture3);
1039             assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1040             assertThat(opHighPowerCapture.getNextActive(TIMEOUT_MS)).isFalse();
1041 
1042             mManager.removeUpdates(capture1);
1043             assertThat(opCapture.getNextActive(TIMEOUT_MS)).isFalse();
1044             assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
1045         }
1046     }
1047 
1048     @Test
1049     @AppModeFull(reason = "Instant apps can't hold INTERACT_ACROSS_USERS permission")
testAddProviderRequestListener()1050     public void testAddProviderRequestListener() throws Exception {
1051         InstrumentationRegistry.getInstrumentation().getUiAutomation()
1052                 .adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
1053 
1054         try (ProviderRequestChangedListenerCapture requestlistener =
1055                      new ProviderRequestChangedListenerCapture(mContext);
1056              LocationListenerCapture locationListener = new LocationListenerCapture(mContext)) {
1057             mManager.addProviderRequestChangedListener(Executors.newSingleThreadExecutor(),
1058                     requestlistener);
1059             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1060                     Executors.newSingleThreadExecutor(), locationListener);
1061 
1062             assertThat(requestlistener.getNextProviderRequest(TIMEOUT_MS)).isNotNull();
1063         } finally {
1064             InstrumentationRegistry.getInstrumentation().getUiAutomation()
1065                     .dropShellPermissionIdentity();
1066         }
1067     }
1068 
1069     @Test
1070     @AppModeFull(reason = "Instant apps can't hold ACCESS_LOCATION_EXTRA_COMMANDS permission")
testRequestGpsUpdates_B9758659()1071     public void testRequestGpsUpdates_B9758659() throws Exception {
1072         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1073 
1074         // test for b/9758659, where the gps provider may reuse network provider positions creating
1075         // an unnatural feedback loop
1076         assertThat(mManager.isProviderEnabled(GPS_PROVIDER)).isTrue();
1077 
1078         Location networkLocation = createLocation(NETWORK_PROVIDER, mRandom);
1079 
1080         mManager.addTestProvider(NETWORK_PROVIDER,
1081                 false,
1082                 false,
1083                 false,
1084                 false,
1085                 true,
1086                 true,
1087                 true,
1088                 Criteria.POWER_LOW,
1089                 Criteria.ACCURACY_COARSE);
1090         mManager.setTestProviderEnabled(NETWORK_PROVIDER, true);
1091         mManager.setTestProviderLocation(NETWORK_PROVIDER, networkLocation);
1092 
1093         // reset gps provider to give it a cold start scenario
1094         mManager.sendExtraCommand(GPS_PROVIDER, "delete_aiding_data", null);
1095 
1096         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1097             mManager.requestLocationUpdates(
1098                     GPS_PROVIDER,
1099                     new LocationRequest.Builder(0).build(),
1100                     Executors.newSingleThreadExecutor(),
1101                     capture);
1102 
1103             Location location = capture.getNextLocation(TIMEOUT_MS);
1104             if (location != null) {
1105                 assertThat(location.distanceTo(networkLocation)).isGreaterThan(1000.0f);
1106             }
1107         }
1108     }
1109 
1110     @Test
testRequestFlush()1111     public void testRequestFlush() throws Exception {
1112         try (LocationListenerCapture capture1 = new LocationListenerCapture(mContext);
1113              LocationListenerCapture capture2 = new LocationListenerCapture(mContext)) {
1114             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1115                     Executors.newSingleThreadExecutor(), capture1);
1116             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1117                     Executors.newSingleThreadExecutor(), capture2);
1118 
1119             mManager.requestFlush(TEST_PROVIDER, capture1, 1);
1120             mManager.requestFlush(TEST_PROVIDER, capture2, 1);
1121             assertThat(capture1.getNextFlush(TIMEOUT_MS)).isEqualTo(1);
1122             assertThat(capture2.getNextFlush(TIMEOUT_MS)).isEqualTo(1);
1123             assertThat(capture1.getNextFlush(FAILURE_TIMEOUT_MS)).isNull();
1124             assertThat(capture2.getNextFlush(FAILURE_TIMEOUT_MS)).isNull();
1125         }
1126 
1127         try {
1128             mManager.requestFlush(TEST_PROVIDER, (LocationListener) null, 0);
1129             fail("Should throw IllegalArgumentException if listener is null!");
1130         } catch (IllegalArgumentException e) {
1131             // expected
1132         }
1133 
1134         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1135             mManager.requestFlush(TEST_PROVIDER, capture, 0);
1136             fail("Should throw IllegalArgumentException if listener is not registered!");
1137         } catch (IllegalArgumentException e) {
1138             // expected
1139         }
1140 
1141         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1142             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Executors.newSingleThreadExecutor(), capture);
1143             mManager.requestFlush(GPS_PROVIDER, capture, 0);
1144             fail("Should throw IllegalArgumentException if listener is not registered!");
1145         } catch (IllegalArgumentException e) {
1146             // expected
1147         }
1148 
1149         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1150             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, Executors.newSingleThreadExecutor(), capture);
1151             mManager.requestFlush(null, capture, 0);
1152             fail("Should throw IllegalArgumentException if provider is null!");
1153         } catch (IllegalArgumentException e) {
1154             // expected
1155         }
1156     }
1157 
1158     @Test
testRequestFlush_PendingIntent()1159     public void testRequestFlush_PendingIntent() throws Exception {
1160         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
1161             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
1162 
1163             mManager.requestFlush(TEST_PROVIDER, capture.getPendingIntent(), 1);
1164             assertThat(capture.getNextFlush(TIMEOUT_MS)).isEqualTo(1);
1165         }
1166 
1167         try {
1168             mManager.requestFlush(TEST_PROVIDER, (PendingIntent) null, 0);
1169             fail("Should throw IllegalArgumentException if pending intent is null!");
1170         } catch (IllegalArgumentException e) {
1171             // expected
1172         }
1173 
1174         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
1175             mManager.requestFlush(TEST_PROVIDER, capture.getPendingIntent(), 0);
1176             fail("Should throw IllegalArgumentException if pending intent is not registered!");
1177         } catch (IllegalArgumentException e) {
1178             // expected
1179         }
1180 
1181         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
1182             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
1183             mManager.requestFlush(GPS_PROVIDER, capture.getPendingIntent(), 0);
1184             fail("Should throw IllegalArgumentException if pending intent is not registered!");
1185         } catch (IllegalArgumentException e) {
1186             // expected
1187         }
1188 
1189         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
1190             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
1191             mManager.requestFlush(null, capture.getPendingIntent(), 0);
1192             fail("Should throw IllegalArgumentException if provider is null!");
1193         } catch (IllegalArgumentException e) {
1194             // expected
1195         }
1196     }
1197 
1198     @Test
testRequestFlush_Ordering()1199     public void testRequestFlush_Ordering() throws Exception {
1200         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1201             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1202                     Executors.newSingleThreadExecutor(), capture);
1203 
1204             for (int i = 0; i < 100; i++) {
1205                 mManager.requestFlush(TEST_PROVIDER, capture, i);
1206             }
1207             for (int i = 0; i < 100; i++) {
1208                 assertThat(capture.getNextFlush(TIMEOUT_MS)).isEqualTo(i);
1209             }
1210         }
1211     }
1212 
1213     @Test
testRequestFlush_Gnss()1214     public void testRequestFlush_Gnss() throws Exception {
1215         assumeTrue(SystemProperties.getInt("ro.product.first_api_level", 0)
1216                 >= Build.VERSION_CODES.S);
1217         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1218 
1219         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1220             mManager.requestLocationUpdates(GPS_PROVIDER, 0, 0,
1221                     Executors.newSingleThreadExecutor(), capture);
1222 
1223             mManager.requestFlush(GPS_PROVIDER, capture, 1);
1224             assertThat(capture.getNextFlush(TIMEOUT_MS)).isEqualTo(1);
1225         }
1226     }
1227 
1228     @Test
testListenProviderEnable_Listener()1229     public void testListenProviderEnable_Listener() throws Exception {
1230         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1231             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1232                     Executors.newSingleThreadExecutor(), capture);
1233 
1234             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1235             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(false);
1236             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
1237             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(true);
1238 
1239             mManager.removeUpdates(capture);
1240 
1241             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1242             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
1243         }
1244     }
1245 
1246     @Test
testListenProviderEnable_PendingIntent()1247     public void testListenProviderEnable_PendingIntent() throws Exception {
1248         try (LocationPendingIntentCapture capture = new LocationPendingIntentCapture(mContext)) {
1249             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0, capture.getPendingIntent());
1250 
1251             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1252             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(false);
1253             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
1254             assertThat(capture.getNextProviderChange(TIMEOUT_MS)).isEqualTo(true);
1255 
1256             mManager.removeUpdates(capture.getPendingIntent());
1257 
1258             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1259             assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
1260         }
1261     }
1262 
1263     @Test
1264     @AppModeFull(reason = "Instant apps can only receive whitelisted broadcasts")
testListenProviderEnable_Broadcast()1265     public void testListenProviderEnable_Broadcast() throws Exception {
1266         try (BroadcastCapture capture = new BroadcastCapture(mContext, PROVIDERS_CHANGED_ACTION)) {
1267             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1268             Intent broadcast = capture.getNextIntent(TIMEOUT_MS);
1269             assertThat(broadcast).isNotNull();
1270             assertThat(broadcast).hasAction(PROVIDERS_CHANGED_ACTION);
1271             assertThat(broadcast).extras().string(EXTRA_PROVIDER_NAME).isEqualTo(TEST_PROVIDER);
1272             assertThat(broadcast).extras().bool(EXTRA_PROVIDER_ENABLED).isFalse();
1273 
1274             mManager.setTestProviderEnabled(TEST_PROVIDER, true);
1275             broadcast = capture.getNextIntent(TIMEOUT_MS);
1276             assertThat(broadcast).isNotNull();
1277             assertThat(broadcast).hasAction(PROVIDERS_CHANGED_ACTION);
1278             assertThat(broadcast).extras().string(EXTRA_PROVIDER_NAME).isEqualTo(TEST_PROVIDER);
1279             assertThat(broadcast).extras().bool(EXTRA_PROVIDER_ENABLED).isTrue();
1280         }
1281     }
1282 
1283     @Test
testGetAllProviders()1284     public void testGetAllProviders() {
1285         List<String> providers = mManager.getAllProviders();
1286         if (mManager.hasProvider(GPS_PROVIDER)) {
1287             assertThat(providers.contains(LocationManager.GPS_PROVIDER)).isTrue();
1288         }
1289         assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
1290         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1291         assertThat(providers.size()).isEqualTo(new HashSet<>(providers).size());
1292 
1293         mManager.removeTestProvider(TEST_PROVIDER);
1294 
1295         providers = mManager.getAllProviders();
1296         assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
1297         assertThat(providers.contains(TEST_PROVIDER)).isFalse();
1298     }
1299 
1300     @Test
testGetProviders()1301     public void testGetProviders() {
1302         List<String> providers = mManager.getProviders(false);
1303         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1304 
1305         providers = mManager.getProviders(true);
1306         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1307 
1308         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1309 
1310         providers = mManager.getProviders(false);
1311         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1312 
1313         providers = mManager.getProviders(true);
1314         assertThat(providers.contains(TEST_PROVIDER)).isFalse();
1315     }
1316 
1317     @Test
testGetProviders_Criteria()1318     public void testGetProviders_Criteria() {
1319         Criteria criteria = new Criteria();
1320 
1321         List<String> providers = mManager.getProviders(criteria, false);
1322         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1323 
1324         providers = mManager.getProviders(criteria, true);
1325         assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1326 
1327         criteria.setPowerRequirement(Criteria.POWER_LOW);
1328 
1329         providers = mManager.getProviders(criteria, false);
1330         assertThat(providers.contains(TEST_PROVIDER)).isFalse();
1331 
1332         providers = mManager.getProviders(criteria, true);
1333         assertThat(providers.contains(TEST_PROVIDER)).isFalse();
1334     }
1335 
1336     @Test
testGetBestProvider()1337     public void testGetBestProvider() {
1338         List<String> allProviders = mManager.getAllProviders();
1339         Criteria criteria = new Criteria();
1340 
1341         String bestProvider = mManager.getBestProvider(criteria, false);
1342         if (allProviders.contains(FUSED_PROVIDER)) {
1343             assertThat(bestProvider).isEqualTo(FUSED_PROVIDER);
1344         } else if (allProviders.contains(GPS_PROVIDER)) {
1345             assertThat(bestProvider).isEqualTo(GPS_PROVIDER);
1346         } else if (allProviders.contains(NETWORK_PROVIDER)) {
1347             assertThat(bestProvider).isEqualTo(NETWORK_PROVIDER);
1348         } else {
1349             assertThat(bestProvider).isEqualTo(TEST_PROVIDER);
1350         }
1351 
1352         // the "perfect" provider - this test case only works if there is no real provider on the
1353         // device with the same "perfect" properties
1354         mManager.addTestProvider(TEST_PROVIDER,
1355                 false,
1356                 false,
1357                 false,
1358                 false,
1359                 true,
1360                 true,
1361                 true,
1362                 Criteria.POWER_LOW,
1363                 Criteria.ACCURACY_FINE);
1364         mManager.addTestProvider(FUSED_PROVIDER,
1365                 true,
1366                 false,
1367                 true,
1368                 false,
1369                 false,
1370                 false,
1371                 false,
1372                 Criteria.POWER_HIGH,
1373                 Criteria.ACCURACY_COARSE);
1374 
1375         criteria.setAccuracy(Criteria.ACCURACY_FINE);
1376         criteria.setPowerRequirement(Criteria.POWER_LOW);
1377         assertThat(mManager.getBestProvider(criteria, false)).isEqualTo(TEST_PROVIDER);
1378 
1379         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1380         assertThat(mManager.getBestProvider(criteria, true)).isNotEqualTo(TEST_PROVIDER);
1381     }
1382 
1383     @Test
testGetProvider()1384     public void testGetProvider() {
1385         LocationProvider provider = mManager.getProvider(TEST_PROVIDER);
1386         assertThat(provider).isNotNull();
1387         assertThat(provider.getName()).isEqualTo(TEST_PROVIDER);
1388 
1389         provider = mManager.getProvider(LocationManager.GPS_PROVIDER);
1390         if (mManager.hasProvider(GPS_PROVIDER)) {
1391             assertThat(provider).isNotNull();
1392             assertThat(provider.getName()).isEqualTo(LocationManager.GPS_PROVIDER);
1393         } else {
1394             assertThat(provider).isNull();
1395         }
1396 
1397         assertThat(mManager.getProvider("fake")).isNull();
1398 
1399         try {
1400             mManager.getProvider(null);
1401             fail("Should throw IllegalArgumentException when provider is null!");
1402         } catch (IllegalArgumentException e) {
1403             // expected
1404         }
1405     }
1406 
1407     @Test
testHasProvider()1408     public void testHasProvider() {
1409         for (String provider : mManager.getAllProviders()) {
1410             assertThat(mManager.hasProvider(provider)).isTrue();
1411         }
1412 
1413         assertThat(mManager.hasProvider("fake")).isFalse();
1414     }
1415 
1416     @Test
testGetProviderProperties()1417     public void testGetProviderProperties() {
1418         for (String provider : mManager.getAllProviders()) {
1419             mManager.getProviderProperties(provider);
1420         }
1421 
1422         try {
1423             mManager.getProviderProperties("fake");
1424             fail("Should throw IllegalArgumentException for non-existent provider");
1425         } catch (IllegalArgumentException e) {
1426             // expected
1427         }
1428     }
1429 
1430     @Test
1431     @AppModeFull(reason = "Instant apps can't hold ACCESS_LOCATION_EXTRA_COMMANDS permission")
testSendExtraCommand()1432     public void testSendExtraCommand() {
1433         for (String provider : mManager.getAllProviders()) {
1434             boolean res = mManager.sendExtraCommand(provider, "dontCrash", null);
1435             assertThat(res).isTrue();
1436 
1437             try {
1438                 mManager.sendExtraCommand(provider, null, null);
1439                 fail("Should throw IllegalArgumentException if command is null!");
1440             } catch (IllegalArgumentException e) {
1441                 // expected
1442             }
1443         }
1444 
1445         try {
1446             mManager.sendExtraCommand(null, "crash", null);
1447             fail("Should throw IllegalArgumentException if provider is null!");
1448         } catch (IllegalArgumentException e) {
1449             // expected
1450         }
1451     }
1452 
1453     @Test
testAddTestProvider()1454     public void testAddTestProvider() {
1455         // overwriting providers should not crash
1456         for (String provider : mManager.getAllProviders()) {
1457             if (PASSIVE_PROVIDER.equals(provider)) {
1458                 continue;
1459             }
1460 
1461             mManager.addTestProvider(provider, true,
1462                     false,
1463                     true,
1464                     false,
1465                     false,
1466                     false,
1467                     false,
1468                     Criteria.POWER_MEDIUM,
1469                     Criteria.ACCURACY_FINE);
1470             mManager.setTestProviderLocation(provider, createLocation(provider, mRandom));
1471         }
1472 
1473         try {
1474             mManager.addTestProvider("passive",
1475                     true,
1476                     false,
1477                     true,
1478                     false,
1479                     false,
1480                     false,
1481                     false,
1482                     Criteria.POWER_MEDIUM,
1483                     Criteria.ACCURACY_FINE);
1484             fail("Should throw IllegalArgumentException if provider is passive!");
1485         } catch (IllegalArgumentException e) {
1486             // expected
1487         }
1488 
1489         try {
1490             mManager.addTestProvider(null,
1491                     true,
1492                     false,
1493                     true,
1494                     false,
1495                     false,
1496                     false,
1497                     false,
1498                     Criteria.POWER_MEDIUM,
1499                     Criteria.ACCURACY_FINE);
1500             fail("Should throw IllegalArgumentException if provider is null!");
1501         } catch (IllegalArgumentException e) {
1502             // expected
1503         }
1504     }
1505 
1506     @Test
testSetTestProviderEnabled()1507     public void testSetTestProviderEnabled() {
1508         for (String provider : mManager.getAllProviders()) {
1509             if (TEST_PROVIDER.equals(provider)) {
1510                 mManager.setTestProviderEnabled(provider, false);
1511                 assertThat(mManager.isProviderEnabled(provider)).isFalse();
1512                 mManager.setTestProviderEnabled(provider, true);
1513                 assertThat(mManager.isProviderEnabled(provider)).isTrue();
1514             } else {
1515                 try {
1516                     mManager.setTestProviderEnabled(provider, false);
1517                     fail("Should throw IllegalArgumentException since " + provider
1518                             + " is not a test provider!");
1519                 } catch (IllegalArgumentException e) {
1520                     // expected
1521                 }
1522             }
1523         }
1524 
1525         mManager.removeTestProvider(TEST_PROVIDER);
1526         try {
1527             mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1528             fail("Should throw IllegalArgumentException since " + TEST_PROVIDER
1529                     + " is not a test provider!");
1530         } catch (IllegalArgumentException e) {
1531             // expected
1532         }
1533 
1534         try {
1535             mManager.setTestProviderEnabled(null, false);
1536             fail("Should throw IllegalArgumentException since provider is null!");
1537         } catch (IllegalArgumentException e) {
1538             // expected
1539         }
1540     }
1541 
1542     @Test
testSetTestProviderLocation()1543     public void testSetTestProviderLocation() throws Exception {
1544         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
1545         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
1546 
1547         for (String provider : mManager.getAllProviders()) {
1548             if (TEST_PROVIDER.equals(provider)) {
1549                 try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1550                     mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1551                             Executors.newSingleThreadExecutor(), capture);
1552                     mManager.setTestProviderLocation(provider, loc1);
1553 
1554                     Location received = capture.getNextLocation(TIMEOUT_MS);
1555                     assertThat(received).isEqualTo(loc1);
1556                     assertThat(received.isFromMockProvider()).isTrue();
1557                     assertThat(mManager.getLastKnownLocation(provider)).isEqualTo(loc1);
1558 
1559                     mManager.setTestProviderEnabled(provider, false);
1560                     mManager.setTestProviderLocation(provider, loc2);
1561                     assertThat(mManager.getLastKnownLocation(provider)).isNull();
1562                     assertThat(capture.getNextLocation(FAILURE_TIMEOUT_MS)).isNull();
1563                 }
1564             } else {
1565                 try {
1566                     mManager.setTestProviderLocation(provider, loc1);
1567                     fail("Should throw IllegalArgumentException since " + provider
1568                             + " is not a test provider!");
1569                 } catch (IllegalArgumentException e) {
1570                     // expected
1571                 }
1572             }
1573         }
1574 
1575         try {
1576             mManager.setTestProviderLocation(TEST_PROVIDER, null);
1577             fail("Should throw IllegalArgumentException since location is null!");
1578         } catch (IllegalArgumentException e) {
1579             // expected
1580         }
1581 
1582         mManager.removeTestProvider(TEST_PROVIDER);
1583         try {
1584             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
1585             fail("Should throw IllegalArgumentException since " + TEST_PROVIDER
1586                     + " is not a test provider!");
1587         } catch (IllegalArgumentException e) {
1588             // expected
1589         }
1590 
1591         try {
1592             mManager.setTestProviderLocation(null, loc1);
1593             fail("Should throw IllegalArgumentException since provider is null!");
1594         } catch (IllegalArgumentException e) {
1595             // expected
1596         }
1597     }
1598 
1599     @Test
1600     @SuppressWarnings("TryFailThrowable")
testSetTestProviderLocation_B33091107()1601     public void testSetTestProviderLocation_B33091107() throws Exception {
1602         // test for b/33091107, where a malicious app could fool a real provider into providing a
1603         // mock location that isn't marked as being mock
1604 
1605         List<String> providers = mManager.getAllProviders();
1606         if (providers.size() <= 2) {
1607             // can't perform the test without any real providers, and no need to do so since there
1608             // are no providers a malicious app could fool
1609             assertThat(providers.contains(TEST_PROVIDER)).isTrue();
1610             assertThat(providers.contains(PASSIVE_PROVIDER)).isTrue();
1611             return;
1612         }
1613 
1614         providers.remove(TEST_PROVIDER);
1615         providers.remove(PASSIVE_PROVIDER);
1616 
1617         String realProvider = providers.get(0);
1618         Location loc = createLocation(realProvider, mRandom);
1619 
1620         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
1621             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
1622                     Executors.newSingleThreadExecutor(), capture);
1623             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
1624 
1625             Location received = capture.getLocation(TIMEOUT_MS);
1626             assertThat(received).isEqualTo(loc);
1627             assertThat(received.isFromMockProvider()).isTrue();
1628 
1629             Location realProvideLocation = mManager.getLastKnownLocation(realProvider);
1630             if (realProvideLocation != null) {
1631                 boolean passed = false;
1632                 try {
1633                     assertThat(realProvideLocation).isEqualTo(loc);
1634                 } catch (AssertionError e) {
1635                     passed = true;
1636                 }
1637                 if (!passed) {
1638                     fail("real provider saw " + TEST_PROVIDER + " location!");
1639                 }
1640             }
1641         }
1642     }
1643 
1644     @Test
testRemoveTestProvider()1645     public void testRemoveTestProvider() {
1646         // removing providers should not crash
1647         for (String provider : mManager.getAllProviders()) {
1648             mManager.removeTestProvider(provider);
1649         }
1650     }
1651 
1652     @Test
testGetGnssCapabilities()1653     public void testGetGnssCapabilities() {
1654         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1655         assertThat(mManager.getGnssCapabilities()).isNotNull();
1656     }
1657 
1658     @Test
testGetGnssYearOfHardware()1659     public void testGetGnssYearOfHardware() {
1660         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1661         mManager.getGnssYearOfHardware();
1662     }
1663 
1664     @Test
testGetGnssHardwareModelName()1665     public void testGetGnssHardwareModelName() {
1666         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1667 
1668         // model name should be longer than 4 characters
1669         String gnssHardwareModelName = mManager.getGnssHardwareModelName();
1670 
1671         // Hardware model name was added in HAL 1.1. HAL 1.0 and earlier do not have this set.
1672         if (gnssHardwareModelName == null) {
1673             Log.w(TAG, "gnssHardwareModelName is null. Skipping test.");
1674             return;
1675         }
1676         assertThat(gnssHardwareModelName.length()).isGreaterThan(3);
1677     }
1678 
1679     @Test
testGetGnssAntennaInfos()1680     public void testGetGnssAntennaInfos() {
1681         assumeTrue(mManager.hasProvider(GPS_PROVIDER));
1682         if (mManager.getGnssCapabilities().hasAntennaInfo()) {
1683             assertThat(mManager.getGnssAntennaInfos()).isNotNull();
1684         } else {
1685             assertThat(mManager.getGnssAntennaInfos()).isNull();
1686         }
1687     }
1688 
1689     @Test
testRegisterGnssStatusCallback()1690     public void testRegisterGnssStatusCallback() {
1691         GnssStatus.Callback callback = new GnssStatus.Callback() {
1692         };
1693 
1694         mManager.registerGnssStatusCallback(Executors.newSingleThreadExecutor(), callback);
1695         mManager.unregisterGnssStatusCallback(callback);
1696     }
1697 
1698     @Test
testAddNmeaListener()1699     public void testAddNmeaListener() {
1700         OnNmeaMessageListener listener = (message, timestamp) -> {
1701         };
1702 
1703         mManager.addNmeaListener(Executors.newSingleThreadExecutor(), listener);
1704         mManager.removeNmeaListener(listener);
1705     }
1706 
1707     @Test
testRegisterGnssMeasurementsCallback()1708     public void testRegisterGnssMeasurementsCallback() throws Exception {
1709         try (GnssMeasurementsCapture capture = new GnssMeasurementsCapture(mContext)) {
1710             mManager.registerGnssMeasurementsCallback(Runnable::run, capture);
1711 
1712             // test deprecated status messages
1713             if (mManager.hasProvider(GPS_PROVIDER)) {
1714                 Integer status = capture.getNextStatus(TIMEOUT_MS);
1715                 assertThat(status).isNotNull();
1716                 assertThat(status).isEqualTo(GnssMeasurementsEvent.Callback.STATUS_READY);
1717             }
1718         }
1719     }
1720 
1721     @Test
testRegisterGnssAntennaInfoCallback()1722     public void testRegisterGnssAntennaInfoCallback() {
1723         try (GnssAntennaInfoCapture capture = new GnssAntennaInfoCapture(mContext)) {
1724             mManager.registerAntennaInfoListener(Runnable::run, capture);
1725         }
1726     }
1727 
1728     @Test
testRegisterGnssNavigationMessageCallback()1729     public void testRegisterGnssNavigationMessageCallback() throws Exception {
1730         try (GnssNavigationMessageCapture capture = new GnssNavigationMessageCapture(mContext)) {
1731             mManager.registerGnssNavigationMessageCallback(Runnable::run, capture);
1732 
1733             // test deprecated status messages
1734             if (mManager.hasProvider(GPS_PROVIDER)) {
1735                 Integer status = capture.getNextStatus(TIMEOUT_MS);
1736                 assertThat(status).isNotNull();
1737                 assertThat(status).isEqualTo(GnssNavigationMessage.Callback.STATUS_READY);
1738             }
1739         }
1740     }
1741 
addTestProviderForAttributionTag(String... attributionTags)1742     private void addTestProviderForAttributionTag(String... attributionTags) {
1743         mManager.removeTestProvider(TEST_PROVIDER);
1744         mManager.addTestProvider(TEST_PROVIDER,
1745                 new ProviderProperties.Builder().build(), (attributionTags != null)
1746                         ? new ArraySet<>(attributionTags)
1747                         : Collections.emptySet());
1748         mManager.setTestProviderEnabled(TEST_PROVIDER, true);
1749     }
1750 
1751     @Ignore("b/181693958")
1752     @Test
testLocationAttributionTagBlaming()1753     public void testLocationAttributionTagBlaming() {
1754         // No tag set
1755         addTestProviderForAttributionTag();
1756         long timeBeforeLocationAccess = System.currentTimeMillis();
1757         accessLocation(VALID_LOCATION_ATTRIBUTION_TAG);
1758         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1759                 /*expectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION,
1760                 /*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1761                 VALID_LOCATION_ATTRIBUTION_TAG);
1762 
1763         // Tag set and using that correct tag
1764         addTestProviderForAttributionTag(VALID_LOCATION_ATTRIBUTION_TAG);
1765         timeBeforeLocationAccess = System.currentTimeMillis();
1766         accessLocation(VALID_LOCATION_ATTRIBUTION_TAG);
1767         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1768                 /*expectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1769                 /*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION,
1770                 VALID_LOCATION_ATTRIBUTION_TAG);
1771 
1772         // Tag set and using a wrong tag
1773         timeBeforeLocationAccess = System.currentTimeMillis();
1774         accessLocation(INVALID_LOCATION_ATTRIBUTION_TAG);
1775         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1776                 /*expectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION,
1777                 /*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1778                 INVALID_LOCATION_ATTRIBUTION_TAG);
1779 
1780         // Tag set and using that correct tag
1781         timeBeforeLocationAccess = System.currentTimeMillis();
1782         accessLocation(VALID_LOCATION_ATTRIBUTION_TAG);
1783         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1784                 /*expectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1785                 /*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION,
1786                 VALID_LOCATION_ATTRIBUTION_TAG);
1787 
1788         // No tag set
1789         addTestProviderForAttributionTag();
1790         timeBeforeLocationAccess = System.currentTimeMillis();
1791         accessLocation(VALID_LOCATION_ATTRIBUTION_TAG);
1792         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1793                 /*expectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION,
1794                 /*unexpectedOp*/ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1795                 VALID_LOCATION_ATTRIBUTION_TAG);
1796     }
1797 
1798     @Test
testGetLastKnownLocationNoteOps()1799     public void testGetLastKnownLocationNoteOps() {
1800         long timeBeforeLocationAccess = System.currentTimeMillis();
1801         mManager.getLastKnownLocation(TEST_PROVIDER);
1802         assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1803                 /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1804                 /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1805                 null);
1806 
1807         // Ensure no note ops when provider disabled
1808         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1809         timeBeforeLocationAccess = System.currentTimeMillis();
1810         mManager.getLastKnownLocation(TEST_PROVIDER);
1811         assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
1812                 AppOpsManager.OPSTR_FINE_LOCATION, null);
1813     }
1814 
1815     @Test
testGetCurrentLocationNoteOps()1816     public void testGetCurrentLocationNoteOps() throws Exception {
1817         long timeBeforeLocationAccess = System.currentTimeMillis();
1818         Location loc = createLocation(TEST_PROVIDER, mRandom);
1819 
1820         try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) {
1821             mManager.getCurrentLocation(TEST_PROVIDER, capture.getCancellationSignal(),
1822                     Executors.newSingleThreadExecutor(), capture);
1823             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
1824             assertThat(capture.getLocation(TIMEOUT_MS)).isEqualTo(loc);
1825             assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1826                     /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1827                     /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1828                     null);
1829         }
1830 
1831         // Ensure no note ops when provider disabled
1832         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1833         timeBeforeLocationAccess = System.currentTimeMillis();
1834         try (GetCurrentLocationCapture capture2 = new GetCurrentLocationCapture()) {
1835             mManager.getCurrentLocation(TEST_PROVIDER, capture2.getCancellationSignal(),
1836                     Executors.newSingleThreadExecutor(), capture2);
1837             mManager.setTestProviderLocation(TEST_PROVIDER, loc);
1838             assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
1839                     AppOpsManager.OPSTR_FINE_LOCATION, null);
1840         }
1841     }
1842 
1843     @Test
testRequestLocationUpdatesNoteOps()1844     public void testRequestLocationUpdatesNoteOps() throws Exception {
1845         long timeBeforeLocationAccess = System.currentTimeMillis();
1846         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
1847 
1848         try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
1849             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1850                     Executors.newSingleThreadExecutor(), capture);
1851 
1852             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
1853             assertThat(capture.getNextLocation(TIMEOUT_MS)).isEqualTo(loc1);
1854             assertNotedOpsSinceLastLocationAccess(timeBeforeLocationAccess,
1855                     /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1856                     /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1857                     null);
1858         }
1859 
1860         // Ensure no note ops when provider disabled
1861         mManager.setTestProviderEnabled(TEST_PROVIDER, false);
1862         timeBeforeLocationAccess = System.currentTimeMillis();
1863         try (LocationListenerCapture capture2 = new LocationListenerCapture(mContext)) {
1864             mManager.requestLocationUpdates(TEST_PROVIDER, 0, 0,
1865                     Executors.newSingleThreadExecutor(), capture2);
1866             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
1867             assertNoOpsNotedSinceLastLocationAccess(timeBeforeLocationAccess,
1868                     AppOpsManager.OPSTR_FINE_LOCATION, null);
1869         }
1870     }
1871 
1872     @Test
testRequestLocationUpdatesNoteOps_simultaneousRequests()1873     public void testRequestLocationUpdatesNoteOps_simultaneousRequests() {
1874         Context attributionContextFast =
1875                 mContext.createAttributionContext(VALID_LOCATION_ATTRIBUTION_TAG);
1876         Context attributionContextSlow =
1877                 mContext.createAttributionContext(ANOTHER_VALID_LOCATION_ATTRIBUTION_TAG);
1878         Location loc1 = createLocation(TEST_PROVIDER, mRandom);
1879         Location loc2 = createLocation(TEST_PROVIDER, mRandom);
1880 
1881         try (LocationListenerCapture fastCapture =
1882                      new LocationListenerCapture(attributionContextFast);
1883              LocationListenerCapture slowCapture =
1884                      new LocationListenerCapture(attributionContextSlow)) {
1885             attributionContextFast
1886                     .getSystemService(LocationManager.class)
1887                     .requestLocationUpdates(
1888                             TEST_PROVIDER,
1889                             new LocationRequest.Builder(0).build(),
1890                             Runnable::run,
1891                             fastCapture);
1892             attributionContextSlow
1893                     .getSystemService(LocationManager.class)
1894                     .requestLocationUpdates(
1895                             TEST_PROVIDER,
1896                             new LocationRequest.Builder(600000).build(),
1897                             Runnable::run,
1898                             slowCapture);
1899 
1900             // Set initial location.
1901             long timeBeforeLocationAccess = System.currentTimeMillis();
1902             mManager.setTestProviderLocation(TEST_PROVIDER, loc1);
1903             assertNotedOpsSinceLastLocationAccess(
1904                     timeBeforeLocationAccess,
1905                     /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1906                     /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1907                    VALID_LOCATION_ATTRIBUTION_TAG);
1908 
1909             // Verify noteOp for the fast request.
1910             timeBeforeLocationAccess = System.currentTimeMillis();
1911             mManager.setTestProviderLocation(TEST_PROVIDER, loc2);
1912             assertNotedOpsSinceLastLocationAccess(
1913                     timeBeforeLocationAccess,
1914                     /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1915                     /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1916                     VALID_LOCATION_ATTRIBUTION_TAG);
1917             assertNoOpsNotedSinceLastLocationAccess(
1918                     timeBeforeLocationAccess,
1919                     AppOpsManager.OPSTR_FINE_LOCATION,
1920                     ANOTHER_VALID_LOCATION_ATTRIBUTION_TAG);
1921 
1922             // Verify noteOp for the slow request.
1923             timeBeforeLocationAccess = System.currentTimeMillis();
1924             Location loc3 = createLocation(TEST_PROVIDER, 0, 1, 10,
1925                     SystemClock.elapsedRealtimeNanos() + 600000000000L);
1926             mManager.setTestProviderLocation(TEST_PROVIDER, loc3);
1927             assertNotedOpsSinceLastLocationAccess(
1928                     timeBeforeLocationAccess,
1929                     /* expectedOp */ AppOpsManager.OPSTR_FINE_LOCATION,
1930                     /* unexpectedOp */ AppOpsManager.OPSTR_FINE_LOCATION_SOURCE,
1931                     ANOTHER_VALID_LOCATION_ATTRIBUTION_TAG);
1932         }
1933     }
1934 
accessLocation(String attributionTag)1935     private void accessLocation(String attributionTag) {
1936         Context attributionContext = mContext.createAttributionContext(attributionTag);
1937         attributionContext.getSystemService(LocationManager.class).getLastKnownLocation(
1938                 TEST_PROVIDER);
1939     }
1940 
assertNotedOpsSinceLastLocationAccess( long timeBeforeLocationAccess, @NonNull String expectedOp, @NonNull String unexpectedOp, String attributionTag)1941     private void assertNotedOpsSinceLastLocationAccess(
1942             long timeBeforeLocationAccess,
1943             @NonNull String expectedOp,
1944             @NonNull String unexpectedOp,
1945             String attributionTag) {
1946         final UiAutomation automation =
1947                 InstrumentationRegistry.getInstrumentation().getUiAutomation();
1948         automation.adoptShellPermissionIdentity(android.Manifest.permission.GET_APP_OPS_STATS);
1949 
1950         try {
1951             final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
1952             final List<AppOpsManager.PackageOps> affectedPackageOps =
1953                     appOpsManager.getPackagesForOps(new String[]{expectedOp, unexpectedOp});
1954             for (AppOpsManager.PackageOps packageOps : affectedPackageOps) {
1955                 if (mContext.getPackageName().equals(packageOps.getPackageName())) {
1956                     // We are pulling stats only for one app op.
1957                     for (AppOpsManager.OpEntry opEntry : packageOps.getOps()) {
1958                         if (unexpectedOp.equals(opEntry.getOpStr())) {
1959                             fail("Unexpected access to " + unexpectedOp);
1960                         } else if (expectedOp.equals(opEntry.getOpStr())
1961                                 && opEntry.getAttributedOpEntries().containsKey(attributionTag)
1962                                 && opEntry
1963                                 .getAttributedOpEntries()
1964                                 .get(attributionTag)
1965                                 .getLastAccessTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)
1966                                 >= timeBeforeLocationAccess) {
1967                             return;
1968                         }
1969                     }
1970                 }
1971             }
1972             fail("No expected access to " + expectedOp);
1973         } finally {
1974             automation.dropShellPermissionIdentity();
1975         }
1976     }
1977 
assertNoOpsNotedSinceLastLocationAccess( long timeBeforeLocationAccess, @NonNull String unexpectedOp, String attributionTag)1978     private void assertNoOpsNotedSinceLastLocationAccess(
1979             long timeBeforeLocationAccess, @NonNull String unexpectedOp, String attributionTag) {
1980         final UiAutomation automation =
1981                 InstrumentationRegistry.getInstrumentation().getUiAutomation();
1982         automation.adoptShellPermissionIdentity(android.Manifest.permission.GET_APP_OPS_STATS);
1983         try {
1984             final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
1985             final List<AppOpsManager.PackageOps> affectedPackageOps =
1986                     appOpsManager.getPackagesForOps(new String[]{unexpectedOp});
1987             for (AppOpsManager.PackageOps packageOps : affectedPackageOps) {
1988                 if (mContext.getPackageName().equals(packageOps.getPackageName())) {
1989                     // We are pulling stats only for one app op.
1990                     for (AppOpsManager.OpEntry opEntry : packageOps.getOps()) {
1991                         if (unexpectedOp.equals(opEntry.getOpStr())
1992                                 && opEntry.getAttributedOpEntries().containsKey(attributionTag)
1993                                 && opEntry
1994                                 .getAttributedOpEntries()
1995                                 .get(attributionTag)
1996                                 .getLastAccessTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)
1997                                 >= timeBeforeLocationAccess) {
1998                             fail("Unexpected access to " + unexpectedOp);
1999                         }
2000                     }
2001                 }
2002             }
2003         } finally {
2004             automation.dropShellPermissionIdentity();
2005         }
2006     }
2007 }
2008