• 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 org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotSame;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 
27 import android.content.Context;
28 import android.content.pm.PackageInfo;
29 import android.content.pm.PackageManager;
30 import android.os.AsyncTask;
31 import android.os.Handler;
32 import android.os.HandlerThread;
33 import android.os.Message;
34 import android.os.Parcel;
35 import android.os.Process;
36 import android.provider.Settings;
37 import android.telephony.AccessNetworkConstants;
38 import android.telephony.CellInfo;
39 import android.telephony.CellInfoGsm;
40 import android.telephony.CellInfoLte;
41 import android.telephony.CellInfoWcdma;
42 import android.telephony.NetworkScan;
43 import android.telephony.NetworkScanRequest;
44 import android.telephony.RadioAccessSpecifier;
45 import android.telephony.TelephonyManager;
46 import android.telephony.TelephonyScanManager;
47 import android.util.Log;
48 
49 import androidx.test.InstrumentationRegistry;
50 import androidx.test.runner.AndroidJUnit4;
51 
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.List;
60 import java.util.stream.Collectors;
61 
62 /**
63  * Build, install and run the tests by running the commands below:
64  *  make cts -j64
65  *  cts-tradefed run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.NetworkScanApiTest
66  */
67 @RunWith(AndroidJUnit4.class)
68 public class NetworkScanApiTest {
69     private TelephonyManager mTelephonyManager;
70     private PackageManager mPackageManager;
71     private static final String TAG = "NetworkScanApiTest";
72     private int mNetworkScanStatus;
73     private static final int EVENT_NETWORK_SCAN_START = 100;
74     private static final int EVENT_NETWORK_SCAN_RESULTS = 200;
75     private static final int EVENT_NETWORK_SCAN_RESTRICTED_RESULTS = 201;
76     private static final int EVENT_NETWORK_SCAN_ERROR = 300;
77     private static final int EVENT_NETWORK_SCAN_COMPLETED = 400;
78     private static final int EVENT_SCAN_DENIED = 500;
79     private List<CellInfo> mScanResults = null;
80     private NetworkScanHandlerThread mTestHandlerThread;
81     private Handler mHandler;
82     private NetworkScan mNetworkScan;
83     private NetworkScanRequest mNetworkScanRequest;
84     private NetworkScanCallbackImpl mNetworkScanCallback;
85     private static final int MAX_CELLINFO_WAIT_MILLIS = 5000; // 5 seconds
86     private static final int MAX_INIT_WAIT_MS = 60000; // 60 seconds
87     private Object mLock = new Object();
88     private boolean mReady;
89     private int mErrorCode;
90     /* All the following constants are used to construct NetworkScanRequest*/
91     private static final int SCAN_TYPE = NetworkScanRequest.SCAN_TYPE_ONE_SHOT;
92     private static final boolean INCREMENTAL_RESULTS = true;
93     private static final int SEARCH_PERIODICITY_SEC = 5;
94     private static final int MAX_SEARCH_TIME_SEC = 300;
95     private static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3;
96     private static final ArrayList<String> MCC_MNC = new ArrayList<>();
97     private static final RadioAccessSpecifier[] RADIO_ACCESS_SPECIFIERS = {
98             new RadioAccessSpecifier(
99                     AccessNetworkConstants.AccessNetworkType.GERAN,
100                     null /* bands */,
101                     null /* channels */),
102             new RadioAccessSpecifier(
103                     AccessNetworkConstants.AccessNetworkType.EUTRAN,
104                     null /* bands */,
105                     null /* channels */),
106             new RadioAccessSpecifier(
107                     AccessNetworkConstants.AccessNetworkType.UTRAN,
108                     null /* bands */,
109                     null /* channels */)
110     };
111 
112     // Needed because NETWORK_SCAN_PERMISSION is a systemapi
113     public static final String NETWORK_SCAN_PERMISSION = "android.permission.NETWORK_SCAN";
114 
115     @Before
setUp()116     public void setUp() throws Exception {
117         Context context = InstrumentationRegistry.getContext();
118         mTelephonyManager = (TelephonyManager)
119                 context.getSystemService(Context.TELEPHONY_SERVICE);
120         mPackageManager = context.getPackageManager();
121         InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
122                 context.getPackageName(), ACCESS_FINE_LOCATION);
123         InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
124                 context.getPackageName(), ACCESS_BACKGROUND_LOCATION);
125         mTestHandlerThread = new NetworkScanHandlerThread(TAG);
126         mTestHandlerThread.start();
127     }
128 
129     @After
tearDown()130     public void tearDown() throws Exception {
131         mTestHandlerThread.quit();
132     }
133 
waitUntilReady()134     private void waitUntilReady() {
135         synchronized (mLock) {
136             try {
137                 mLock.wait(MAX_INIT_WAIT_MS);
138             } catch (InterruptedException ie) {
139             }
140 
141             if (!mReady) {
142                 fail("NetworkScanApiTest failed to initialize");
143             }
144         }
145     }
146 
setReady(boolean ready)147     private void setReady(boolean ready) {
148         synchronized (mLock) {
149             mReady = ready;
150             mLock.notifyAll();
151         }
152     }
153 
154     private class NetworkScanHandlerThread extends HandlerThread {
155 
NetworkScanHandlerThread(String name)156         public NetworkScanHandlerThread(String name) {
157             super(name);
158         }
159 
160         @Override
onLooperPrepared()161         public void onLooperPrepared() {
162             /* create a custom handler for the Handler Thread */
163             mHandler = new Handler(mTestHandlerThread.getLooper()) {
164                 @Override
165                 public void handleMessage(Message msg) {
166                     switch (msg.what) {
167                         case EVENT_NETWORK_SCAN_START:
168                             Log.d(TAG, "request network scan");
169                             boolean useShellIdentity = (Boolean) msg.obj;
170                             if (useShellIdentity) {
171                                 InstrumentationRegistry.getInstrumentation().getUiAutomation()
172                                         .adoptShellPermissionIdentity();
173                             }
174                             try {
175                                 mNetworkScan = mTelephonyManager.requestNetworkScan(
176                                         mNetworkScanRequest,
177                                         AsyncTask.SERIAL_EXECUTOR,
178                                         mNetworkScanCallback);
179                                 if (mNetworkScan == null) {
180                                     mNetworkScanStatus = EVENT_SCAN_DENIED;
181                                     setReady(true);
182                                 }
183                             } catch (SecurityException e) {
184                                 mNetworkScanStatus = EVENT_SCAN_DENIED;
185                                 setReady(true);
186                             } finally {
187                                 if (useShellIdentity) {
188                                     InstrumentationRegistry.getInstrumentation().getUiAutomation()
189                                             .dropShellPermissionIdentity();
190                                 }
191                             }
192                             break;
193                         default:
194                             Log.d(TAG, "Unknown Event " + msg.what);
195                     }
196                 }
197             };
198         }
199     }
200 
201     private class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback {
202         @Override
onResults(List<CellInfo> results)203         public void onResults(List<CellInfo> results) {
204             Log.d(TAG, "onResults: " + results.toString());
205             mNetworkScanStatus = EVENT_NETWORK_SCAN_RESULTS;
206             mScanResults = results;
207         }
208 
209         @Override
onComplete()210         public void onComplete() {
211             Log.d(TAG, "onComplete");
212             mNetworkScanStatus = EVENT_NETWORK_SCAN_COMPLETED;
213             setReady(true);
214         }
215 
216         @Override
onError(int error)217         public void onError(int error) {
218             Log.d(TAG, "onError: " + String.valueOf(error));
219             mNetworkScanStatus = EVENT_NETWORK_SCAN_ERROR;
220             mErrorCode = error;
221             setReady(true);
222         }
223     }
224 
225     private class CellInfoResultsCallback extends TelephonyManager.CellInfoCallback {
226         public List<CellInfo> cellInfo;
227 
228         @Override
onCellInfo(List<CellInfo> cellInfo)229         public synchronized void onCellInfo(List<CellInfo> cellInfo) {
230             this.cellInfo = cellInfo;
231             notifyAll();
232         }
233 
wait(int millis)234         public synchronized void wait(int millis) throws InterruptedException {
235             if (cellInfo == null) {
236                 super.wait(millis);
237             }
238         }
239     }
240 
getRadioAccessSpecifier(List<CellInfo> allCellInfo)241     private List<RadioAccessSpecifier> getRadioAccessSpecifier(List<CellInfo> allCellInfo) {
242         List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
243         List<Integer> lteChannels = new ArrayList<>();
244         List<Integer> wcdmaChannels = new ArrayList<>();
245         List<Integer> gsmChannels = new ArrayList<>();
246         for (int i = 0; i < allCellInfo.size(); i++) {
247             CellInfo cellInfo = allCellInfo.get(i);
248             if (cellInfo instanceof CellInfoLte) {
249                 lteChannels.add(((CellInfoLte) cellInfo).getCellIdentity().getEarfcn());
250             } else if (cellInfo instanceof CellInfoWcdma) {
251                 wcdmaChannels.add(((CellInfoWcdma) cellInfo).getCellIdentity().getUarfcn());
252             } else if (cellInfo instanceof CellInfoGsm) {
253                 gsmChannels.add(((CellInfoGsm) cellInfo).getCellIdentity().getArfcn());
254             }
255         }
256         if (!lteChannels.isEmpty()) {
257             Log.d(TAG, "lte channels" + lteChannels.toString());
258             int ranLte = AccessNetworkConstants.AccessNetworkType.EUTRAN;
259             radioAccessSpecifier.add(
260                     new RadioAccessSpecifier(ranLte, null /* bands */,
261                             lteChannels.stream().mapToInt(i->i).toArray()));
262         }
263         if (!wcdmaChannels.isEmpty()) {
264             Log.d(TAG, "wcdma channels" + wcdmaChannels.toString());
265             int ranWcdma = AccessNetworkConstants.AccessNetworkType.UTRAN;
266             radioAccessSpecifier.add(
267                     new RadioAccessSpecifier(ranWcdma, null /* bands */,
268                             wcdmaChannels.stream().mapToInt(i->i).toArray()));
269         }
270         if (!gsmChannels.isEmpty()) {
271             Log.d(TAG, "gsm channels" + gsmChannels.toString());
272             int ranGsm = AccessNetworkConstants.AccessNetworkType.GERAN;
273             radioAccessSpecifier.add(
274                     new RadioAccessSpecifier(ranGsm, null /* bands */,
275                             gsmChannels.stream().mapToInt(i->i).toArray()));
276         }
277         return radioAccessSpecifier;
278     }
279 
280     /**
281      * Tests that the device properly requests a network scan.
282      */
283     @Test
testRequestNetworkScan()284     public void testRequestNetworkScan() {
285         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
286             // Checks whether the cellular stack should be running on this device.
287             Log.e(TAG, "No cellular support, the test will be skipped.");
288             return;
289         }
290         if (!mTelephonyManager.hasCarrierPrivileges()) {
291             fail("This test requires a SIM card with carrier privilege rule on it.");
292         }
293         boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
294         try {
295             mNetworkScanRequest = buildNetworkScanRequest(true);
296             mNetworkScanCallback = new NetworkScanCallbackImpl();
297             Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_START, false);
298             setReady(false);
299             startNetworkScan.sendToTarget();
300             waitUntilReady();
301 
302             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
303             assertTrue("The final scan status is " + mNetworkScanStatus + " with error code "
304                             + mErrorCode + ", not ScanCompleted"
305                             + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
306                             + " ERROR_UNSUPPORTED",
307                     isScanStatusValid());
308         } finally {
309             getAndSetLocationSwitch(isLocationSwitchOn);
310         }
311     }
312 
313     @Test
testRequestNetworkScanLocationOffPass()314     public void testRequestNetworkScanLocationOffPass() {
315         requestNetworkScanLocationOffHelper(false, true);
316     }
317 
318     @Test
testRequestNetworkScanLocationOffFail()319     public void testRequestNetworkScanLocationOffFail() {
320         requestNetworkScanLocationOffHelper(true, true);
321     }
322 
requestNetworkScanLocationOffHelper(boolean includeBandsAndChannels, boolean useSpecialScanPermission)323     public void requestNetworkScanLocationOffHelper(boolean includeBandsAndChannels,
324             boolean useSpecialScanPermission) {
325         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
326             // Checks whether the cellular stack should be running on this device.
327             Log.e(TAG, "No cellular support, the test will be skipped.");
328             return;
329         }
330         if (!mTelephonyManager.hasCarrierPrivileges()) {
331             fail("This test requires a SIM card with carrier privilege rule on it.");
332         }
333 
334         mNetworkScanRequest = buildNetworkScanRequest(includeBandsAndChannels);
335 
336         boolean isLocationSwitchOn = getAndSetLocationSwitch(false);
337         try {
338             mNetworkScanCallback = new NetworkScanCallbackImpl();
339             Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_START,
340                     useSpecialScanPermission);
341             setReady(false);
342             startNetworkScan.sendToTarget();
343             waitUntilReady();
344             if (includeBandsAndChannels) {
345                 // If we included the bands when location is off, expect a security error and
346                 // nothing else.
347                 assertEquals(EVENT_SCAN_DENIED, mNetworkScanStatus);
348                 return;
349             }
350 
351             Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
352             assertTrue("The final scan status is " + mNetworkScanStatus + " with error code "
353                             + mErrorCode + ", not ScanCompleted"
354                             + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
355                             + " ERROR_UNSUPPORTED",
356                     isScanStatusValid());
357         } finally {
358             getAndSetLocationSwitch(isLocationSwitchOn);
359         }
360     }
361 
buildNetworkScanRequest(boolean includeBandsAndChannels)362     private NetworkScanRequest buildNetworkScanRequest(boolean includeBandsAndChannels) {
363         // Make sure that there should be at least one entry.
364         List<CellInfo> allCellInfo = getCellInfo();
365         List<RadioAccessSpecifier> radioAccessSpecifier = new ArrayList<>();
366 
367         if (allCellInfo != null && allCellInfo.size() != 0) {
368             // Construct a NetworkScanRequest
369             radioAccessSpecifier = getRadioAccessSpecifier(allCellInfo);
370             if (!includeBandsAndChannels) {
371                 radioAccessSpecifier = radioAccessSpecifier.stream().map(spec ->
372                     new RadioAccessSpecifier(spec.getRadioAccessNetwork(), null, null))
373                     .collect(Collectors.toList());
374             }
375         }
376 
377         Log.d(TAG, "number of radioAccessSpecifier: " + radioAccessSpecifier.size());
378         if (radioAccessSpecifier.isEmpty()) {
379             // Put in some arbitrary bands and channels so that we trip the location check if needed
380             int[] fakeBands = includeBandsAndChannels
381                     ? new int[] { AccessNetworkConstants.EutranBand.BAND_5 }
382                     : null;
383             int[] fakeChannels = includeBandsAndChannels ? new int[] { 2400 } : null;
384 
385             RadioAccessSpecifier gsm = new RadioAccessSpecifier(
386                     AccessNetworkConstants.AccessNetworkType.GERAN,
387                     null /* bands */,
388                     null /* channels */);
389             RadioAccessSpecifier lte = new RadioAccessSpecifier(
390                     AccessNetworkConstants.AccessNetworkType.EUTRAN,
391                     fakeBands /* bands */,
392                     fakeChannels /* channels */);
393             RadioAccessSpecifier wcdma = new RadioAccessSpecifier(
394                     AccessNetworkConstants.AccessNetworkType.UTRAN,
395                     null /* bands */,
396                     null /* channels */);
397             radioAccessSpecifier.add(gsm);
398             radioAccessSpecifier.add(lte);
399             radioAccessSpecifier.add(wcdma);
400         }
401         RadioAccessSpecifier[] radioAccessSpecifierArray =
402                 new RadioAccessSpecifier[radioAccessSpecifier.size()];
403         return new NetworkScanRequest(
404                 NetworkScanRequest.SCAN_TYPE_ONE_SHOT /* scan type */,
405                 radioAccessSpecifier.toArray(radioAccessSpecifierArray),
406                 5 /* search periodicity */,
407                 60 /* max search time */,
408                 true /*enable incremental results*/,
409                 5 /* incremental results periodicity */,
410                 null /* List of PLMN ids (MCC-MNC) */);
411 
412     }
413 
getCellInfo()414     private List<CellInfo> getCellInfo() {
415         CellInfoResultsCallback resultsCallback = new CellInfoResultsCallback();
416         mTelephonyManager.requestCellInfoUpdate(r -> r.run(), resultsCallback);
417         try {
418             resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
419         } catch (InterruptedException ex) {
420             fail("CellInfoCallback was interrupted: " + ex);
421         }
422         return resultsCallback.cellInfo;
423     }
424 
425     @Test
testNetworkScanPermission()426     public void testNetworkScanPermission() {
427         PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
428 
429         List<Integer> specialUids = Arrays.asList(Process.SYSTEM_UID,
430                 Process.PHONE_UID, Process.SHELL_UID);
431 
432         List<PackageInfo> holding = pm.getPackagesHoldingPermissions(
433                 new String[] { NETWORK_SCAN_PERMISSION },
434                 PackageManager.MATCH_DISABLED_COMPONENTS);
435 
436         List<Integer> nonSpecialPackages = holding.stream()
437                 .map(pi -> {
438                     try {
439                         return pm.getPackageUid(pi.packageName, 0);
440                     } catch (PackageManager.NameNotFoundException e) {
441                         return Process.INVALID_UID;
442                     }
443                 })
444                 .filter(uid -> !specialUids.contains(uid))
445                 .collect(Collectors.toList());
446 
447         if (nonSpecialPackages.size() > 1) {
448             fail("Only one app on the device is allowed to hold the NETWORK_SCAN permission.");
449         }
450     }
451 
getAndSetLocationSwitch(boolean enabled)452     private boolean getAndSetLocationSwitch(boolean enabled) {
453         InstrumentationRegistry.getInstrumentation().getUiAutomation()
454                 .adoptShellPermissionIdentity();
455         try {
456             int oldLocationMode = Settings.Secure.getInt(
457                     InstrumentationRegistry.getContext().getContentResolver(),
458                     Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
459 
460             int locationMode = enabled ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
461                     : Settings.Secure.LOCATION_MODE_OFF;
462             if (locationMode != oldLocationMode) {
463                 Settings.Secure.putInt(InstrumentationRegistry.getContext().getContentResolver(),
464                         Settings.Secure.LOCATION_MODE, locationMode);
465             }
466             return oldLocationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
467         } finally {
468             InstrumentationRegistry.getInstrumentation().getUiAutomation()
469                     .dropShellPermissionIdentity();
470         }
471     }
472 
isScanStatusValid()473     private boolean isScanStatusValid() {
474         // TODO(b/72162885): test the size of ScanResults is not zero after the blocking bug fixed.
475         if ((mNetworkScanStatus == EVENT_NETWORK_SCAN_COMPLETED) && (mScanResults != null)) {
476             // Scan complete.
477             return true;
478         }
479         if ((mNetworkScanStatus == EVENT_NETWORK_SCAN_ERROR)
480                 && ((mErrorCode == NetworkScan.ERROR_MODEM_UNAVAILABLE)
481                 || (mErrorCode == NetworkScan.ERROR_UNSUPPORTED))) {
482             // Scan error but the error type is allowed.
483             return true;
484         }
485         return false;
486     }
487 
getPlmns()488     private ArrayList<String> getPlmns() {
489         ArrayList<String> mccMncs = new ArrayList<>();
490         mccMncs.add("310260");
491         mccMncs.add("310120");
492         return mccMncs;
493     }
494 
495     /**
496      * To test its constructor and getters.
497      */
498     @Test
testNetworkScanRequest_ConstructorAndGetters()499     public void testNetworkScanRequest_ConstructorAndGetters() {
500         NetworkScanRequest networkScanRequest = new NetworkScanRequest(
501                 SCAN_TYPE,
502                 RADIO_ACCESS_SPECIFIERS,
503                 SEARCH_PERIODICITY_SEC,
504                 MAX_SEARCH_TIME_SEC,
505                 INCREMENTAL_RESULTS,
506                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
507                 getPlmns());
508 
509         assertEquals("getScanType() returns wrong value",
510                 SCAN_TYPE, networkScanRequest.getScanType());
511         assertEquals("getSpecifiers() returns wrong value",
512                 RADIO_ACCESS_SPECIFIERS, networkScanRequest.getSpecifiers());
513         assertEquals("getSearchPeriodicity() returns wrong value",
514                 SEARCH_PERIODICITY_SEC, networkScanRequest.getSearchPeriodicity());
515         assertEquals("getMaxSearchTime() returns wrong value",
516                 MAX_SEARCH_TIME_SEC, networkScanRequest.getMaxSearchTime());
517         assertEquals("getIncrementalResults() returns wrong value",
518                 INCREMENTAL_RESULTS, networkScanRequest.getIncrementalResults());
519         assertEquals("getIncrementalResultsPeriodicity() returns wrong value",
520                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
521                 networkScanRequest.getIncrementalResultsPeriodicity());
522         assertEquals("getPlmns() returns wrong value", getPlmns(), networkScanRequest.getPlmns());
523         assertEquals("describeContents() returns wrong value",
524                 0, networkScanRequest.describeContents());
525     }
526 
527     /**
528      * To test its hashCode method.
529      */
530     @Test
testNetworkScanRequestParcel_Hashcode()531     public void testNetworkScanRequestParcel_Hashcode() {
532         NetworkScanRequest networkScanRequest1 = new NetworkScanRequest(
533                 SCAN_TYPE,
534                 RADIO_ACCESS_SPECIFIERS,
535                 SEARCH_PERIODICITY_SEC,
536                 MAX_SEARCH_TIME_SEC,
537                 INCREMENTAL_RESULTS,
538                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
539                 getPlmns());
540 
541         NetworkScanRequest networkScanRequest2 = new NetworkScanRequest(
542                 SCAN_TYPE,
543                 RADIO_ACCESS_SPECIFIERS,
544                 SEARCH_PERIODICITY_SEC,
545                 MAX_SEARCH_TIME_SEC,
546                 INCREMENTAL_RESULTS,
547                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
548                 getPlmns());
549 
550         NetworkScanRequest networkScanRequest3 = new NetworkScanRequest(
551                 SCAN_TYPE,
552                 null,
553                 SEARCH_PERIODICITY_SEC,
554                 MAX_SEARCH_TIME_SEC,
555                 false,
556                 0,
557                 getPlmns());
558 
559         assertEquals("hashCode() returns different hash code for same objects",
560                 networkScanRequest1.hashCode(), networkScanRequest2.hashCode());
561         assertNotSame("hashCode() returns same hash code for different objects",
562                 networkScanRequest1.hashCode(), networkScanRequest3.hashCode());
563     }
564 
565     /**
566      * To test its comparision method.
567      */
568     @Test
testNetworkScanRequestParcel_Equals()569     public void testNetworkScanRequestParcel_Equals() {
570         NetworkScanRequest networkScanRequest1 = new NetworkScanRequest(
571                 SCAN_TYPE,
572                 RADIO_ACCESS_SPECIFIERS,
573                 SEARCH_PERIODICITY_SEC,
574                 MAX_SEARCH_TIME_SEC,
575                 INCREMENTAL_RESULTS,
576                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
577                 getPlmns());
578 
579         NetworkScanRequest networkScanRequest2 = new NetworkScanRequest(
580                 SCAN_TYPE,
581                 RADIO_ACCESS_SPECIFIERS,
582                 SEARCH_PERIODICITY_SEC,
583                 MAX_SEARCH_TIME_SEC,
584                 INCREMENTAL_RESULTS,
585                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
586                 getPlmns());
587 
588         assertTrue(networkScanRequest1.equals(networkScanRequest2));
589 
590         networkScanRequest2 = new NetworkScanRequest(
591                 SCAN_TYPE,
592                 RADIO_ACCESS_SPECIFIERS,
593                 SEARCH_PERIODICITY_SEC,
594                 MAX_SEARCH_TIME_SEC,
595                 INCREMENTAL_RESULTS,
596                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
597                 null /* List of PLMN ids (MCC-MNC) */);
598         assertFalse(networkScanRequest1.equals(networkScanRequest2));
599     }
600 
601     /**
602      * To test its writeToParcel and createFromParcel methods.
603      */
604     @Test
testNetworkScanRequestParcel_Parcel()605     public void testNetworkScanRequestParcel_Parcel() {
606         NetworkScanRequest networkScanRequest = new NetworkScanRequest(
607                 SCAN_TYPE,
608                 null /* Radio Access Specifier */,
609                 SEARCH_PERIODICITY_SEC,
610                 MAX_SEARCH_TIME_SEC,
611                 INCREMENTAL_RESULTS,
612                 INCREMENTAL_RESULTS_PERIODICITY_SEC,
613                 getPlmns());
614 
615         Parcel p = Parcel.obtain();
616         networkScanRequest.writeToParcel(p, 0);
617         p.setDataPosition(0);
618         NetworkScanRequest newnsr = NetworkScanRequest.CREATOR.createFromParcel(p);
619         assertTrue(networkScanRequest.equals(newnsr));
620     }
621 }
622