| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.phone; |
| |
| import static android.content.pm.PackageManager.PERMISSION_DENIED; |
| import static android.content.pm.PackageManager.PERMISSION_GRANTED; |
| import static android.provider.Telephony.ServiceStateTable; |
| import static android.provider.Telephony.ServiceStateTable.DATA_NETWORK_TYPE; |
| import static android.provider.Telephony.ServiceStateTable.DATA_REG_STATE; |
| import static android.provider.Telephony.ServiceStateTable.DUPLEX_MODE; |
| import static android.provider.Telephony.ServiceStateTable.VOICE_OPERATOR_NUMERIC; |
| import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE; |
| import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId; |
| import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME; |
| |
| import static com.android.phone.ServiceStateProvider.ENFORCE_LOCATION_PERMISSION_CHECK; |
| import static com.android.phone.ServiceStateProvider.NETWORK_ID; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertThrows; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.ArgumentMatchers.nullable; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.Manifest; |
| import android.app.AppOpsManager; |
| import android.compat.testing.PlatformCompatChangeRule; |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ProviderInfo; |
| import android.database.ContentObserver; |
| import android.database.Cursor; |
| import android.location.LocationManager; |
| import android.net.Uri; |
| import android.os.Build; |
| import android.os.UserHandle; |
| import android.telephony.AccessNetworkConstants; |
| import android.telephony.NetworkRegistrationInfo; |
| import android.telephony.ServiceState; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.test.mock.MockContentResolver; |
| import android.test.suitebuilder.annotation.SmallTest; |
| |
| import androidx.test.ext.junit.runners.AndroidJUnit4; |
| |
| import libcore.junit.util.compat.CoreCompatChangeRule; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TestRule; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| /** |
| * Tests for simple queries of ServiceStateProvider. |
| * |
| * Build, install and run the tests by running the commands below: |
| * atest ServiceStateProviderTest |
| */ |
| @RunWith(AndroidJUnit4.class) |
| public class ServiceStateProviderTest { |
| private static final String TAG = "ServiceStateProviderTest"; |
| private static final int TEST_NETWORK_ID = 123; |
| private static final int TEST_SYSTEM_ID = 123; |
| |
| private MockContentResolver mContentResolver; |
| private ServiceState mTestServiceState; |
| private ServiceState mTestServiceStateForSubId1; |
| |
| @Mock Context mContext; |
| @Mock AppOpsManager mAppOpsManager; |
| @Mock LocationManager mLocationManager; |
| @Mock PackageManager mPackageManager; |
| |
| @Rule |
| public TestRule compatChangeRule = new PlatformCompatChangeRule(); |
| |
| // Exception used internally to verify if the Resolver#notifyChange has been called. |
| private class TestNotifierException extends RuntimeException { |
| TestNotifierException() { |
| super(); |
| } |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| mockSystemService(AppOpsManager.class, mAppOpsManager, Context.APP_OPS_SERVICE); |
| mockSystemService(LocationManager.class, mLocationManager, Context.LOCATION_SERVICE); |
| doReturn(mPackageManager).when(mContext).getPackageManager(); |
| |
| mContentResolver = new MockContentResolver() { |
| @Override |
| public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { |
| throw new TestNotifierException(); |
| } |
| }; |
| doReturn(mContentResolver).when(mContext).getContentResolver(); |
| |
| mTestServiceState = new ServiceState(); |
| mTestServiceState.setStateOutOfService(); |
| mTestServiceState.setCdmaSystemAndNetworkId(TEST_SYSTEM_ID, TEST_NETWORK_ID); |
| mTestServiceStateForSubId1 = new ServiceState(); |
| mTestServiceStateForSubId1.setStateOff(); |
| |
| // Add NRI to trigger SS with non-default values (e.g. duplex mode) |
| NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build(); |
| mTestServiceStateForSubId1.addNetworkRegistrationInfo(nriWwan); |
| mTestServiceStateForSubId1.setChannelNumber(65536); // EutranBand.BAND_65, DUPLEX_MODE_FDD |
| |
| // Mock out the actual phone state |
| ServiceStateProvider provider = new ServiceStateProvider() { |
| @Override |
| public ServiceState getServiceState(int subId) { |
| if (subId == 1) { |
| return mTestServiceStateForSubId1; |
| } else { |
| return mTestServiceState; |
| } |
| } |
| |
| @Override |
| public int getDefaultSubId() { |
| return 0; |
| } |
| }; |
| ProviderInfo providerInfo = new ProviderInfo(); |
| providerInfo.authority = "service-state"; |
| provider.attachInfoForTesting(mContext, providerInfo); |
| mContentResolver.addProvider("service-state", provider); |
| |
| // By default, test with app target R, no READ_PRIVILEGED_PHONE_STATE permission |
| setTargetSdkVersion(Build.VERSION_CODES.R); |
| setCanReadPrivilegedPhoneState(false); |
| |
| // TODO(b/191995565): Turn on all ignored cases once location access is allow to be off |
| // Do not allow phone process to always access location so we can test various scenarios |
| // LocationAccessPolicy.alwaysAllowPrivilegedProcessToAccessLocationForTesting(false); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| // LocationAccessPolicy.alwaysAllowPrivilegedProcessToAccessLocationForTesting(true); |
| } |
| |
| /** |
| * Verify that when calling query with no subId in the uri the default ServiceState is returned. |
| * In this case the subId is set to 0 and the expected service state is mTestServiceState. |
| */ |
| // TODO(b/191995565): Turn this on when location access can be off |
| @Ignore |
| @SmallTest |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void testQueryServiceState_withNoSubId_withoutLocation() { |
| setLocationPermissions(false); |
| |
| verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState, |
| false /*hasLocation*/); |
| } |
| |
| @Test |
| @SmallTest |
| public void testQueryServiceState_withNoSubId_withLocation() { |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState, |
| true /*hasLocation*/); |
| } |
| |
| /** |
| * Verify that when calling with the DEFAULT_SUBSCRIPTION_ID the correct ServiceState is |
| * returned. In this case the subId is set to 0 and the expected service state is |
| * mTestServiceState. |
| */ |
| // TODO(b/191995565): Turn case on when location access can be off |
| @Ignore |
| @SmallTest |
| public void testGetServiceState_withDefaultSubId_withoutLocation() { |
| setLocationPermissions(false); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, false /*hasLocation*/); |
| } |
| |
| @Test |
| @SmallTest |
| public void testGetServiceState_withDefaultSubId_withLocation() { |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasLocation*/); |
| } |
| |
| /** |
| * Verify that when calling with a specific subId the correct ServiceState is returned. In this |
| * case the subId is set to 1 and the expected service state is mTestServiceStateForSubId1 |
| */ |
| @Test |
| @SmallTest |
| public void testGetServiceStateForSubId_withoutLocation() { |
| setLocationPermissions(false); |
| |
| verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1, |
| false /*hasLocation*/); |
| } |
| |
| @Test |
| @SmallTest |
| public void testGetServiceStateForSubId_withLocation() { |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1, |
| true /*hasLocation*/); |
| } |
| |
| /** |
| * Verify that apps target S+ without READ_PRIVILEGED_PHONE_STATE permission can access the |
| * public columns of ServiceStateTable. |
| */ |
| @Test |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void |
| query_publicColumns_enforceLocatoinEnabled_targetS_noReadPrivilege_getPublicColumns() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(false); |
| |
| verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/); |
| } |
| |
| @Test |
| @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void |
| query_publicColumns_enforceLocationDisabled_targetS_noReadPrivilege_getPublicColumns() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(false); |
| |
| verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/); |
| } |
| |
| /** |
| * Verify that apps target S+ without READ_PRIVILEGED_PHONE_STATE permission try to access |
| * non-public columns should throw IllegalArgumentException. |
| */ |
| @Test |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_hideColumn_targetS_noReadPrivilege_throwIllegalArgumentException() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(false); |
| |
| // DATA_ROAMING_TYPE is a non-public column |
| String[] projection = new String[]{"data_roaming_type"}; |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> verifyServiceStateWithPublicColumns(mTestServiceState, projection)); |
| } |
| |
| /** |
| * Verify that with changeId ENFORCE_LOCATION_PERMISSION_CHECK enabled, apps target S+ with |
| * READ_PRIVILEGED_PHONE_STATE and location permissions should be able to access all columns. |
| */ |
| @Test |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void |
| query_allColumn_enforceLocationEnabled_targetS_withReadPrivilegedAndLocation_getUnredacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(true); |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that with changeId ENFORCE_LOCATION_PERMISSION_CHECK disabled, apps target S+ with |
| * READ_PRIVILEGED_PHONE_STATE and location permissions should be able to access all columns. |
| */ |
| @Test |
| @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void |
| query_allColumn_enforceLocationDisabled_targetS_withReadPrivilegedAndLocation_getUnredacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(true); |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that apps target S+ with READ_PRIVILEGED_PHONE_STATE permission but no location |
| * permission, try to access location sensitive columns should throw SecurityException. |
| */ |
| // TODO(b/191995565): Turn this on once b/191995565 is integrated |
| @Ignore |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_locationColumn_targetS_withReadPrivilegeNoLocation_throwSecurityExecption() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setCanReadPrivilegedPhoneState(true); |
| setLocationPermissions(false); |
| |
| assertThrows(SecurityException.class, |
| () -> verifyServiceStateWithLocationColumns(mTestServiceState)); |
| } |
| |
| /** |
| * Verify that when changeId ENFORCE_LOCATION_PERMISSION_CHECK is enabled, apps target R- with |
| * location permissions should be able to access all columns. |
| */ |
| @Test |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_allColumn_enforceLocationEnabled_targetR_withLocation_getUnredacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.R); |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that when changeId ENFORCE_LOCATION_PERMISSION_CHECK is disabled, apps target R- with |
| * location permissions should be able to access all columns. |
| */ |
| @Test |
| @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_allColumn_enforceLocationDisabled_targetR_withLocation_getUnredacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.R); |
| setLocationPermissions(true); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that changeId ENFORCE_LOCATION_PERMISSION_CHECK is enabled, apps target R- w/o |
| * location permissions should be able to access all columns but with redacted ServiceState. |
| */ |
| // TODO(b/191995565): Turn case on when location access can be off |
| @Ignore |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_allColumn_enforceLocationEnabled_targetR_noLocation_getRedacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.R); |
| setLocationPermissions(false); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| ServiceStateProvider.getLocationRedactedServiceState(mTestServiceState), |
| true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that changeId ENFORCE_LOCATION_PERMISSION_CHECK is disabled, apps target R- w/o |
| * location permissions should be able to access all columns and with unredacted ServiceState. |
| */ |
| // TODO(b/191995565): Turn case on when location access can be off |
| @Ignore |
| @CoreCompatChangeRule.DisableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void query_allColumn_enforceLocationDisabled_targetR_noLocation_getUnredacted() { |
| setTargetSdkVersion(Build.VERSION_CODES.R); |
| setLocationPermissions(false); |
| |
| verifyServiceStateForSubId( |
| getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), |
| mTestServiceState, true /*hasPermission*/); |
| } |
| |
| /** |
| * Verify that when caller with targetSDK S+ has location permission and try to query |
| * location non-sensitive info, it should not get blamed. |
| */ |
| @Test |
| @CoreCompatChangeRule.EnableCompatChanges({ENFORCE_LOCATION_PERMISSION_CHECK}) |
| public void testQuery_noLocationBlamed_whenQueryNonLocationInfo_withPermission() { |
| setTargetSdkVersion(Build.VERSION_CODES.S); |
| setLocationPermissions(true); |
| |
| verifyServiceStateWithPublicColumns(mTestServiceState, null /*projection*/); |
| verify(mAppOpsManager, never()).noteOpNoThrow(any(), anyInt(), any(), any(), any()); |
| } |
| |
| private void verifyServiceStateWithLocationColumns(ServiceState ss) { |
| // NETWORK_ID is a location-sensitive column |
| try (Cursor cursor = mContentResolver.query(ServiceStateTable.CONTENT_URI, |
| new String[]{NETWORK_ID}, null, null)) { |
| assertNotNull(cursor); |
| } |
| } |
| |
| private void verifyServiceStateWithPublicColumns(ServiceState ss, String[] projection) { |
| try (Cursor cursor = mContentResolver.query(ServiceStateTable.CONTENT_URI, projection, null, |
| null)) { |
| assertNotNull(cursor); |
| |
| cursor.moveToFirst(); |
| assertEquals(ss.getVoiceRegState(), |
| cursor.getInt(cursor.getColumnIndex(VOICE_REG_STATE))); |
| assertEquals(ss.getDataRegistrationState(), |
| cursor.getInt(cursor.getColumnIndex(DATA_REG_STATE))); |
| assertEquals(ss.getOperatorNumeric(), |
| cursor.getString(cursor.getColumnIndex(VOICE_OPERATOR_NUMERIC))); |
| assertEquals(ss.getDataNetworkType(), |
| cursor.getInt(cursor.getColumnIndex(DATA_NETWORK_TYPE))); |
| assertEquals(ss.getDuplexMode(), cursor.getInt(cursor.getColumnIndex(DUPLEX_MODE))); |
| } |
| } |
| |
| private void verifyServiceStateForSubId(Uri uri, ServiceState ss, boolean hasLocation) { |
| Cursor cursor = mContentResolver.query(uri, ServiceStateProvider.ALL_COLUMNS, "", |
| null, null); |
| assertNotNull(cursor); |
| cursor.moveToFirst(); |
| |
| final int voiceRegState = ss.getState(); |
| final int dataRegState = ss.getDataRegistrationState(); |
| final int voiceRoamingType = ss.getVoiceRoamingType(); |
| final int dataRoamingType = ss.getDataRoamingType(); |
| final String voiceOperatorAlphaLong = hasLocation ? ss.getOperatorAlphaLong() : null; |
| final String voiceOperatorAlphaShort = hasLocation ? ss.getOperatorAlphaShort() : null; |
| final String voiceOperatorNumeric = hasLocation ? ss.getOperatorNumeric() : null; |
| final String dataOperatorAlphaLong = hasLocation ? ss.getOperatorAlphaLong() : null; |
| final String dataOperatorAlphaShort = hasLocation ? ss.getOperatorAlphaShort() : null; |
| final String dataOperatorNumeric = hasLocation ? ss.getOperatorNumeric() : null; |
| final int isManualNetworkSelection = (ss.getIsManualSelection()) ? 1 : 0; |
| final int rilVoiceRadioTechnology = ss.getRilVoiceRadioTechnology(); |
| final int rilDataRadioTechnology = ss.getRilDataRadioTechnology(); |
| final int cssIndicator = ss.getCssIndicator(); |
| final int networkId = hasLocation ? ss.getCdmaNetworkId() : ServiceState.UNKNOWN_ID; |
| final int systemId = hasLocation ? ss.getCdmaSystemId() : ServiceState.UNKNOWN_ID; |
| final int cdmaRoamingIndicator = ss.getCdmaRoamingIndicator(); |
| final int cdmaDefaultRoamingIndicator = ss.getCdmaDefaultRoamingIndicator(); |
| final int cdmaEriIconIndex = ss.getCdmaEriIconIndex(); |
| final int cdmaEriIconMode = ss.getCdmaEriIconMode(); |
| final int isEmergencyOnly = (ss.isEmergencyOnly()) ? 1 : 0; |
| final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0; |
| final String operatorAlphaLongRaw = ss.getOperatorAlphaLongRaw(); |
| final String operatorAlphaShortRaw = ss.getOperatorAlphaShortRaw(); |
| final int dataNetworkType = ss.getDataNetworkType(); |
| final int duplexMode = ss.getDuplexMode(); |
| |
| assertEquals(voiceRegState, cursor.getInt(0)); |
| assertEquals(dataRegState, cursor.getInt(1)); |
| assertEquals(voiceRoamingType, cursor.getInt(2)); |
| assertEquals(dataRoamingType, cursor.getInt(3)); |
| assertEquals(voiceOperatorAlphaLong, cursor.getString(4)); |
| assertEquals(voiceOperatorAlphaShort, cursor.getString(5)); |
| assertEquals(voiceOperatorNumeric, cursor.getString(6)); |
| assertEquals(dataOperatorAlphaLong, cursor.getString(7)); |
| assertEquals(dataOperatorAlphaShort, cursor.getString(8)); |
| assertEquals(dataOperatorNumeric, cursor.getString(9)); |
| assertEquals(isManualNetworkSelection, cursor.getInt(10)); |
| assertEquals(rilVoiceRadioTechnology, cursor.getInt(11)); |
| assertEquals(rilDataRadioTechnology, cursor.getInt(12)); |
| assertEquals(cssIndicator, cursor.getInt(13)); |
| assertEquals(networkId, cursor.getInt(14)); |
| assertEquals(systemId, cursor.getInt(15)); |
| assertEquals(cdmaRoamingIndicator, cursor.getInt(16)); |
| assertEquals(cdmaDefaultRoamingIndicator, cursor.getInt(17)); |
| assertEquals(cdmaEriIconIndex, cursor.getInt(18)); |
| assertEquals(cdmaEriIconMode, cursor.getInt(19)); |
| assertEquals(isEmergencyOnly, cursor.getInt(20)); |
| assertEquals(isUsingCarrierAggregation, cursor.getInt(21)); |
| assertEquals(operatorAlphaLongRaw, cursor.getString(22)); |
| assertEquals(operatorAlphaShortRaw, cursor.getString(23)); |
| assertEquals(dataNetworkType, cursor.getInt(24)); |
| assertEquals(duplexMode, cursor.getInt(25)); |
| } |
| |
| /** |
| * Test that we don't notify for certain field changes. (e.g. we don't notify when the NetworkId |
| * or SystemId change) This is an intentional behavior change from the broadcast. |
| */ |
| @Test |
| @SmallTest |
| public void testNoNotify() { |
| int subId = 0; |
| |
| ServiceState oldSS = new ServiceState(); |
| oldSS.setStateOutOfService(); |
| oldSS.setCdmaSystemAndNetworkId(1, 1); |
| |
| ServiceState newSS = new ServiceState(); |
| newSS.setStateOutOfService(); |
| newSS.setCdmaSystemAndNetworkId(0, 0); |
| |
| // Test that notifyChange is not called for these fields |
| assertFalse(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId)); |
| } |
| |
| @Test |
| @SmallTest |
| public void testNotifyChanged_noStateUpdated() { |
| int subId = 0; |
| |
| ServiceState oldSS = new ServiceState(); |
| oldSS.setStateOutOfService(); |
| oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE); |
| |
| ServiceState copyOfOldSS = new ServiceState(); |
| copyOfOldSS.setStateOutOfService(); |
| copyOfOldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE); |
| |
| // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField |
| assertFalse(notifyChangeCalledForSubId(oldSS, copyOfOldSS, subId)); |
| |
| // Test that notifyChange is not called with no change in notifyChangeForSubId |
| assertFalse(notifyChangeCalledForSubIdAndField(oldSS, copyOfOldSS, subId)); |
| } |
| |
| @Test |
| @SmallTest |
| public void testNotifyChanged_voiceRegStateUpdated() { |
| int subId = 0; |
| |
| ServiceState oldSS = new ServiceState(); |
| oldSS.setStateOutOfService(); |
| oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE); |
| |
| ServiceState newSS = new ServiceState(); |
| newSS.setStateOutOfService(); |
| newSS.setVoiceRegState(ServiceState.STATE_POWER_OFF); |
| |
| // Test that notifyChange is called by notifyChangeForSubIdAndField when the voice_reg_state |
| // changes |
| assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId)); |
| |
| // Test that notifyChange is called by notifyChangeForSubId when the voice_reg_state changes |
| assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId)); |
| } |
| |
| @Test |
| @SmallTest |
| public void testNotifyChanged_dataNetworkTypeUpdated() { |
| int subId = 0; |
| |
| // While we don't have a method to directly set dataNetworkType, we emulate a ServiceState |
| // change that will trigger the change of dataNetworkType, according to the logic in |
| // ServiceState#getDataNetworkType |
| ServiceState oldSS = new ServiceState(); |
| oldSS.setStateOutOfService(); |
| |
| ServiceState newSS = new ServiceState(); |
| newSS.setStateOutOfService(); |
| |
| NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setRegistrationState(REGISTRATION_STATE_HOME) |
| .build(); |
| newSS.addNetworkRegistrationInfo(nriWwan); |
| |
| // Test that notifyChange is called by notifyChangeForSubId when the |
| // data_network_type changes |
| assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId)); |
| |
| // Test that notifyChange is called by notifyChangeForSubIdAndField when the |
| // data_network_type changes |
| assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId)); |
| } |
| |
| @Test |
| @SmallTest |
| public void testNotifyChanged_dataRegStateUpdated() { |
| int subId = 0; |
| |
| ServiceState oldSS = new ServiceState(); |
| oldSS.setStateOutOfService(); |
| oldSS.setDataRegState(ServiceState.STATE_OUT_OF_SERVICE); |
| |
| ServiceState newSS = new ServiceState(); |
| newSS.setStateOutOfService(); |
| newSS.setDataRegState(ServiceState.STATE_POWER_OFF); |
| |
| // Test that notifyChange is called by notifyChangeForSubId |
| // when the data_reg_state changes |
| assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId)); |
| |
| // Test that notifyChange is called by notifyChangeForSubIdAndField |
| // when the data_reg_state changes |
| assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId)); |
| } |
| |
| // Check if notifyChange was called by notifyChangeForSubId |
| private boolean notifyChangeCalledForSubId(ServiceState oldSS, |
| ServiceState newSS, int subId) { |
| try { |
| ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, newSS, subId); |
| } catch (TestNotifierException e) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Check if notifyChange was called by notifyChangeForSubIdAndField |
| private boolean notifyChangeCalledForSubIdAndField(ServiceState oldSS, |
| ServiceState newSS, int subId) { |
| try { |
| ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId); |
| } catch (TestNotifierException e) { |
| return true; |
| } |
| return false; |
| } |
| |
| private void setLocationPermissions(boolean hasPermission) { |
| if (!hasPermission) { |
| // System location off, LocationAccessPolicy#checkLocationPermission returns DENIED_SOFT |
| when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))) |
| .thenReturn(false); |
| } else { |
| // Turn on all to let LocationAccessPolicy#checkLocationPermission returns ALLOWED |
| when(mContext.checkPermission(eq(Manifest.permission.ACCESS_FINE_LOCATION), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| when(mContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION), |
| anyInt(), anyString(), nullable(String.class), nullable(String.class))) |
| .thenReturn(AppOpsManager.MODE_ALLOWED); |
| when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_COARSE_LOCATION), |
| anyInt(), anyString(), nullable(String.class), nullable(String.class))) |
| .thenReturn(AppOpsManager.MODE_ALLOWED); |
| |
| when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))).thenReturn(true); |
| when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| } |
| } |
| |
| private <T> void mockSystemService(Class<T> clazz , T obj, String serviceName) { |
| when(mContext.getSystemServiceName(eq(clazz))).thenReturn(serviceName); |
| when(mContext.getSystemService(eq(serviceName))).thenReturn(obj); |
| } |
| |
| private void setTargetSdkVersion(int version) { |
| ApplicationInfo testAppInfo = new ApplicationInfo(); |
| testAppInfo.targetSdkVersion = version; |
| try { |
| when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) |
| .thenReturn(testAppInfo); |
| } catch (Exception ignored) { |
| } |
| } |
| |
| private void setCanReadPrivilegedPhoneState(boolean granted) { |
| doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED).when(mContext) |
| .checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); |
| } |
| } |