blob: 8873402c8e0377834d2984e7ec3bc8b337651753 [file] [log] [blame]
/*
* Copyright 2020 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.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.provider.Telephony.SimInfo;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyRegistryManager;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsConfig;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableLooper;
import android.util.Log;
import com.android.ims.FeatureConnector;
import com.android.ims.RcsFeatureManager;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.metrics.RcsStats;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Unit tests for RcsProvisioningMonitor
*/
public class RcsProvisioningMonitorTest {
private static final String TAG = "RcsProvisioningMonitorTest";
private static final String CONFIG_DEFAULT = "<?xml version=\"1.0\"?>\n"
+ "<wap-provisioningdoc version=\"1.1\">\n"
+ "\t<characteristic type=\"APPLICATION\">\n"
+ "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ "\t\t\t<characteristic type=\"Ext\">\n"
+ "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"1\"/>\n"
+ "\t\t\t\t</characteristic>\n"
+ "\t\t\t</characteristic>\n"
+ "\t\t</characteristic>\n"
+ "\t\t<characteristic type=\"SERVICES\">\n"
+ "\t\t\t<parm name=\"SupportedRCSProfileVersions\" value=\"UP2.3\"/>\n"
+ "\t\t\t<parm name=\"ChatAuth\" value=\"1\"/>\n"
+ "\t\t\t<parm name=\"GroupChatAuth\" value=\"1\"/>\n"
+ "\t\t\t<parm name=\"ftAuth\" value=\"1\"/>\n"
+ "\t\t\t<parm name=\"standaloneMsgAuth\" value=\"1\"/>\n"
+ "\t\t\t<parm name=\"geolocPushAuth\" value=\"1\"/>\n"
+ "\t\t\t<characteristic type=\"Ext\">\n"
+ "\t\t\t\t<characteristic type=\"DataOff\">\n"
+ "\t\t\t\t\t<parm name=\"rcsMessagingDataOff\" value=\"1\"/>\n"
+ "\t\t\t\t\t<parm name=\"fileTransferDataOff\" value=\"1\"/>\n"
+ "\t\t\t\t\t<parm name=\"mmsDataOff\" value=\"1\"/>\n"
+ "\t\t\t\t\t<parm name=\"syncDataOff\" value=\"1\"/>\n"
+ "\t\t\t\t\t<characteristic type=\"Ext\"/>\n"
+ "\t\t\t\t</characteristic>\n"
+ "\t\t\t</characteristic>\n"
+ "\t\t</characteristic>\n"
+ "\t</characteristic>\n"
+ "</wap-provisioningdoc>\n";
private static final String CONFIG_SINGLE_REGISTRATION_DISABLED = "<?xml version=\"1.0\"?>\n"
+ "<wap-provisioningdoc version=\"1.1\">\n"
+ "\t<characteristic type=\"APPLICATION\">\n"
+ "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ "\t\t\t<characteristic type=\"Ext\">\n"
+ "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"0\"/>\n"
+ "\t\t\t\t</characteristic>\n"
+ "\t\t\t</characteristic>\n"
+ "\t\t</characteristic>\n"
+ "\t</characteristic>\n"
+ "</wap-provisioningdoc>\n";
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";
private RcsProvisioningMonitor mRcsProvisioningMonitor;
private Handler mHandler;
private HandlerThread mHandlerThread;
private TestableLooper mLooper;
private PersistableBundle mBundle;
private MockContentResolver mContentResolver = new MockContentResolver();
private SimInfoContentProvider mProvider;
private BroadcastReceiver mReceiver;
@Mock
private Cursor mCursor;
@Mock
private SubscriptionManager mSubscriptionManager;
private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener;
@Mock
private TelephonyRegistryManager mTelephonyRegistryManager;
@Mock
private CarrierConfigManager mCarrierConfigManager;
private OnRoleHoldersChangedListener mRoleHolderChangedListener;
@Mock
private RcsProvisioningMonitor.RoleManagerAdapter mRoleManager;
@Mock
private ITelephony.Stub mITelephony;
@Mock
private RcsFeatureManager mFeatureManager;
@Mock
private RcsProvisioningMonitor.FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
@Mock
private FeatureConnector<RcsFeatureManager> mFeatureConnector;
@Captor
ArgumentCaptor<FeatureConnector.Listener<RcsFeatureManager>> mConnectorListener;
@Mock
private IImsConfig.Stub mIImsConfig;
@Mock
private Resources mResources;
@Mock
private PhoneGlobals mPhone;
@Mock
private IRcsConfigCallback mCallback;
@Mock
private PackageManager mPackageManager;
@Mock
private RcsStats mRcsStats;
@Mock
private RcsStats.RcsProvisioningCallback mRcsProvisioningCallback;
private Executor mExecutor = new Executor() {
@Override
public void execute(Runnable r) {
r.run();
}
};
private class SimInfoContentProvider extends MockContentProvider {
private Cursor mCursor;
private ContentValues mValues;
SimInfoContentProvider(Context context) {
super(context);
}
public void setCursor(Cursor cursor) {
mCursor = cursor;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return mCursor;
}
@Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
mValues = values;
return 1;
}
ContentValues getContentValues() {
return mValues;
}
}
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mPhone.getResources()).thenReturn(mResources);
when(mPhone.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
when(mPhone.getMainExecutor()).thenReturn(mExecutor);
when(mPhone.getSystemServiceName(eq(CarrierConfigManager.class)))
.thenReturn(Context.CARRIER_CONFIG_SERVICE);
when(mPhone.getSystemServiceName(eq(SubscriptionManager.class)))
.thenReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
when(mPhone.getSystemServiceName(eq(TelephonyRegistryManager.class)))
.thenReturn(Context.TELEPHONY_REGISTRY_SERVICE);
when(mPhone.getSystemServiceName(eq(RoleManager.class)))
.thenReturn(Context.ROLE_SERVICE);
when(mPhone.getSystemService(eq(Context.CARRIER_CONFIG_SERVICE)))
.thenReturn(mCarrierConfigManager);
when(mPhone.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
.thenReturn(mSubscriptionManager);
when(mPhone.getSystemService(eq(Context.TELEPHONY_REGISTRY_SERVICE)))
.thenReturn(mTelephonyRegistryManager);
mBundle = new PersistableBundle();
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
mReceiver = (BroadcastReceiver) invocation.getArguments()[0];
return null;
}
}).when(mPhone).registerReceiver(any(BroadcastReceiver.class), any());
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
mSubChangedListener = (SubscriptionManager.OnSubscriptionsChangedListener)
invocation.getArguments()[0];
return null;
}
}).when(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(
any(SubscriptionManager.OnSubscriptionsChangedListener.class),
any());
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
mRoleHolderChangedListener = (OnRoleHoldersChangedListener)
invocation.getArguments()[1];
return null;
}
}).when(mRoleManager).addOnRoleHoldersChangedListenerAsUser(any(Executor.class),
any(OnRoleHoldersChangedListener.class), any(UserHandle.class));
List<String> dmas = new ArrayList<>();
dmas.add(DEFAULT_MESSAGING_APP1);
when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_SMS))).thenReturn(dmas);
mProvider = new SimInfoContentProvider(mPhone);
mProvider.setCursor(mCursor);
mContentResolver.addProvider(SimInfo.CONTENT_URI.getAuthority(), mProvider);
when(mPhone.getContentResolver()).thenReturn(mContentResolver);
when(mCursor.moveToFirst()).thenReturn(true);
when(mCursor.getColumnIndexOrThrow(any())).thenReturn(1);
when(mCursor.getBlob(anyInt())).thenReturn(
RcsConfig.compressGzip(CONFIG_DEFAULT.getBytes()));
mHandlerThread = new HandlerThread("RcsProvisioningMonitorTest");
mHandlerThread.start();
}
@After
public void tearDown() throws Exception {
if (mRcsProvisioningMonitor != null) {
mRcsProvisioningMonitor.destroy();
mRcsProvisioningMonitor = null;
}
if (mLooper != null) {
mLooper.destroy();
mLooper = null;
}
}
@Test
@SmallTest
public void testInitWithSavedConfig() throws Exception {
createMonitor(3);
for (int i = 0; i < 3; i++) {
assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE + i)));
}
verify(mIImsConfig, times(3)).notifyRcsAutoConfigurationReceived(any(), anyBoolean());
}
@Test
@SmallTest
public void testInitWithoutSavedConfig() throws Exception {
when(mCursor.getBlob(anyInt())).thenReturn(null);
createMonitor(3);
//Should not notify null config
verify(mIImsConfig, never()).notifyRcsAutoConfigurationReceived(any(), anyBoolean());
}
@Test
@SmallTest
public void testSubInfoChanged() throws Exception {
createMonitor(3);
for (int i = 0; i < 3; i++) {
assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE + i)));
}
verify(mIImsConfig, times(3)).notifyRcsAutoConfigurationReceived(any(), anyBoolean());
makeFakeActiveSubIds(1);
mExecutor.execute(() -> mSubChangedListener.onSubscriptionsChanged());
processAllMessages();
for (int i = 1; i < 3; i++) {
assertNull(mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE + i));
}
verify(mIImsConfig, times(2)).notifyRcsAutoConfigurationRemoved();
}
@Test
@SmallTest
public void testDefaultMessagingApplicationChangedWithAcs() throws Exception {
createMonitor(1);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, true);
processAllMessages();
byte[] configCached = mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE);
assertNull(configCached);
assertNull(mProvider.getContentValues().get(SimInfo.COLUMN_RCS_CONFIG));
verify(mIImsConfig, atLeastOnce()).notifyRcsAutoConfigurationRemoved();
verify(mIImsConfig, atLeastOnce()).triggerRcsReconfiguration();
// The api should only be called when monitor is initilized.
verify(mIImsConfig, times(1))
.notifyRcsAutoConfigurationReceived(any(), anyBoolean());
}
@Test
@SmallTest
public void testDefaultMessagingApplicationChangedWithoutAcs() throws Exception {
createMonitor(1);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, false);
processAllMessages();
byte[] configCached = mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE);
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.
verify(mIImsConfig, times(2))
.notifyRcsAutoConfigurationReceived(any(), anyBoolean());
}
@Test
@SmallTest
public void testCarrierConfigChanged() throws Exception {
createMonitor(1);
// should not broadcast message if carrier config is not ready
verify(mPhone, never()).sendBroadcast(any(), any());
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mPhone, times(1)).sendBroadcast(captorIntent.capture(), any());
Intent capturedIntent = captorIntent.getValue();
assertEquals(capturedIntent.getAction(),
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
assertEquals(FAKE_SUB_ID_BASE, capturedIntent.getIntExtra(
ProvisioningManager.EXTRA_SUBSCRIPTION_ID, -1));
assertEquals(ProvisioningManager.STATUS_CAPABLE,
capturedIntent.getIntExtra(ProvisioningManager.EXTRA_STATUS, -1));
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mPhone, times(2)).sendBroadcast(captorIntent.capture(), any());
capturedIntent = captorIntent.getValue();
assertEquals(capturedIntent.getAction(),
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
assertEquals(FAKE_SUB_ID_BASE, capturedIntent.getIntExtra(
ProvisioningManager.EXTRA_SUBSCRIPTION_ID, -1));
assertEquals(ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE,
capturedIntent.getIntExtra(ProvisioningManager.EXTRA_STATUS, -1));
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mPhone, times(3)).sendBroadcast(captorIntent.capture(), any());
capturedIntent = captorIntent.getValue();
assertEquals(capturedIntent.getAction(),
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
assertEquals(FAKE_SUB_ID_BASE, capturedIntent.getIntExtra(
ProvisioningManager.EXTRA_SUBSCRIPTION_ID, -1));
assertEquals(ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE
| ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE,
capturedIntent.getIntExtra(ProvisioningManager.EXTRA_STATUS, -1));
}
@Test
@SmallTest
public void testUpdateConfig() throws Exception {
createMonitor(1);
final ArgumentCaptor<byte[]> argumentBytes = ArgumentCaptor.forClass(byte[].class);
mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
verify(mIImsConfig, atLeastOnce()).notifyRcsAutoConfigurationReceived(
argumentBytes.capture(), eq(false));
assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(), argumentBytes.getValue()));
}
@Test
@SmallTest
public void testRequestReconfig() throws Exception {
createMonitor(1);
mRcsProvisioningMonitor.requestReconfig(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mIImsConfig, times(1)).notifyRcsAutoConfigurationRemoved();
verify(mIImsConfig, times(1)).triggerRcsReconfiguration();
}
@Test
@SmallTest
public void testIsRcsVolteSingleRegistrationEnabled() throws Exception {
createMonitor(1);
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
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, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
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();
assertTrue(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();
assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
assertNull(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(
FAKE_SUB_ID_BASE + 1));
}
@Test
@SmallTest
public void testRegisterThenUnregisterCallback() throws Exception {
createMonitor(1);
boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
assertTrue(result);
verify(mIImsConfig, times(1)).addRcsConfigCallback(eq(mCallback));
result = mRcsProvisioningMonitor.unregisterRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
assertTrue(result);
verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
verify(mCallback, times(1)).onRemoved();
}
@Test
@SmallTest
public void testCallbackRemovedWhenSubInfoChanged() throws Exception {
createMonitor(1);
boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
makeFakeActiveSubIds(0);
mExecutor.execute(() -> mSubChangedListener.onSubscriptionsChanged());
processAllMessages();
assertTrue(result);
verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
verify(mCallback, times(1)).onRemoved();
}
@Test
@SmallTest
public void testCallbackRemovedWhenDmaChanged() throws Exception {
createMonitor(1);
boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
processAllMessages();
assertTrue(result);
verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
verify(mCallback, times(1)).onRemoved();
}
@Test
@SmallTest
public void testSendBroadcastWhenDmaChanged() throws Exception {
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(null);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
createMonitor(1);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
processAllMessages();
// should not broadcast message as no carrier config change happens
verify(mPhone, never()).sendBroadcast(any(), any());
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle);
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mPhone, times(1)).sendBroadcast(captorIntent.capture(), any());
Intent capturedIntent = captorIntent.getValue();
assertEquals(capturedIntent.getAction(),
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP1);
processAllMessages();
// should broadcast message when default messaging application changed if carrier config
// has been loaded
verify(mPhone, times(2)).sendBroadcast(captorIntent.capture(), any());
capturedIntent = captorIntent.getValue();
assertEquals(capturedIntent.getAction(),
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
}
@Test
@SmallTest
public void testRcsConnectedAndDisconnected() throws Exception {
createMonitor(1);
mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
verify(mIImsConfig, times(1))
.notifyRcsAutoConfigurationReceived(any(), anyBoolean());
mConnectorListener.getValue().connectionUnavailable(0);
verify(mCallback, times(1)).onRemoved();
}
@Test
@SmallTest
public void testOverrideDeviceSingleRegistrationEnabled() throws Exception {
createMonitor(1);
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, 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.overrideDeviceSingleRegistrationEnabled(false);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(null);
processAllMessages();
assertTrue(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
//use carrier config change to refresh the value as system feature is static
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(true);
processAllMessages();
assertTrue(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(null);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
}
@Test
@SmallTest
public void testTestModeEnabledAndDisabled() throws Exception {
when(mCursor.getBlob(anyInt())).thenReturn(null);
createMonitor(1);
verify(mCursor, times(1)).getBlob(anyInt());
mRcsProvisioningMonitor.setTestModeEnabled(true);
processAllMessages();
//should not query db in test mode
verify(mCursor, times(1)).getBlob(anyInt());
assertNull(mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE));
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(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE)));
//verify if monitor goes back to normal mode
mRcsProvisioningMonitor.setTestModeEnabled(false);
processAllMessages();
verify(mCursor, times(2)).getBlob(anyInt());
assertNull(mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
assertTrue(Arrays.equals(CONFIG_DEFAULT.getBytes(),
mRcsProvisioningMonitor.getConfig(FAKE_SUB_ID_BASE)));
assertTrue(Arrays.equals(RcsConfig.compressGzip(CONFIG_DEFAULT.getBytes()),
(byte[]) mProvider.getContentValues().get(SimInfo.COLUMN_RCS_CONFIG)));
}
@Test
@SmallTest
public void testOverrideCarrierSingleRegistrationEnabled() throws Exception {
createMonitor(1);
when(mPackageManager.hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, 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
.overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, false);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor
.overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, null);
processAllMessages();
assertTrue(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mBundle.putBoolean(
CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor
.overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, true);
processAllMessages();
assertTrue(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor
.overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, null);
processAllMessages();
assertFalse(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
}
@Test
@SmallTest
public void testOverrideImsFeatureValidation() throws Exception {
createMonitor(1);
mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, false);
assertFalse(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, true);
assertTrue(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, null);
assertNull(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
}
@Test
@SmallTest
public void testMetricsAcsNotUsed() throws Exception {
createMonitor(1);
// Not used ACS
mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, false);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
verify(mRcsStats, never()).onRcsAcsProvisioningStats(anyInt(), anyInt(),
anyInt(), anyBoolean());
}
@Test
@SmallTest
public void testMetricsAcsUsed() throws Exception {
when(mRcsStats.getRcsProvisioningCallback(anyInt(), anyBoolean()))
.thenReturn(mRcsProvisioningCallback);
createMonitor(1);
verify(mIImsConfig, times(1))
.notifyRcsAutoConfigurationReceived(any(), anyBoolean());
// verify RcsStats.getRcsProvisioningCallback() is called
verify(mRcsStats, times(1)).getRcsProvisioningCallback(
eq(FAKE_SUB_ID_BASE), anyBoolean());
// verify registered callback obj which comes from RcsStats.getRcsProvisioningCallback()
verify(mIImsConfig, times(1))
.addRcsConfigCallback(eq(mRcsProvisioningCallback));
// Config data received and ACS used
int errorCode = 200;
mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, true);
broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
processAllMessages();
mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
processAllMessages();
verify(mRcsStats, times(1)).onRcsAcsProvisioningStats(eq(FAKE_SUB_ID_BASE), eq(errorCode),
eq(RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML), anyBoolean());
}
@Test
@SmallTest
public void testMetricsClientProvisioningStats() throws Exception {
createMonitor(1);
// reconfig trigger
mRcsProvisioningMonitor.requestReconfig(FAKE_SUB_ID_BASE);
processAllMessages();
verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION));
// DMA changed
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
processAllMessages();
verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED));
}
private void createMonitor(int subCount) throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
}
makeFakeActiveSubIds(subCount);
when(mFeatureFactory.create(any(), anyInt(), mConnectorListener.capture(), any(), any()))
.thenReturn(mFeatureConnector);
when(mFeatureManager.getConfig()).thenReturn(mIImsConfig);
mRcsProvisioningMonitor = new RcsProvisioningMonitor(mPhone, mHandlerThread.getLooper(),
mRoleManager, mFeatureFactory, mRcsStats);
mHandler = mRcsProvisioningMonitor.getHandler();
try {
mLooper = new TestableLooper(mHandler.getLooper());
} catch (Exception e) {
logd("Unable to create looper from handler.");
}
mConnectorListener.getValue().connectionReady(mFeatureManager);
verify(mFeatureConnector, atLeastOnce()).connect();
}
private void broadcastCarrierConfigChange(int subId) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
mExecutor.execute(() -> {
mReceiver.onReceive(mPhone, intent);
});
}
private void makeFakeActiveSubIds(int count) {
final int[] subIds = new int[count];
for (int i = 0; i < count; i++) {
subIds[i] = FAKE_SUB_ID_BASE + i;
}
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(subIds);
}
private void updateDefaultMessageApplication(String packageName) {
List<String> dmas = new ArrayList<>();
dmas.add(packageName);
when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_SMS))).thenReturn(dmas);
mExecutor.execute(() -> mRoleHolderChangedListener.onRoleHoldersChanged(
RoleManager.ROLE_SMS, UserHandle.ALL));
}
private void processAllMessages() {
while (!mLooper.getLooper().getQueue().isIdle()) {
mLooper.processAllMessages();
}
}
private static void logd(String str) {
Log.d(TAG, str);
}
}