1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.phone;
18 
19 import static android.content.pm.PackageManager.PERMISSION_DENIED;
20 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
21 import static android.provider.Telephony.ServiceStateTable;
22 import static android.provider.Telephony.ServiceStateTable.DATA_NETWORK_TYPE;
23 import static android.provider.Telephony.ServiceStateTable.DATA_REG_STATE;
24 import static android.provider.Telephony.ServiceStateTable.DUPLEX_MODE;
25 import static android.provider.Telephony.ServiceStateTable.VOICE_OPERATOR_NUMERIC;
26 import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
27 import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
28 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
29 
30 import static com.android.phone.ServiceStateProvider.ENFORCE_LOCATION_PERMISSION_CHECK;
31 import static com.android.phone.ServiceStateProvider.NETWORK_ID;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertFalse;
35 import static org.junit.Assert.assertNotNull;
36 import static org.junit.Assert.assertThrows;
37 import static org.junit.Assert.assertTrue;
38 import static org.mockito.ArgumentMatchers.any;
39 import static org.mockito.ArgumentMatchers.anyInt;
40 import static org.mockito.ArgumentMatchers.anyString;
41 import static org.mockito.ArgumentMatchers.eq;
42 import static org.mockito.ArgumentMatchers.nullable;
43 import static org.mockito.Mockito.doReturn;
44 import static org.mockito.Mockito.never;
45 import static org.mockito.Mockito.verify;
46 import static org.mockito.Mockito.when;
47 
48 import android.Manifest;
49 import android.app.AppOpsManager;
50 import android.compat.testing.PlatformCompatChangeRule;
51 import android.content.Context;
52 import android.content.pm.ApplicationInfo;
53 import android.content.pm.PackageManager;
54 import android.content.pm.ProviderInfo;
55 import android.database.ContentObserver;
56 import android.database.Cursor;
57 import android.location.LocationManager;
58 import android.net.Uri;
59 import android.os.Build;
60 import android.os.UserHandle;
61 import android.telephony.AccessNetworkConstants;
62 import android.telephony.NetworkRegistrationInfo;
63 import android.telephony.ServiceState;
64 import android.telephony.SubscriptionManager;
65 import android.telephony.TelephonyManager;
66 import android.test.mock.MockContentResolver;
67 
68 import androidx.test.ext.junit.runners.AndroidJUnit4;
69 import androidx.test.filters.SmallTest;
70 
71 import libcore.junit.util.compat.CoreCompatChangeRule;
72 
73 import org.junit.After;
74 import org.junit.Before;
75 import org.junit.Ignore;
76 import org.junit.Rule;
77 import org.junit.Test;
78 import org.junit.rules.TestRule;
79 import org.junit.runner.RunWith;
80 import org.mockito.Mock;
81 import org.mockito.MockitoAnnotations;
82 
83 /**
84  * Tests for simple queries of ServiceStateProvider.
85  *
86  * Build, install and run the tests by running the commands below:
87  *     atest ServiceStateProviderTest
88  */
89 @RunWith(AndroidJUnit4.class)
90 public class ServiceStateProviderTest {
91     private static final String TAG = "ServiceStateProviderTest";
92     private static final int TEST_NETWORK_ID = 123;
93     private static final int TEST_SYSTEM_ID = 123;
94 
95     private MockContentResolver mContentResolver;
96     private ServiceState mTestServiceState;
97     private ServiceState mTestServiceStateForSubId1;
98 
99     @Mock Context mContext;
100     @Mock AppOpsManager mAppOpsManager;
101     @Mock LocationManager mLocationManager;
102     @Mock PackageManager mPackageManager;
103 
104     @Rule
105     public TestRule compatChangeRule = new PlatformCompatChangeRule();
106 
107     // Exception used internally to verify if the Resolver#notifyChange has been called.
108     private class TestNotifierException extends RuntimeException {
TestNotifierException()109         TestNotifierException() {
110             super();
111         }
112     }
113 
114     @Before
setUp()115     public void setUp() throws Exception {
116         MockitoAnnotations.initMocks(this);
117         mockSystemService(AppOpsManager.class, mAppOpsManager, Context.APP_OPS_SERVICE);
118         mockSystemService(LocationManager.class, mLocationManager, Context.LOCATION_SERVICE);
119         doReturn(mPackageManager).when(mContext).getPackageManager();
120 
121         mContentResolver = new MockContentResolver() {
122             @Override
123             public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
124                 throw new TestNotifierException();
125             }
126             @Override
127             public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
128                     int userHandle) {
129                 throw new TestNotifierException();
130             }
131         };
132         doReturn(mContentResolver).when(mContext).getContentResolver();
133 
134         mTestServiceState = new ServiceState();
135         mTestServiceState.setStateOutOfService();
136         mTestServiceState.setCdmaSystemAndNetworkId(TEST_SYSTEM_ID, TEST_NETWORK_ID);
137         mTestServiceStateForSubId1 = new ServiceState();
138         mTestServiceStateForSubId1.setStateOff();
139 
140         // Add NRI to trigger SS with non-default values (e.g. duplex mode)
141         NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder()
142                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
143                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
144                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
145                 .build();
146         mTestServiceStateForSubId1.addNetworkRegistrationInfo(nriWwan);
147         mTestServiceStateForSubId1.setChannelNumber(65536); // EutranBand.BAND_65, DUPLEX_MODE_FDD
148 
149         // Mock out the actual phone state
150         ServiceStateProvider provider = new ServiceStateProvider() {
151             @Override
152             public ServiceState getServiceState(int subId) {
153                 if (subId == 1) {
154                     return mTestServiceStateForSubId1;
155                 } else {
156                     return mTestServiceState;
157                 }
158             }
159 
160             @Override
161             public int getDefaultSubId() {
162                 return 0;
163             }
164         };
165         ProviderInfo providerInfo = new ProviderInfo();
166         providerInfo.authority = "service-state";
167         provider.attachInfoForTesting(mContext, providerInfo);
168         mContentResolver.addProvider("service-state", provider);
169 
170         // By default, test with app target R, no READ_PRIVILEGED_PHONE_STATE permission
171         setTargetSdkVersion(Build.VERSION_CODES.R);
172         setCanReadPrivilegedPhoneState(false);
173 
174         // TODO(b/191995565): Turn on all ignored cases once location access is allow to be off
175         // Do not allow phone process to always access location so we can test various scenarios
176         // LocationAccessPolicy.alwaysAllowPrivilegedProcessToAccessLocationForTesting(false);
177     }
178 
179     @After
tearDown()180     public void tearDown() throws Exception {
181         // LocationAccessPolicy.alwaysAllowPrivilegedProcessToAccessLocationForTesting(true);
182     }
183 
184     /**
185      * Verify that when calling query with no subId in the uri the default ServiceState is returned.
186      * In this case the subId is set to 0 and the expected service state is mTestServiceState.
187      */
188     // TODO(b/191995565): Turn this on when location access can be off
189     @Ignore
190     @SmallTest
191     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
testQueryServiceState_withNoSubId_withoutLocation()192     public void testQueryServiceState_withNoSubId_withoutLocation() {
193         setLocationPermissions(false);
194 
195         verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState,
196                 false /*hasLocation*/);
197     }
198 
199     @Test
200     @SmallTest
testQueryServiceState_withNoSubId_withLocation()201     public void testQueryServiceState_withNoSubId_withLocation() {
202         setLocationPermissions(true);
203 
204         verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState,
205                 true /*hasLocation*/);
206     }
207 
208     /**
209      * Verify that when calling with the DEFAULT_SUBSCRIPTION_ID the correct ServiceState is
210      * returned. In this case the subId is set to 0 and the expected service state is
211      * mTestServiceState.
212      */
213     // TODO(b/191995565): Turn case on when location access can be off
214     @Ignore
215     @SmallTest
testGetServiceState_withDefaultSubId_withoutLocation()216     public void testGetServiceState_withDefaultSubId_withoutLocation() {
217         setLocationPermissions(false);
218 
219         verifyServiceStateForSubId(
220                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
221                 mTestServiceState, false /*hasLocation*/);
222     }
223 
224     @Test
225     @SmallTest
testGetServiceState_withDefaultSubId_withLocation()226     public void testGetServiceState_withDefaultSubId_withLocation() {
227         setLocationPermissions(true);
228 
229         verifyServiceStateForSubId(
230                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
231                 mTestServiceState, true /*hasLocation*/);
232     }
233 
234     /**
235      * Verify that when calling with a specific subId the correct ServiceState is returned. In this
236      * case the subId is set to 1 and the expected service state is mTestServiceStateForSubId1
237      */
238     @Test
239     @SmallTest
testGetServiceStateForSubId_withoutLocation()240     public void testGetServiceStateForSubId_withoutLocation() {
241         setLocationPermissions(false);
242 
243         verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1,
244                 false /*hasLocation*/);
245     }
246 
247     @Test
248     @SmallTest
testGetServiceStateForSubId_withLocation()249     public void testGetServiceStateForSubId_withLocation() {
250         setLocationPermissions(true);
251 
252         verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1,
253                 true /*hasLocation*/);
254     }
255 
256     /**
257      * Verify that apps target S+ without READ_PRIVILEGED_PHONE_STATE permission can access the
258      * public columns of ServiceStateTable.
259      */
260     @Test
261     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
262     public void
query_publicColumns_enforceLocatoinEnabled_targetS_noReadPrivilege_getPublicColumns()263     query_publicColumns_enforceLocatoinEnabled_targetS_noReadPrivilege_getPublicColumns() {
264         setTargetSdkVersion(Build.VERSION_CODES.S);
265         setCanReadPrivilegedPhoneState(false);
266 
267         verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/);
268     }
269 
270     @Test
271     @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
272     public void
query_publicColumns_enforceLocationDisabled_targetS_noReadPrivilege_getPublicColumns()273     query_publicColumns_enforceLocationDisabled_targetS_noReadPrivilege_getPublicColumns() {
274         setTargetSdkVersion(Build.VERSION_CODES.S);
275         setCanReadPrivilegedPhoneState(false);
276 
277         verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/);
278     }
279 
280     /**
281      * Verify that apps target S+ without READ_PRIVILEGED_PHONE_STATE permission try to access
282      * non-public columns should throw IllegalArgumentException.
283      */
284     @Test
285     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_hideColumn_targetS_noReadPrivilege_throwIllegalArgumentException()286     public void query_hideColumn_targetS_noReadPrivilege_throwIllegalArgumentException() {
287         setTargetSdkVersion(Build.VERSION_CODES.S);
288         setCanReadPrivilegedPhoneState(false);
289 
290         // DATA_ROAMING_TYPE is a non-public column
291         String[] projection = new String[]{"data_roaming_type"};
292 
293         assertThrows(IllegalArgumentException.class,
294                 () -> verifyServiceStateWithPublicColumns(mTestServiceState, projection));
295     }
296 
297     /**
298      * Verify that with changeId ENFORCE_LOCATION_PERMISSION_CHECK enabled, apps target S+ with
299      * READ_PRIVILEGED_PHONE_STATE and location permissions should be able to access all columns.
300      */
301     @Test
302     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
303     public void
query_allColumn_enforceLocationEnabled_targetS_withReadPrivilegedAndLocation_getUnredacted()304     query_allColumn_enforceLocationEnabled_targetS_withReadPrivilegedAndLocation_getUnredacted() {
305         setTargetSdkVersion(Build.VERSION_CODES.S);
306         setCanReadPrivilegedPhoneState(true);
307         setLocationPermissions(true);
308 
309         verifyServiceStateForSubId(
310                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
311                 mTestServiceState, true /*hasPermission*/);
312     }
313 
314     /**
315      * Verify that with changeId ENFORCE_LOCATION_PERMISSION_CHECK disabled, apps target S+ with
316      * READ_PRIVILEGED_PHONE_STATE and location permissions should be able to access all columns.
317      */
318     @Test
319     @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
320     public void
query_allColumn_enforceLocationDisabled_targetS_withReadPrivilegedAndLocation_getUnredacted()321     query_allColumn_enforceLocationDisabled_targetS_withReadPrivilegedAndLocation_getUnredacted() {
322         setTargetSdkVersion(Build.VERSION_CODES.S);
323         setCanReadPrivilegedPhoneState(true);
324         setLocationPermissions(true);
325 
326         verifyServiceStateForSubId(
327                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
328                 mTestServiceState, true /*hasPermission*/);
329     }
330 
331     /**
332      * Verify that apps target S+ with READ_PRIVILEGED_PHONE_STATE permission but no location
333      * permission, try to access location sensitive columns should throw SecurityException.
334      */
335     // TODO(b/191995565): Turn this on once b/191995565 is integrated
336     @Ignore
337     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_locationColumn_targetS_withReadPrivilegeNoLocation_throwSecurityExecption()338     public void query_locationColumn_targetS_withReadPrivilegeNoLocation_throwSecurityExecption() {
339         setTargetSdkVersion(Build.VERSION_CODES.S);
340         setCanReadPrivilegedPhoneState(true);
341         setLocationPermissions(false);
342 
343         assertThrows(SecurityException.class,
344                 () -> verifyServiceStateWithLocationColumns(mTestServiceState));
345     }
346 
347     /**
348      * Verify that when changeId ENFORCE_LOCATION_PERMISSION_CHECK is enabled, apps target R- with
349      * location permissions should be able to access all columns.
350      */
351     @Test
352     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_allColumn_enforceLocationEnabled_targetR_withLocation_getUnredacted()353     public void query_allColumn_enforceLocationEnabled_targetR_withLocation_getUnredacted() {
354         setTargetSdkVersion(Build.VERSION_CODES.R);
355         setLocationPermissions(true);
356 
357         verifyServiceStateForSubId(
358                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
359                 mTestServiceState, true /*hasPermission*/);
360     }
361 
362     /**
363      * Verify that when changeId ENFORCE_LOCATION_PERMISSION_CHECK is disabled, apps target R- with
364      * location permissions should be able to access all columns.
365      */
366     @Test
367     @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_allColumn_enforceLocationDisabled_targetR_withLocation_getUnredacted()368     public void query_allColumn_enforceLocationDisabled_targetR_withLocation_getUnredacted() {
369         setTargetSdkVersion(Build.VERSION_CODES.R);
370         setLocationPermissions(true);
371 
372         verifyServiceStateForSubId(
373                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
374                 mTestServiceState, true /*hasPermission*/);
375     }
376 
377     /**
378      * Verify that changeId ENFORCE_LOCATION_PERMISSION_CHECK is enabled, apps target R- w/o
379      * location permissions should be able to access all columns but with redacted ServiceState.
380      */
381     // TODO(b/191995565): Turn case on when location access can be off
382     @Ignore
383     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_allColumn_enforceLocationEnabled_targetR_noLocation_getRedacted()384     public void query_allColumn_enforceLocationEnabled_targetR_noLocation_getRedacted() {
385         setTargetSdkVersion(Build.VERSION_CODES.R);
386         setLocationPermissions(false);
387 
388         verifyServiceStateForSubId(
389                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
390                 ServiceStateProvider.getLocationRedactedServiceState(mTestServiceState),
391                 true /*hasPermission*/);
392     }
393 
394     /**
395      * Verify that changeId ENFORCE_LOCATION_PERMISSION_CHECK is disabled, apps target R- w/o
396      * location permissions should be able to access all columns and with unredacted ServiceState.
397      */
398     // TODO(b/191995565): Turn case on when location access can be off
399     @Ignore
400     @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
query_allColumn_enforceLocationDisabled_targetR_noLocation_getUnredacted()401     public void query_allColumn_enforceLocationDisabled_targetR_noLocation_getUnredacted() {
402         setTargetSdkVersion(Build.VERSION_CODES.R);
403         setLocationPermissions(false);
404 
405         verifyServiceStateForSubId(
406                 getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
407                 mTestServiceState, true /*hasPermission*/);
408     }
409 
410     /**
411      * Verify that when caller with targetSDK S+ has location permission and try to query
412      * location non-sensitive info, it should not get blamed.
413      */
414     @Test
415     @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK})
testQuery_noLocationBlamed_whenQueryNonLocationInfo_withPermission()416     public void testQuery_noLocationBlamed_whenQueryNonLocationInfo_withPermission() {
417         setTargetSdkVersion(Build.VERSION_CODES.S);
418         setLocationPermissions(true);
419 
420         verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/);
421         verify(mAppOpsManager, never()).noteOpNoThrow(any(), anyInt(), any(), any(), any());
422     }
423 
verifyServiceStateWithLocationColumns(ServiceState ss)424     private void verifyServiceStateWithLocationColumns(ServiceState ss) {
425         // NETWORK_ID is a location-sensitive column
426         try (Cursor cursor = mContentResolver.query(ServiceStateTable.CONTENT_URI,
427                 new String[]{NETWORK_ID}, null, null)) {
428             assertNotNull(cursor);
429         }
430     }
431 
verifyServiceStateWithPublicColumns(ServiceState ss, String[] projection)432     private void verifyServiceStateWithPublicColumns(ServiceState ss, String[] projection) {
433         try (Cursor cursor = mContentResolver.query(ServiceStateTable.CONTENT_URI, projection, null,
434                 null)) {
435             assertNotNull(cursor);
436 
437             cursor.moveToFirst();
438             assertEquals(ss.getVoiceRegState(),
439                     cursor.getInt(cursor.getColumnIndex(VOICE_REG_STATE)));
440             assertEquals(ss.getDataRegistrationState(),
441                     cursor.getInt(cursor.getColumnIndex(DATA_REG_STATE)));
442             assertEquals(ss.getOperatorNumeric(),
443                     cursor.getString(cursor.getColumnIndex(VOICE_OPERATOR_NUMERIC)));
444             assertEquals(ss.getDataNetworkType(),
445                     cursor.getInt(cursor.getColumnIndex(DATA_NETWORK_TYPE)));
446             assertEquals(ss.getDuplexMode(), cursor.getInt(cursor.getColumnIndex(DUPLEX_MODE)));
447         }
448     }
449 
verifyServiceStateForSubId(Uri uri, ServiceState ss, boolean hasLocation)450     private void verifyServiceStateForSubId(Uri uri, ServiceState ss, boolean hasLocation) {
451         Cursor cursor = mContentResolver.query(uri, ServiceStateProvider.ALL_COLUMNS, "",
452                 null, null);
453         assertNotNull(cursor);
454         cursor.moveToFirst();
455 
456         final int voiceRegState = ss.getState();
457         final int dataRegState = ss.getDataRegistrationState();
458         final int voiceRoamingType = ss.getVoiceRoamingType();
459         final int dataRoamingType = ss.getDataRoamingType();
460         final String voiceOperatorAlphaLong = hasLocation ? ss.getOperatorAlphaLong() : null;
461         final String voiceOperatorAlphaShort = hasLocation ? ss.getOperatorAlphaShort() : null;
462         final String voiceOperatorNumeric = hasLocation ? ss.getOperatorNumeric() : null;
463         final String dataOperatorAlphaLong = hasLocation ? ss.getOperatorAlphaLong() : null;
464         final String dataOperatorAlphaShort = hasLocation ? ss.getOperatorAlphaShort() : null;
465         final String dataOperatorNumeric = hasLocation ? ss.getOperatorNumeric() : null;
466         final int isManualNetworkSelection = (ss.getIsManualSelection()) ? 1 : 0;
467         final int rilVoiceRadioTechnology = ss.getRilVoiceRadioTechnology();
468         final int rilDataRadioTechnology = ss.getRilDataRadioTechnology();
469         final int cssIndicator = ss.getCssIndicator();
470         final int networkId = hasLocation ? ss.getCdmaNetworkId() : ServiceState.UNKNOWN_ID;
471         final int systemId = hasLocation ? ss.getCdmaSystemId() : ServiceState.UNKNOWN_ID;
472         final int cdmaRoamingIndicator = ss.getCdmaRoamingIndicator();
473         final int cdmaDefaultRoamingIndicator = ss.getCdmaDefaultRoamingIndicator();
474         final int cdmaEriIconIndex = ss.getCdmaEriIconIndex();
475         final int cdmaEriIconMode = ss.getCdmaEriIconMode();
476         final int isEmergencyOnly = (ss.isEmergencyOnly()) ? 1 : 0;
477         final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
478         final String operatorAlphaLongRaw = ss.getOperatorAlphaLongRaw();
479         final String operatorAlphaShortRaw = ss.getOperatorAlphaShortRaw();
480         final int dataNetworkType = ss.getDataNetworkType();
481         final int duplexMode = ss.getDuplexMode();
482 
483         assertEquals(voiceRegState, cursor.getInt(0));
484         assertEquals(dataRegState, cursor.getInt(1));
485         assertEquals(voiceRoamingType, cursor.getInt(2));
486         assertEquals(dataRoamingType, cursor.getInt(3));
487         assertEquals(voiceOperatorAlphaLong, cursor.getString(4));
488         assertEquals(voiceOperatorAlphaShort, cursor.getString(5));
489         assertEquals(voiceOperatorNumeric, cursor.getString(6));
490         assertEquals(dataOperatorAlphaLong, cursor.getString(7));
491         assertEquals(dataOperatorAlphaShort, cursor.getString(8));
492         assertEquals(dataOperatorNumeric, cursor.getString(9));
493         assertEquals(isManualNetworkSelection, cursor.getInt(10));
494         assertEquals(rilVoiceRadioTechnology, cursor.getInt(11));
495         assertEquals(rilDataRadioTechnology, cursor.getInt(12));
496         assertEquals(cssIndicator, cursor.getInt(13));
497         assertEquals(networkId, cursor.getInt(14));
498         assertEquals(systemId, cursor.getInt(15));
499         assertEquals(cdmaRoamingIndicator, cursor.getInt(16));
500         assertEquals(cdmaDefaultRoamingIndicator, cursor.getInt(17));
501         assertEquals(cdmaEriIconIndex, cursor.getInt(18));
502         assertEquals(cdmaEriIconMode, cursor.getInt(19));
503         assertEquals(isEmergencyOnly, cursor.getInt(20));
504         assertEquals(isUsingCarrierAggregation, cursor.getInt(21));
505         assertEquals(operatorAlphaLongRaw, cursor.getString(22));
506         assertEquals(operatorAlphaShortRaw, cursor.getString(23));
507         assertEquals(dataNetworkType, cursor.getInt(24));
508         assertEquals(duplexMode, cursor.getInt(25));
509     }
510 
511     /**
512      * Test that we don't notify for certain field changes. (e.g. we don't notify when the NetworkId
513      * or SystemId change) This is an intentional behavior change from the broadcast.
514      */
515     @Test
516     @SmallTest
testNoNotify()517     public void testNoNotify() {
518         int subId = 0;
519 
520         ServiceState oldSS = new ServiceState();
521         oldSS.setStateOutOfService();
522         oldSS.setCdmaSystemAndNetworkId(1, 1);
523 
524         ServiceState newSS = new ServiceState();
525         newSS.setStateOutOfService();
526         newSS.setCdmaSystemAndNetworkId(0, 0);
527 
528         // Test that notifyChange is not called for these fields
529         assertFalse(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
530     }
531 
532     @Test
533     @SmallTest
testNotifyChanged_noStateUpdated()534     public void testNotifyChanged_noStateUpdated() {
535         int subId = 0;
536 
537         ServiceState oldSS = new ServiceState();
538         oldSS.setStateOutOfService();
539         oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
540 
541         ServiceState copyOfOldSS = new ServiceState();
542         copyOfOldSS.setStateOutOfService();
543         copyOfOldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
544 
545         // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField
546         assertFalse(notifyChangeCalledForSubId(oldSS, copyOfOldSS, subId));
547 
548         // Test that notifyChange is not called with no change in notifyChangeForSubId
549         assertFalse(notifyChangeCalledForSubIdAndField(oldSS, copyOfOldSS, subId));
550     }
551 
552     @Test
553     @SmallTest
testNotifyChanged_voiceRegStateUpdated()554     public void testNotifyChanged_voiceRegStateUpdated() {
555         int subId = 0;
556 
557         ServiceState oldSS = new ServiceState();
558         oldSS.setStateOutOfService();
559         oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
560 
561         ServiceState newSS = new ServiceState();
562         newSS.setStateOutOfService();
563         newSS.setVoiceRegState(ServiceState.STATE_POWER_OFF);
564 
565         // Test that notifyChange is called by notifyChangeForSubIdAndField when the voice_reg_state
566         // changes
567         assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
568 
569         // Test that notifyChange is called by notifyChangeForSubId when the voice_reg_state changes
570         assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
571     }
572 
573     @Test
574     @SmallTest
testNotifyChanged_dataNetworkTypeUpdated()575     public void testNotifyChanged_dataNetworkTypeUpdated() {
576         int subId = 0;
577 
578         // While we don't have a method to directly set dataNetworkType, we emulate a ServiceState
579         // change that will trigger the change of dataNetworkType, according to the logic in
580         // ServiceState#getDataNetworkType
581         ServiceState oldSS = new ServiceState();
582         oldSS.setStateOutOfService();
583 
584         ServiceState newSS = new ServiceState();
585         newSS.setStateOutOfService();
586 
587         NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder()
588                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
589                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
590                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
591                 .setRegistrationState(REGISTRATION_STATE_HOME)
592                 .build();
593         newSS.addNetworkRegistrationInfo(nriWwan);
594 
595         // Test that notifyChange is called by notifyChangeForSubId when the
596         // data_network_type changes
597         assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
598 
599         // Test that notifyChange is called by notifyChangeForSubIdAndField when the
600         // data_network_type changes
601         assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
602     }
603 
604     @Test
605     @SmallTest
testNotifyChanged_dataRegStateUpdated()606     public void testNotifyChanged_dataRegStateUpdated() {
607         int subId = 0;
608 
609         ServiceState oldSS = new ServiceState();
610         oldSS.setStateOutOfService();
611         oldSS.setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
612 
613         ServiceState newSS = new ServiceState();
614         newSS.setStateOutOfService();
615         newSS.setDataRegState(ServiceState.STATE_POWER_OFF);
616 
617         // Test that notifyChange is called by notifyChangeForSubId
618         // when the data_reg_state changes
619         assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
620 
621         // Test that notifyChange is called by notifyChangeForSubIdAndField
622         // when the data_reg_state changes
623         assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
624     }
625 
626     // Check if notifyChange was called by notifyChangeForSubId
notifyChangeCalledForSubId(ServiceState oldSS, ServiceState newSS, int subId)627     private boolean notifyChangeCalledForSubId(ServiceState oldSS,
628             ServiceState newSS, int subId) {
629         try {
630             ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, newSS, subId);
631         } catch (TestNotifierException e) {
632             return true;
633         }
634         return false;
635     }
636 
637     // Check if notifyChange was called by notifyChangeForSubIdAndField
notifyChangeCalledForSubIdAndField(ServiceState oldSS, ServiceState newSS, int subId)638     private boolean notifyChangeCalledForSubIdAndField(ServiceState oldSS,
639             ServiceState newSS, int subId) {
640         try {
641             ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
642         } catch (TestNotifierException e) {
643             return true;
644         }
645         return false;
646     }
647 
setLocationPermissions(boolean hasPermission)648     private void setLocationPermissions(boolean hasPermission) {
649         if (!hasPermission) {
650             // System location off, LocationAccessPolicy#checkLocationPermission returns DENIED_SOFT
651             when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class)))
652                     .thenReturn(false);
653         } else {
654             // Turn on all to let LocationAccessPolicy#checkLocationPermission returns ALLOWED
655             when(mContext.checkPermission(eq(Manifest.permission.ACCESS_FINE_LOCATION),
656                     anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
657 
658             when(mContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION),
659                     anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
660 
661             when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION),
662                     anyInt(), anyString(), nullable(String.class), nullable(String.class)))
663                     .thenReturn(AppOpsManager.MODE_ALLOWED);
664             when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_COARSE_LOCATION),
665                     anyInt(), anyString(), nullable(String.class), nullable(String.class)))
666                     .thenReturn(AppOpsManager.MODE_ALLOWED);
667 
668             when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))).thenReturn(true);
669             when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
670                     anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
671         }
672     }
673 
mockSystemService(Class<T> clazz , T obj, String serviceName)674     private <T> void mockSystemService(Class<T> clazz , T obj, String serviceName) {
675         when(mContext.getSystemServiceName(eq(clazz))).thenReturn(serviceName);
676         when(mContext.getSystemService(eq(serviceName))).thenReturn(obj);
677     }
678 
setTargetSdkVersion(int version)679     private void setTargetSdkVersion(int version) {
680         ApplicationInfo testAppInfo = new ApplicationInfo();
681         testAppInfo.targetSdkVersion = version;
682         try {
683             when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
684                     .thenReturn(testAppInfo);
685         } catch (Exception ignored) {
686         }
687     }
688 
setCanReadPrivilegedPhoneState(boolean granted)689     private void setCanReadPrivilegedPhoneState(boolean granted) {
690         doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED).when(mContext)
691                 .checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
692     }
693 }
694