| /* |
| * Copyright (C) 2014 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 android.telephony.cts; |
| |
| import static android.app.AppOpsManager.MODE_ALLOWED; |
| import static android.app.AppOpsManager.MODE_IGNORED; |
| import static android.app.AppOpsManager.OPSTR_READ_PHONE_STATE; |
| import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL; |
| import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_STRING; |
| import static android.telephony.CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL; |
| import static android.telephony.CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL; |
| import static android.telephony.ServiceState.STATE_IN_SERVICE; |
| |
| import static androidx.test.InstrumentationRegistry.getContext; |
| import static androidx.test.InstrumentationRegistry.getInstrumentation; |
| |
| import static com.android.compatibility.common.util.AppOpsUtils.setOpMode; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| |
| import android.app.UiAutomation; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.PackageManager; |
| import android.os.Looper; |
| import android.os.PersistableBundle; |
| import android.platform.test.annotations.AsbSecurityTest; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; |
| import android.telephony.TelephonyManager; |
| |
| import com.android.compatibility.common.util.ShellIdentityUtils; |
| import com.android.compatibility.common.util.TestThread; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.io.IOException; |
| import java.util.concurrent.ArrayBlockingQueue; |
| import java.util.concurrent.BlockingQueue; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| public class CarrierConfigManagerTest { |
| |
| private static final String CARRIER_NAME_OVERRIDE = "carrier_a"; |
| private CarrierConfigManager mConfigManager; |
| private TelephonyManager mTelephonyManager; |
| private SubscriptionManager mSubscriptionManager; |
| private PackageManager mPackageManager; |
| |
| // Use a long timeout to accommodate devices with lower amounts of memory, as it will take |
| // longer for these devices to receive the broadcast (b/161963269). It is expected that all |
| // devices can receive the broadcast in under 5s (most should receive it well before then). |
| private static final int BROADCAST_TIMEOUT_MILLIS = 5000; |
| private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(1); |
| |
| @Before |
| public void setUp() throws Exception { |
| mTelephonyManager = (TelephonyManager) |
| getContext().getSystemService(Context.TELEPHONY_SERVICE); |
| mConfigManager = (CarrierConfigManager) |
| getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); |
| mSubscriptionManager = |
| (SubscriptionManager) |
| getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); |
| mPackageManager = getContext().getPackageManager(); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| try { |
| setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_ALLOWED); |
| } catch (IOException e) { |
| fail(); |
| } |
| } |
| |
| /** |
| * Checks whether the telephony stack should be running on this device. |
| * |
| * Note: "Telephony" means only SMS/MMS and voice calls in some contexts, but we also care if |
| * the device supports cellular data. |
| */ |
| private boolean hasTelephony() { |
| return mTelephonyManager.isDataCapable(); |
| } |
| |
| private boolean isSimCardPresent() { |
| return mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE && |
| mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_UNKNOWN && |
| mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT; |
| } |
| |
| private boolean isSimCardAbsent() { |
| return mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_ABSENT; |
| } |
| |
| private void checkConfig(PersistableBundle config) { |
| if (config == null) { |
| assertFalse( |
| "Config should only be null when telephony is not running.", hasTelephony()); |
| return; |
| } |
| assertNotNull("CarrierConfigManager should not return null config", config); |
| if (isSimCardAbsent()) { |
| // Static default in CarrierConfigManager will be returned when no sim card present. |
| assertEquals("Config doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_ADDITIONAL_CALL_SETTING_BOOL), true); |
| |
| assertEquals("KEY_VVM_DESTINATION_NUMBER_STRING doesn't match static default.", |
| config.getString(CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING), ""); |
| assertEquals("KEY_VVM_PORT_NUMBER_INT doesn't match static default.", |
| config.getInt(CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT), 0); |
| assertEquals("KEY_VVM_TYPE_STRING doesn't match static default.", |
| config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING), ""); |
| assertEquals("KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL), |
| false); |
| assertEquals("KEY_VVM_PREFETCH_BOOLEAN doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_VVM_PREFETCH_BOOL), true); |
| assertEquals("KEY_CARRIER_VVM_PACKAGE_NAME_STRING doesn't match static default.", |
| config.getString(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING), ""); |
| assertFalse(CarrierConfigManager.isConfigForIdentifiedCarrier(config)); |
| |
| // Check default value matching |
| assertEquals("KEY_DATA_LIMIT_NOTIFICATION_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_DATA_LIMIT_NOTIFICATION_BOOL), |
| true); |
| assertEquals("KEY_DATA_RAPID_NOTIFICATION_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_DATA_RAPID_NOTIFICATION_BOOL), |
| true); |
| assertEquals("KEY_DATA_WARNING_NOTIFICATION_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL), |
| true); |
| assertEquals("Gps.KEY_PERSIST_LPP_MODE_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL), |
| true); |
| assertEquals("KEY_MONTHLY_DATA_CYCLE_DAY_INT doesn't match static default.", |
| config.getInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT), |
| CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT); |
| assertEquals("KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL), |
| false); |
| assertEquals("KEY_SUPPORTS_CALL_COMPOSER_BOOL doesn't match static default.", |
| config.getBoolean(CarrierConfigManager.KEY_SUPPORTS_CALL_COMPOSER_BOOL), |
| false); |
| assertEquals("KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING doesn't match static" |
| + " default.", config.getString( |
| CarrierConfigManager.KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING), ""); |
| assertEquals("KEY_CARRIER_USSD_METHOD_INT doesn't match static default.", |
| config.getInt(CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT), |
| CarrierConfigManager.USSD_OVER_CS_PREFERRED); |
| } |
| |
| // These key should return default values if not customized. |
| assertNotNull(config.getIntArray( |
| CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY)); |
| assertNotNull(config.getIntArray( |
| CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY)); |
| assertNotNull(config.getIntArray( |
| CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY)); |
| assertNotNull(config.getIntArray( |
| CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY)); |
| assertNotNull(config.getIntArray( |
| CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY)); |
| |
| // Check the GPS key prefix |
| assertTrue("Gps.KEY_PREFIX doesn't match the prefix of the name of " |
| + "Gps.KEY_PERSIST_LPP_MODE_BOOL", |
| CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL.startsWith( |
| CarrierConfigManager.Gps.KEY_PREFIX)); |
| } |
| |
| @Test |
| public void testGetConfig() { |
| PersistableBundle config = mConfigManager.getConfig(); |
| checkConfig(config); |
| } |
| |
| @Test |
| @AsbSecurityTest(cveBugId = 73136824) |
| public void testRevokePermission() { |
| if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { |
| return; |
| } |
| PersistableBundle config; |
| |
| try { |
| setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_IGNORED); |
| } catch (IOException e) { |
| fail(); |
| } |
| |
| config = mConfigManager.getConfig(); |
| assertTrue(config.isEmptyParcel()); |
| |
| try { |
| setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_ALLOWED); |
| } catch (IOException e) { |
| fail(); |
| } |
| |
| config = mConfigManager.getConfig(); |
| checkConfig(config); |
| } |
| |
| @Test |
| public void testGetConfigForSubId() { |
| PersistableBundle config = |
| mConfigManager.getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); |
| checkConfig(config); |
| } |
| |
| /** |
| * Tests the CarrierConfigManager.notifyConfigChangedForSubId() API. This makes a call to |
| * notifyConfigChangedForSubId() API and expects a SecurityException since the test apk is not signed |
| * by certificate on the SIM. |
| */ |
| @Test |
| public void testNotifyConfigChangedForSubId() { |
| try { |
| if (isSimCardPresent()) { |
| mConfigManager.notifyConfigChangedForSubId( |
| SubscriptionManager.getDefaultSubscriptionId()); |
| fail("Expected SecurityException. App doesn't have carrier privileges."); |
| } |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * The following methods may return any value depending on the state of the device. Simply |
| * call them to make sure they do not throw any exceptions. |
| */ |
| @Test |
| public void testCarrierConfigManagerResultDependentApi() { |
| assertNotNull(ShellIdentityUtils.invokeMethodWithShellPermissions(mConfigManager, |
| (cm) -> cm.getDefaultCarrierServicePackageName())); |
| } |
| |
| /** |
| * This checks that {@link CarrierConfigManager#overrideConfig(int, PersistableBundle)} |
| * correctly overrides the Carrier Name (SPN) string. |
| */ |
| @Test |
| public void testCarrierConfigNameOverride() throws Exception { |
| if (!isSimCardPresent() |
| || mTelephonyManager.getServiceState().getState() != STATE_IN_SERVICE) { |
| return; |
| } |
| |
| // Adopt shell permission so the required permission (android.permission.MODIFY_PHONE_STATE) |
| // is granted. |
| UiAutomation ui = getInstrumentation().getUiAutomation(); |
| ui.adoptShellPermissionIdentity(); |
| |
| int subId = SubscriptionManager.getDefaultSubscriptionId(); |
| TestThread t = new TestThread(new Runnable() { |
| @Override |
| public void run() { |
| Looper.prepare(); |
| |
| OnSubscriptionsChangedListener listener = |
| new OnSubscriptionsChangedListener() { |
| @Override |
| public void onSubscriptionsChanged() { |
| if (CARRIER_NAME_OVERRIDE.equals( |
| mTelephonyManager.getSimOperatorName())) { |
| COUNT_DOWN_LATCH.countDown(); |
| } |
| } |
| }; |
| mSubscriptionManager.addOnSubscriptionsChangedListener(listener); |
| |
| PersistableBundle carrierNameOverride = new PersistableBundle(3); |
| carrierNameOverride.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, true); |
| carrierNameOverride.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, true); |
| carrierNameOverride.putString(KEY_CARRIER_NAME_STRING, CARRIER_NAME_OVERRIDE); |
| mConfigManager.overrideConfig(subId, carrierNameOverride); |
| |
| Looper.loop(); |
| } |
| }); |
| |
| try { |
| t.start(); |
| boolean didCarrierNameUpdate = |
| COUNT_DOWN_LATCH.await(BROADCAST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); |
| if (!didCarrierNameUpdate) { |
| fail("CarrierName not overridden in " + BROADCAST_TIMEOUT_MILLIS + " ms"); |
| } |
| } finally { |
| mConfigManager.overrideConfig(subId, null); |
| ui.dropShellPermissionIdentity(); |
| } |
| } |
| |
| @Test |
| public void testExtraRebroadcastOnUnlock() throws Throwable { |
| if (!hasTelephony()) { |
| return; |
| } |
| |
| BlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(5); |
| BroadcastReceiver receiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { |
| queue.add(new Boolean(true)); |
| // verify that REBROADCAST_ON_UNLOCK is populated |
| assertFalse( |
| intent.getBooleanExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, |
| true)); |
| } |
| } |
| }; |
| |
| try { |
| final IntentFilter filter = |
| new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); |
| getContext().registerReceiver(receiver, filter); |
| |
| // verify that carrier config is received |
| int subId = SubscriptionManager.getDefaultSubscriptionId(); |
| getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); |
| mConfigManager.notifyConfigChangedForSubId(subId); |
| |
| Boolean broadcastReceived = queue.poll(BROADCAST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); |
| assertNotNull(broadcastReceived); |
| assertTrue(broadcastReceived); |
| } finally { |
| // unregister receiver |
| getContext().unregisterReceiver(receiver); |
| receiver = null; |
| } |
| } |
| |
| @Test |
| public void testGetConfigByComponentForSubId() { |
| PersistableBundle config = |
| mConfigManager.getConfigByComponentForSubId( |
| CarrierConfigManager.Wifi.KEY_PREFIX, |
| SubscriptionManager.getDefaultSubscriptionId()); |
| if (config != null) { |
| assertTrue(config.containsKey(CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT)); |
| assertFalse(config.containsKey(KEY_CARRIER_VOLTE_PROVISIONED_BOOL)); |
| assertFalse(config.containsKey(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING)); |
| } |
| } |
| } |