• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.telephony.cts;
17 
18 import static androidx.test.InstrumentationRegistry.getContext;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assume.assumeTrue;
26 import static org.junit.Assert.fail;
27 
28 import android.annotation.Nullable;
29 import android.content.Context;
30 import android.content.pm.PackageManager;
31 import android.os.Parcel;
32 import android.os.SystemClock;
33 import android.telephony.AccessNetworkConstants;
34 import android.telephony.CellIdentity;
35 import android.telephony.CellIdentityCdma;
36 import android.telephony.CellIdentityGsm;
37 import android.telephony.CellIdentityLte;
38 import android.telephony.CellIdentityNr;
39 import android.telephony.CellIdentityTdscdma;
40 import android.telephony.CellIdentityWcdma;
41 import android.telephony.CellInfo;
42 import android.telephony.CellInfoCdma;
43 import android.telephony.CellInfoGsm;
44 import android.telephony.CellInfoLte;
45 import android.telephony.CellInfoNr;
46 import android.telephony.CellInfoTdscdma;
47 import android.telephony.CellInfoWcdma;
48 import android.telephony.CellSignalStrengthCdma;
49 import android.telephony.CellSignalStrengthGsm;
50 import android.telephony.CellSignalStrengthLte;
51 import android.telephony.CellSignalStrengthNr;
52 import android.telephony.CellSignalStrengthTdscdma;
53 import android.telephony.CellSignalStrengthWcdma;
54 import android.telephony.ClosedSubscriberGroupInfo;
55 import android.telephony.NetworkRegistrationInfo;
56 import android.telephony.PhoneStateListener;
57 import android.telephony.ServiceState;
58 import android.telephony.TelephonyManager;
59 import android.text.TextUtils;
60 import android.util.Log;
61 import android.util.Pair;
62 
63 import androidx.test.InstrumentationRegistry;
64 
65 import org.junit.Before;
66 import org.junit.Test;
67 
68 import java.util.Arrays;
69 import java.util.List;
70 import java.util.concurrent.Executor;
71 
72 /**
73  * Test TelephonyManager.getAllCellInfo()
74  * <p>
75  *
76  * Test that the Cellular Location APIs return proper and complete information.
77  * <ul>
78  *     <li>At least one cell must be reported as the registered cell.
79  *     <li>Registered cells must report the technology-specific fields consisting of a globally
80  *         unique cell identifier.
81  *     <li>All cells must report a technology-specific physical cell identifier, such as a tuple
82  *         of the frequency and a phyisical cell ID that allows them to be uniquely identified
83  *         given a known global cell.
84  *     <li>All cells must report at least one valid power measurement.
85  * </ul>
86  *
87  */
88 public class CellInfoTest {
89     private static final String TAG = "android.telephony.cts.CellInfoTest";
90 
91     // Maximum and minimum possible RSSI values(in dbm).
92     private static final int MAX_RSSI = -10;
93     private static final int MIN_RSSI = -150;
94     // Maximum and minimum possible RSRP values(in dbm).
95     private static final int MAX_RSRP = -44;
96     private static final int MIN_RSRP = -140;
97     // Maximum and minimum possible RSRQ values.
98     private static final int MAX_RSRQ = -3;
99     private static final int MIN_RSRQ = -35;
100     // Maximum and minimum possible RSSNR values.
101     private static final int MAX_RSSNR = 30;
102     private static final int MIN_RSSNR = -20;
103     // Maximum and minimum possible CQI values.
104     private static final int MAX_CQI = 15;
105     private static final int MIN_CQI = 0;
106 
107     /**
108      * Maximum and minimum valid LTE RSSI values in dBm
109      *
110      * The valid RSSI ASU range from current HAL is [0,31].
111      * Convert RSSI ASU to dBm: dBm = -113 + 2 * ASU, which is [-113, -51]
112      *
113      * Reference: TS 27.007 8.5 - Signal quality +CSQ
114      */
115     private static final int MAX_LTE_RSSI = -51;
116     private static final int MIN_LTE_RSSI = -113;
117 
118     // The followings are parameters for testing CellIdentityCdma
119     // Network Id ranges from 0 to 65535.
120     private static final int NETWORK_ID  = 65535;
121     // CDMA System Id ranges from 0 to 32767
122     private static final int SYSTEM_ID = 32767;
123     // Base Station Id ranges from 0 to 65535
124     private static final int BASESTATION_ID = 65535;
125     // Longitude ranges from -2592000 to 2592000.
126     private static final int LONGITUDE = 2592000;
127     // Latitude ranges from -1296000 to 1296000.
128     private static final int LATITUDE = 1296000;
129     // Cell identity ranges from 0 to 268435456.
130 
131     // The followings are parameters for testing CellIdentityLte
132     private static final int CI = 268435456;
133     // Physical cell id ranges from 0 to 503.
134     private static final int PCI = 503;
135     // Tracking area code ranges from 0 to 65535.
136     private static final int TAC = 65535;
137     // Absolute RF Channel Number ranges from 0 to 262143.
138     private static final int EARFCN_MAX = 262143;
139     private static final int BANDWIDTH_LOW = 1400;  // kHz
140     private static final int BANDWIDTH_HIGH = 20000;  // kHz
141     // 3GPP TS 36.101
142     private static final int BAND_MIN_LTE = 1;
143     private static final int BAND_MAX_LTE = 88;
144     //3GPP TS 136.213 section 7.2.3
145     private static final int CQI_TABLE_INDEX_MIN_LTE = 1;
146     private static final int CQI_TABLE_INDEX_MAX_LTE = 6;
147 
148     // The followings are parameters for testing CellIdentityWcdma
149     // Location Area Code ranges from 0 to 65535.
150     private static final int LAC = 65535;
151     // UMTS Cell Identity ranges from 0 to 268435455.
152     private static final int CID_UMTS = 268435455;
153     // Primary Scrambling Code ranges from 0 to 511.
154     private static final int PSC = 511;
155     // Cell Parameters Index rangest from 0-127.
156     private static final int CPID = 127;
157 
158     // The followings are parameters for testing CellIdentityGsm
159     // GSM Cell Identity ranges from 0 to 65535.
160     private static final int CID_GSM = 65535;
161     // GSM Absolute RF Channel Number ranges from 0 to 65535.
162     private static final int ARFCN = 1024;
163 
164     // The followings are parameters for testing CellIdentityNr
165     // 3GPP TS 38.101-1 and 38.101-2
166     private static final int BAND_FR1_MIN_NR = 1;
167     private static final int BAND_FR1_MAX_NR = 95;
168     private static final int BAND_FR2_MIN_NR = 257;
169     private static final int BAND_FR2_MAX_NR = 261;
170     //3GPP TS 138.214 section 5.2.2.1
171     private static final int CQI_TABLE_INDEX_MIN_NR = 1;
172     private static final int CQI_TABLE_INDEX_MAX_NR = 3;
173 
174     // 3gpp 36.101 Sec 5.7.2
175     private static final int CHANNEL_RASTER_EUTRAN = 100; //kHz
176 
177     private static final int MAX_CELLINFO_WAIT_MILLIS = 5000;
178     private static final int MAX_LISTENER_WAIT_MILLIS = 1000; // usually much less
179     // The maximum interval between CellInfo updates from the modem. In the AOSP code it varies
180     // between 2 and 10 seconds, and there is an allowable modem delay of 3 seconds, so if we
181     // cannot get a seconds CellInfo update within 15 seconds, then something is broken.
182     // See DeviceStateMonitor#CELL_INFO_INTERVAL_*
183     private static final int MAX_CELLINFO_INTERVAL_MILLIS = 15000; // in AOSP the max is 10s
184     private static final int RADIO_HAL_VERSION_1_2 = makeRadioVersion(1, 2);
185     private static final int RADIO_HAL_VERSION_1_5 = makeRadioVersion(1, 5);
186 
187     private PackageManager mPm;
188     private TelephonyManager mTm;
189 
190     private int mNetworkHalVersion;
191 
makeRadioVersion(int major, int minor)192     private static final int makeRadioVersion(int major, int minor) {
193         if (major < 0 || minor < 0) return 0;
194         return major * 100 + minor;
195     }
196 
197     private Executor mSimpleExecutor = new Executor() {
198         @Override
199         public void execute(Runnable r) {
200             r.run();
201         }
202     };
203 
204     private static class CellInfoResultsCallback extends TelephonyManager.CellInfoCallback {
205         List<CellInfo> cellInfo;
206 
207         @Override
onCellInfo(List<CellInfo> cellInfo)208         public synchronized void onCellInfo(List<CellInfo> cellInfo) {
209             this.cellInfo = cellInfo;
210             notifyAll();
211         }
212 
wait(int millis)213         public synchronized void wait(int millis) throws InterruptedException {
214             if (cellInfo == null) {
215                 super.wait(millis);
216             }
217         }
218     }
219 
220     private static class CellInfoListener extends PhoneStateListener {
221         List<CellInfo> cellInfo;
222 
CellInfoListener(Executor e)223         public CellInfoListener(Executor e) {
224             super(e);
225         }
226 
227         @Override
onCellInfoChanged(List<CellInfo> cellInfo)228         public synchronized void onCellInfoChanged(List<CellInfo> cellInfo) {
229             this.cellInfo = cellInfo;
230             notifyAll();
231         }
232 
wait(int millis)233         public synchronized void wait(int millis) throws InterruptedException {
234             if (cellInfo == null) {
235                 super.wait(millis);
236             }
237         }
238     }
239 
isCamped()240     private boolean isCamped() {
241         InstrumentationRegistry.getInstrumentation().getUiAutomation()
242                 .adoptShellPermissionIdentity("android.permission.READ_PHONE_STATE");
243 
244         ServiceState ss = mTm.getServiceState();
245         if (ss == null) return false;
246         if (ss.getState() == ServiceState.STATE_EMERGENCY_ONLY) return true;
247         List<NetworkRegistrationInfo> nris = ss.getNetworkRegistrationInfoList();
248         for (NetworkRegistrationInfo nri : nris) {
249             if (nri.getTransportType() != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) continue;
250             if (nri.isRegistered()) return true;
251         }
252         return false;
253     }
254 
255     @Before
setUp()256     public void setUp() throws Exception {
257         mPm = getContext().getPackageManager();
258         assumeTrue(mPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
259 
260         mTm = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
261         Pair<Integer, Integer> verPair =
262                 mTm.getHalVersion(TelephonyManager.HAL_SERVICE_NETWORK);
263         mNetworkHalVersion = makeRadioVersion(verPair.first, verPair.second);
264         TelephonyManagerTest.grantLocationPermissions();
265     }
266 
267     /**
268      * Test to ensure that the PhoneStateListener receives callbacks every time that new CellInfo
269      * is received and not otherwise.
270      */
271     @Test
testPhoneStateListenerCallback()272     public void testPhoneStateListenerCallback() throws Throwable {
273         CellInfoResultsCallback resultsCallback = new CellInfoResultsCallback();
274         // Prime the system by requesting a CellInfoUpdate
275         mTm.requestCellInfoUpdate(mSimpleExecutor, resultsCallback);
276         resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
277         // Register a new PhoneStateListener for CellInfo
278         CellInfoListener listener = new CellInfoListener(mSimpleExecutor);
279         mTm.listen(listener, PhoneStateListener.LISTEN_CELL_INFO);
280         // Expect a callback immediately upon registration
281         listener.wait(MAX_LISTENER_WAIT_MILLIS);
282         assertNotNull("CellInfo Listener Never Fired on Registration", listener.cellInfo);
283         // Save the initial listener result as a baseline
284         List<CellInfo> referenceList = listener.cellInfo;
285         assertFalse("CellInfo does not contain valid results", referenceList.isEmpty());
286         assertTrue("Listener Didn't Receive the Right Data",
287                 referenceList.containsAll(resultsCallback.cellInfo));
288         listener.cellInfo = null;
289         resultsCallback.cellInfo = null;
290         long timeoutTime = SystemClock.elapsedRealtime() + MAX_CELLINFO_INTERVAL_MILLIS;
291         while (timeoutTime > SystemClock.elapsedRealtime()) {
292             // Request a CellInfo update to try and coax an update from the listener
293             mTm.requestCellInfoUpdate(mSimpleExecutor, resultsCallback);
294             resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
295             assertNotNull("CellInfoCallback should return valid data", resultsCallback.cellInfo);
296             if (referenceList.containsAll(resultsCallback.cellInfo)) {
297                 // Check the a call to getAllCellInfo doesn't trigger the listener.
298                 mTm.getAllCellInfo();
299                 // Wait for the listener to fire; it shouldn't.
300                 listener.wait(MAX_LISTENER_WAIT_MILLIS);
301                 // Check to ensure the listener didn't fire for stale data.
302                 assertNull("PhoneStateListener Fired For Old CellInfo Data", listener.cellInfo);
303             } else {
304                 // If there is new CellInfo data, then the listener should fire
305                 listener.wait(MAX_LISTENER_WAIT_MILLIS);
306                 assertNotNull("Listener did not receive updated CellInfo Data",
307                         listener.cellInfo);
308                 assertFalse("CellInfo data should be different from the old listener data."
309                         + referenceList + " : " + listener.cellInfo,
310                         referenceList.containsAll(listener.cellInfo));
311                 return; // pass the test
312             }
313             // Reset the resultsCallback for the next iteration
314             resultsCallback.cellInfo = null;
315         }
316     }
317 
318     @Test
testCellInfo()319     public void testCellInfo() throws Throwable {
320         if (!isCamped()) fail("Device is not camped to a cell");
321 
322         // Make a blocking call to requestCellInfoUpdate for results (for simplicity of test).
323         CellInfoResultsCallback resultsCallback = new CellInfoResultsCallback();
324         mTm.requestCellInfoUpdate(mSimpleExecutor, resultsCallback);
325         resultsCallback.wait(MAX_CELLINFO_WAIT_MILLIS);
326         List<CellInfo> allCellInfo = resultsCallback.cellInfo;
327 
328         assertNotNull("TelephonyManager.getAllCellInfo() returned NULL!", allCellInfo);
329         assertTrue("TelephonyManager.getAllCellInfo() returned zero-length list!",
330             allCellInfo.size() > 0);
331 
332         int numRegisteredCells = 0;
333         for (CellInfo cellInfo : allCellInfo) {
334             if (cellInfo.isRegistered()) {
335                 ++numRegisteredCells;
336             }
337             verifyBaseCellInfo(cellInfo);
338             verifyBaseCellIdentity(cellInfo.getCellIdentity(), cellInfo.isRegistered());
339             if (cellInfo instanceof CellInfoLte) {
340                 verifyLteInfo((CellInfoLte) cellInfo);
341             } else if (cellInfo instanceof CellInfoWcdma) {
342                 verifyWcdmaInfo((CellInfoWcdma) cellInfo);
343             } else if (cellInfo instanceof CellInfoGsm) {
344                 verifyGsmInfo((CellInfoGsm) cellInfo);
345             } else if (cellInfo instanceof CellInfoCdma) {
346                 verifyCdmaInfo((CellInfoCdma) cellInfo);
347             } else if (cellInfo instanceof CellInfoTdscdma) {
348                 verifyTdscdmaInfo((CellInfoTdscdma) cellInfo);
349             } else if (cellInfo instanceof CellInfoNr) {
350                 verifyNrInfo((CellInfoNr) cellInfo);
351             } else {
352                 fail("Unknown CellInfo Type reported.");
353             }
354         }
355 
356         //FIXME: The maximum needs to be calculated based on the number of
357         //       radios and the technologies used (ex SRLTE); however, we have
358         //       not hit any of these cases yet.
359         assertTrue("None or too many registered cells : " + numRegisteredCells,
360                 numRegisteredCells > 0 && numRegisteredCells <= 2);
361     }
362 
verifyBaseCellInfo(CellInfo info)363     private void verifyBaseCellInfo(CellInfo info) {
364         assertTrue("Invalid timestamp in CellInfo: " + info.getTimeStamp(),
365                 info.getTimeStamp() > 0 && info.getTimeStamp() < Long.MAX_VALUE);
366 
367         long curTime = SystemClock.elapsedRealtime();
368         assertTrue("Invalid timestamp in CellInfo: " + info.getTimestampMillis(),
369                 info.getTimestampMillis() > 0 && info.getTimestampMillis() <= curTime);
370 
371         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
372             // In HAL 1.2 or greater, the connection status must be reported
373             assertTrue(info.getCellConnectionStatus() != CellInfo.CONNECTION_UNKNOWN);
374         }
375     }
376 
verifyBaseCellIdentity(CellIdentity id, boolean isRegistered)377     private void verifyBaseCellIdentity(CellIdentity id, boolean isRegistered) {
378         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
379             if (isRegistered) {
380                 String alphaLong = (String) id.getOperatorAlphaLong();
381                 assertNotNull("getOperatorAlphaLong() returns NULL!", alphaLong);
382 
383                 String alphaShort = (String) id.getOperatorAlphaShort();
384                 assertNotNull("getOperatorAlphaShort() returns NULL!", alphaShort);
385             }
386         }
387     }
388 
verifyCdmaInfo(CellInfoCdma cdma)389     private void verifyCdmaInfo(CellInfoCdma cdma) {
390         verifyCellConnectionStatus(cdma.getCellConnectionStatus());
391         verifyCellInfoCdmaParcelandHashcode(cdma);
392         verifyCellIdentityCdma(cdma.getCellIdentity(), cdma.isRegistered());
393         verifyCellIdentityCdmaParcel(cdma.getCellIdentity());
394         verifyCellSignalStrengthCdma(cdma.getCellSignalStrength());
395         verifyCellSignalStrengthCdmaParcel(cdma.getCellSignalStrength());
396     }
397 
verifyCellInfoCdmaParcelandHashcode(CellInfoCdma cdma)398     private void verifyCellInfoCdmaParcelandHashcode(CellInfoCdma cdma) {
399         Parcel p = Parcel.obtain();
400         cdma.writeToParcel(p, 0);
401         p.setDataPosition(0);
402 
403         CellInfoCdma newCi = CellInfoCdma.CREATOR.createFromParcel(p);
404         assertTrue(cdma.equals(newCi));
405         assertEquals("hashCode() did not get right hashCode", cdma.hashCode(), newCi.hashCode());
406     }
407 
verifyCellIdentityCdma(CellIdentityCdma cdma, boolean isRegistered)408     private void verifyCellIdentityCdma(CellIdentityCdma cdma, boolean isRegistered) {
409         int networkId = cdma.getNetworkId();
410         assertTrue("getNetworkId() out of range [0,65535], networkId=" + networkId,
411                 networkId == CellInfo.UNAVAILABLE || (networkId >= 0 && networkId <= NETWORK_ID));
412 
413         int systemId = cdma.getSystemId();
414         assertTrue("getSystemId() out of range [0,32767], systemId=" + systemId,
415                 systemId == CellInfo.UNAVAILABLE || (systemId >= 0 && systemId <= SYSTEM_ID));
416 
417         int basestationId = cdma.getBasestationId();
418         assertTrue("getBasestationId() out of range [0,65535], basestationId=" + basestationId,
419                 basestationId == CellInfo.UNAVAILABLE
420                         || (basestationId >= 0 && basestationId <= BASESTATION_ID));
421 
422         int longitude = cdma.getLongitude();
423         assertTrue("getLongitude() out of range [-2592000,2592000], longitude=" + longitude,
424                 longitude == CellInfo.UNAVAILABLE
425                         || (longitude >= -LONGITUDE && longitude <= LONGITUDE));
426 
427         int latitude = cdma.getLatitude();
428         assertTrue("getLatitude() out of range [-1296000,1296000], latitude=" + latitude,
429                 latitude == CellInfo.UNAVAILABLE
430                         || (latitude >= -LATITUDE && latitude <= LATITUDE));
431 
432         if (isRegistered) {
433             assertTrue("SID is required for registered cells", systemId != CellInfo.UNAVAILABLE);
434             assertTrue("NID is required for registered cells", networkId != CellInfo.UNAVAILABLE);
435             assertTrue("BSID is required for registered cells",
436                     basestationId != CellInfo.UNAVAILABLE);
437         }
438 
439         verifyCellIdentityCdmaLocationSanitation(cdma);
440     }
441 
verifyCellIdentityCdmaLocationSanitation(CellIdentityCdma cdma)442     private void verifyCellIdentityCdmaLocationSanitation(CellIdentityCdma cdma) {
443         CellIdentityCdma sanitized = cdma.sanitizeLocationInfo();
444         assertEquals(CellInfo.UNAVAILABLE, sanitized.getNetworkId());
445         assertEquals(CellInfo.UNAVAILABLE, sanitized.getSystemId());
446         assertEquals(CellInfo.UNAVAILABLE, sanitized.getBasestationId());
447         assertEquals(CellInfo.UNAVAILABLE, sanitized.getLongitude());
448         assertEquals(CellInfo.UNAVAILABLE, sanitized.getLatitude());
449     }
450 
verifyCellIdentityCdmaParcel(CellIdentityCdma cdma)451     private void verifyCellIdentityCdmaParcel(CellIdentityCdma cdma) {
452         Parcel p = Parcel.obtain();
453         cdma.writeToParcel(p, 0);
454         p.setDataPosition(0);
455 
456         CellIdentityCdma newCi = CellIdentityCdma.CREATOR.createFromParcel(p);
457         assertTrue(cdma.equals(newCi));
458     }
459 
verifyCellSignalStrengthCdma(CellSignalStrengthCdma cdma)460     private void verifyCellSignalStrengthCdma(CellSignalStrengthCdma cdma) {
461         int level = cdma.getLevel();
462         assertTrue("getLevel() out of range [0,4], level=" + level,
463                 level >= 0 && level <= 4);
464 
465         int asuLevel = cdma.getAsuLevel();
466         assertTrue("getAsuLevel() out of range [0,97] (or 99 is unknown), asuLevel=" + asuLevel,
467                 asuLevel == 99 || (asuLevel >= 0 && asuLevel <= 97));
468 
469         int cdmaLevel = cdma.getCdmaLevel();
470         assertTrue("getCdmaLevel() out of range [0,4], cdmaLevel=" + cdmaLevel,
471                 cdmaLevel >= 0 && cdmaLevel <= 4);
472 
473         int evdoLevel = cdma.getEvdoLevel();
474         assertTrue("getEvdoLevel() out of range [0,4], evdoLevel=" + evdoLevel,
475                 evdoLevel >= 0 && evdoLevel <= 4);
476 
477         // The following four fields do not have specific limits. So just calling to verify that
478         // they don't crash the phone.
479         int cdmaDbm = cdma.getCdmaDbm();
480         int evdoDbm = cdma.getEvdoDbm();
481         cdma.getCdmaEcio();
482         cdma.getEvdoEcio();
483 
484         int dbm = (cdmaDbm < evdoDbm) ? cdmaDbm : evdoDbm;
485         assertEquals("getDbm() did not get correct value", dbm, cdma.getDbm());
486 
487         int evdoSnr = cdma.getEvdoSnr();
488         assertTrue("getEvdoSnr() out of range [0,8], evdoSnr=" + evdoSnr,
489                 (evdoSnr == CellInfo.UNAVAILABLE) || (evdoSnr >= 0 && evdoSnr <= 8));
490     }
491 
verifyCellSignalStrengthCdmaParcel(CellSignalStrengthCdma cdma)492     private void verifyCellSignalStrengthCdmaParcel(CellSignalStrengthCdma cdma) {
493         Parcel p = Parcel.obtain();
494         cdma.writeToParcel(p, 0);
495         p.setDataPosition(0);
496 
497         CellSignalStrengthCdma newCss = CellSignalStrengthCdma.CREATOR.createFromParcel(p);
498         assertEquals(cdma, newCss);
499     }
500 
verifyPlmnInfo(String mccStr, String mncStr, int mcc, int mnc)501     private static void verifyPlmnInfo(String mccStr, String mncStr, int mcc, int mnc) {
502         // If either int value is invalid, all values must be invalid
503         if (mcc == CellInfo.UNAVAILABLE) {
504             assertTrue("MNC and MNC must always be reported together.",
505                     mnc == CellInfo.UNAVAILABLE && mccStr == null && mncStr == null);
506             return;
507         }
508 
509         assertTrue("getMcc() out of range [0, 999], mcc=" + mcc, (mcc >= 0 && mcc <= 999));
510         assertTrue("getMnc() out of range [0, 999], mnc=" + mnc, (mnc >= 0 && mnc <= 999));
511         assertTrue("MCC and MNC Strings must always be reported together.",
512                 (mccStr == null) == (mncStr == null));
513 
514         // For legacy compatibility, it's possible to have int values without valid string values
515         // but not the other way around.
516         // mccStr is set as NULL if empty, unknown or invalid.
517         assertTrue("getMccString() out of range [0, 999], mcc=" + mccStr,
518                 mccStr == null || mccStr.matches("^[0-9]{3}$"));
519         // mccStr must either be null or match mcc integer.
520         assertTrue("MccString must match Mcc Integer, str=" + mccStr + " int=" + mcc,
521                 mccStr == null || mcc == Integer.parseInt(mccStr));
522 
523         // mncStr is set as NULL if empty, unknown or invalid.
524         assertTrue("getMncString() out of range [0, 999], mnc=" + mncStr,
525                 mncStr == null || mncStr.matches("^[0-9]{2,3}$"));
526         // mncStr must either be null or match mnc integer.
527         assertTrue("MncString must match Mnc Integer, str=" + mncStr + " int=" + mnc,
528                 mncStr == null || mnc == Integer.parseInt(mncStr));
529     }
530 
531     // Verify lte cell information is within correct range.
verifyLteInfo(CellInfoLte lte)532     private void verifyLteInfo(CellInfoLte lte) {
533         verifyCellConnectionStatus(lte.getCellConnectionStatus());
534         verifyCellInfoLteParcelandHashcode(lte);
535         verifyCellIdentityLte(lte.getCellIdentity(), lte.isRegistered());
536         verifyCellIdentityLteParcel(lte.getCellIdentity());
537         verifyCellSignalStrengthLte(lte.getCellSignalStrength());
538         verifyCellSignalStrengthLteParcel(lte.getCellSignalStrength());
539     }
540 
541     // Verify NR 5G cell information is within correct range.
verifyNrInfo(CellInfoNr nr)542     private void verifyNrInfo(CellInfoNr nr) {
543         verifyCellConnectionStatus(nr.getCellConnectionStatus());
544         verifyCellIdentityNr((CellIdentityNr) nr.getCellIdentity(), nr.isRegistered());
545         verifyCellIdentityNrParcel((CellIdentityNr) nr.getCellIdentity());
546         verifyCellSignalStrengthNr((CellSignalStrengthNr) nr.getCellSignalStrength());
547         verifyCellSignalStrengthNrParcel((CellSignalStrengthNr) nr.getCellSignalStrength());
548     }
549 
verifyCellSignalStrengthNrParcel(CellSignalStrengthNr nr)550     private void verifyCellSignalStrengthNrParcel(CellSignalStrengthNr nr) {
551         Parcel p = Parcel.obtain();
552         nr.writeToParcel(p, 0);
553         p.setDataPosition(0);
554 
555         CellSignalStrengthNr newCss = CellSignalStrengthNr.CREATOR.createFromParcel(p);
556         assertEquals(nr, newCss);
557     }
558 
verifyCellIdentityNrParcel(CellIdentityNr nr)559     private void verifyCellIdentityNrParcel(CellIdentityNr nr) {
560         Parcel p = Parcel.obtain();
561         nr.writeToParcel(p, 0);
562         p.setDataPosition(0);
563 
564         CellIdentityNr newCi = CellIdentityNr.CREATOR.createFromParcel(p);
565         assertEquals(nr, newCi);
566     }
567 
verifyCellIdentityNr(CellIdentityNr nr, boolean isRegistered)568     private void verifyCellIdentityNr(CellIdentityNr nr, boolean isRegistered) {
569         // This class was added after numeric mcc/mncs were no longer provided, so it lacks the
570         // basic getMcc() and getMnc() - empty out those checks.
571         String mccStr = nr.getMccString();
572         String mncStr = nr.getMncString();
573         verifyPlmnInfo(mccStr, mncStr,
574                 mccStr != null ? Integer.parseInt(mccStr) : CellInfo.UNAVAILABLE,
575                 mncStr != null ? Integer.parseInt(mncStr) : CellInfo.UNAVAILABLE);
576 
577         int pci = nr.getPci();
578         assertTrue("getPci() out of range [0, 1007], pci = " + pci, 0 <= pci && pci <= 1007);
579 
580         int tac = nr.getTac();
581         assertTrue("getTac() out of range [0, 16777215], tac = " + tac,
582             (tac == Integer.MAX_VALUE) || (0 <= tac && tac <= 16777215));
583 
584         int nrArfcn = nr.getNrarfcn();
585         assertTrue("getNrarfcn() out of range [0, 3279165], nrarfcn = " + nrArfcn,
586                 0 <= nrArfcn && nrArfcn <= 3279165);
587 
588         for (String plmnId : nr.getAdditionalPlmns()) {
589             verifyPlmnId(plmnId);
590         }
591 
592         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_5) {
593             int[] bands = nr.getBands();
594 
595             for (int band: bands) {
596                 assertTrue("getBand out of range [1, 95] or [257, 261], band = " + band,
597                         (band >= BAND_FR1_MIN_NR && band <= BAND_FR1_MAX_NR)
598                         || (band >= BAND_FR2_MIN_NR && band <= BAND_FR2_MAX_NR));
599 
600                 verifyCellIdentityNrBands(bands);
601             }
602         }
603 
604         // If the cell is reported as registered, then all the logical cell info must be reported
605         if (isRegistered) {
606             assertTrue("TAC is required for registered cells", tac != CellInfo.UNAVAILABLE);
607             assertTrue("MCC is required for registered cells", nr.getMccString() != null);
608             assertTrue("MNC is required for registered cells", nr.getMncString() != null);
609         }
610 
611         verifyCellIdentityNrLocationSanitation(nr);
612     }
613 
verifyCellIdentityNrLocationSanitation(CellIdentityNr nr)614     private void verifyCellIdentityNrLocationSanitation(CellIdentityNr nr) {
615         CellIdentityNr sanitized = nr.sanitizeLocationInfo();
616         assertEquals(CellInfo.UNAVAILABLE, sanitized.getPci());
617         assertEquals(CellInfo.UNAVAILABLE, sanitized.getTac());
618         assertEquals(CellInfo.UNAVAILABLE_LONG, sanitized.getNci());
619     }
620 
verifyCellSignalStrengthNr(CellSignalStrengthNr nr)621     private void verifyCellSignalStrengthNr(CellSignalStrengthNr nr) {
622         int csiRsrp = nr.getCsiRsrp();
623         int csiRsrq = nr.getCsiRsrq();
624         int csiSinr = nr.getSsSinr();
625         int csiCqiTableIndex = nr.getCsiCqiTableIndex();
626         List<Integer> csiCqiReport = nr.getCsiCqiReport();
627         int ssRsrp = nr.getSsRsrp();
628         int ssRsrq = nr.getSsRsrq();
629         int ssSinr = nr.getSsSinr();
630         int timingAdvance = nr.getTimingAdvanceMicros();
631 
632         assertTrue("getCsiRsrp() out of range [-140, -44] | Integer.MAX_INTEGER, csiRsrp = "
633                         + csiRsrp, -140 <= csiRsrp && csiRsrp <= -44
634                 || csiRsrp == CellInfo.UNAVAILABLE);
635         assertTrue("getCsiRsrq() out of range [-20, -3] | Integer.MAX_INTEGER, csiRsrq = "
636                 + csiRsrq, -20 <= csiRsrq && csiRsrq <= -3 || csiRsrq == CellInfo.UNAVAILABLE);
637         assertTrue("getCsiSinr() out of range [-23, 40] | Integer.MAX_INTEGER, csiSinr = "
638                 + csiSinr, -23 <= csiSinr && csiSinr <= 40 || csiSinr == CellInfo.UNAVAILABLE);
639         assertTrue("getCsiCqiTableIndex() out of range | CellInfo.UNAVAILABLE, csiCqiTableIndex="
640                 + csiCqiTableIndex, csiCqiTableIndex == CellInfo.UNAVAILABLE
641                         || (csiCqiTableIndex >= CQI_TABLE_INDEX_MIN_NR
642                                 && csiCqiTableIndex <= CQI_TABLE_INDEX_MAX_NR));
643         assertTrue("cqi in getCsiCqiReport() out of range | CellInfo.UNAVAILABLE, csiCqiReport="
644                 + csiCqiReport, csiCqiReport.stream().allMatch(
645                         cqi -> cqi == CellInfo.UNAVAILABLE || (cqi >= MIN_CQI && cqi <= MAX_CQI)));
646         assertTrue("getSsRsrp() out of range [-140, -44] | Integer.MAX_INTEGER, ssRsrp = "
647                         + ssRsrp, -140 <= ssRsrp && ssRsrp <= -44
648                 || ssRsrp == CellInfo.UNAVAILABLE);
649         assertTrue("getSsRsrq() out of range [-20, -3] | Integer.MAX_INTEGER, ssRsrq = "
650                 + ssRsrq, -20 <= ssRsrq && ssRsrq <= -3 || ssRsrq == CellInfo.UNAVAILABLE);
651         assertTrue("getSsSinr() out of range [-23, 40] | Integer.MAX_INTEGER, ssSinr = "
652                 + ssSinr, -23 <= ssSinr && ssSinr <= 40 || ssSinr == CellInfo.UNAVAILABLE);
653         assertTrue("getTimingAdvanceMicros() out of range [0, 1282] | Integer.MAX_INTEGER, "
654                 + "timingAdvance = " + timingAdvance, 0 <= timingAdvance && timingAdvance <= 1282
655                 || timingAdvance == CellInfo.UNAVAILABLE);
656     }
657 
verifyCellIdentityNrBands(int[] nrBands)658     private void verifyCellIdentityNrBands(int[] nrBands) {
659         //Verify the registered cell reports non-null band.
660         assertTrue(nrBands != null);
661 
662         //Verify the registered cell reports at least one band.
663         assertTrue(Arrays.stream(nrBands).anyMatch(band -> band > 0));
664     }
665 
verifyCellInfoLteParcelandHashcode(CellInfoLte lte)666     private void verifyCellInfoLteParcelandHashcode(CellInfoLte lte) {
667         Parcel p = Parcel.obtain();
668         lte.writeToParcel(p, 0);
669         p.setDataPosition(0);
670 
671         CellInfoLte newCi = CellInfoLte.CREATOR.createFromParcel(p);
672         assertTrue(lte.equals(newCi));
673         assertEquals("hashCode() did not get right hashCode", lte.hashCode(), newCi.hashCode());
674     }
675 
verifyCellIdentityLte(CellIdentityLte lte, boolean isRegistered)676     private void verifyCellIdentityLte(CellIdentityLte lte, boolean isRegistered) {
677         verifyPlmnInfo(lte.getMccString(), lte.getMncString(), lte.getMcc(), lte.getMnc());
678 
679         // Cell identity ranges from 0 to 268435456.
680         int ci = lte.getCi();
681         assertTrue("getCi() out of range [0,268435456], ci=" + ci,
682                 (ci == CellInfo.UNAVAILABLE) || (ci >= 0 && ci <= CI));
683 
684         // Verify LTE physical cell id information.
685         // Only physical cell id is available for LTE neighbor.
686         int pci = lte.getPci();
687         // Physical cell id should be within [0, 503].
688         assertTrue("getPci() out of range [0, 503], pci=" + pci, (pci >= 0 && pci <= PCI));
689 
690         // Tracking area code ranges from 0 to 65535.
691         int tac = lte.getTac();
692         assertTrue("getTac() out of range [0,65535], tac=" + tac,
693                 (tac == CellInfo.UNAVAILABLE) || (tac >= 0 && tac <= TAC));
694 
695         // Bandwidth ranges from 1400 to 20000
696         int bw = lte.getBandwidth();
697         assertTrue("getBandwidth out of range [1400, 20000] | Integer.Max_Value, bw=" + bw,
698                 bw == CellInfo.UNAVAILABLE || bw >= BANDWIDTH_LOW && bw <= BANDWIDTH_HIGH);
699 
700         int earfcn = lte.getEarfcn();
701         // Reference 3GPP 36.101 Table 5.7.3-1
702         // As per NOTE 1 in the table, although 0-6 are valid channel numbers for
703         // LTE, the reported EARFCN is the center frequency, rendering these channels
704         // out of the range of the narrowest 1.4Mhz deployment.
705         int minEarfcn = 7;
706         int maxEarfcn = EARFCN_MAX - 7;
707         if (bw != CellInfo.UNAVAILABLE) {
708             // The number of channels used by a cell is equal to the cell bandwidth divided
709             // by the channel raster (bandwidth of a channel). The center channel is the channel
710             // the n/2-th channel where n is the number of channels, and since it is the center
711             // channel that is reported as the channel number for a cell, we can exclude any channel
712             // numbers within a band that would place the bottom of a cell's bandwidth below the
713             // edge of the band. For channel numbers in Band 1, the EARFCN numbering starts from
714             // channel 0, which means that we can exclude from the valid range channels starting
715             // from 0 and numbered less than half the total number of channels occupied by a cell.
716             minEarfcn = bw / CHANNEL_RASTER_EUTRAN / 2;
717             maxEarfcn = EARFCN_MAX - (bw / CHANNEL_RASTER_EUTRAN / 2);
718         }
719         assertTrue(
720                 "getEarfcn() out of range [" + minEarfcn + "," + maxEarfcn + "], earfcn=" + earfcn,
721                 (earfcn >= minEarfcn && earfcn <= maxEarfcn));
722 
723         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_5) {
724             int[] bands = lte.getBands();
725 
726             for (int band: bands) {
727                 assertTrue("getBand out of range [1, 88], band = " + band,
728                         band >= BAND_MIN_LTE && band <= BAND_MAX_LTE);
729 
730                 verifyCellIdentityLteBands(bands);
731             }
732         }
733 
734         verifyPlmnId(lte.getMobileNetworkOperator());
735 
736         for (String plmnId : lte.getAdditionalPlmns()) {
737             verifyPlmnId(plmnId);
738         }
739 
740         verifyCsgInfo(lte.getClosedSubscriberGroupInfo());
741 
742         verifyCellIdentityLteLocationSanitation(lte);
743 
744         // If the cell is reported as registered, then all the logical cell info must be reported
745         if (isRegistered) {
746             assertTrue("TAC is required for registered cells", tac != CellInfo.UNAVAILABLE);
747             assertTrue("CID is required for registered cells", ci != CellInfo.UNAVAILABLE);
748             assertTrue("MCC is required for registered cells",
749                     lte.getMccString() != null || lte.getMcc() != CellInfo.UNAVAILABLE);
750             assertTrue("MNC is required for registered cells",
751                     lte.getMncString() != null || lte.getMnc() != CellInfo.UNAVAILABLE);
752             assertFalse("PLMN-ID is required for registered cells",
753                     TextUtils.isEmpty(lte.getMobileNetworkOperator()));
754         }
755     }
756 
verifyCellIdentityLteLocationSanitation(CellIdentityLte lte)757     private void verifyCellIdentityLteLocationSanitation(CellIdentityLte lte) {
758         CellIdentityLte sanitized = lte.sanitizeLocationInfo();
759         assertEquals(CellInfo.UNAVAILABLE, sanitized.getCi());
760         assertEquals(CellInfo.UNAVAILABLE, sanitized.getEarfcn());
761         assertEquals(CellInfo.UNAVAILABLE, sanitized.getPci());
762         assertEquals(CellInfo.UNAVAILABLE, sanitized.getTac());
763     }
764 
verifyCellIdentityLteParcel(CellIdentityLte lte)765     private void verifyCellIdentityLteParcel(CellIdentityLte lte) {
766         Parcel p = Parcel.obtain();
767         lte.writeToParcel(p, 0);
768         p.setDataPosition(0);
769 
770         CellIdentityLte newci = CellIdentityLte.CREATOR.createFromParcel(p);
771         assertEquals(lte, newci);
772     }
773 
verifyCellSignalStrengthLte(CellSignalStrengthLte cellSignalStrengthLte)774     private void verifyCellSignalStrengthLte(CellSignalStrengthLte cellSignalStrengthLte) {
775         verifyRssiDbm(cellSignalStrengthLte.getDbm());
776 
777         //ICellInfo.UNAVAILABLE indicates an unavailable field
778         int rsrp = cellSignalStrengthLte.getRsrp();
779         // RSRP is being treated as RSSI in LTE (they are similar but not quite right)
780         // so reusing the constants here.
781         assertTrue("getRsrp() out of range, rsrp=" + rsrp, rsrp >= MIN_RSRP && rsrp <= MAX_RSRP);
782 
783         int rsrq = cellSignalStrengthLte.getRsrq();
784         assertTrue("getRsrq() out of range | CellInfo.UNAVAILABLE, rsrq=" + rsrq,
785                 rsrq == CellInfo.UNAVAILABLE || (rsrq >= MIN_RSRQ && rsrq <= MAX_RSRQ));
786 
787         int rssi = cellSignalStrengthLte.getRssi();
788         assertTrue("getRssi() out of range [-113, -51] or CellInfo.UNAVAILABLE if unknown, rssi="
789                 + rssi, rssi == CellInfo.UNAVAILABLE
790                 || (rssi >= MIN_LTE_RSSI && rssi <= MAX_LTE_RSSI));
791 
792         int rssnr = cellSignalStrengthLte.getRssnr();
793         assertTrue("getRssnr() out of range | CellInfo.UNAVAILABLE, rssnr=" + rssnr,
794                 rssnr == CellInfo.UNAVAILABLE || (rssnr >= MIN_RSSNR && rssnr <= MAX_RSSNR));
795 
796         int cqiTableIndex = cellSignalStrengthLte.getCqiTableIndex();
797         assertTrue("getCqiTableIndex() out of range | CellInfo.UNAVAILABLE, cqi=" + cqiTableIndex,
798                 cqiTableIndex == CellInfo.UNAVAILABLE || (cqiTableIndex >= CQI_TABLE_INDEX_MIN_LTE
799                         && cqiTableIndex <= CQI_TABLE_INDEX_MAX_LTE));
800 
801         int cqi = cellSignalStrengthLte.getCqi();
802         assertTrue("getCqi() out of range | CellInfo.UNAVAILABLE, cqi=" + cqi,
803                 cqi == CellInfo.UNAVAILABLE || (cqi >= MIN_CQI && cqi <= MAX_CQI));
804 
805         int ta = cellSignalStrengthLte.getTimingAdvance();
806         assertTrue("getTimingAdvance() invalid [0-1282] | CellInfo.UNAVAILABLE, ta=" + ta,
807                 ta == CellInfo.UNAVAILABLE || (ta >= 0 && ta <= 1282));
808 
809         int level = cellSignalStrengthLte.getLevel();
810         assertTrue("getLevel() out of range [0,4], level=" + level, level >= 0 && level <= 4);
811 
812         int asuLevel = cellSignalStrengthLte.getAsuLevel();
813         assertTrue("getAsuLevel() out of range [0,97] (or 99 is unknown), asuLevel=" + asuLevel,
814                 (asuLevel == 99) || (asuLevel >= 0 && asuLevel <= 97));
815 
816         int timingAdvance = cellSignalStrengthLte.getTimingAdvance();
817         assertTrue("getTimingAdvance() out of range [0,1282], timingAdvance=" + timingAdvance,
818                 timingAdvance == CellInfo.UNAVAILABLE
819                         || (timingAdvance >= 0 && timingAdvance <= 1282));
820 
821         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
822             assertTrue("RSRP Must be valid for LTE",
823                     cellSignalStrengthLte.getRsrp() != CellInfo.UNAVAILABLE);
824         }
825     }
826 
verifyCellSignalStrengthLteParcel(CellSignalStrengthLte cellSignalStrengthLte)827     private void verifyCellSignalStrengthLteParcel(CellSignalStrengthLte cellSignalStrengthLte) {
828         Parcel p = Parcel.obtain();
829         cellSignalStrengthLte.writeToParcel(p, 0);
830         p.setDataPosition(0);
831 
832         CellSignalStrengthLte newCss = CellSignalStrengthLte.CREATOR.createFromParcel(p);
833         assertEquals(cellSignalStrengthLte, newCss);
834     }
835 
verifyCellIdentityLteBands(int[] lteBands)836     private void verifyCellIdentityLteBands(int[] lteBands) {
837         //Verify the registered cell reports non-null band.
838         assertTrue(lteBands != null);
839 
840         //Verify the registered cell reports at least one band.
841         assertTrue(Arrays.stream(lteBands).anyMatch(band -> band > 0));
842     }
843 
844     // Verify wcdma cell information is within correct range.
verifyWcdmaInfo(CellInfoWcdma wcdma)845     private void verifyWcdmaInfo(CellInfoWcdma wcdma) {
846         verifyCellConnectionStatus(wcdma.getCellConnectionStatus());
847         verifyCellInfoWcdmaParcelandHashcode(wcdma);
848         verifyCellIdentityWcdma(wcdma.getCellIdentity(), wcdma.isRegistered());
849         verifyCellIdentityWcdmaParcel(wcdma.getCellIdentity());
850         verifyCellSignalStrengthWcdma(wcdma.getCellSignalStrength());
851         verifyCellSignalStrengthWcdmaParcel(wcdma.getCellSignalStrength());
852     }
853 
verifyCellInfoWcdmaParcelandHashcode(CellInfoWcdma wcdma)854     private void verifyCellInfoWcdmaParcelandHashcode(CellInfoWcdma wcdma) {
855         Parcel p = Parcel.obtain();
856         wcdma.writeToParcel(p, 0);
857         p.setDataPosition(0);
858 
859         CellInfoWcdma newCi = CellInfoWcdma.CREATOR.createFromParcel(p);
860         assertTrue(wcdma.equals(newCi));
861         assertEquals("hashCode() did not get right hashCode", wcdma.hashCode(), newCi.hashCode());
862     }
863 
verifyCellIdentityWcdma(CellIdentityWcdma wcdma, boolean isRegistered)864     private void verifyCellIdentityWcdma(CellIdentityWcdma wcdma, boolean isRegistered) {
865         verifyPlmnInfo(wcdma.getMccString(), wcdma.getMncString(), wcdma.getMcc(), wcdma.getMnc());
866 
867         int lac = wcdma.getLac();
868         assertTrue("getLac() out of range [0, 65535], lac=" + lac,
869                 (lac >= 0 && lac <= LAC) || lac == CellInfo.UNAVAILABLE);
870 
871         int cid = wcdma.getCid();
872         assertTrue("getCid() out of range [0, 268435455], cid=" + cid,
873                 (cid >= 0 && cid <= CID_UMTS) || cid == CellInfo.UNAVAILABLE);
874 
875         // Verify wcdma primary scrambling code information.
876         // Primary scrambling code should be within [0, 511].
877         int psc = wcdma.getPsc();
878         assertTrue("getPsc() out of range [0, 511], psc=" + psc, psc >= 0 && psc <= PSC);
879 
880         verifyPlmnId(wcdma.getMobileNetworkOperator());
881 
882         int uarfcn = wcdma.getUarfcn();
883         // Reference 3GPP 25.101 Table 5.2
884         // From Appendix E.1, even though UARFCN is numbered from 400, the minumum
885         // usable channel is 412 due to the fixed bandwidth of 5Mhz
886         assertTrue("getUarfcn() out of range [412,11000], uarfcn=" + uarfcn,
887                 uarfcn >= 412 && uarfcn <= 11000);
888 
889         for (String plmnId : wcdma.getAdditionalPlmns()) {
890             verifyPlmnId(plmnId);
891         }
892 
893         verifyCsgInfo(wcdma.getClosedSubscriberGroupInfo());
894 
895         // If the cell is reported as registered, then all the logical cell info must be reported
896         if (isRegistered) {
897             assertTrue("LAC is required for registered cells", lac != CellInfo.UNAVAILABLE);
898             assertTrue("CID is required for registered cells", cid != CellInfo.UNAVAILABLE);
899             assertTrue("MCC is required for registered cells",
900                     wcdma.getMccString() != null || wcdma.getMcc() != CellInfo.UNAVAILABLE);
901             assertTrue("MNC is required for registered cells",
902                     wcdma.getMncString() != null || wcdma.getMnc() != CellInfo.UNAVAILABLE);
903             assertFalse("PLMN-ID is required for registered cells",
904                     TextUtils.isEmpty(wcdma.getMobileNetworkOperator()));
905         }
906 
907         verifyCellIdentityWcdmaLocationSanitation(wcdma);
908     }
909 
verifyCellIdentityWcdmaLocationSanitation(CellIdentityWcdma wcdma)910     private void verifyCellIdentityWcdmaLocationSanitation(CellIdentityWcdma wcdma) {
911         CellIdentityWcdma sanitized = wcdma.sanitizeLocationInfo();
912         assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
913         assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
914         assertEquals(CellInfo.UNAVAILABLE, sanitized.getPsc());
915         assertEquals(CellInfo.UNAVAILABLE, sanitized.getUarfcn());
916     }
917 
verifyCellIdentityWcdmaParcel(CellIdentityWcdma wcdma)918     private void verifyCellIdentityWcdmaParcel(CellIdentityWcdma wcdma) {
919         Parcel p = Parcel.obtain();
920         wcdma.writeToParcel(p, 0);
921         p.setDataPosition(0);
922 
923         CellIdentityWcdma newci = CellIdentityWcdma.CREATOR.createFromParcel(p);
924         assertEquals(wcdma, newci);
925     }
926 
verifyCellSignalStrengthWcdma(CellSignalStrengthWcdma wcdma)927     private void verifyCellSignalStrengthWcdma(CellSignalStrengthWcdma wcdma) {
928         verifyRssiDbm(wcdma.getDbm());
929 
930         // Dbm here does not have specific limits. So just calling to verify that it does not crash
931         // the phone
932         wcdma.getDbm();
933 
934         int asuLevel = wcdma.getAsuLevel();
935         if (wcdma.getRscp() != CellInfo.UNAVAILABLE) {
936             assertTrue("getAsuLevel() out of range 0..96, 255), asuLevel=" + asuLevel,
937                     asuLevel == 255 || (asuLevel >= 0 && asuLevel <= 96));
938         } else if (wcdma.getRssi() != CellInfo.UNAVAILABLE) {
939             assertTrue("getAsuLevel() out of range 0..31, 99), asuLevel=" + asuLevel,
940                     asuLevel == 99 || (asuLevel >= 0 && asuLevel <= 31));
941         } else {
942             assertTrue("getAsuLevel() out of range 0..96, 255), asuLevel=" + asuLevel,
943                     asuLevel == 255);
944         }
945 
946         int level = wcdma.getLevel();
947         assertTrue("getLevel() out of range [0,4], level=" + level, level >= 0 && level <= 4);
948 
949         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
950             assertTrue("RSCP Must be valid for WCDMA", wcdma.getRscp() != CellInfo.UNAVAILABLE);
951         }
952 
953         int ecNo = wcdma.getEcNo();
954         assertTrue("getEcNo() out of range [-24,1], EcNo=" + ecNo,
955                 (ecNo >= -24 && ecNo <= 1) || ecNo == CellInfo.UNAVAILABLE);
956     }
957 
verifyCellSignalStrengthWcdmaParcel(CellSignalStrengthWcdma wcdma)958     private void verifyCellSignalStrengthWcdmaParcel(CellSignalStrengthWcdma wcdma) {
959         Parcel p = Parcel.obtain();
960         wcdma.writeToParcel(p, 0);
961         p.setDataPosition(0);
962 
963         CellSignalStrengthWcdma newCss = CellSignalStrengthWcdma.CREATOR.createFromParcel(p);
964         assertEquals(wcdma, newCss);
965     }
966 
967     // Verify gsm cell information is within correct range.
verifyGsmInfo(CellInfoGsm gsm)968     private void verifyGsmInfo(CellInfoGsm gsm) {
969         verifyCellConnectionStatus(gsm.getCellConnectionStatus());
970         verifyCellInfoWcdmaParcelandHashcode(gsm);
971         verifyCellIdentityGsm(gsm.getCellIdentity(), gsm.isRegistered());
972         verifyCellIdentityGsmParcel(gsm.getCellIdentity());
973         verifyCellSignalStrengthGsm(gsm.getCellSignalStrength());
974         verifyCellSignalStrengthGsmParcel(gsm.getCellSignalStrength());
975     }
976 
verifyCellInfoWcdmaParcelandHashcode(CellInfoGsm gsm)977     private void verifyCellInfoWcdmaParcelandHashcode(CellInfoGsm gsm) {
978         Parcel p = Parcel.obtain();
979         gsm.writeToParcel(p, 0);
980         p.setDataPosition(0);
981 
982         CellInfoGsm newCi = CellInfoGsm.CREATOR.createFromParcel(p);
983         assertTrue(gsm.equals(newCi));
984         assertEquals("hashCode() did not get right hashCode", gsm.hashCode(), newCi.hashCode());
985     }
986 
verifyCellIdentityGsm(CellIdentityGsm gsm, boolean isRegistered)987     private void verifyCellIdentityGsm(CellIdentityGsm gsm, boolean isRegistered) {
988         verifyPlmnInfo(gsm.getMccString(), gsm.getMncString(), gsm.getMcc(), gsm.getMnc());
989 
990         // Local area code and cellid should be with [0, 65535].
991         int lac = gsm.getLac();
992         assertTrue("getLac() out of range [0, 65535], lac=" + lac,
993                 lac == CellInfo.UNAVAILABLE || (lac >= 0 && lac <= LAC));
994         int cid = gsm.getCid();
995         assertTrue("getCid() out range [0, 65535], cid=" + cid,
996                 cid == CellInfo.UNAVAILABLE || (cid >= 0 && cid <= CID_GSM));
997 
998         int arfcn = gsm.getArfcn();
999         // Reference 3GPP 45.005 Table 2-2
1000         assertTrue("getArfcn() out of range [0,1024], arfcn=" + arfcn,
1001                 arfcn == CellInfo.UNAVAILABLE || (arfcn >= 0 && arfcn <= ARFCN));
1002 
1003         int bsic = gsm.getBsic();
1004         assertTrue("getBsic() out of range [0,63]", bsic >= 0 && bsic <= 63);
1005 
1006         for (String plmnId : gsm.getAdditionalPlmns()) {
1007             verifyPlmnId(plmnId);
1008         }
1009         verifyPlmnId(gsm.getMobileNetworkOperator());
1010 
1011         // If the cell is reported as registered, then all the logical cell info must be reported
1012         if (isRegistered) {
1013             assertTrue("LAC is required for registered cells", lac != CellInfo.UNAVAILABLE);
1014             assertTrue("CID is required for registered cells", cid != CellInfo.UNAVAILABLE);
1015             assertTrue("MCC is required for registered cells",
1016                     gsm.getMccString() != null || gsm.getMcc() != CellInfo.UNAVAILABLE);
1017             assertTrue("MNC is required for registered cells",
1018                     gsm.getMncString() != null || gsm.getMnc() != CellInfo.UNAVAILABLE);
1019             assertFalse("PLMN-ID is required for registered cells",
1020                     TextUtils.isEmpty(gsm.getMobileNetworkOperator()));
1021         }
1022 
1023         verifyCellIdentityGsmLocationSanitation(gsm);
1024     }
1025 
verifyCellIdentityGsmLocationSanitation(CellIdentityGsm gms)1026     private void verifyCellIdentityGsmLocationSanitation(CellIdentityGsm gms) {
1027         CellIdentityGsm sanitized = gms.sanitizeLocationInfo();
1028         assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
1029         assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
1030         assertEquals(CellInfo.UNAVAILABLE, sanitized.getArfcn());
1031         assertEquals(CellInfo.UNAVAILABLE, sanitized.getBsic());
1032     }
1033 
verifyCellIdentityGsmParcel(CellIdentityGsm gsm)1034     private void verifyCellIdentityGsmParcel(CellIdentityGsm gsm) {
1035         Parcel p = Parcel.obtain();
1036         gsm.writeToParcel(p, 0);
1037         p.setDataPosition(0);
1038 
1039         CellIdentityGsm newci = CellIdentityGsm.CREATOR.createFromParcel(p);
1040         assertEquals(gsm, newci);
1041     }
1042 
verifyCellSignalStrengthGsm(CellSignalStrengthGsm gsm)1043     private void verifyCellSignalStrengthGsm(CellSignalStrengthGsm gsm) {
1044         verifyRssiDbm(gsm.getDbm());
1045 
1046         int level = gsm.getLevel();
1047         assertTrue("getLevel() out of range [0,4], level=" + level, level >= 0 && level <= 4);
1048 
1049         int ta = gsm.getTimingAdvance();
1050         assertTrue("getTimingAdvance() out of range [0,219] | CellInfo.UNAVAILABLE, ta=" + ta,
1051                 ta == CellInfo.UNAVAILABLE || (ta >= 0 && ta <= 219));
1052 
1053         assertEquals(gsm.getDbm(), gsm.getRssi());
1054 
1055         int asuLevel = gsm.getAsuLevel();
1056         assertTrue("getLevel() out of range [0,31] (or 99 is unknown), level=" + asuLevel,
1057                 asuLevel == 99 || (asuLevel >=0 && asuLevel <= 31));
1058 
1059         int ber = gsm.getBitErrorRate();
1060         assertTrue("getBitErrorRate out of range [0,7], 99, or CellInfo.UNAVAILABLE, ber=" + ber,
1061                 ber == 99 || ber == CellInfo.UNAVAILABLE || (ber >= 0 && ber <= 7));
1062 
1063         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
1064             assertTrue("RSSI Must be valid for GSM", gsm.getDbm() != CellInfo.UNAVAILABLE);
1065         }
1066     }
1067 
verifyCellSignalStrengthGsmParcel(CellSignalStrengthGsm gsm)1068     private void verifyCellSignalStrengthGsmParcel(CellSignalStrengthGsm gsm) {
1069         Parcel p = Parcel.obtain();
1070         gsm.writeToParcel(p, 0);
1071         p.setDataPosition(0);
1072 
1073         CellSignalStrengthGsm newCss = CellSignalStrengthGsm.CREATOR.createFromParcel(p);
1074         assertEquals(gsm, newCss);
1075     }
1076 
1077     // Verify tdscdma cell information is within correct range.
verifyTdscdmaInfo(CellInfoTdscdma tdscdma)1078     private void verifyTdscdmaInfo(CellInfoTdscdma tdscdma) {
1079         verifyCellConnectionStatus(tdscdma.getCellConnectionStatus());
1080         verifyCellInfoTdscdmaParcelandHashcode(tdscdma);
1081         verifyCellIdentityTdscdma(tdscdma.getCellIdentity(), tdscdma.isRegistered());
1082         verifyCellIdentityTdscdmaParcel(tdscdma.getCellIdentity());
1083         verifyCellSignalStrengthTdscdma(tdscdma.getCellSignalStrength());
1084         verifyCellSignalStrengthTdscdmaParcel(tdscdma.getCellSignalStrength());
1085     }
1086 
verifyCellInfoTdscdmaParcelandHashcode(CellInfoTdscdma tdscdma)1087     private void verifyCellInfoTdscdmaParcelandHashcode(CellInfoTdscdma tdscdma) {
1088         Parcel p = Parcel.obtain();
1089         tdscdma.writeToParcel(p, 0);
1090         p.setDataPosition(0);
1091 
1092         CellInfoTdscdma newCi = CellInfoTdscdma.CREATOR.createFromParcel(p);
1093         assertTrue(tdscdma.equals(newCi));
1094         assertEquals("hashCode() did not get right hashCode", tdscdma.hashCode(), newCi.hashCode());
1095     }
1096 
verifyCellIdentityTdscdma(CellIdentityTdscdma tdscdma, boolean isRegistered)1097     private void verifyCellIdentityTdscdma(CellIdentityTdscdma tdscdma, boolean isRegistered) {
1098         String mccStr = tdscdma.getMccString();
1099         String mncStr = tdscdma.getMncString();
1100 
1101         // This class was added after numeric mcc/mncs were no longer provided, so it lacks the
1102         // basic getMcc() and getMnc() - empty out those checks.
1103         verifyPlmnInfo(tdscdma.getMccString(), tdscdma.getMncString(),
1104                 mccStr != null ? Integer.parseInt(mccStr) : CellInfo.UNAVAILABLE,
1105                 mncStr != null ? Integer.parseInt(mncStr) : CellInfo.UNAVAILABLE);
1106 
1107         int lac = tdscdma.getLac();
1108         assertTrue("getLac() out of range [0, 65535], lac=" + lac,
1109                 (lac >= 0 && lac <= LAC) || lac == CellInfo.UNAVAILABLE);
1110 
1111         int cid = tdscdma.getCid();
1112         assertTrue("getCid() out of range [0, 268435455], cid=" + cid,
1113                 (cid >= 0 && cid <= CID_UMTS) || cid == CellInfo.UNAVAILABLE);
1114 
1115         // Verify tdscdma primary scrambling code information.
1116         // Primary scrambling code should be within [0, 511].
1117         int cpid = tdscdma.getCpid();
1118         assertTrue("getCpid() out of range [0, 127], cpid=" + cpid, (cpid >= 0 && cpid <= CPID));
1119 
1120         verifyPlmnId(tdscdma.getMobileNetworkOperator());
1121 
1122         int uarfcn = tdscdma.getUarfcn();
1123         // Reference 3GPP 25.101 Table 5.2
1124         // From Appendix E.1, even though UARFCN is numbered from 400, the minumum
1125         // usable channel is 412 due to the fixed bandwidth of 5Mhz
1126         assertTrue("getUarfcn() out of range [412,11000], uarfcn=" + uarfcn,
1127                 uarfcn >= 412 && uarfcn <= 11000);
1128 
1129         for (String plmnId : tdscdma.getAdditionalPlmns()) {
1130             verifyPlmnId(plmnId);
1131         }
1132 
1133         verifyCsgInfo(tdscdma.getClosedSubscriberGroupInfo());
1134 
1135         // If the cell is reported as registered, then all the logical cell info must be reported
1136         if (isRegistered) {
1137             assertTrue("LAC is required for registered cells", lac != CellInfo.UNAVAILABLE);
1138             assertTrue("CID is required for registered cells", cid != CellInfo.UNAVAILABLE);
1139             assertTrue("MCC is required for registered cells", tdscdma.getMccString() != null);
1140             assertTrue("MNC is required for registered cells", tdscdma.getMncString() != null);
1141             assertFalse("PLMN-ID is required for registered cells",
1142                     TextUtils.isEmpty(tdscdma.getMobileNetworkOperator()));
1143         }
1144 
1145         verifyCellIdentityTdscdmaLocationSanitation(tdscdma);
1146     }
1147 
verifyCellIdentityTdscdmaLocationSanitation(CellIdentityTdscdma tdscdma)1148     private void verifyCellIdentityTdscdmaLocationSanitation(CellIdentityTdscdma tdscdma) {
1149         CellIdentityTdscdma sanitized = tdscdma.sanitizeLocationInfo();
1150         assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
1151         assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
1152         assertEquals(CellInfo.UNAVAILABLE, sanitized.getCpid());
1153         assertEquals(CellInfo.UNAVAILABLE, sanitized.getUarfcn());
1154     }
1155 
verifyCellIdentityTdscdmaParcel(CellIdentityTdscdma tdscdma)1156     private void verifyCellIdentityTdscdmaParcel(CellIdentityTdscdma tdscdma) {
1157         Parcel p = Parcel.obtain();
1158         tdscdma.writeToParcel(p, 0);
1159         p.setDataPosition(0);
1160 
1161         CellIdentityTdscdma newci = CellIdentityTdscdma.CREATOR.createFromParcel(p);
1162         assertEquals(tdscdma, newci);
1163     }
1164 
verifyCellSignalStrengthTdscdma(CellSignalStrengthTdscdma tdscdma)1165     private void verifyCellSignalStrengthTdscdma(CellSignalStrengthTdscdma tdscdma) {
1166         verifyRssiDbm(tdscdma.getDbm());
1167 
1168         // Dbm here does not have specific limits. So just calling to verify that it does not crash
1169         // the phone
1170         tdscdma.getDbm();
1171 
1172         int asuLevel = tdscdma.getAsuLevel();
1173         assertTrue("getLevel() out of range [0,31] (or 99 is unknown), level=" + asuLevel,
1174                 asuLevel == 99 || (asuLevel >= 0 && asuLevel <= 31));
1175 
1176         int level = tdscdma.getLevel();
1177         assertTrue("getLevel() out of range [0,4], level=" + level, level >= 0 && level <= 4);
1178 
1179         if (mNetworkHalVersion >= RADIO_HAL_VERSION_1_2) {
1180             assertTrue("RSCP Must be valid for TDSCDMA", tdscdma.getRscp() != CellInfo.UNAVAILABLE);
1181         }
1182     }
1183 
verifyCellSignalStrengthTdscdmaParcel(CellSignalStrengthTdscdma tdscdma)1184     private void verifyCellSignalStrengthTdscdmaParcel(CellSignalStrengthTdscdma tdscdma) {
1185         Parcel p = Parcel.obtain();
1186         tdscdma.writeToParcel(p, 0);
1187         p.setDataPosition(0);
1188 
1189         CellSignalStrengthTdscdma newCss = CellSignalStrengthTdscdma.CREATOR.createFromParcel(p);
1190         assertEquals(tdscdma, newCss);
1191     }
1192 
1193     // Rssi(in dbm) should be within [MIN_RSSI, MAX_RSSI].
verifyRssiDbm(int dbm)1194     private static void verifyRssiDbm(int dbm) {
1195         assertTrue("getCellSignalStrength().getDbm() out of range, dbm=" + dbm,
1196                 dbm >= MIN_RSSI && dbm <= MAX_RSSI);
1197     }
1198 
verifyCellConnectionStatus(int status)1199     private static void verifyCellConnectionStatus(int status) {
1200         assertTrue("getCellConnectionStatus() invalid [0,2] | Integer.MAX_VALUE, status=",
1201             status == CellInfo.CONNECTION_NONE
1202                 || status == CellInfo.CONNECTION_PRIMARY_SERVING
1203                 || status == CellInfo.CONNECTION_SECONDARY_SERVING
1204                 || status == CellInfo.CONNECTION_UNKNOWN);
1205     }
1206 
verifyPlmnId(String plmnId)1207     private static void verifyPlmnId(String plmnId) {
1208         if (TextUtils.isEmpty(plmnId)) return;
1209 
1210         assertTrue("PlmnId() out of range [00000 - 999999], PLMN ID=" + plmnId,
1211                 plmnId.matches("^[0-9]{5,6}$"));
1212     }
1213 
verifyCsgInfo(@ullable ClosedSubscriberGroupInfo csgInfo)1214     private static void verifyCsgInfo(@Nullable ClosedSubscriberGroupInfo csgInfo) {
1215         if (csgInfo == null) return;
1216 
1217         // This is boolean, so as long as it doesn't crash, we're good.
1218         csgInfo.getCsgIndicator();
1219         // This is nullable, and it's free-form so all we can do is ensure it doesn't crash.
1220         csgInfo.getHomeNodebName();
1221 
1222         // It might be technically possible to have a CSG ID of zero, but if that's the case
1223         // then let someone complain about it. It's far more likely that if it's '0', then there
1224         // is a bug.
1225         assertTrue("CSG Identity out of range", csgInfo.getCsgIdentity() > 0
1226                 && csgInfo.getCsgIdentity() <= 0x7FFFFF);
1227     }
1228 }
1229