Merge "Support multi sim on ims reg state change"
diff --git a/res/values/config.xml b/res/values/config.xml
index e6c578a..7dd26bb 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -306,4 +306,8 @@
<!-- Whether or not to support RCS VoLTE single registration -->
<bool name="config_rcsVolteSingleRegistrationEnabled">true</bool>
+
+ <!-- Whether or not to support device to device communication using RTP and DTMF communication
+ transports. -->
+ <bool name="config_use_device_to_device_communication">false</bool>
</resources>
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 5f99ab7..8261756 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -9581,10 +9581,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .addRcsProvisioningCallbackForSubscription(callback, subId);
- } catch (ImsException e) {
- throw new ServiceSpecificException(e.getCode());
+ if (!RcsProvisioningMonitor.getInstance()
+ .registerRcsProvisioningChangedCallback(subId, callback)) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "Service not available for the subscription.");
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9608,11 +9609,8 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeRcsProvisioningCallbackForSubscription(callback, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterRcsProvisioningChangedCallback: " + subId
- + "is inactive, ignoring unregister.");
+ RcsProvisioningMonitor.getInstance()
+ .unregisterRcsProvisioningChangedCallback(subId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index c4f367d..7b51eeb 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -36,19 +36,18 @@
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsConfig;
import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.ImsFeature;
import android.text.TextUtils;
-import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.telephony.Rlog;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -69,10 +68,8 @@
private final PhoneGlobals mPhone;
private final Handler mHandler;
- //cache the rcs config per sub id
- private final Map<Integer, byte[]> mConfigs = Collections.synchronizedMap(new HashMap<>());
- //cache the single registration config per sub id
- private final ConcurrentHashMap<Integer, Integer> mSingleRegistrations =
+ // Cache the RCS provsioning info and related sub id
+ private final ConcurrentHashMap<Integer, RcsProvisioningInfo> mRcsProvisioningInfos =
new ConcurrentHashMap<>();
private Boolean mDeviceSingleRegistrationEnabledOverride;
private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride =
@@ -185,6 +182,105 @@
}
}
+ private final class RcsProvisioningInfo {
+ private int mSubId;
+ private volatile int mSingleRegistrationCapability;
+ private volatile byte[] mConfig;
+ private HashSet<IRcsConfigCallback> mRcsConfigCallbacks;
+
+ RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config) {
+ mSubId = subId;
+ mSingleRegistrationCapability = singleRegistrationCapability;
+ mConfig = config;
+ mRcsConfigCallbacks = new HashSet<>();
+ }
+
+ void setSingleRegistrationCapability(int singleRegistrationCapability) {
+ mSingleRegistrationCapability = singleRegistrationCapability;
+ }
+
+ int getSingleRegistrationCapability() {
+ return mSingleRegistrationCapability;
+ }
+
+ void setConfig(byte[] config) {
+ mConfig = config;
+ }
+
+ byte[] getConfig() {
+ return mConfig;
+ }
+
+ boolean addRcsConfigCallback(IRcsConfigCallback cb) {
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+ if (imsConfig == null) {
+ logd("fail to addRcsConfigCallback as imsConfig is null");
+ return false;
+ }
+
+ synchronized (mRcsConfigCallbacks) {
+ try {
+ imsConfig.addRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to addRcsConfigCallback due to " + e);
+ return false;
+ }
+ mRcsConfigCallbacks.add(cb);
+ }
+ return true;
+ }
+
+ boolean removeRcsConfigCallback(IRcsConfigCallback cb) {
+ boolean result = true;
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+
+ synchronized (mRcsConfigCallbacks) {
+ if (imsConfig != null) {
+ try {
+ imsConfig.removeRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to removeRcsConfigCallback due to " + e);
+ }
+ } else {
+ // Return false but continue to remove the callback
+ result = false;
+ }
+
+ try {
+ cb.onRemoved();
+ } catch (RemoteException e) {
+ logd("Failed to notify onRemoved due to dead binder of " + cb);
+ }
+ mRcsConfigCallbacks.remove(cb);
+ }
+ return result;
+ }
+
+ void clear() {
+ setConfig(null);
+ synchronized (mRcsConfigCallbacks) {
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+ Iterator<IRcsConfigCallback> it = mRcsConfigCallbacks.iterator();
+ while (it.hasNext()) {
+ IRcsConfigCallback cb = it.next();
+ if (imsConfig != null) {
+ try {
+ imsConfig.removeRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to removeRcsConfigCallback due to " + e);
+ }
+ }
+ try {
+ cb.onRemoved();
+ } catch (RemoteException e) {
+ logd("Failed to notify onRemoved due to dead binder of " + cb);
+ }
+ it.remove();
+ }
+ }
+ }
+ }
+
@VisibleForTesting
public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager) {
mPhone = app;
@@ -252,15 +348,19 @@
*/
@VisibleForTesting
public byte[] getConfig(int subId) {
- return mConfigs.get(subId);
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return mRcsProvisioningInfos.get(subId).getConfig();
+ }
+ return null;
}
/**
* Returns whether Rcs Volte single registration is enabled for the sub.
*/
public boolean isRcsVolteSingleRegistrationEnabled(int subId) {
- if (mSingleRegistrations.containsKey(subId)) {
- return mSingleRegistrations.get(subId) == ProvisioningManager.STATUS_CAPABLE;
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
+ == ProvisioningManager.STATUS_CAPABLE;
}
return false;
}
@@ -281,6 +381,34 @@
}
/**
+ * Called when the application registers rcs provisioning changed callback
+ */
+ public boolean registerRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ // should not happen in normal case
+ if (info == null) {
+ logd("fail to register rcs provisioning changed due to subscription unavailable");
+ return false;
+ }
+
+ return info.addRcsConfigCallback(cb);
+ }
+
+ /**
+ * Called when the application unregisters rcs provisioning changed callback
+ */
+ public boolean unregisterRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ // should not happen in normal case
+ if (info == null) {
+ logd("fail to unregister rcs provisioning changed due to subscription unavailable");
+ return false;
+ }
+
+ return info.removeRcsConfigCallback(cb);
+ }
+
+ /**
* override the device config whether single registration is enabled
*/
public void overrideDeviceSingleRegistrationEnabled(Boolean enabled) {
@@ -291,7 +419,7 @@
* Overrides the carrier config whether single registration is enabled
*/
public boolean overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled) {
- if (!mSingleRegistrations.containsKey(subId)) {
+ if (!mRcsProvisioningInfos.containsKey(subId)) {
return false;
}
mHandler.sendMessage(mHandler.obtainMessage(
@@ -303,8 +431,9 @@
* Returns the device config whether single registration is enabled
*/
public boolean getDeviceSingleRegistrationEnabled() {
- for (int val : mSingleRegistrations.values()) {
- return (val & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
+ for (RcsProvisioningInfo info : mRcsProvisioningInfos.values()) {
+ return (info.getSingleRegistrationCapability()
+ & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
}
return false;
}
@@ -313,8 +442,8 @@
* Returns the carrier config whether single registration is enabled
*/
public boolean getCarrierSingleRegistrationEnabled(int subId) {
- if (mSingleRegistrations.containsKey(subId)) {
- return (mSingleRegistrations.get(subId)
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return (mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
& ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE) == 0;
}
return false;
@@ -323,20 +452,21 @@
private void onDefaultMessagingApplicationChanged() {
final String packageName = getDmaPackageName();
if (!TextUtils.equals(mDmaPackageName, packageName)) {
- //clear old callbacks
- ImsManager.getInstance(mPhone, mPhone.getPhone().getPhoneId())
- .clearRcsProvisioningCallbacks();
mDmaPackageName = packageName;
logv("new default messaging application " + mDmaPackageName);
- mConfigs.forEach((k, v) -> {
+
+ mRcsProvisioningInfos.forEach((k, v) -> {
+ byte[] cachedConfig = v.getConfig();
+ //clear old callbacks
+ v.clear();
if (isAcsUsed(k)) {
logv("acs used, trigger to re-configure.");
- mConfigs.put(k, null);
notifyRcsAutoConfigurationRemoved(k);
triggerRcsReconfiguration(k);
} else {
+ v.setConfig(cachedConfig);
logv("acs not used, notify.");
- notifyRcsAutoConfigurationReceived(k, v, false);
+ notifyRcsAutoConfigurationReceived(k, v.getConfig(), false);
}
});
}
@@ -425,58 +555,68 @@
private void onCarrierConfigChange() {
logv("onCarrierConfigChange");
- mConfigs.forEach((subId, config) -> {
+ mRcsProvisioningInfos.forEach((subId, info) -> {
int value = getSingleRegistrationCapableValue(subId);
- if (value != mSingleRegistrations.get(subId)) {
- mSingleRegistrations.put(subId, value);
- notifyDmaForSub(subId);
+ if (value != info.getSingleRegistrationCapability()) {
+ info.setSingleRegistrationCapability(value);
+ notifyDmaForSub(subId, value);
}
});
}
private void onSubChanged() {
final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList();
- final HashSet<Integer> subsToBeDeactivated = new HashSet<>(mConfigs.keySet());
+ final HashSet<Integer> subsToBeDeactivated = new HashSet<>(mRcsProvisioningInfos.keySet());
for (int i : activeSubs) {
subsToBeDeactivated.remove(i);
- if (!mConfigs.containsKey(i)) {
+ if (!mRcsProvisioningInfos.containsKey(i)) {
byte[] data = RcsConfig.loadRcsConfigForSub(mPhone, i, false);
- logv("new config is created for sub : " + i);
- mConfigs.put(i, data);
+ int capability = getSingleRegistrationCapableValue(i);
+ logv("new info is created for sub : " + i + ", single registration capability :"
+ + capability + ", rcs config : " + data);
+ mRcsProvisioningInfos.put(i, new RcsProvisioningInfo(i, capability, data));
notifyRcsAutoConfigurationReceived(i, data, false);
- mSingleRegistrations.put(i, getSingleRegistrationCapableValue(i));
- notifyDmaForSub(i);
+ notifyDmaForSub(i, capability);
}
}
subsToBeDeactivated.forEach(i -> {
- mConfigs.remove(i);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.remove(i);
notifyRcsAutoConfigurationRemoved(i);
+ if (info != null) {
+ info.clear();
+ }
});
}
private void onConfigReceived(int subId, byte[] config, boolean isCompressed) {
logv("onConfigReceived, subId:" + subId + ", config:"
+ config + ", isCompressed:" + isCompressed);
- mConfigs.put(subId, isCompressed ? RcsConfig.decompressGzip(config) : config);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ if (info != null) {
+ info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config);
+ }
RcsConfig.updateConfigForSub(mPhone, subId, config, isCompressed);
notifyRcsAutoConfigurationReceived(subId, config, isCompressed);
}
private void onReconfigRequest(int subId) {
logv("onReconfigRequest, subId:" + subId);
- mConfigs.put(subId, null);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ if (info != null) {
+ info.setConfig(null);
+ }
notifyRcsAutoConfigurationRemoved(subId);
triggerRcsReconfiguration(subId);
}
- private void notifyDmaForSub(int subId) {
+ private void notifyDmaForSub(int subId, int capability) {
final Intent intent = new Intent(
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
intent.setPackage(mDmaPackageName);
intent.putExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID, subId);
- intent.putExtra(ProvisioningManager.EXTRA_STATUS, mSingleRegistrations.get(subId));
+ intent.putExtra(ProvisioningManager.EXTRA_STATUS, capability);
logv("notify " + intent);
mPhone.sendBroadcast(intent);
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3e7f29c..6814a00 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -46,6 +46,8 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.RtpHeaderExtension;
+import android.telephony.ims.RtpHeaderExtensionType;
import android.text.TextUtils;
import android.util.Pair;
@@ -61,6 +63,9 @@
import com.android.internal.telephony.Connection.PostDialListener;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.d2d.Communicator;
+import com.android.internal.telephony.d2d.RtpAdapter;
+import com.android.internal.telephony.d2d.RtpTransport;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
@@ -85,7 +90,7 @@
/**
* Base class for CDMA and GSM connections.
*/
-abstract class TelephonyConnection extends Connection implements Holdable {
+abstract class TelephonyConnection extends Connection implements Holdable, Communicator.Callback {
private static final String LOG_TAG = "TelephonyConnection";
private static final int MSG_PRECISE_CALL_STATE_CHANGED = 1;
@@ -487,6 +492,19 @@
public void onRingbackRequested(Connection c, boolean ringback) {}
}
+ public static class D2DCallStateAdapter extends TelephonyConnectionListener {
+ private Communicator mCommunicator;
+
+ D2DCallStateAdapter(Communicator communicator) {
+ mCommunicator = communicator;
+ }
+
+ @Override
+ public void onStateChanged(android.telecom.Connection c, int state) {
+ mCommunicator.onStateChanged(c, state);
+ }
+ }
+
private final PostDialListener mPostDialListener = new PostDialListener() {
@Override
public void onPostDialWait() {
@@ -701,6 +719,20 @@
public void onIsNetworkEmergencyCallChanged(boolean isEmergencyCall) {
setIsNetworkIdentifiedEmergencyCall(isEmergencyCall);
}
+
+ /**
+ * Indicates data from an RTP header extension has been received from the network.
+ * @param extensionData The extension data.
+ */
+ @Override
+ public void onReceivedRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> extensionData) {
+ if (mRtpTransport == null) {
+ return;
+ }
+ Log.i(this, "onReceivedRtpHeaderExtensions: received %d extensions",
+ extensionData.size());
+ mRtpTransport.onRtpHeaderExtensionsReceived(extensionData);
+ }
};
private TelephonyConnectionService mTelephonyConnectionService;
@@ -805,6 +837,18 @@
private int mHangupDisconnectCause = DisconnectCause.NOT_VALID;
/**
+ * Provides a means for a {@link Communicator} to be informed of call state changes.
+ */
+ private D2DCallStateAdapter mD2DCallStateAdapter;
+
+ private RtpTransport mRtpTransport;
+
+ /**
+ * Facilitates device to device communication.
+ */
+ private Communicator mCommunicator;
+
+ /**
* Listeners to our TelephonyConnection specific callbacks
*/
private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -1404,6 +1448,9 @@
if (isImsConnection()) {
mWasImsConnection = true;
}
+ if (originalConnection instanceof ImsPhoneConnection) {
+ maybeConfigureDeviceToDeviceCommunication();
+ }
mIsMultiParty = mOriginalConnection.isMultiparty();
Bundle extrasToPut = new Bundle();
@@ -2218,6 +2265,10 @@
case DISCONNECTING:
break;
}
+
+ if (mCommunicator != null) {
+ mCommunicator.onStateChanged(this, getState());
+ }
}
}
@@ -3112,6 +3163,56 @@
}
/**
+ * Where device to device communication is available and this is an IMS call, configures the
+ * D2D communication infrastructure for operation.
+ */
+ private void maybeConfigureDeviceToDeviceCommunication() {
+ if (!getPhone().getContext().getResources().getBoolean(
+ R.bool.config_use_device_to_device_communication) || !isImsConnection()) {
+ Log.d(this, "maybeConfigureDeviceToDeviceCommunication: not using D2D.");
+ return;
+ }
+ // Implement abstracted out RTP functionality the RTP transport depends on.
+ RtpAdapter rtpAdapter = new RtpAdapter() {
+ @Override
+ public Set<RtpHeaderExtensionType> getAcceptedRtpHeaderExtensions() {
+ if (!isImsConnection()) {
+ return Collections.EMPTY_SET;
+ }
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ return originalConnection.getAcceptedRtpHeaderExtensions();
+ }
+
+ @Override
+ public void sendRtpHeaderExtensions(
+ @NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
+ if (!isImsConnection()) {
+ Log.w(this, "sendRtpHeaderExtensions: not an ims connection.");
+ }
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ originalConnection.sendRtpHeaderExtensions(rtpHeaderExtensions);
+ }
+ };
+ mRtpTransport = new RtpTransport(rtpAdapter, null /* TODO: not needed yet */, mHandler);
+ mCommunicator = new Communicator(List.of(mRtpTransport), this);
+ mD2DCallStateAdapter = new D2DCallStateAdapter(mCommunicator);
+ addTelephonyConnectionListener(mD2DCallStateAdapter);
+ }
+
+ /**
+ * Called by {@link Communicator} associated with this {@link TelephonyConnection} when there
+ * are incoming device-to-device messages received.
+ * @param messages the incoming messages.
+ */
+ @Override
+ public void onMessagesReceived(@NonNull Set<Communicator.Message> messages) {
+ Log.i(this, "onMessagesReceived: got d2d messages: %s", messages);
+ // TODO: Actually do something WITH the messages.
+ }
+
+ /**
* Called by a {@link ConnectionService} to notify Telecom that a {@link Conference#onMerge()}
* operation has started.
*/
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 1d8fa3b..18ad98e 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -163,8 +163,8 @@
public void dump(PrintWriter printWriter) {
printWriter.println("Last reg state: " + mLastRegState);
printWriter.println("Denied tags: " + mDelegateDeniedTags);
- printWriter.println("Most recent logs: ");
printWriter.println();
+ printWriter.println("Most recent logs: ");
mLocalLog.dump(printWriter);
}
diff --git a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
index 0691ae5..c42472d 100644
--- a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
+++ b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
@@ -343,6 +343,7 @@
/** Dump state about this tracker that should be included in the dumpsys */
public void dump(PrintWriter printWriter) {
+ printWriter.println("Most recent logs:");
mLocalLog.dump(printWriter);
}
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 4b3176a..2d6d4f0 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -376,14 +376,23 @@
IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
pw.println("SipDelegateController" + "[" + mSubId + "]:");
pw.increaseIndent();
+ pw.println("Most recent logs:");
+ pw.increaseIndent();
+ mLocalLog.dump(pw);
+ pw.decreaseIndent();
+
+ pw.println();
pw.println("DelegateStateTracker:");
pw.increaseIndent();
- mDelegateStateTracker.dump(printWriter);
+ mDelegateStateTracker.dump(pw);
pw.decreaseIndent();
+
+ pw.println();
pw.println("MessageStateTracker:");
pw.increaseIndent();
- mMessageTransportStateTracker.dump(printWriter);
+ mMessageTransportStateTracker.dump(pw);
pw.decreaseIndent();
+
pw.decreaseIndent();
}
diff --git a/src/com/android/services/telephony/rcs/UceControllerManager.java b/src/com/android/services/telephony/rcs/UceControllerManager.java
index d1f91d1..09288f1 100644
--- a/src/com/android/services/telephony/rcs/UceControllerManager.java
+++ b/src/com/android/services/telephony/rcs/UceControllerManager.java
@@ -51,6 +51,7 @@
private final ExecutorService mExecutorService;
private volatile UceController mUceController;
+ private volatile RcsFeatureManager mRcsFeatureManager;
public UceControllerManager(Context context, int slotId, int subId) {
Log.d(LOG_TAG, "create: slotId=" + slotId + ", subId=" + subId);
@@ -74,12 +75,18 @@
@Override
public void onRcsConnected(RcsFeatureManager manager) {
- mExecutorService.submit(() -> mUceController.onRcsConnected(manager));
+ mExecutorService.submit(() -> {
+ mRcsFeatureManager = manager;
+ mUceController.onRcsConnected(manager);
+ });
}
@Override
public void onRcsDisconnected() {
- mExecutorService.submit(() -> mUceController.onRcsDisconnected());
+ mExecutorService.submit(() -> {
+ mRcsFeatureManager = null;
+ mUceController.onRcsDisconnected();
+ });
}
@Override
@@ -103,6 +110,12 @@
// Destroy existing UceController and create a new one.
mUceController.onDestroy();
mUceController = new UceController(mContext, subId);
+
+ // The RCS should be connected when the mRcsFeatureManager is not null. Set it to the
+ // new UceController instance.
+ if (mRcsFeatureManager != null) {
+ mUceController.onRcsConnected(mRcsFeatureManager);
+ }
});
}
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index fb1e502..02d2f8a 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -53,6 +53,7 @@
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsConfig;
import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.ImsFeature;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -90,7 +91,7 @@
+ "\t\t<GroupChatAuth>1</GroupChatAuth>\n"
+ "\t\t<ftAuth>1</ftAuth>\n"
+ "\t\t<standaloneMsgAuth>1</standaloneMsgAuth>\n"
- + "\t\t<geolocPushAuth>1<geolocPushAuth>\n"
+ + "\t\t<geolocPushAuth>1</geolocPushAuth>\n"
+ "\t\t<Ext>\n"
+ "\t\t\t<DataOff>\n"
+ "\t\t\t\t<rcsMessagingDataOff>1</rcsMessagingDataOff>\n"
@@ -135,6 +136,8 @@
private Resources mResources;
@Mock
private PhoneGlobals mPhone;
+ @Mock
+ private IRcsConfigCallback mCallback;
private Executor mExecutor = new Executor() {
@Override
@@ -433,7 +436,6 @@
verify(mIImsConfig, times(1)).triggerRcsReconfiguration();
}
-
@Test
@SmallTest
public void testIsRcsVolteSingleRegistrationEnabled() throws Exception {
@@ -463,6 +465,56 @@
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
}
+ @Test
+ @SmallTest
+ public void testRegisterThenUnregisterCallback() throws Exception {
+ createMonitor(1);
+
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).addRcsConfigCallback(eq(mCallback));
+
+ result = mRcsProvisioningMonitor.unregisterRcsProvisioningChangedCallback(
+ 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.registerRcsProvisioningChangedCallback(
+ 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.registerRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+ updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
+ processAllMessages();
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
+ verify(mCallback, times(1)).onRemoved();
+ }
+
private void createMonitor(int subCount) {
if (Looper.myLooper() == null) {
Looper.prepare();