Merge "s/enforece/enforce/"
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 4ff7316..76a16d3 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -36,6 +36,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
@@ -55,6 +56,7 @@
import android.util.LocalLog;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.Phone;
@@ -201,6 +203,10 @@
// 3. clearing config (e.g. due to sim removal)
// 4. encountering bind or IPC error
private class ConfigHandler extends Handler {
+ ConfigHandler(@NonNull Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
final int phoneId = msg.arg1;
@@ -666,11 +672,13 @@
* Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
* receiver for relevant events.
*/
- private CarrierConfigLoader(Context context) {
+ @VisibleForTesting
+ /* package */ CarrierConfigLoader(Context context,
+ SubscriptionInfoUpdater subscriptionInfoUpdater, @NonNull Looper looper) {
mContext = context;
mPlatformCarrierConfigPackage =
mContext.getString(R.string.platform_carrier_config_package);
- mHandler = new ConfigHandler();
+ mHandler = new ConfigHandler(looper);
IntentFilter bootFilter = new IntentFilter();
bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
@@ -701,7 +709,7 @@
TelephonyFrameworkInitializer
.getTelephonyServiceManager().getCarrierConfigServiceRegisterer().register(this);
logd("CarrierConfigLoader has started");
- mSubscriptionInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater();
+ mSubscriptionInfoUpdater = subscriptionInfoUpdater;
mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
}
@@ -710,11 +718,11 @@
*
* This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
*/
- /* package */
- static CarrierConfigLoader init(Context context) {
+ /* package */ static CarrierConfigLoader init(Context context) {
synchronized (CarrierConfigLoader.class) {
if (sInstance == null) {
- sInstance = new CarrierConfigLoader(context);
+ sInstance = new CarrierConfigLoader(context,
+ PhoneFactory.getSubscriptionInfoUpdater(), Looper.myLooper());
} else {
Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
}
@@ -722,7 +730,8 @@
}
}
- private void clearConfigForPhone(int phoneId, boolean fetchNoSimConfig) {
+ @VisibleForTesting
+ /* package */ void clearConfigForPhone(int phoneId, boolean fetchNoSimConfig) {
/* Ignore clear configuration request if device is being shutdown. */
Phone phone = PhoneFactory.getPhone(phoneId);
if (phone != null) {
@@ -844,7 +853,8 @@
}
}
- private CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) {
+ @VisibleForTesting
+ /* package */ CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) {
String mcc = "";
String mnc = "";
String imsi = "";
@@ -1000,12 +1010,14 @@
}
}
- private void saveConfigToXml(String packageName, @NonNull String extraString, int phoneId,
+ @VisibleForTesting
+ /* package */ void saveConfigToXml(String packageName, @NonNull String extraString, int phoneId,
CarrierIdentifier carrierId, PersistableBundle config) {
saveConfigToXml(packageName, extraString, phoneId, carrierId, config, false);
}
- private void saveNoSimConfigToXml(String packageName, PersistableBundle config) {
+ @VisibleForTesting
+ /* package */ void saveNoSimConfigToXml(String packageName, PersistableBundle config) {
saveConfigToXml(packageName, "", -1, null, config, true);
}
@@ -1166,20 +1178,20 @@
@Override
@NonNull
- public PersistableBundle getConfigForSubId(int subId, String callingPackage) {
- return getConfigForSubIdWithFeature(subId, callingPackage, null);
+ public PersistableBundle getConfigForSubId(int subscriptionId, String callingPackage) {
+ return getConfigForSubIdWithFeature(subscriptionId, callingPackage, null);
}
@Override
@NonNull
- public PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage,
+ public PersistableBundle getConfigForSubIdWithFeature(int subscriptionId, String callingPackage,
String callingFeatureId) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
- callingFeatureId, "getCarrierConfig")) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subscriptionId,
+ callingPackage, callingFeatureId, "getCarrierConfig")) {
return new PersistableBundle();
}
- int phoneId = SubscriptionManager.getPhoneId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
if (SubscriptionManager.isValidPhoneId(phoneId)) {
PersistableBundle config = mConfigFromDefaultApp[phoneId];
@@ -1223,7 +1235,8 @@
int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
- return;
+ throw new IllegalArgumentException(
+ "Invalid phoneId " + phoneId + " for subId " + subscriptionId);
}
// Post to run on handler thread on which all states should be confined.
mHandler.post(() -> {
@@ -1262,17 +1275,18 @@
}
@Override
- public void notifyConfigChangedForSubId(int subId) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
- if (!SubscriptionManager.isValidPhoneId(phoneId)) {
- logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
- return;
- }
-
+ public void notifyConfigChangedForSubId(int subscriptionId) {
// Requires the calling app to be either a carrier privileged app for this subId or
// system privileged app with MODIFY_PHONE_STATE permission.
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext, subId,
- "Require carrier privileges or MODIFY_PHONE_STATE permission.");
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext,
+ subscriptionId, "Require carrier privileges or MODIFY_PHONE_STATE permission.");
+
+ int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
+ if (!SubscriptionManager.isValidPhoneId(phoneId)) {
+ logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
+ throw new IllegalArgumentException(
+ "Invalid phoneId " + phoneId + " for subId " + subscriptionId);
+ }
// This method should block until deleting has completed, so that an error which prevents us
// from clearing the cache is passed back to the carrier app. With the files successfully
@@ -1289,7 +1303,7 @@
android.Manifest.permission.MODIFY_PHONE_STATE, null);
logdWithLocalLog("Update config for phoneId: " + phoneId + " simState: " + simState);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
- return;
+ throw new IllegalArgumentException("Invalid phoneId: " + phoneId);
}
// requires Java 7 for switch on string.
switch (simState) {
@@ -1315,6 +1329,31 @@
return mPlatformCarrierConfigPackage;
}
+ @VisibleForTesting
+ /* package */ Handler getHandler() {
+ return mHandler;
+ }
+
+ @VisibleForTesting
+ /* package */ PersistableBundle getConfigFromDefaultApp(int phoneId) {
+ return mConfigFromDefaultApp[phoneId];
+ }
+
+ @VisibleForTesting
+ /* package */ PersistableBundle getConfigFromCarrierApp(int phoneId) {
+ return mConfigFromCarrierApp[phoneId];
+ }
+
+ @VisibleForTesting
+ /* package */ PersistableBundle getNoSimConfig() {
+ return mNoSimConfig;
+ }
+
+ @VisibleForTesting
+ /* package */ PersistableBundle getOverrideConfig(int phoneId) {
+ return mOverrideConfigs[phoneId];
+ }
+
private void unbindIfBound(Context context, CarrierServiceConnection conn,
int phoneId) {
if (mServiceBound[phoneId]) {
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 6fdde78..445ff84 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -539,8 +539,15 @@
*/
public boolean isRcsVolteSingleRegistrationEnabled(int subId) {
if (mRcsProvisioningInfos.containsKey(subId)) {
- return mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
- == ProvisioningManager.STATUS_CAPABLE;
+ if (mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
+ == ProvisioningManager.STATUS_CAPABLE) {
+ try {
+ RcsConfig rcsConfig = new RcsConfig(getConfig(subId));
+ return rcsConfig.isRcsVolteSingleRegistrationSupported();
+ } catch (IllegalArgumentException e) {
+ logd("fail to get rcs config for sub:" + subId);
+ }
+ }
}
return false;
}
diff --git a/src/com/android/phone/SimPhonebookProvider.java b/src/com/android/phone/SimPhonebookProvider.java
index 6a27130..4a15950 100644
--- a/src/com/android/phone/SimPhonebookProvider.java
+++ b/src/com/android/phone/SimPhonebookProvider.java
@@ -818,15 +818,15 @@
int efid;
if (efName != null) {
switch (efName) {
- case ElementaryFiles.EF_ADN_PATH_SEGMENT:
+ case ElementaryFiles.PATH_SEGMENT_EF_ADN:
efType = ElementaryFiles.EF_ADN;
efid = IccConstants.EF_ADN;
break;
- case ElementaryFiles.EF_FDN_PATH_SEGMENT:
+ case ElementaryFiles.PATH_SEGMENT_EF_FDN:
efType = ElementaryFiles.EF_FDN;
efid = IccConstants.EF_FDN;
break;
- case ElementaryFiles.EF_SDN_PATH_SEGMENT:
+ case ElementaryFiles.PATH_SEGMENT_EF_SDN:
efType = ElementaryFiles.EF_SDN;
efid = IccConstants.EF_SDN;
break;
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java
index 75eb48d..e3a091d 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java
@@ -88,7 +88,7 @@
return (Message)
method.invoke(
new StringMsgParser(),
- message.getEncodedMessage(),
+ message.toEncodedMessage(),
true,
false,
(ParseExceptionListener)
@@ -98,7 +98,7 @@
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
try {
method = StringMsgParser.class.getDeclaredMethod("parseSIPMessage", byte[].class);
- return (Message) method.invoke(new StringMsgParser(), message.getEncodedMessage());
+ return (Message) method.invoke(new StringMsgParser(), message.toEncodedMessage());
} catch (IllegalAccessException | InvocationTargetException
| NoSuchMethodException ex) {
ex.printStackTrace();
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 9d712d3..fc5ee4c 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Handler;
import android.os.PersistableBundle;
import android.telecom.TelecomManager;
@@ -32,16 +34,22 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsManager;
import android.test.mock.MockContext;
+import android.util.Log;
import android.util.SparseArray;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.util.HashSet;
import java.util.concurrent.Executor;
public class TestContext extends MockContext {
+ private static final String TAG = "TestContext";
+ // Stub used to grant all permissions
+ public static final String STUB_PERMISSION_ENABLE_ALL = "stub_permission_enable_all";
+
@Mock CarrierConfigManager mMockCarrierConfigManager;
@Mock TelecomManager mMockTelecomManager;
@Mock TelephonyManager mMockTelephonyManager;
@@ -50,6 +58,8 @@
private SparseArray<PersistableBundle> mCarrierConfigs = new SparseArray<>();
+ private final HashSet<String> mPermissionTable = new HashSet<>();
+
public TestContext() {
MockitoAnnotations.initMocks(this);
doAnswer((Answer<PersistableBundle>) invocation -> {
@@ -161,4 +171,67 @@
}
return b;
}
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(permission + " denied: " + message);
+ }
+ }
+
+ @Override
+ public void enforcePermission(String permission, int pid, int uid, String message) {
+ enforceCallingOrSelfPermission(permission, message);
+ }
+
+ @Override
+ public void enforceCallingPermission(String permission, String message) {
+ enforceCallingOrSelfPermission(permission, message);
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ return checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid());
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ synchronized (mPermissionTable) {
+ if (mPermissionTable.contains(permission)
+ || mPermissionTable.contains(STUB_PERMISSION_ENABLE_ALL)) {
+ logd("checkCallingOrSelfPermission: " + permission + " return GRANTED");
+ return PackageManager.PERMISSION_GRANTED;
+ } else {
+ logd("checkCallingOrSelfPermission: " + permission + " return DENIED");
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+ }
+
+ public void grantPermission(String permission) {
+ synchronized (mPermissionTable) {
+ if (mPermissionTable != null && permission != null) {
+ mPermissionTable.remove(STUB_PERMISSION_ENABLE_ALL);
+ mPermissionTable.add(permission);
+ }
+ }
+ }
+
+ public void revokePermission(String permission) {
+ synchronized (mPermissionTable) {
+ if (mPermissionTable != null && permission != null) {
+ mPermissionTable.remove(permission);
+ }
+ }
+ }
+
+ public void revokeAllPermissions() {
+ synchronized (mPermissionTable) {
+ mPermissionTable.clear();
+ }
+ }
+
+ private static void logd(String s) {
+ Log.d(TAG, s);
+ }
}
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
new file mode 100644
index 0000000..f58e6cc
--- /dev/null
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2021 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 com.android.TestContext.STUB_PERMISSION_ENABLE_ALL;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+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.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.service.carrier.CarrierIdentifier;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.SubscriptionInfoUpdater;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+/**
+ * Unit Test for CarrierConfigLoader.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarrierConfigLoaderTest extends TelephonyTestBase {
+
+ private static final int DEFAULT_PHONE_ID = 0;
+ private static final int DEFAULT_SUB_ID = SubscriptionManager.getDefaultSubscriptionId();
+ private static final String PLATFORM_CARRIER_CONFIG_PACKAGE = "com.android.carrierconfig";
+ private static final long PLATFORM_CARRIER_CONFIG_PACKAGE_VERSION_CODE = 1;
+ private static final String CARRIER_CONFIG_EXAMPLE_KEY =
+ CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT;
+ private static final int CARRIER_CONFIG_EXAMPLE_VALUE =
+ CarrierConfigManager.USSD_OVER_CS_PREFERRED;
+
+ @Mock Resources mResources;
+ @Mock PackageManager mPackageManager;
+ @Mock PackageInfo mPackageInfo;
+ @Mock SubscriptionInfoUpdater mSubscriptionInfoUpdater;
+ @Mock SharedPreferences mSharedPreferences;
+
+ private TelephonyManager mTelephonyManager;
+ private CarrierConfigLoader mCarrierConfigLoader;
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ doReturn(mSharedPreferences).when(mContext).getSharedPreferences(anyString(), anyInt());
+ doReturn(Build.FINGERPRINT).when(mSharedPreferences).getString(eq("build_fingerprint"),
+ any());
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(InstrumentationRegistry.getTargetContext().getFilesDir()).when(
+ mContext).getFilesDir();
+ doReturn(PLATFORM_CARRIER_CONFIG_PACKAGE).when(mResources).getString(
+ eq(R.string.platform_carrier_config_package));
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ doReturn(1).when(mTelephonyManager).getSupportedModemCount();
+ doReturn(1).when(mTelephonyManager).getActiveModemCount();
+ doReturn("spn").when(mTelephonyManager).getSimOperatorNameForPhone(anyInt());
+ doReturn("310260").when(mTelephonyManager).getSimOperatorNumericForPhone(anyInt());
+ doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(
+ eq(PLATFORM_CARRIER_CONFIG_PACKAGE), eq(0) /*flags*/);
+ doReturn(PLATFORM_CARRIER_CONFIG_PACKAGE_VERSION_CODE).when(
+ mPackageInfo).getLongVersionCode();
+
+ mHandlerThread = new HandlerThread("CarrierConfigLoaderTest");
+ mHandlerThread.start();
+
+ mTestableLooper = new TestableLooper(mHandlerThread.getLooper());
+ mCarrierConfigLoader = new CarrierConfigLoader(mContext, mSubscriptionInfoUpdater,
+ mTestableLooper.getLooper());
+ mHandler = mCarrierConfigLoader.getHandler();
+
+ // Clear all configs to have the same starting point.
+ mCarrierConfigLoader.clearConfigForPhone(DEFAULT_PHONE_ID, false);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mContext.revokeAllPermissions();
+ mTestableLooper.destroy();
+ super.tearDown();
+ }
+
+ /**
+ * Verifies that SecurityException should throw when call #updateConfigForPhoneId() without
+ * MODIFY_PHONE_STATE permission.
+ */
+ @Test
+ public void testUpdateConfigForPhoneId_noPermission() throws Exception {
+ assertThrows(SecurityException.class,
+ () -> mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID,
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT));
+ }
+
+ /**
+ * Verifies that IllegalArgumentException should throw when call #updateConfigForPhoneId() with
+ * invalid phoneId.
+ */
+ @Test
+ public void testUpdateConfigForPhoneId_invalidPhoneId() throws Exception {
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarrierConfigLoader.updateConfigForPhoneId(
+ SubscriptionManager.INVALID_PHONE_INDEX,
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT));
+ }
+
+ /**
+ * Verifies that when call #updateConfigForPhoneId() with SIM absence, both carrier config from
+ * default app and carrier should be cleared but no-sim config should be loaded.
+ */
+ @Test
+ public void testUpdateConfigForPhoneId_simAbsent() throws Exception {
+ // Bypass case if default subId is not supported by device to reduce flakiness
+ if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
+ return;
+ }
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
+
+ // Prepare a cached config to fetch from xml
+ PersistableBundle config = getTestConfig();
+ mCarrierConfigLoader.saveNoSimConfigToXml(PLATFORM_CARRIER_CONFIG_PACKAGE, config);
+ mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID,
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mCarrierConfigLoader.getConfigFromDefaultApp(DEFAULT_PHONE_ID)).isNull();
+ assertThat(mCarrierConfigLoader.getConfigFromCarrierApp(DEFAULT_PHONE_ID)).isNull();
+ assertThat(mCarrierConfigLoader.getNoSimConfig().getInt(CARRIER_CONFIG_EXAMPLE_KEY))
+ .isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE);
+ verify(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
+ }
+
+ /**
+ * Verifies that with cached config in XML, calling #updateConfigForPhoneId() with SIM loaded
+ * will return the right config in the XML.
+ */
+ @Test
+ public void testUpdateConfigForPhoneId_simLoaded_withCachedConfigInXml() throws Exception {
+ // Bypass case if default subId is not supported by device to reduce flakiness
+ if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
+ return;
+ }
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ // Prepare to make sure we can save the config into the XML file which used as cache
+ List<String> carrierPackages = List.of(PLATFORM_CARRIER_CONFIG_PACKAGE);
+ doReturn(carrierPackages).when(mTelephonyManager).getCarrierPackageNamesForIntentAndPhone(
+ nullable(Intent.class), anyInt());
+
+ // Save the sample config into the XML file
+ PersistableBundle config = getTestConfig();
+ CarrierIdentifier carrierId = mCarrierConfigLoader.getCarrierIdentifierForPhoneId(
+ DEFAULT_PHONE_ID);
+ mCarrierConfigLoader.saveConfigToXml(PLATFORM_CARRIER_CONFIG_PACKAGE, "",
+ DEFAULT_PHONE_ID, carrierId, config);
+ mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID,
+ IccCardConstants.INTENT_VALUE_ICC_LOADED);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mCarrierConfigLoader.getConfigFromDefaultApp(DEFAULT_PHONE_ID).getInt(
+ CARRIER_CONFIG_EXAMPLE_KEY)).isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE);
+
+ }
+
+ /**
+ * Verifies that SecurityException should throw if call #overrideConfig() without
+ * MODIFY_PHONE_STATE permission.
+ */
+ @Test
+ public void testOverrideConfig_noPermission() throws Exception {
+ assertThrows(SecurityException.class,
+ () -> mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, PersistableBundle.EMPTY,
+ false));
+ }
+
+ /**
+ * Verifies IllegalArgumentException should throw if call #overrideConfig() with invalid subId.
+ */
+ @Test
+ public void testOverrideConfig_invalidSubId() throws Exception {
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ assertThrows(IllegalArgumentException.class, () -> mCarrierConfigLoader.overrideConfig(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, new PersistableBundle(), false));
+ }
+
+ /**
+ * Verifies that override config is not null when calling #overrideConfig with null bundle.
+ */
+ @Test
+ public void testOverrideConfig_withNullBundle() throws Exception {
+ // Bypass case if default subId is not supported by device to reduce flakiness
+ if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
+ return;
+ }
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, null /*overrides*/,
+ false/*persistent*/);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).isEmpty()).isTrue();
+ verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
+ eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+ any(PersistableBundle.class), any(Message.class));
+ }
+
+ /**
+ * Verifies that override config is not null when calling #overrideConfig with non-null bundle.
+ */
+ @Test
+ public void testOverrideConfig_withNonNullBundle() throws Exception {
+ // Bypass case if default subId is not supported by device to reduce flakiness
+ if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
+ return;
+ }
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ PersistableBundle config = getTestConfig();
+ mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, config /*overrides*/,
+ false/*persistent*/);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).getInt(
+ CARRIER_CONFIG_EXAMPLE_KEY)).isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE);
+ verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
+ eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+ any(PersistableBundle.class), any(Message.class));
+ }
+
+ /**
+ * Verifies that IllegalArgumentException should throw when calling
+ * #notifyConfigChangedForSubId() with invalid subId.
+ */
+ @Test
+ public void testNotifyConfigChangedForSubId_invalidSubId() throws Exception {
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarrierConfigLoader.notifyConfigChangedForSubId(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ // TODO(b/184040111): Enable test case when support disabling carrier privilege
+ // Phone/System UID always has carrier privilege (TelephonyPermission#getCarrierPrivilegeStatus)
+ // when running the test here.
+ /**
+ * Verifies that SecurityException should throw when calling notifyConfigChangedForSubId without
+ * MODIFY_PHONE_STATE permission.
+ */
+ @Ignore
+ public void testNotifyConfigChangedForSubId_noPermission() throws Exception {
+ setCarrierPrivilegesForSubId(false, DEFAULT_SUB_ID);
+
+ assertThrows(SecurityException.class,
+ () -> mCarrierConfigLoader.notifyConfigChangedForSubId(DEFAULT_SUB_ID));
+ }
+
+ /**
+ * Verifies that SecurityException should throw when calling getDefaultCarrierServicePackageName
+ * without READ_PRIVILEGED_PHONE_STATE permission.
+ */
+ @Test
+ public void testGetDefaultCarrierServicePackageName_noPermission() {
+ assertThrows(SecurityException.class,
+ () -> mCarrierConfigLoader.getDefaultCarrierServicePackageName());
+ }
+
+ /**
+ * Verifies that the right default carrier service package name is return when calling
+ * getDefaultCarrierServicePackageName with permission.
+ */
+ @Test
+ public void testGetDefaultCarrierServicePackageName_withPermission() {
+ mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+ assertThat(mCarrierConfigLoader.getDefaultCarrierServicePackageName())
+ .isEqualTo(PLATFORM_CARRIER_CONFIG_PACKAGE);
+ }
+
+ // TODO(b/184040111): Enable test case when support disabling carrier privilege
+ // Phone/System UID always has carrier privilege (TelephonyPermission#getCarrierPrivilegeStatus)
+ // when running the test here.
+ /**
+ * Verifies that without permission, #getConfigForSubId will return an empty PersistableBundle.
+ */
+ @Ignore
+ public void testGetConfigForSubId_noPermission() {
+ // Bypass case if default subId is not supported by device to reduce flakiness
+ if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
+ return;
+ }
+ setCarrierPrivilegesForSubId(false, DEFAULT_SUB_ID);
+
+ assertThat(mCarrierConfigLoader.getConfigForSubId(DEFAULT_SUB_ID,
+ PLATFORM_CARRIER_CONFIG_PACKAGE)).isEqualTo(PersistableBundle.EMPTY);
+ }
+
+ /**
+ * Verifies that when have no DUMP permission, the #dump() method shows permission denial.
+ */
+ @Test
+ public void testDump_noPermission() {
+ StringWriter stringWriter = new StringWriter();
+ mCarrierConfigLoader.dump(new FileDescriptor(), new PrintWriter(stringWriter),
+ new String[0]);
+ stringWriter.flush();
+
+ assertThat(stringWriter.toString()).contains("Permission Denial:");
+ }
+
+ /**
+ * Verifies that when have DUMP permission, the #dump() method can dump the CarrierConfigLoader.
+ */
+ @Test
+ public void testDump_withPermission() {
+ mContext.grantPermission(android.Manifest.permission.DUMP);
+
+ StringWriter stringWriter = new StringWriter();
+ mCarrierConfigLoader.dump(new FileDescriptor(), new PrintWriter(stringWriter),
+ new String[0]);
+ stringWriter.flush();
+
+ String dumpContent = stringWriter.toString();
+ assertThat(dumpContent).contains("CarrierConfigLoader:");
+ assertThat(dumpContent).doesNotContain("Permission Denial:");
+ }
+
+ private static PersistableBundle getTestConfig() {
+ PersistableBundle config = new PersistableBundle();
+ config.putInt(CARRIER_CONFIG_EXAMPLE_KEY, CARRIER_CONFIG_EXAMPLE_VALUE);
+ return config;
+ }
+
+ private void setCarrierPrivilegesForSubId(boolean hasCarrierPrivileges, int subId) {
+ TelephonyManager mockTelephonyManager = Mockito.mock(TelephonyManager.class);
+ doReturn(mockTelephonyManager).when(mTelephonyManager).createForSubscriptionId(subId);
+ doReturn(hasCarrierPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS).when(
+ mockTelephonyManager).getCarrierPrivilegeStatus(anyInt());
+ }
+}
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index 54333bb..c7d0c8f 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -85,7 +85,7 @@
*/
public class RcsProvisioningMonitorTest {
private static final String TAG = "RcsProvisioningMonitorTest";
- private static final String SAMPLE_CONFIG = "<RCSConfig>\n"
+ private static final String CONFIG_DEFAULT = "<RCSConfig>\n"
+ "\t<rcsVolteSingleRegistration>1</rcsVolteSingleRegistration>\n"
+ "\t<SERVICES>\n"
+ "\t\t<SupportedRCSProfileVersions>UP_2.0</SupportedRCSProfileVersions>\n"
@@ -104,6 +104,9 @@
+ "\t\t</Ext>\n"
+ "\t</SERVICES>\n"
+ "</RCSConfig>";
+ private static final String CONFIG_SINGLE_REGISTRATION_DISABLED = "<RCSConfig>\n"
+ + "\t<rcsVolteSingleRegistration>0</rcsVolteSingleRegistration>\n"
+ + "</RCSConfig>";
private static final int FAKE_SUB_ID_BASE = 0x0FFFFFF0;
private static final String DEFAULT_MESSAGING_APP1 = "DMA1";
private static final String DEFAULT_MESSAGING_APP2 = "DMA2";
@@ -252,7 +255,7 @@
when(mCursor.moveToFirst()).thenReturn(true);
when(mCursor.getColumnIndexOrThrow(any())).thenReturn(1);
when(mCursor.getBlob(anyInt())).thenReturn(
- RcsConfig.compressGzip(SAMPLE_CONFIG.getBytes()));
+ RcsConfig.compressGzip(CONFIG_DEFAULT.getBytes()));
mHandlerThread = new HandlerThread("RcsProvisioningMonitorTest");
mHandlerThread.start();
@@ -278,7 +281,7 @@
createMonitor(3);
for (int i = 0; i < 3; i++) {
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(),
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE + i)));
}
@@ -312,7 +315,7 @@
ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
for (int i = 0; i < 3; i++) {
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(),
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE + i)));
}
verify(mPhone, times(3)).sendBroadcast(captorIntent.capture(), any());
@@ -358,7 +361,7 @@
processAllMessages();
byte[] configCached = mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE);
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(), configCached));
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(), configCached));
verify(mIImsConfig, times(1)).notifyRcsAutoConfigurationRemoved();
// The api should be called 2 times, one happens when monitor is initilized,
// Another happens when DMS is changed.
@@ -421,12 +424,12 @@
createMonitor(1);
final ArgumentCaptor<byte[]> argumentBytes = ArgumentCaptor.forClass(byte[].class);
- mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, SAMPLE_CONFIG.getBytes(), false);
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
verify(mIImsConfig, atLeastOnce()).notifyRcsAutoConfigurationReceived(
argumentBytes.capture(), eq(false));
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(), argumentBytes.getValue()));
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(), argumentBytes.getValue()));
}
@Test
@@ -447,13 +450,15 @@
createMonitor(1);
when(mPackageManager.hasSystemFeature(
- eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
mBundle.putBoolean(
- CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
- assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ when(mPackageManager.hasSystemFeature(
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
@@ -468,6 +473,27 @@
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ when(mPackageManager.hasSystemFeature(
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
+ mBundle.putBoolean(
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, null, false);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE,
+ CONFIG_SINGLE_REGISTRATION_DISABLED.getBytes(), false);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
}
@Test
@@ -594,12 +620,12 @@
verify(mCursor, times(1)).getBlob(anyInt());
assertNull(mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE));
- mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, SAMPLE_CONFIG.getBytes(), false);
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
//config cahced in monitor should be updated, but db should not
assertNull(mProvider.getContentValues());
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(),
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE)));
//verify if monitor goes back to normal mode
@@ -609,12 +635,12 @@
verify(mCursor, times(2)).getBlob(anyInt());
assertNull(mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE));
- mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, SAMPLE_CONFIG.getBytes(), false);
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
- assertTrue(Arrays.equals(SAMPLE_CONFIG.getBytes(),
+ assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE)));
- assertTrue(Arrays.equals(RcsConfig.compressGzip(SAMPLE_CONFIG.getBytes()),
+ assertTrue(Arrays.equals(RcsConfig.compressGzip(CONFIG_DEFAULT.getBytes()),
(byte[]) mProvider.getContentValues().get(SimInfo.COLUMN_RCS_CONFIG)));
}