• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package android.carrierapi.cts;
17 
18 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
19 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import static org.junit.Assert.fail;
25 
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.PackageManager;
32 import android.location.LocationManager;
33 import android.os.AsyncTask;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.Message;
37 import android.os.Parcel;
38 import android.os.Process;
39 import android.os.UserHandle;
40 import android.telephony.AccessNetworkConstants;
41 import android.telephony.CellIdentityLte;
42 import android.telephony.CellInfo;
43 import android.telephony.CellInfoGsm;
44 import android.telephony.CellInfoLte;
45 import android.telephony.CellInfoWcdma;
46 import android.telephony.NetworkScan;
47 import android.telephony.NetworkScanRequest;
48 import android.telephony.RadioAccessSpecifier;
49 import android.telephony.TelephonyManager;
50 import android.telephony.TelephonyScanManager;
51 import android.util.Log;
52 
53 import androidx.test.InstrumentationRegistry;
54 import androidx.test.runner.AndroidJUnit4;
55 
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.List;
64 import java.util.concurrent.CountDownLatch;
65 import java.util.concurrent.TimeUnit;
66 import java.util.stream.Collectors;
67 
68 /**
69  * Unit tests for {@link TelephonyManager}'s network scan APIs.
70  *
71  * <p>Test using `atest CtsCarrierApiTestCases:NetworkScanApiTest` or `make cts -j64 && cts-tradefed
72  * run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.NetworkScanApiTest`
73  */
74 @RunWith(AndroidJUnit4.class)
75 public class NetworkScanApiTest extends BaseCarrierApiTest {
76     private static final String TAG = "NetworkScanApiTest";
77 
78     private TelephonyManager mTelephonyManager;
79     private int mNetworkScanStatus;
80     private static final int EVENT_NETWORK_SCAN_START = 100;
81     private static final int EVENT_NETWORK_SCAN_RENOUNCE_START = 101;
82     private static final int EVENT_NETWORK_SCAN_RESULTS = 200;
83     private static final int EVENT_NETWORK_SCAN_RESTRICTED_RESULTS = 201;
84     private static final int EVENT_NETWORK_SCAN_ERROR = 300;
85     private static final int EVENT_NETWORK_SCAN_COMPLETED = 400;
86     private static final int EVENT_SCAN_DENIED = 500;
87     private List<CellInfo> mScanResults = null;
88     private HandlerThread mTestHandlerThread;
89     private Handler mHandler;
90     private NetworkScan mNetworkScan;
91     private NetworkScanRequest mNetworkScanRequest;
92     private NetworkScanCallbackImpl mNetworkScanCallback;
93     private static final int LOCATION_SETTING_CHANGE_WAIT_MS = 1000;
94     private static final int MAX_CELLINFO_WAIT_MILLIS = 5000; // 5 seconds
95     private static final int SCAN_SEARCH_TIME_SECONDS = 60;
96     // Wait one second longer than the max scan search time to give the test time to receive the
97     // results.
98     private static final int MAX_INIT_WAIT_MS = (SCAN_SEARCH_TIME_SECONDS + 1) * 1000;
99     private Object mLock = new Object();
100     private boolean mReady;
101     private int mErrorCode;
102     /* All the following constants are used to construct NetworkScanRequest*/
103     private static final int SCAN_TYPE = NetworkScanRequest.SCAN_TYPE_ONE_SHOT;
104     private static final boolean INCREMENTAL_RESULTS = true;
105     private static final int SEARCH_PERIODICITY_SEC = 5;
106     private static final int MAX_SEARCH_TIME_SEC = 300;
107     private static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3;
108     private static final ArrayList<String> MCC_MNC = new ArrayList<>();
109     private static final RadioAccessSpecifier[] RADIO_ACCESS_SPECIFIERS = {
110         new RadioAccessSpecifier(
111                 AccessNetworkConstants.AccessNetworkType.GERAN,
112                 null /* bands */,
113                 null /* channels */),
114         new RadioAccessSpecifier(
115                 AccessNetworkConstants.AccessNetworkType.EUTRAN,
116                 null /* bands */,
117                 null /* channels */),
118         new RadioAccessSpecifier(
119                 AccessNetworkConstants.AccessNetworkType.UTRAN,
120                 null /* bands */,
121                 null /* channels */)
122     };
123 
124     // Needed because NETWORK_SCAN_PERMISSION is a systemapi
125     public static final String NETWORK_SCAN_PERMISSION = "android.permission.NETWORK_SCAN";
126 
127     @Before
setUp()128     public void setUp() throws Exception {
129         mTelephonyManager = getContext().getSystemService(TelephonyManager.class);
130         String selfPackageName = getContext().getPackageName();
131         InstrumentationRegistry.getInstrumentation()
132                 .getUiAutomation()
133                 .grantRuntimePermission(selfPackageName, ACCESS_FINE_LOCATION);
134         InstrumentationRegistry.getInstrumentation()
135                 .getUiAutomation()
136                 .grantRuntimePermission(selfPackageName, ACCESS_BACKGROUND_LOCATION);
137         mTestHandlerThread = new HandlerThread(TAG);
138         mTestHandlerThread.start();
139         /* create a custom handler for the Handler Thread */
140         mHandler =
141                 new Handler(mTestHandlerThread.getLooper()) {
142                     @Override
143                     public void handleMessage(Message msg) {
144                         switch (msg.what) {
145                             case EVENT_NETWORK_SCAN_START: {
146                                 Log.d(TAG, "request network scan");
147                                 boolean useShellIdentity = (Boolean) msg.obj;
148                                 if (useShellIdentity) {
149                                     InstrumentationRegistry.getInstrumentation()
150                                             .getUiAutomation()
151                                             .adoptShellPermissionIdentity();
152                                 }
153                                 try {
154                                     mNetworkScan =
155                                             mTelephonyManager.requestNetworkScan(
156                                                     mNetworkScanRequest,
157                                                     AsyncTask.SERIAL_EXECUTOR,
158                                                     mNetworkScanCallback);
159                                     if (mNetworkScan == null) {
160                                         mNetworkScanStatus = EVENT_SCAN_DENIED;
161                                         setReady(true);
162                                     }
163                                 } catch (SecurityException e) {
164                                     mNetworkScanStatus = EVENT_SCAN_DENIED;
165                                     setReady(true);
166                                 } finally {
167                                     if (useShellIdentity) {
168                                         InstrumentationRegistry.getInstrumentation()
169                                                 .getUiAutomation()
170                                                 .dropShellPermissionIdentity();
171                                     }
172                                 }
173                                 break;
174                             }
175                             case EVENT_NETWORK_SCAN_RENOUNCE_START: {
176                                 Log.d(TAG, "request network scan with renounce");
177                                 boolean useShellIdentity = (Boolean) msg.obj;
178                                 if (useShellIdentity) {
179                                     InstrumentationRegistry.getInstrumentation()
180                                             .getUiAutomation()
181                                             .adoptShellPermissionIdentity();
182                                 }
183                                 try {
184                                     mNetworkScan = mTelephonyManager.requestNetworkScan(
185                                             TelephonyManager.INCLUDE_LOCATION_DATA_NONE,
186                                             mNetworkScanRequest,
187                                             AsyncTask.SERIAL_EXECUTOR,
188                                             mNetworkScanCallback);
189                                     if (mNetworkScan == null) {
190                                         mNetworkScanStatus = EVENT_SCAN_DENIED;
191                                         setReady(true);
192                                     }
193                                 } catch (SecurityException e) {
194                                     mNetworkScanStatus = EVENT_SCAN_DENIED;
195                                     setReady(true);
196                                 } finally {
197                                     if (useShellIdentity) {
198                                         InstrumentationRegistry.getInstrumentation()
199                                                 .getUiAutomation()
200                                                 .dropShellPermissionIdentity();
201                                     }
202                                 }
203                                 break;
204                             }
205                             default:
206                                 Log.d(TAG, "Unknown Event " + msg.what);
207                         }
208                     }
209                 };
210     }
211 
212     @After
tearDown()213     public void tearDown() throws Exception {
214         if (!werePreconditionsSatisfied()) return;
215 
216         // Revoking runtime permissions makes ActivityManager kill our process, so we don't do it,
217         // as the test harness will eventually uninstall this APK after testing completes anyway, so
218         // we aren't really leaking anything long-term.
219         mTestHandlerThread.quit();
220     }
221 
waitUntilReady()222     private void waitUntilReady() {
223         synchronized (mLock) {
224             try {
225                 mLock.wait(MAX_INIT_WAIT_MS);
226             } catch (InterruptedException ie) {
227             }
228 
229             assertWithMessage("NetworkScanApiTest failed to initialize").that(mReady).isTrue();
230         }
231     }
232 
setReady(boolean ready)233     private void setReady(boolean ready) {
234         synchronized (mLock) {
235             mReady = ready;
236             mLock.notifyAll();
237         }
238     }
239 
240     private class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback {
241         @Override
onResults(List<CellInfo> results)242         public void onResults(List<CellInfo> results) {
243             Log.d(TAG, "onResults: " + results.toString());
244             mNetworkScanStatus = EVENT_NETWORK_SCAN_RESULTS;
245             mScanResults = results;
246         }
247 
248         @Override
onComplete()249         public void onComplete() {
250             Log.d(TAG, "onComplete");
251             mNetworkScanStatus = EVENT_NETWORK_SCAN_COMPLETED;
252             setReady(true);
253         }
254 
255         @Override
onError(int error)256         public void onError(int error) {
257             Log.d(TAG, "onError: " + String.valueOf(error));
258             mNetworkScanStatus = EVENT_NETWORK_SCAN_ERROR;
259             mErrorCode = error;
260             setReady(true);
261         }
262     }
263 
264     private class CellInfoResultsCallback extends TelephonyManager.CellInfoCallback {
265         public List<CellInfo> cellInfo;
266 
267         @Override
onCellInfo(List<CellInfo> cellInfo)268         public synchronized void onCellInfo(List<CellInfo> cellInfo) {
269             this.cellInfo = cellInfo;
270             notifyAll();
271         }
272 
wait(int millis)273         public synchronized void wait(int millis) throws InterruptedException {
274             if (cellInfo == null) {
275                 super.wait(millis);
276             }
277         }
278     }
279 
getRadioAccessSpecifier(List<CellInfo> allCellInfo)280     private List<RadioAccessSpecifier> getRadioAccessSpecifier(List<CellInfo> allCellInfo) {
281         List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
282         List<Integer> wcdmaChannels = new ArrayList<>();
283         List<Integer> gsmChannels = new ArrayList<>();
284         for (int i = 0; i < allCellInfo.size(); i++) {
285             CellInfo cellInfo = allCellInfo.get(i);
286             if (cellInfo instanceof CellInfoLte) {
287                 CellIdentityLte cellIdentity = ((CellInfoLte) cellInfo).getCellIdentity();
288                 if (cellIdentity.getBands().length > 0) {
289                     Log.d(
290                             TAG,
291                             "lte channel:"
292                                     + cellIdentity.getEarfcn()
293                                     + " lte bands:"
294                                     + Arrays.toString(cellIdentity.getBands()));
295                     int ranLte = AccessNetworkConstants.AccessNetworkType.EUTRAN;
296                     radioAccessSpecifier.add(
297                             new RadioAccessSpecifier(
298                                     ranLte,
299                                     cellIdentity.getBands(),
300                                     cellIdentity.getEarfcn() == cellInfo.UNAVAILABLE
301                                             ? null
302                                             : new int[] {cellIdentity.getEarfcn()}));
303                 }
304             } else if (cellInfo instanceof CellInfoWcdma) {
305                 wcdmaChannels.add(((CellInfoWcdma) cellInfo).getCellIdentity().getUarfcn());
306             } else if (cellInfo instanceof CellInfoGsm) {
307                 gsmChannels.add(((CellInfoGsm) cellInfo).getCellIdentity().getArfcn());
308             }
309         }
310         if (!wcdmaChannels.isEmpty()) {
311             Log.d(TAG, "wcdma channels" + wcdmaChannels.toString());
312             int ranWcdma = AccessNetworkConstants.AccessNetworkType.UTRAN;
313             radioAccessSpecifier.add(
314                     new RadioAccessSpecifier(
315                             ranWcdma,
316                             null /* bands */,
317                             wcdmaChannels.stream().mapToInt(i -> i).toArray()));
318         }
319         if (!gsmChannels.isEmpty()) {
320             Log.d(TAG, "gsm channels" + gsmChannels.toString());
321             int ranGsm = AccessNetworkConstants.AccessNetworkType.GERAN;
322             radioAccessSpecifier.add(
323                     new RadioAccessSpecifier(
324                             ranGsm,
325                             null /* bands */,
326                             gsmChannels.stream().mapToInt(i -> i).toArray()));
327         }
328         return radioAccessSpecifier;
329     }
330 
331     /** Tests that the device properly requests a network scan. */
332     @Test
testRequestNetworkScan()333     public void testRequestNetworkScan() {
334         boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
335         try {
336             mNetworkScanRequest = buildNetworkScanRequest(true);
337             mNetworkScanCallback = new NetworkScanCallbackImpl();
338             Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_START, false);
339             setReady(false);
340             startNetworkScan.sendToTarget();
341             waitUntilReady();
342 
343             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
344             assertWithMessage(
345                             "The final scan status is "
346                                     + mNetworkScanStatus
347                                     + " with error code "
348                                     + mErrorCode
349                                     + ", not ScanCompleted"
350                                     + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
351                                     + " ERROR_UNSUPPORTED")
352                     .that(isScanStatusValid())
353                     .isTrue();
354         } finally {
355             getAndSetLocationSwitch(isLocationSwitchOn);
356         }
357     }
358 
359     /** Tests that the device properly requests a network scan. */
360     @Test
testRequestNetworkScanWithRenounce()361     public void testRequestNetworkScanWithRenounce() {
362         boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
363         try {
364             mNetworkScanRequest = buildNetworkScanRequest(true);
365             mNetworkScanCallback = new NetworkScanCallbackImpl();
366             Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RENOUNCE_START,
367                     false);
368             setReady(false);
369             startNetworkScan.sendToTarget();
370             waitUntilReady();
371 
372             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
373             assertWithMessage(
374                     "The final scan status is "
375                             + mNetworkScanStatus
376                             + " with error code "
377                             + mErrorCode
378                             + ", not ScanCompleted"
379                             + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
380                             + " ERROR_UNSUPPORTED")
381                     .that(mNetworkScanStatus)
382                     .isEqualTo(EVENT_SCAN_DENIED);
383         } finally {
384             getAndSetLocationSwitch(isLocationSwitchOn);
385         }
386     }
387 
388     @Test
testRequestNetworkScanWithRenounceWithoutChannels()389     public void testRequestNetworkScanWithRenounceWithoutChannels() {
390         boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
391         try {
392             mNetworkScanRequest = buildNetworkScanRequest(/*includeBandsAndChannels=*/false);
393             mNetworkScanCallback = new NetworkScanCallbackImpl();
394             Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RENOUNCE_START,
395                     false);
396             setReady(false);
397             startNetworkScan.sendToTarget();
398             waitUntilReady();
399 
400             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
401             assertWithMessage(
402                     "The final scan status is "
403                             + mNetworkScanStatus
404                             + " with error code "
405                             + mErrorCode
406                             + ", not ScanCompleted"
407                             + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
408                             + " ERROR_UNSUPPORTED")
409                     .that(isScanStatusValid())
410                     .isTrue();
411         } finally {
412             getAndSetLocationSwitch(isLocationSwitchOn);
413         }
414     }
415 
416     @Test
testRequestNetworkScanLocationOffPass()417     public void testRequestNetworkScanLocationOffPass() {
418         requestNetworkScanLocationOffHelper(false, true);
419     }
420 
421     @Test
testRequestNetworkScanLocationOffFail()422     public void testRequestNetworkScanLocationOffFail() {
423         requestNetworkScanLocationOffHelper(true, true);
424     }
425 
requestNetworkScanLocationOffHelper( boolean includeBandsAndChannels, boolean useSpecialScanPermission)426     public void requestNetworkScanLocationOffHelper(
427             boolean includeBandsAndChannels, boolean useSpecialScanPermission) {
428         mNetworkScanRequest = buildNetworkScanRequest(includeBandsAndChannels);
429 
430         boolean isLocationSwitchOn = getAndSetLocationSwitch(false);
431         try {
432             mNetworkScanCallback = new NetworkScanCallbackImpl();
433             Message startNetworkScan =
434                     mHandler.obtainMessage(EVENT_NETWORK_SCAN_START, useSpecialScanPermission);
435             setReady(false);
436             startNetworkScan.sendToTarget();
437             waitUntilReady();
438             if (includeBandsAndChannels) {
439                 // If we included the bands when location is off, expect a security error and
440                 // nothing else.
441                 assertThat(mNetworkScanStatus).isEqualTo(EVENT_SCAN_DENIED);
442                 return;
443             }
444 
445             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
446             assertWithMessage(
447                             "The final scan status is "
448                                     + mNetworkScanStatus
449                                     + " with error code "
450                                     + mErrorCode
451                                     + ", not ScanCompleted"
452                                     + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
453                                     + " ERROR_UNSUPPORTED")
454                     .that(isScanStatusValid())
455                     .isTrue();
456         } finally {
457             getAndSetLocationSwitch(isLocationSwitchOn);
458         }
459     }
460 
buildNetworkScanRequest(boolean includeBandsAndChannels)461     private NetworkScanRequest buildNetworkScanRequest(boolean includeBandsAndChannels) {
462         // Make sure that there should be at least one entry.
463         List<CellInfo> allCellInfo = getCellInfo();
464         List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
465 
466         if (allCellInfo != null && allCellInfo.size() != 0) {
467             // Construct a NetworkScanRequest
468             radioAccessSpecifier = getRadioAccessSpecifier(allCellInfo);
469             if (!includeBandsAndChannels) {
470                 radioAccessSpecifier =
471                         radioAccessSpecifier.stream()
472                                 .map(
473                                         spec ->
474                                                 new RadioAccessSpecifier(
475                                                         spec.getRadioAccessNetwork(), null, null))
476                                 .collect(Collectors.toList());
477             }
478         }
479 
480         Log.d(TAG, "number of radioAccessSpecifier: " + radioAccessSpecifier.size());
481         if (radioAccessSpecifier.isEmpty()) {
482             // Put in some arbitrary bands and channels so that we trip the location check if needed
483             int[] fakeBands =
484                     includeBandsAndChannels
485                             ? new int[] {AccessNetworkConstants.EutranBand.BAND_5}
486                             : null;
487             int[] fakeChannels = includeBandsAndChannels ? new int[] {2400} : null;
488 
489             RadioAccessSpecifier gsm =
490                     new RadioAccessSpecifier(
491                             AccessNetworkConstants.AccessNetworkType.GERAN,
492                             null /* bands */,
493                             null /* channels */);
494             RadioAccessSpecifier lte =
495                     new RadioAccessSpecifier(
496                             AccessNetworkConstants.AccessNetworkType.EUTRAN,
497                             fakeBands /* bands */,
498                             fakeChannels /* channels */);
499             RadioAccessSpecifier wcdma =
500                     new RadioAccessSpecifier(
501                             AccessNetworkConstants.AccessNetworkType.UTRAN,
502                             null /* bands */,
503                             null /* channels */);
504             radioAccessSpecifier.add(gsm);
505             radioAccessSpecifier.add(lte);
506             radioAccessSpecifier.add(wcdma);
507         }
508         RadioAccessSpecifier[] radioAccessSpecifierArray =
509                 new RadioAccessSpecifier[radioAccessSpecifier.size()];
510         return new NetworkScanRequest(
511                 NetworkScanRequest.SCAN_TYPE_ONE_SHOT /* scan type */,
512                 radioAccessSpecifier.toArray(radioAccessSpecifierArray),
513                 5 /* search periodicity */,
514                 SCAN_SEARCH_TIME_SECONDS /* max search time */,
515                 true /*enable incremental results*/,
516                 5 /* incremental results periodicity */,
517                 null /* List of PLMN ids (MCC-MNC) */);
518     }
519 
getCellInfo()520     private List<CellInfo> getCellInfo() {
521         CellInfoResultsCallback resultsCallback = new CellInfoResultsCallback();
522         mTelephonyManager.requestCellInfoUpdate(r -> r.run(), resultsCallback);
523         try {
524             resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
525         } catch (InterruptedException ex) {
526             fail("CellInfoCallback was interrupted: " + ex);
527         }
528         return resultsCallback.cellInfo;
529     }
530 
531     @Test
testNetworkScanPermission()532     public void testNetworkScanPermission() {
533         PackageManager pm = getContext().getPackageManager();
534 
535         List<Integer> specialUids =
536                 Arrays.asList(Process.SYSTEM_UID, Process.PHONE_UID, Process.SHELL_UID);
537 
538         List<PackageInfo> holding =
539                 pm.getPackagesHoldingPermissions(
540                         new String[] {NETWORK_SCAN_PERMISSION},
541                         PackageManager.MATCH_DISABLED_COMPONENTS);
542 
543         List<Integer> nonSpecialPackages =
544                 holding.stream()
545                         .map(
546                                 pi -> {
547                                     try {
548                                         return pm.getPackageUid(pi.packageName, 0);
549                                     } catch (PackageManager.NameNotFoundException e) {
550                                         return Process.INVALID_UID;
551                                     }
552                                 })
553                         .filter(uid -> !specialUids.contains(UserHandle.getAppId(uid)))
554                         .collect(Collectors.toList());
555 
556         assertWithMessage(
557                         "Only one app on the device is allowed to hold the NETWORK_SCAN"
558                                 + " permission.")
559                 .that(nonSpecialPackages.size())
560                 .isAtMost(1);
561     }
562 
getAndSetLocationSwitch(boolean enabled)563     private boolean getAndSetLocationSwitch(boolean enabled) {
564         CountDownLatch locationChangeLatch = new CountDownLatch(1);
565         BroadcastReceiver locationModeChangeReceiver = new BroadcastReceiver() {
566             @Override
567             public void onReceive(Context context, Intent intent) {
568                 if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())
569                         && intent.getBooleanExtra(LocationManager.EXTRA_LOCATION_ENABLED, !enabled)
570                         == enabled) {
571                     locationChangeLatch.countDown();
572                 }
573             }
574         };
575 
576         InstrumentationRegistry.getInstrumentation().getUiAutomation()
577                 .adoptShellPermissionIdentity();
578         try {
579             Context context = InstrumentationRegistry.getContext();
580             LocationManager lm = context.getSystemService(
581                     LocationManager.class);
582             boolean oldLocationOn = lm.isLocationEnabledForUser(
583                     UserHandle.of(UserHandle.myUserId()));
584 
585             if (enabled != oldLocationOn) {
586                 context.registerReceiver(locationModeChangeReceiver,
587                         new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
588                 lm.setLocationEnabledForUser(enabled, UserHandle.of(UserHandle.myUserId()));
589                 try {
590                     assertThat(locationChangeLatch.await(LOCATION_SETTING_CHANGE_WAIT_MS,
591                             TimeUnit.MILLISECONDS)).isTrue();
592                 } catch (InterruptedException e) {
593                     Log.w(NetworkScanApiTest.class.getSimpleName(),
594                             "Interrupted while waiting for location settings change. Test results"
595                                     + " may not be accurate.");
596                 } finally {
597                     context.unregisterReceiver(locationModeChangeReceiver);
598                 }
599             }
600             return oldLocationOn;
601         } finally {
602             InstrumentationRegistry.getInstrumentation().getUiAutomation()
603                     .dropShellPermissionIdentity();
604         }
605     }
606 
isScanStatusValid()607     private boolean isScanStatusValid() {
608         // TODO(b/72162885): test the size of ScanResults is not zero after the blocking bug fixed.
609         if ((mNetworkScanStatus == EVENT_NETWORK_SCAN_COMPLETED) && (mScanResults != null)) {
610             // Scan complete.
611             return true;
612         }
613         if ((mNetworkScanStatus == EVENT_NETWORK_SCAN_ERROR)
614                 && ((mErrorCode == NetworkScan.ERROR_MODEM_UNAVAILABLE)
615                         || (mErrorCode == NetworkScan.ERROR_UNSUPPORTED))) {
616             // Scan error but the error type is allowed.
617             return true;
618         }
619         return false;
620     }
621 
getPlmns()622     private ArrayList<String> getPlmns() {
623         ArrayList<String> mccMncs = new ArrayList<>();
624         mccMncs.add("310260");
625         mccMncs.add("310120");
626         return mccMncs;
627     }
628 
629     /** To test its constructor and getters. */
630     @Test
testNetworkScanRequest_constructorAndGetters()631     public void testNetworkScanRequest_constructorAndGetters() {
632         NetworkScanRequest networkScanRequest =
633                 new NetworkScanRequest(
634                         SCAN_TYPE,
635                         RADIO_ACCESS_SPECIFIERS,
636                         SEARCH_PERIODICITY_SEC,
637                         MAX_SEARCH_TIME_SEC,
638                         INCREMENTAL_RESULTS,
639                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
640                         getPlmns());
641 
642         assertWithMessage("getScanType() returns wrong value")
643                 .that(networkScanRequest.getScanType())
644                 .isEqualTo(SCAN_TYPE);
645         assertWithMessage("getSpecifiers() returns wrong value")
646                 .that(networkScanRequest.getSpecifiers())
647                 .isEqualTo(RADIO_ACCESS_SPECIFIERS);
648         assertWithMessage("getSearchPeriodicity() returns wrong value")
649                 .that(networkScanRequest.getSearchPeriodicity())
650                 .isEqualTo(SEARCH_PERIODICITY_SEC);
651         assertWithMessage("getMaxSearchTime() returns wrong value")
652                 .that(networkScanRequest.getMaxSearchTime())
653                 .isEqualTo(MAX_SEARCH_TIME_SEC);
654         assertWithMessage("getIncrementalResults() returns wrong value")
655                 .that(networkScanRequest.getIncrementalResults())
656                 .isEqualTo(INCREMENTAL_RESULTS);
657         assertWithMessage("getIncrementalResultsPeriodicity() returns wrong value")
658                 .that(networkScanRequest.getIncrementalResultsPeriodicity())
659                 .isEqualTo(INCREMENTAL_RESULTS_PERIODICITY_SEC);
660         assertWithMessage("getPlmns() returns wrong value")
661                 .that(networkScanRequest.getPlmns())
662                 .isEqualTo(getPlmns());
663         assertWithMessage("describeContents() returns wrong value")
664                 .that(networkScanRequest.describeContents())
665                 .isEqualTo(0);
666     }
667 
668     /** To test its hashCode method. */
669     @Test
testNetworkScanRequestParcel_hashCode()670     public void testNetworkScanRequestParcel_hashCode() {
671         NetworkScanRequest networkScanRequest1 =
672                 new NetworkScanRequest(
673                         SCAN_TYPE,
674                         RADIO_ACCESS_SPECIFIERS,
675                         SEARCH_PERIODICITY_SEC,
676                         MAX_SEARCH_TIME_SEC,
677                         INCREMENTAL_RESULTS,
678                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
679                         getPlmns());
680 
681         NetworkScanRequest networkScanRequest2 =
682                 new NetworkScanRequest(
683                         SCAN_TYPE,
684                         RADIO_ACCESS_SPECIFIERS,
685                         SEARCH_PERIODICITY_SEC,
686                         MAX_SEARCH_TIME_SEC,
687                         INCREMENTAL_RESULTS,
688                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
689                         getPlmns());
690 
691         NetworkScanRequest networkScanRequest3 =
692                 new NetworkScanRequest(
693                         SCAN_TYPE,
694                         null,
695                         SEARCH_PERIODICITY_SEC,
696                         MAX_SEARCH_TIME_SEC,
697                         false,
698                         0,
699                         getPlmns());
700 
701         assertWithMessage("hashCode() returns different hash code for same objects")
702                 .that(networkScanRequest1.hashCode())
703                 .isEqualTo(networkScanRequest2.hashCode());
704         assertWithMessage("hashCode() returns same hash code for different objects")
705                 .that(networkScanRequest1.hashCode())
706                 .isNotEqualTo(networkScanRequest3.hashCode());
707     }
708 
709     /** To test its comparison method. */
710     @Test
testNetworkScanRequestParcel_equals()711     public void testNetworkScanRequestParcel_equals() {
712         NetworkScanRequest networkScanRequest1 =
713                 new NetworkScanRequest(
714                         SCAN_TYPE,
715                         RADIO_ACCESS_SPECIFIERS,
716                         SEARCH_PERIODICITY_SEC,
717                         MAX_SEARCH_TIME_SEC,
718                         INCREMENTAL_RESULTS,
719                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
720                         getPlmns());
721 
722         NetworkScanRequest networkScanRequest2 =
723                 new NetworkScanRequest(
724                         SCAN_TYPE,
725                         RADIO_ACCESS_SPECIFIERS,
726                         SEARCH_PERIODICITY_SEC,
727                         MAX_SEARCH_TIME_SEC,
728                         INCREMENTAL_RESULTS,
729                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
730                         getPlmns());
731 
732         assertThat(networkScanRequest1).isEqualTo(networkScanRequest2);
733 
734         networkScanRequest2 =
735                 new NetworkScanRequest(
736                         SCAN_TYPE,
737                         RADIO_ACCESS_SPECIFIERS,
738                         SEARCH_PERIODICITY_SEC,
739                         MAX_SEARCH_TIME_SEC,
740                         INCREMENTAL_RESULTS,
741                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
742                         null /* List of PLMN ids (MCC-MNC) */);
743         assertThat(networkScanRequest1).isNotEqualTo(networkScanRequest2);
744     }
745 
746     /** To test its writeToParcel and createFromParcel methods. */
747     @Test
testNetworkScanRequestParcel_parcel()748     public void testNetworkScanRequestParcel_parcel() {
749         NetworkScanRequest networkScanRequest =
750                 new NetworkScanRequest(
751                         SCAN_TYPE,
752                         null /* Radio Access Specifier */,
753                         SEARCH_PERIODICITY_SEC,
754                         MAX_SEARCH_TIME_SEC,
755                         INCREMENTAL_RESULTS,
756                         INCREMENTAL_RESULTS_PERIODICITY_SEC,
757                         getPlmns());
758 
759         Parcel p = Parcel.obtain();
760         networkScanRequest.writeToParcel(p, 0);
761         p.setDataPosition(0);
762         NetworkScanRequest newnsr = NetworkScanRequest.CREATOR.createFromParcel(p);
763         assertThat(networkScanRequest).isEqualTo(newnsr);
764     }
765 }
766