Merge "Swap parameters in QosCallback#registerQosCallback"
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index ef83ead..ae6f072 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -30,6 +30,9 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.os.UserManager;
import android.preference.Preference;
@@ -40,8 +43,8 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.feature.ImsFeature;
@@ -103,6 +106,7 @@
private ImsManager mImsMgr;
private SubscriptionInfoHelper mSubscriptionInfoHelper;
private TelecomManager mTelecomManager;
+ private TelephonyCallback mTelephonyCallback;
private SwitchPreference mButtonAutoRetry;
private PreferenceScreen mVoicemailSettingsScreen;
@@ -263,6 +267,7 @@
mSubscriptionInfoHelper.setActionBarTitle(
getActionBar(), getResourcesForSubId(), R.string.call_settings_with_label);
mTelecomManager = getSystemService(TelecomManager.class);
+ mTelephonyCallback = new CallFeaturesTelephonyCallback();
}
private void updateImsManager(Phone phone) {
@@ -279,11 +284,16 @@
private void listenPhoneState(boolean listen) {
TelephonyManager telephonyManager = getSystemService(TelephonyManager.class)
.createForSubscriptionId(mPhone.getSubId());
- telephonyManager.listen(mPhoneStateListener, listen
- ? PhoneStateListener.LISTEN_CALL_STATE : PhoneStateListener.LISTEN_NONE);
+ if (listen) {
+ telephonyManager.registerTelephonyCallback(
+ new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback);
+ } else {
+ telephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
+ }
}
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ private final class CallFeaturesTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.CallStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (DBG) log("PhoneStateListener onCallStateChanged: state is " + state);
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 6c18623..1a867b6 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -25,13 +25,14 @@
import android.media.ToneGenerator;
import android.os.AsyncResult;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Message;
import android.os.SystemProperties;
import android.telecom.TelecomManager;
-import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
@@ -68,8 +69,8 @@
/** The singleton instance. */
private static CallNotifier sInstance;
- private Map<Integer, CallNotifierPhoneStateListener> mPhoneStateListeners =
- new ArrayMap<Integer, CallNotifierPhoneStateListener>();
+ private Map<Integer, CallNotifierTelephonyCallback> mTelephonyCallback =
+ new ArrayMap<Integer, CallNotifierTelephonyCallback>();
private Map<Integer, Boolean> mCFIStatus = new ArrayMap<Integer, Boolean>();
private Map<Integer, Boolean> mMWIStatus = new ArrayMap<Integer, Boolean>();
private PhoneGlobals mApplication;
@@ -566,7 +567,7 @@
// slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
// both slots, user always sees icon related to slot 0 on left side followed by that of
// slot 1.
- List<Integer> subIdList = new ArrayList<Integer>(mPhoneStateListeners.keySet());
+ List<Integer> subIdList = new ArrayList<Integer>(mTelephonyCallback.keySet());
Collections.sort(subIdList, new Comparator<Integer>() {
public int compare(Integer sub1, Integer sub2) {
int slotId1 = SubscriptionController.getInstance().getSlotIndex(sub1);
@@ -583,10 +584,9 @@
mApplication.notificationMgr.updateMwi(subId, false);
mApplication.notificationMgr.updateCfi(subId, false);
- // Listening to LISTEN_NONE removes the listener.
- mTelephonyManager.listen(
- mPhoneStateListeners.get(subId), PhoneStateListener.LISTEN_NONE);
- mPhoneStateListeners.remove(subId);
+ // Unregister the listener.
+ mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback.get(subId));
+ mTelephonyCallback.remove(subId);
} else {
Log.d(LOG_TAG, "updatePhoneStateListeners: update CF notifications.");
@@ -616,12 +616,11 @@
// Register new phone listeners for active subscriptions.
for (int i = 0; i < subInfos.size(); i++) {
int subId = subInfos.get(i).getSubscriptionId();
- if (!mPhoneStateListeners.containsKey(subId)) {
- CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener(subId);
- mTelephonyManager.createForSubscriptionId(subId).listen(listener,
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
- mPhoneStateListeners.put(subId, listener);
+ if (!mTelephonyCallback.containsKey(subId)) {
+ CallNotifierTelephonyCallback listener = new CallNotifierTelephonyCallback(subId);
+ mTelephonyManager.createForSubscriptionId(subId).registerTelephonyCallback(
+ new HandlerExecutor(this), listener);
+ mTelephonyCallback.put(subId, listener);
}
}
}
@@ -768,10 +767,13 @@
}
};
- private class CallNotifierPhoneStateListener extends PhoneStateListener {
+ private class CallNotifierTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.MessageWaitingIndicatorListener,
+ TelephonyCallback.CallForwardingIndicatorListener {
+
private final int mSubId;
- CallNotifierPhoneStateListener(int subId) {
+ CallNotifierTelephonyCallback(int subId) {
super();
this.mSubId = subId;
}
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 831b537..de41309 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -247,6 +247,12 @@
}
case EVENT_DO_FETCH_DEFAULT: {
+ // Clear in-memory cache for carrier app config, so when carrier app gets
+ // uninstalled, no stale config is left.
+ if (mConfigFromCarrierApp[phoneId] != null
+ && getCarrierPackageForPhoneId(phoneId) == null) {
+ mConfigFromCarrierApp[phoneId] = null;
+ }
// Restore persistent override values.
PersistableBundle config = restoreConfigFromXml(
mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId);
@@ -1142,12 +1148,6 @@
* have a saved config file to use instead.
*/
private void updateConfigForPhoneId(int phoneId) {
- // Clear in-memory cache for carrier app config, so when carrier app gets uninstalled, no
- // stale config is left.
- if (mConfigFromCarrierApp[phoneId] != null &&
- getCarrierPackageForPhoneId(phoneId) == null) {
- mConfigFromCarrierApp[phoneId] = null;
- }
mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));
}
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 5e616b7..ad33302 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -28,6 +28,7 @@
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter.PublishState;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -56,6 +57,7 @@
import com.android.services.telephony.rcs.UceControllerManager;
import java.util.List;
+import java.util.Set;
/**
* Implementation of the IImsRcsController interface.
@@ -336,6 +338,82 @@
}
}
+ /**
+ * Add new feature tags to the Set used to calculate the capabilities in PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
+ Set<String> featureTags) throws ImsException {
+ // Permission check happening in PhoneInterfaceManager.
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ return null;
+ }
+ return uceCtrlManager.addUceRegistrationOverride(featureTags);
+ }
+
+ /**
+ * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
+ Set<String> featureTags) throws ImsException {
+ // Permission check happening in PhoneInterfaceManager.
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ return null;
+ }
+ return uceCtrlManager.removeUceRegistrationOverride(featureTags);
+ }
+
+ /**
+ * Clear all overrides in the Set used to calculate the capabilities in PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId)
+ throws ImsException {
+ // Permission check happening in PhoneInterfaceManager.
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ return null;
+ }
+ return uceCtrlManager.clearUceRegistrationOverride();
+ }
+
+ /**
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId)
+ throws ImsException {
+ // Permission check happening in PhoneInterfaceManager.
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ return null;
+ }
+ return uceCtrlManager.getLatestRcsContactUceCapability();
+ }
+
+ /**
+ * @return the PIDf XML used in the last PUBLISH procedure or "none" if the device is not
+ * published. Returns {@code null} if the operation failed due to an error.
+ */
+ // Used for SHELL command only right now.
+ public String getLastUcePidfXmlShell(int subId) throws ImsException {
+ // Permission check happening in PhoneInterfaceManager.
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ return null;
+ }
+ String pidfXml = uceCtrlManager.getLastPidfXml();
+ return pidfXml == null ? "none" : pidfXml;
+ }
+
@Override
public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
enforceReadPrivilegedPermission("registerUcePublishStateCallback");
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 38d3299..d2cfa29 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -67,7 +67,6 @@
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.ThermalMitigationResult;
import android.telephony.CallForwardingInfo;
-import android.telephony.CarrierBandwidth;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellIdentity;
@@ -111,6 +110,7 @@
import android.telephony.ims.ImsException;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsClientConfiguration;
+import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
@@ -159,6 +159,8 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.ProxyController;
import com.android.internal.telephony.RIL;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.RadioInterfaceCapabilityController;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.SmsController;
import com.android.internal.telephony.SmsPermissions;
@@ -341,6 +343,7 @@
private SubscriptionController mSubscriptionController;
private SharedPreferences mTelephonySharedPreferences;
private PhoneConfigurationManager mPhoneConfigurationManager;
+ private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
/** User Activity */
private AtomicBoolean mNotifyUserActivity;
@@ -861,6 +864,10 @@
request.result =
TelephonyManager
.ENABLE_NR_DUAL_CONNECTIVITY_RADIO_NOT_AVAILABLE;
+ } else if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+ request.result =
+ TelephonyManager
+ .ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED;
}
loge("enableNrDualConnectivity" + ": CommandException: "
+ ar.exception);
@@ -2091,6 +2098,7 @@
PreferenceManager.getDefaultSharedPreferences(mApp);
mNetworkScanRequestTracker = new NetworkScanRequestTracker();
mPhoneConfigurationManager = PhoneConfigurationManager.getInstance();
+ mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
mNotifyUserActivity = new AtomicBoolean(false);
publish();
@@ -2798,9 +2806,7 @@
if (sst == null) return "";
LocaleTracker lt = sst.getLocaleTracker();
if (lt == null) return "";
- if (!TextUtils.isEmpty(lt.getCurrentCountry())) return lt.getCurrentCountry();
- EmergencyNumberTracker ent = phone.getEmergencyNumberTracker();
- return (ent == null) ? "" : ent.getEmergencyCountryIso();
+ return lt.getCurrentCountry();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -6047,9 +6053,8 @@
@Override
public long getAllowedNetworkTypesForReason(int subId,
@TelephonyManager.AllowedNetworkTypesReason int reason) {
- TelephonyPermissions
- .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
- mApp, subId, "getAllowedNetworkTypesForReason");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getAllowedNetworkTypesForReason");
final long identity = Binder.clearCallingIdentity();
try {
return getPhoneFromSubId(subId).getAllowedNetworkTypes(reason);
@@ -6076,6 +6081,11 @@
@TelephonyManager.NrDualConnectivityState int nrDualConnectivityState) {
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
mApp, subId, "enableNRDualConnectivity");
+ if (!isRadioInterfaceCapabilitySupported(
+ TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE)) {
+ return TelephonyManager.ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED;
+ }
+
WorkSource workSource = getWorkSource(Binder.getCallingUid());
final long identity = Binder.clearCallingIdentity();
try {
@@ -6098,6 +6108,10 @@
TelephonyPermissions
.enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
mApp, subId, "isNRDualConnectivityEnabled");
+ if (!isRadioInterfaceCapabilitySupported(
+ TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE)) {
+ return false;
+ }
WorkSource workSource = getWorkSource(Binder.getCallingUid());
final long identity = Binder.clearCallingIdentity();
try {
@@ -6111,28 +6125,6 @@
}
/**
- * get carrier bandwidth per primary and secondary carrier
- * @param subId subscription id of the sim card
- * @return CarrierBandwidth with bandwidth of both primary and secondary carrier..
- */
- @Override
- public CarrierBandwidth getCarrierBandwidth(int subId) {
- TelephonyPermissions
- .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
- mApp, subId, "isNRDualConnectivityEnabled");
- WorkSource workSource = getWorkSource(Binder.getCallingUid());
- final long identity = Binder.clearCallingIdentity();
- try {
- CarrierBandwidth carrierBandwidth =
- getPhoneFromSubId(subId).getCarrierBandwidth();
- if (DBG) log("getCarrierBandwidth: " + carrierBandwidth);
- return carrierBandwidth;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
* Set the allowed network types of the device and
* provide the reason triggering the allowed network change.
*
@@ -6152,10 +6144,15 @@
return false;
}
- if (DBG) {
- log("setAllowedNetworkTypesForReason: " + reason
- + " value: " + allowedNetworkTypes);
+ log("setAllowedNetworkTypesForReason: " + reason + " value: "
+ + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes));
+
+
+ if (allowedNetworkTypes == getPhoneFromSubId(subId).getAllowedNetworkTypes(reason)) {
+ log("setAllowedNetworkTypesForReason: " + reason + "does not change value");
+ return true;
}
+
final long identity = Binder.clearCallingIdentity();
try {
Boolean success = (Boolean) sendRequest(
@@ -7231,15 +7228,14 @@
setDataEnabledForReason(subId, TelephonyManager.DATA_ENABLED_REASON_USER,
getDefaultDataEnabled());
setNetworkSelectionModeAutomatic(subId);
- setAllowedNetworkTypesForReason(subId,
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
- RadioAccessFamily.getRafFromNetworkType(getDefaultNetworkType(subId)));
- setAllowedNetworkTypesForReason(subId,
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER,
- RadioAccessFamily.getRafFromNetworkType(getDefaultNetworkType(subId)));
- setAllowedNetworkTypesForReason(subId,
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER,
- RadioAccessFamily.getRafFromNetworkType(getDefaultNetworkType(subId)));
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ SubscriptionManager.setSubscriptionProperty(subId,
+ SubscriptionManager.ALLOWED_NETWORK_TYPES,
+ "user=" + RadioAccessFamily.getRafFromNetworkType(
+ RILConstants.PREFERRED_NETWORK_MODE));
+ phone.loadAllowedNetworksFromSubscriptionDatabase();
+ }
setDataRoamingEnabled(subId, getDefaultDataRoamingEnabled(subId));
CarrierInfoManager.deleteAllCarrierKeysForImsiEncryption(mApp);
}
@@ -9306,7 +9302,7 @@
public boolean isRadioInterfaceCapabilitySupported(
@NonNull @TelephonyManager.RadioInterfaceCapability String capability) {
Set<String> radioInterfaceCapabilities =
- mPhoneConfigurationManager.getRadioInterfaceCapabilities();
+ mRadioInterfaceCapabilities.getCapabilities();
if (radioInterfaceCapabilities == null) {
throw new RuntimeException("radio interface capabilities are not available");
} else {
@@ -9622,10 +9618,10 @@
* Register RCS provisioning callback.
*/
@Override
- public void registerRcsProvisioningChangedCallback(int subId,
+ public void registerRcsProvisioningCallback(int subId,
IRcsConfigCallback callback) {
TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges(mApp, subId,
- Binder.getCallingUid(), "registerRcsProvisioningChangedCallback",
+ Binder.getCallingUid(), "registerRcsProvisioningCallback",
Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION,
permission.READ_PRIVILEGED_PHONE_STATE);
@@ -9640,7 +9636,7 @@
final long identity = Binder.clearCallingIdentity();
try {
if (!RcsProvisioningMonitor.getInstance()
- .registerRcsProvisioningChangedCallback(subId, callback)) {
+ .registerRcsProvisioningCallback(subId, callback)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"Service not available for the subscription.");
}
@@ -9653,10 +9649,10 @@
* Unregister RCS provisioning callback.
*/
@Override
- public void unregisterRcsProvisioningChangedCallback(int subId,
+ public void unregisterRcsProvisioningCallback(int subId,
IRcsConfigCallback callback) {
TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges(mApp, subId,
- Binder.getCallingUid(), "unregisterRcsProvisioningChangedCallback",
+ Binder.getCallingUid(), "unregisterRcsProvisioningCallback",
Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION,
permission.READ_PRIVILEGED_PHONE_STATE);
@@ -9671,7 +9667,7 @@
final long identity = Binder.clearCallingIdentity();
try {
RcsProvisioningMonitor.getInstance()
- .unregisterRcsProvisioningChangedCallback(subId, callback);
+ .unregisterRcsProvisioningCallback(subId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9896,6 +9892,104 @@
}
}
+ /**
+ * Add new feature tags to the Set used to calculate the capabilities in PUBLISH.
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ @Override
+ public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
+ List<String> featureTags) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "addUceRegistrationOverrideShell");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mApp.imsRcsController.addUceRegistrationOverrideShell(subId,
+ new ArraySet<>(featureTags));
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH.
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ @Override
+ public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
+ List<String> featureTags) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "removeUceRegistrationOverrideShell");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mApp.imsRcsController.removeUceRegistrationOverrideShell(subId,
+ new ArraySet<>(featureTags));
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Clear all overrides in the Set used to calculate the capabilities in PUBLISH.
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ @Override
+ public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "clearUceRegistrationOverrideShell");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mApp.imsRcsController.clearUceRegistrationOverrideShell(subId);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ @Override
+ public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "getLatestRcsContactUceCapabilityShell");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mApp.imsRcsController.getLatestRcsContactUceCapabilityShell(subId);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Returns the last PIDF XML sent to the network during the last PUBLISH or "none" if the
+ * device does not have an active PUBLISH.
+ */
+ // Used for SHELL command only right now.
+ @Override
+ public String getLastUcePidfXmlShell(int subId) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "uceGetLastPidfXml");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mApp.imsRcsController.getLastUcePidfXmlShell(subId);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+
@Override
public void setSignalStrengthUpdateRequest(int subId, SignalStrengthUpdateRequest request,
String callingPackage) {
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 2191e28..bcf1491 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -558,13 +558,13 @@
}
/**
- * Called when the application registers rcs provisioning changed callback
+ * Called when the application registers rcs provisioning callback
*/
- public boolean registerRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ public boolean registerRcsProvisioningCallback(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");
+ logd("fail to register rcs provisioning callback due to subscription unavailable");
return false;
}
@@ -572,9 +572,9 @@
}
/**
- * Called when the application unregisters rcs provisioning changed callback
+ * Called when the application unregisters rcs provisioning callback
*/
- public boolean unregisterRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ public boolean unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback cb) {
RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
// should not happen in normal case
if (info == null) {
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 74d6b57..87dc868 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -26,15 +26,21 @@
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.provider.BlockedNumberContract;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.feature.ImsFeature;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
+import com.android.ims.rcs.uce.util.FeatureTags;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
@@ -45,9 +51,12 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeSet;
/**
@@ -113,6 +122,11 @@
private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact";
private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled";
private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled";
+ private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps";
+ private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf";
+
+ // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId.
+ private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges";
// Take advantage of existing methods that already contain permissions checks when possible.
private final ITelephony mInterface;
@@ -164,6 +178,48 @@
}
};
+ /**
+ * Map from a shorthand string to the feature tags required in registration required in order
+ * for the RCS feature to be considered "capable".
+ */
+ private static final Map<String, Set<String>> TEST_FEATURE_TAG_MAP;
+ static {
+ ArrayMap<String, Set<String>> map = new ArrayMap<>(18);
+ map.put("chat_v1", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM));
+ map.put("chat_v2", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_SESSION));
+ map.put("ft", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER));
+ map.put("ft_sms", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS));
+ map.put("mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_MMTEL));
+ map.put("mmtel_vt", new ArraySet<>(Arrays.asList(FeatureTags.FEATURE_TAG_MMTEL,
+ FeatureTags.FEATURE_TAG_VIDEO)));
+ map.put("geo_push", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH));
+ map.put("geo_push_sms", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS));
+ map.put("call_comp",
+ Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING));
+ map.put("call_comp_mmtel",
+ Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY));
+ map.put("call_post", Collections.singleton(FeatureTags.FEATURE_TAG_POST_CALL));
+ map.put("map", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_MAP));
+ map.put("sketch", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_SKETCH));
+ // Feature tags defined twice for chatbot session because we want v1 and v2 based on bot
+ // version
+ map.put("chatbot", new ArraySet<>(Arrays.asList(
+ FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
+ FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
+ map.put("chatbot_v2", new ArraySet<>(Arrays.asList(
+ FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION,
+ FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
+ map.put("chatbot_sa", new ArraySet<>(Arrays.asList(
+ FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
+ FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
+ map.put("chatbot_sa_v2", new ArraySet<>(Arrays.asList(
+ FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG,
+ FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED)));
+ map.put("chatbot_role", Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE));
+ TEST_FEATURE_TAG_MAP = Collections.unmodifiableMap(map);
+ }
+
+
public TelephonyShellCommand(ITelephony binder, Context context) {
mInterface = binder;
mCarrierConfigManager =
@@ -206,6 +262,8 @@
return handleRestartModemCommand();
case UNATTENDED_REBOOT:
return handleUnattendedReboot();
+ case HAS_CARRIER_PRIVILEGES_COMMAND:
+ return handleHasCarrierPrivilegesCommand();
default: {
return handleDefaultCommands(cmd);
}
@@ -238,6 +296,8 @@
pw.println(" Restart modem command.");
pw.println(" unattended-reboot");
pw.println(" Prepare for unattended reboot.");
+ pw.println(" has-carrier-privileges [package]");
+ pw.println(" Query carrier privilege status for a package. Prints true or false.");
onHelpIms();
onHelpUce();
onHelpEmergencyNumber();
@@ -321,6 +381,22 @@
pw.println(" uce set-device-enabled true|false");
pw.println(" Set the device config for RCS User Capability Exchange to the value.");
pw.println(" The value could be true, false.");
+ pw.println(" uce override-published-caps [-s SLOT_ID] add|remove|clear [CAPABILITIES]");
+ pw.println(" Override the existing SIP PUBLISH with different capabilities.");
+ pw.println(" Options are:");
+ pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
+ pw.println(" is specified, it will choose the default voice SIM slot.");
+ pw.println(" add [CAPABILITY]: add a new capability");
+ pw.println(" remove [CAPABILITY]: remove a capability");
+ pw.println(" clear: clear all capability overrides");
+ pw.println(" CAPABILITY: \":\" separated list of capabilities.");
+ pw.println(" Valid options are: [mmtel(_vt), chat_v1, chat_v2, ft, ft_sms,");
+ pw.println(" geo_push, geo_push_sms, call_comp, call_post, map, sketch, chatbot,");
+ pw.println(" chatbot_sa, chatbot_role] as well as full length");
+ pw.println(" featureTag=\"featureValue\" feature tags that are not defined here.");
+ pw.println(" uce get-last-publish-pidf [-s SLOT_ID]");
+ pw.println(" Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no ");
+ pw.println(" PUBLISH is active");
}
private void onHelpNumberVerification() {
@@ -666,7 +742,7 @@
errPw.println("message value must be a valid integer");
return -1;
}
-
+
try {
mInterface.sendDeviceToDeviceMessage(messageType, messageValue);
} catch (RemoteException e) {
@@ -1651,8 +1727,8 @@
private int handleRcsUceCommand() {
String arg = getNextArg();
if (arg == null) {
- Log.w(LOG_TAG, "cannot get uce parameter");
- return -1;
+ onHelpUce();
+ return 0;
}
switch (arg) {
@@ -1664,6 +1740,10 @@
return handleUceGetDeviceEnabledCommand();
case UCE_SET_DEVICE_ENABLED:
return handleUceSetDeviceEnabledCommand();
+ case UCE_OVERRIDE_PUBLISH_CAPS:
+ return handleUceOverridePublishCaps();
+ case UCE_GET_LAST_PIDF_XML:
+ return handleUceGetPidfXml();
}
return -1;
}
@@ -1784,6 +1864,101 @@
return 0;
}
+ private int handleUceOverridePublishCaps() {
+ int subId = getSubId("uce override-published-caps");
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+ //uce override-published-caps [-s SLOT_ID] add|remove|clear|list [CAPABILITIES]
+ String operation = getNextArgRequired();
+ String caps = getNextArg();
+ if (!"add".equals(operation) && !"remove".equals(operation) && !"clear".equals(operation)
+ && !"list".equals(operation)) {
+ getErrPrintWriter().println("Invalid operation: " + operation);
+ return -1;
+ }
+
+ // add/remove requires capabilities to be specified.
+ if ((!"clear".equals(operation) && !"list".equals(operation)) && TextUtils.isEmpty(caps)) {
+ getErrPrintWriter().println("\"" + operation + "\" requires capabilities to be "
+ + "specified");
+ return -1;
+ }
+
+ ArraySet<String> capSet = new ArraySet<>();
+ if (!TextUtils.isEmpty(caps)) {
+ String[] capArray = caps.split(":");
+ for (String cap : capArray) {
+ // Allow unknown tags to be passed in as well.
+ capSet.addAll(TEST_FEATURE_TAG_MAP.getOrDefault(cap, Collections.singleton(cap)));
+ }
+ }
+
+ RcsContactUceCapability result = null;
+ try {
+ switch (operation) {
+ case "add":
+ result = mInterface.addUceRegistrationOverrideShell(subId,
+ new ArrayList<>(capSet));
+ break;
+ case "remove":
+ result = mInterface.removeUceRegistrationOverrideShell(subId,
+ new ArrayList<>(capSet));
+ break;
+ case "clear":
+ result = mInterface.clearUceRegistrationOverrideShell(subId);
+ break;
+ case "list":
+ result = mInterface.getLatestRcsContactUceCapabilityShell(subId);
+ break;
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "uce override-published-caps, error " + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ } catch (ServiceSpecificException sse) {
+ // Reconstruct ImsException
+ ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
+ Log.w(LOG_TAG, "uce override-published-caps, error " + imsException);
+ getErrPrintWriter().println("Exception: " + imsException);
+ return -1;
+ }
+ if (result == null) {
+ getErrPrintWriter().println("Service not available");
+ return -1;
+ }
+ getOutPrintWriter().println(result);
+ return 0;
+ }
+
+ private int handleUceGetPidfXml() {
+ int subId = getSubId("uce get-last-publish-pidf");
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ String result;
+ try {
+ result = mInterface.getLastUcePidfXmlShell(subId);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "uce get-last-publish-pidf, error " + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ } catch (ServiceSpecificException sse) {
+ // Reconstruct ImsException
+ ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode);
+ Log.w(LOG_TAG, "uce get-last-publish-pidf error " + imsException);
+ getErrPrintWriter().println("Exception: " + imsException);
+ return -1;
+ }
+ if (result == null) {
+ getErrPrintWriter().println("Service not available");
+ return -1;
+ }
+ getOutPrintWriter().println(result);
+ return 0;
+ }
+
private int handleSrcSetDeviceEnabledCommand() {
String enabledStr = getNextArg();
if (enabledStr == null) {
@@ -1866,4 +2041,22 @@
getOutPrintWriter().println(result);
return 0;
}
+
+ private int handleHasCarrierPrivilegesCommand() {
+ String packageName = getNextArgRequired();
+
+ boolean hasCarrierPrivileges;
+ try {
+ hasCarrierPrivileges =
+ mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e);
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ }
+
+ getOutPrintWriter().println(hasCarrierPrivileges);
+ return 0;
+ }
}
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index ad3f133..8355fa6 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -19,6 +19,9 @@
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
@@ -27,8 +30,8 @@
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -56,13 +59,10 @@
private static final int WFC_QUERY_TIMEOUT_MILLIS = 20;
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- /**
- * Disable the TTY setting when in/out of a call (and if carrier doesn't
- * support VoLTE with TTY).
- * @see android.telephony.PhoneStateListener#onCallStateChanged(int,
- * java.lang.String)
- */
+ private final TelephonyCallback mTelephonyCallback = new AccessibilityTelephonyCallback();
+
+ private final class AccessibilityTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.CallStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (DBG) Log.d(LOG_TAG, "PhoneStateListener.onCallStateChanged: state=" + state);
@@ -148,7 +148,8 @@
super.onResume();
TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ tm.registerTelephonyCallback(new HandlerExecutor(new Handler(Looper.getMainLooper())),
+ mTelephonyCallback);
}
@Override
@@ -156,7 +157,7 @@
super.onPause();
TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ tm.unregisterTelephonyCallback(mTelephonyCallback);
}
@Override
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index b7a413c..3f4ae58 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -36,6 +36,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.SystemProperties;
@@ -56,13 +57,13 @@
import android.telephony.CellSignalStrengthWcdma;
import android.telephony.DataSpecificRegistrationInfo;
import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneStateListener;
import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -295,10 +296,20 @@
};
// not final because we need to recreate this object to register on a new subId (b/117555407)
- private PhoneStateListener mPhoneStateListener = new RadioInfoPhoneStateListener();
- private class RadioInfoPhoneStateListener extends PhoneStateListener {
+ private TelephonyCallback mTelephonyCallback = new RadioInfoTelephonyCallback();
+ private class RadioInfoTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.DataConnectionStateListener,
+ TelephonyCallback.DataActivityListener,
+ TelephonyCallback.CallStateListener,
+ TelephonyCallback.MessageWaitingIndicatorListener,
+ TelephonyCallback.CallForwardingIndicatorListener,
+ TelephonyCallback.CellInfoListener,
+ TelephonyCallback.SignalStrengthsListener,
+ TelephonyCallback.ServiceStateListener,
+ TelephonyCallback.PreciseCallStateListener {
+
@Override
- public void onDataConnectionStateChanged(int state) {
+ public void onDataConnectionStateChanged(int state, int networkType) {
updateDataState();
updateNetworkType();
}
@@ -673,7 +684,7 @@
log("onPause: unregister phone & data intents");
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mTelephonyManager.setCellInfoListRate(sCellInfoListRateDisabled);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
@@ -774,7 +785,7 @@
}
private void unregisterPhoneStateListener() {
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mPhone.unregisterForPhysicalChannelConfig(mHandler);
// clear all fields so they are blank until the next listener event occurs
@@ -796,21 +807,11 @@
mPhyChanConfig.setText("");
}
- // register mPhoneStateListener for relevant fields using the current TelephonyManager
+ // register mTelephonyCallback for relevant fields using the current TelephonyManager
private void registerPhoneStateListener() {
- mPhoneStateListener = new RadioInfoPhoneStateListener();
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_CALL_STATE
- //b/27803938 - RadioInfo currently cannot read PRECISE_CALL_STATE
- // | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
- | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_DATA_ACTIVITY
- | PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
- | PhoneStateListener.LISTEN_CELL_INFO
- | PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+ mTelephonyCallback = new RadioInfoTelephonyCallback();
+ mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
+ mTelephonyCallback);
}
private void updateDnsCheckState() {
diff --git a/src/com/android/phone/vvm/VvmSimStateTracker.java b/src/com/android/phone/vvm/VvmSimStateTracker.java
index c648d9c..a77bd7b 100644
--- a/src/com/android/phone/vvm/VvmSimStateTracker.java
+++ b/src/com/android/phone/vvm/VvmSimStateTracker.java
@@ -20,13 +20,16 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.os.SystemProperties;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -68,7 +71,8 @@
* Waits for the account to become {@link ServiceState#STATE_IN_SERVICE} and notify the
* connected event. Will unregister itself once the event has been triggered.
*/
- private class ServiceStateListener extends PhoneStateListener {
+ private class ServiceStateListener extends TelephonyCallback implements
+ TelephonyCallback.ServiceStateListener {
private final PhoneAccountHandle mPhoneAccountHandle;
private final Context mContext;
@@ -84,7 +88,8 @@
VvmLog.e(TAG, "Cannot create TelephonyManager from " + mPhoneAccountHandle);
return;
}
- telephonyManager.listen(this, PhoneStateListener.LISTEN_SERVICE_STATE);
+ telephonyManager.registerTelephonyCallback(
+ new HandlerExecutor(new Handler(Looper.getMainLooper())), this);
}
public void unlisten() {
@@ -92,7 +97,7 @@
// PhoneStateListener, and mPhoneAccountHandle might be invalid at this point
// (e.g. SIM removal)
mContext.getSystemService(TelephonyManager.class)
- .listen(this, PhoneStateListener.LISTEN_NONE);
+ .unregisterTelephonyCallback(this);
sListeners.put(mPhoneAccountHandle, null);
}
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 9d4edfd..9226cae 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -32,6 +32,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PersistableBundle;
@@ -42,11 +43,11 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsMmTelManager;
@@ -113,6 +114,8 @@
private static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK =
"android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
+ private Handler mHandler;
+
final class AccountEntry implements PstnPhoneCapabilitiesNotifier.Listener {
private final Phone mPhone;
private PhoneAccount mAccount;
@@ -1078,7 +1081,11 @@
}
};
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ private final TelephonyCallback mTelephonyCallback = new TelecomAccountTelephonyCallback();
+
+ private class TelecomAccountTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.ActiveDataSubscriptionIdListener,
+ TelephonyCallback.ServiceStateListener {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
int newState = serviceState.getState();
@@ -1144,6 +1151,7 @@
mTelephonyManager = TelephonyManager.from(context);
mSubscriptionManager = SubscriptionManager.from(context);
mHandlerThread.start();
+ mHandler = new Handler(Looper.getMainLooper());
mRegisterSubscriptionListenerBackoff = new ExponentialBackoff(
REGISTER_START_DELAY_MS,
REGISTER_MAXIMUM_DELAY_MS,
@@ -1371,8 +1379,8 @@
// We also need to listen for changes to the service state (e.g. emergency -> in service)
// because this could signal a removal or addition of a SIM in a single SIM phone.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+ mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
+ mTelephonyCallback);
// Listen for user switches. When the user switches, we need to ensure that if the current
// use is not the primary user we disable video calling.
@@ -1392,8 +1400,7 @@
private void registerContentObservers() {
// Listen to the RTT system setting so that we update it when the user flips it.
- ContentObserver rttUiSettingObserver = new ContentObserver(
- new Handler(Looper.getMainLooper())) {
+ ContentObserver rttUiSettingObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
synchronized (mAccountsLock) {
@@ -1409,8 +1416,7 @@
rttSettingUri, false, rttUiSettingObserver);
// Listen to the changes to the user's Contacts Discovery Setting.
- ContentObserver contactDiscoveryObserver = new ContentObserver(
- new Handler(Looper.getMainLooper())) {
+ ContentObserver contactDiscoveryObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
synchronized (mAccountsLock) {
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index 5a1acb5..3eefdb0 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -20,7 +20,9 @@
import android.content.Context;
import android.net.Uri;
import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsRcsManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -63,12 +65,16 @@
void onRcsDisconnected();
/**
- * The subscription associated with the slot this controller is bound to has changed or its
- * carrier configuration has changed.
+ * The subscription associated with the slot this controller is bound to has changed.
*/
void onAssociatedSubscriptionUpdated(int subId);
/**
+ * The carrier configuration associated with the active subscription id has changed.
+ */
+ void onCarrierConfigChanged();
+
+ /**
* Called when the feature should be destroyed.
*/
void onDestroy();
@@ -118,6 +124,7 @@
private final Object mLock = new Object();
private FeatureConnector<RcsFeatureManager> mFeatureConnector;
private RcsFeatureManager mFeatureManager;
+ private int mAssociatedSubId;
private FeatureConnector.Listener<RcsFeatureManager> mFeatureConnectorListener =
new FeatureConnector.Listener<RcsFeatureManager>() {
@@ -171,9 +178,10 @@
}
};
- public RcsFeatureController(Context context, int slotId) {
+ public RcsFeatureController(Context context, int slotId, int associatedSubId) {
mContext = context;
mSlotId = slotId;
+ mAssociatedSubId = associatedSubId;
mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
mContext.getMainExecutor());
}
@@ -182,9 +190,11 @@
* Should only be used to inject registration helpers for testing.
*/
@VisibleForTesting
- public RcsFeatureController(Context context, int slotId, RegistrationHelperFactory f) {
+ public RcsFeatureController(Context context, int slotId, int associatedSubId,
+ RegistrationHelperFactory f) {
mContext = context;
mSlotId = slotId;
+ mAssociatedSubId = associatedSubId;
mRegistrationHelperFactory = f;
mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
mContext.getMainExecutor());
@@ -248,17 +258,12 @@
}
/**
- * Update the subscription associated with this controller.
+ * Update the Features associated with this controller due to the associated subscription
+ * changing.
*/
public void updateAssociatedSubscription(int newSubId) {
- RcsFeatureManager manager = getFeatureManager();
- if (manager != null) {
- try {
- manager.updateCapabilities();
- } catch (ImsException e) {
- Log.w(LOG_TAG, "associatedSubscriptionChanged failed:" + e);
- }
- }
+ mAssociatedSubId = newSubId;
+ updateCapabilities();
synchronized (mLock) {
for (Feature c : mFeatures.values()) {
c.onAssociatedSubscriptionUpdated(newSubId);
@@ -267,6 +272,19 @@
}
/**
+ * Update the features associated with this controller due to the carrier configuration
+ * changing.
+ */
+ public void onCarrierConfigChangedForSubscription() {
+ updateCapabilities();
+ synchronized (mLock) {
+ for (Feature c : mFeatures.values()) {
+ c.onCarrierConfigChanged();
+ }
+ }
+ }
+
+ /**
* Call before this controller is destroyed to tear down associated features.
*/
public void destroy() {
@@ -314,8 +332,8 @@
}
/**
- * Register an {@link ImsRcsManager.AvailabilityCallback} with the associated RcsFeature,
- * which will provide availability updates.
+ * Register an {@link ImsRcsManager.OnAvailabilityChangedListener} with the associated
+ * RcsFeature, which will provide availability updates.
*/
public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
throws ImsException {
@@ -328,7 +346,7 @@
}
/**
- * Remove a registered {@link ImsRcsManager.AvailabilityCallback} from the RcsFeature.
+ * Remove a registered {@link ImsRcsManager.OnAvailabilityChangedListener} from the RcsFeature.
*/
public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
RcsFeatureManager manager = getFeatureManager();
@@ -381,10 +399,21 @@
callback.accept(mImsRcsRegistrationHelper.getImsRegistrationState());
}
+ private void updateCapabilities() {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ try {
+ manager.updateCapabilities(mAssociatedSubId);
+ } catch (ImsException e) {
+ Log.w(LOG_TAG, "updateCapabilities failed:" + e);
+ }
+ }
+ }
+
private void setupConnectionToService(RcsFeatureManager manager) throws ImsException {
// Open persistent listener connection, sends RcsFeature#onFeatureReady.
manager.openConnection();
- manager.updateCapabilities();
+ manager.updateCapabilities(mAssociatedSubId);
manager.registerImsRegistrationCallback(mImsRcsRegistrationHelper.getCallbackBinder());
}
diff --git a/src/com/android/services/telephony/rcs/SipTransportController.java b/src/com/android/services/telephony/rcs/SipTransportController.java
index 028e49f..a948cdb 100644
--- a/src/com/android/services/telephony/rcs/SipTransportController.java
+++ b/src/com/android/services/telephony/rcs/SipTransportController.java
@@ -296,6 +296,11 @@
}
@Override
+ public void onCarrierConfigChanged() {
+ mExecutorService.submit(this::onCarrierConfigChangedInternal);
+ }
+
+ @Override
public void onDestroy() {
mExecutorService.submit(()-> {
// Ensure new create/destroy requests are denied.
@@ -903,8 +908,7 @@
}
/**
- * Called when either the sub ID associated with the slot has changed or the carrier
- * configuration associated with the same subId has changed.
+ * Called when the sub ID associated with the slot has changed.
*/
private void onSubIdChanged(int newSubId) {
logi("subId changed, " + mSubId + "->" + newSubId);
@@ -913,10 +917,14 @@
mSubId = newSubId;
scheduleDestroyDelegates(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
- return;
}
- // TODO: if subId hasn't changed this means that we should load in any new carrier configs
- // that we care about and apply.
+ }
+
+ /**
+ * Called when the carrier configuration associated with the same subId has changed.
+ */
+ private void onCarrierConfigChangedInternal() {
+ logi("Carrier Config changed for subId: " + mSubId);
}
/**
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 66492ae..034382c 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -55,7 +55,7 @@
/**
* @return an {@link RcsFeatureController} associated with the slot specified.
*/
- RcsFeatureController createController(Context context, int slotId);
+ RcsFeatureController createController(Context context, int slotId, int subId);
/**
* @return an instance of {@link UceControllerManager} associated with the slot specified.
@@ -71,8 +71,8 @@
private FeatureFactory mFeatureFactory = new FeatureFactory() {
@Override
- public RcsFeatureController createController(Context context, int slotId) {
- return new RcsFeatureController(context, slotId);
+ public RcsFeatureController createController(Context context, int slotId, int subId) {
+ return new RcsFeatureController(context, slotId, subId);
}
@Override
@@ -113,6 +113,8 @@
// Maps slot ID -> RcsFeatureController.
private SparseArray<RcsFeatureController> mFeatureControllers;
+ // Maps slotId -> associatedSubIds
+ private SparseArray<Integer> mSlotToAssociatedSubIds;
// Whether the device supports User Capability Exchange
private boolean mRcsUceEnabled;
@@ -132,7 +134,7 @@
SubscriptionManager.INVALID_PHONE_INDEX);
int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- updateFeatureControllerSubscription(slotId, subId);
+ onCarrierConfigChangedForSlot(slotId, subId);
}
}
};
@@ -159,6 +161,7 @@
mContext = context;
mNumSlots = numSlots;
mFeatureControllers = new SparseArray<>(numSlots);
+ mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
}
@@ -167,6 +170,7 @@
mContext = context;
mNumSlots = numSlots;
mFeatureControllers = new SparseArray<>(numSlots);
+ mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
sResourceProxy = resourceProxy;
mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
}
@@ -218,6 +222,8 @@
// Do not add feature controllers for inactive subscriptions
if (c.hasActiveFeatures()) {
mFeatureControllers.put(i, c);
+ // Do not change mSlotToAssociatedSubIds, it will be updated upon carrier
+ // config change.
}
}
} else {
@@ -225,6 +231,7 @@
RcsFeatureController c = mFeatureControllers.get(i);
if (c != null) {
mFeatureControllers.remove(i);
+ mSlotToAssociatedSubIds.remove(i);
c.destroy();
}
}
@@ -232,19 +239,29 @@
}
}
- private void updateFeatureControllerSubscription(int slotId, int newSubId) {
+ /**
+ * ACTION_CARRIER_CONFIG_CHANGED was received by this service for a specific slot.
+ * @param slotId The slotId associated with the event.
+ * @param subId The subId associated with the event. May cause the subId associated with the
+ * RcsFeatureController to change if the subscription itself has changed.
+ */
+ private void onCarrierConfigChangedForSlot(int slotId, int subId) {
synchronized (mLock) {
RcsFeatureController f = mFeatureControllers.get(slotId);
- Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId + " newSubId="
- + newSubId + ", existing feature=" + (f != null));
- if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+ final int oldSubId = mSlotToAssociatedSubIds.get(slotId,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ mSlotToAssociatedSubIds.put(slotId, subId);
+ Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId
+ + ", oldSubId= " + oldSubId + ", subId=" + subId + ", existing feature="
+ + (f != null));
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
if (f == null) {
// A controller doesn't exist for this slot yet.
- f = mFeatureFactory.createController(mContext, slotId);
- updateSupportedFeatures(f, slotId, newSubId);
+ f = mFeatureFactory.createController(mContext, slotId, subId);
+ updateSupportedFeatures(f, slotId, subId);
if (f.hasActiveFeatures()) mFeatureControllers.put(slotId, f);
} else {
- updateSupportedFeatures(f, slotId, newSubId);
+ updateSupportedFeatures(f, slotId, subId);
// Do not keep an empty container around.
if (!f.hasActiveFeatures()) {
f.destroy();
@@ -252,13 +269,19 @@
}
}
}
- if (f != null) f.updateAssociatedSubscription(newSubId);
+ if (f != null) {
+ if (oldSubId == subId) {
+ f.onCarrierConfigChangedForSubscription();
+ } else {
+ f.updateAssociatedSubscription(subId);
+ }
+ }
}
}
private RcsFeatureController constructFeatureController(int slotId) {
- RcsFeatureController c = mFeatureFactory.createController(mContext, slotId);
int subId = getSubscriptionFromSlot(slotId);
+ RcsFeatureController c = mFeatureFactory.createController(mContext, slotId, subId);
updateSupportedFeatures(c, slotId, subId);
return c;
}
diff --git a/src/com/android/services/telephony/rcs/UceControllerManager.java b/src/com/android/services/telephony/rcs/UceControllerManager.java
index 7270d69..3051253 100644
--- a/src/com/android/services/telephony/rcs/UceControllerManager.java
+++ b/src/com/android/services/telephony/rcs/UceControllerManager.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.net.Uri;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.RcsUceAdapter.PublishState;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
@@ -32,6 +33,7 @@
import java.io.PrintWriter;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -50,6 +52,7 @@
private final Context mContext;
private final ExecutorService mExecutorService;
+ private volatile int mSubId;
private volatile UceController mUceController;
private volatile RcsFeatureManager mRcsFeatureManager;
@@ -57,6 +60,7 @@
Log.d(LOG_TAG, "create: slotId=" + slotId + ", subId=" + subId);
mSlotId = slotId;
+ mSubId = subId;
mContext = context;
mExecutorService = Executors.newSingleThreadExecutor();
mUceController = new UceController(mContext, subId);
@@ -68,6 +72,7 @@
@VisibleForTesting
public UceControllerManager(Context context, int slotId, int subId, ExecutorService executor) {
mSlotId = slotId;
+ mSubId = subId;
mContext = context;
mExecutorService = executor;
mUceController = new UceController(mContext, subId);
@@ -98,15 +103,19 @@
}
/**
- * This method will be called when either the subscription ID associated with the slot has
- * changed or the carrier configuration associated with the same subId has changed.
+ * This method will be called when the subscription ID associated with the slot has
+ * changed.
*/
@Override
public void onAssociatedSubscriptionUpdated(int subId) {
mExecutorService.submit(() -> {
Log.i(LOG_TAG, "onAssociatedSubscriptionUpdated: slotId=" + mSlotId
- + ", subId=" + subId);
-
+ + ", subId=" + mSubId + ", newSubId=" + subId);
+ if (mSubId == subId) {
+ Log.w(LOG_TAG, "onAssociatedSubscriptionUpdated called with the same subId");
+ return;
+ }
+ mSubId = subId;
// Destroy existing UceController and create a new one.
mUceController.onDestroy();
mUceController = new UceController(mContext, subId);
@@ -119,6 +128,18 @@
});
}
+ /**
+ * This method will be called when the carrier config of the subscription associated with this
+ * manager has changed.
+ */
+ @Override
+ public void onCarrierConfigChanged() {
+ mExecutorService.submit(() -> {
+ Log.i(LOG_TAG, "onCarrierConfigChanged: subId=" + mSubId);
+ mUceController.onCarrierConfigChanged();
+ });
+ }
+
@VisibleForTesting
public void setUceController(UceController uceController) {
mUceController = uceController;
@@ -181,15 +202,15 @@
* @throws ImsException if the ImsService connected to this controller is currently down.
*/
public @PublishState int getUcePublishState() throws ImsException {
- Future future = mExecutorService.submit(() -> {
+ Future<Integer> future = mExecutorService.submit(() -> {
checkUceControllerState();
return mUceController.getUcePublishState();
});
try {
- return (Integer) future.get();
+ return future.get();
} catch (ExecutionException | InterruptedException e) {
- Log.w(LOG_TAG, "requestNetworkAvailability exception: " + e);
+ Log.w(LOG_TAG, "getUcePublishState exception: " + e);
Throwable cause = e.getCause();
if (cause instanceof ImsException) {
throw (ImsException) cause;
@@ -199,6 +220,114 @@
}
/**
+ * Add new feature tags to the Set used to calculate the capabilities in PUBLISH.
+ */
+ public RcsContactUceCapability addUceRegistrationOverride(
+ Set<String> featureTags) throws ImsException {
+ Future<RcsContactUceCapability> future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.addRegistrationOverrideCapabilities(featureTags);
+ });
+
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "addUceRegistrationOverride exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH.
+ */
+ public RcsContactUceCapability removeUceRegistrationOverride(
+ Set<String> featureTags) throws ImsException {
+ Future<RcsContactUceCapability> future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.removeRegistrationOverrideCapabilities(featureTags);
+ });
+
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "removeUceRegistrationOverride exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Clear all overrides in the Set used to calculate the capabilities in PUBLISH.
+ */
+ public RcsContactUceCapability clearUceRegistrationOverride() throws ImsException {
+ Future<RcsContactUceCapability> future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.clearRegistrationOverrideCapabilities();
+ });
+
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "clearUceRegistrationOverride exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * @return current RcsContactUceCapability instance that will be used for PUBLISH.
+ */
+ public RcsContactUceCapability getLatestRcsContactUceCapability() throws ImsException {
+ Future<RcsContactUceCapability> future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.getLatestRcsContactUceCapability();
+ });
+
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "getLatestRcsContactUceCapability exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return null;
+ }
+ }
+
+ /**
+ *
+ * @return The last PIDF XML sent to the IMS stack to be published.
+ */
+ public String getLastPidfXml() throws ImsException {
+ Future<String> future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.getLastPidfXml();
+ });
+
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "getLastPidfXml exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return null;
+ }
+ }
+
+ /**
* Register the Publish state changed callback.
*
* @throws ImsException if the ImsService connected to this controller is currently down.
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 2eea909..4e40120 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -19,8 +19,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.sample.rcsclient"
- android:versionCode="6"
- android:versionName="1.0.5">
+ android:versionCode="9"
+ android:versionName="1.0.8">
<uses-sdk
android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/TestApp/res/layout/provision_layout.xml b/testapps/TestRcsApp/TestApp/res/layout/provision_layout.xml
index d98dde2..a70cd4a 100644
--- a/testapps/TestRcsApp/TestApp/res/layout/provision_layout.xml
+++ b/testapps/TestRcsApp/TestApp/res/layout/provision_layout.xml
@@ -11,12 +11,30 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rcs_profile"
+ android:textSize="15dp"
+ android:textStyle="bold" />
+
+ <Spinner
+ android:id="@+id/rcs_profile_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
<Button
android:id="@+id/provisioning_register_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:text="register"
+ android:text="@string/register_provisioning_callback"
android:textAllCaps="false" />
<Button
@@ -24,7 +42,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:text="unregister"
+ android:text="@string/unregister_provisioning_callback"
android:textAllCaps="false" />
<Button
@@ -33,7 +51,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
- android:text="isRcsVolteSingleRegCapable"
+ android:text="@string/isRcsVolteSingleRegCapable"
android:textAllCaps="false" />
<TextView
diff --git a/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml b/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
index a193b46..502874f 100644
--- a/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
@@ -6,6 +6,10 @@
<string name="gba_test">GBA Test</string>
<string name="test_msg_client">TestMessageClient</string>
<string name="db_client">DBClient</string>
+ <string name="rcs_profile">RcsProfile:</string>
+ <string name="register_provisioning_callback">registerProvisioningCallback</string>
+ <string name="unregister_provisioning_callback">unRegisterProvisioningCallback</string>
+ <string name="isRcsVolteSingleRegCapable">isRcsVolteSingleRegCapable</string>
<string name="result">Result:</string>
<string name="callback_result">Callback Result:</string>
<string name="initialize_delegate">initializeSipDelegate</string>
@@ -49,6 +53,10 @@
<string name="registration_failed">Registration failed</string>
<string name="version_info">Version: %s</string>
+ <string-array name="rcs_profile">
+ <item>UP_1.0</item>
+ <item>UP_2.3</item>
+ </string-array>
<string-array name="organization">
<item>NONE</item>
<item>3GPP</item>
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
index bb1283a..8f7e6a8 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
@@ -49,10 +49,10 @@
public class ChatActivity extends AppCompatActivity {
public static final String EXTRA_REMOTE_PHONE_NUMBER = "REMOTE_PHONE_NUMBER";
- public static final String TELURI_PREFIX = "tel:";
private static final String TAG = "TestRcsApp.ChatActivity";
private static final int INIT_LIST = 1;
private static final int SHOW_STATUS = 2;
+ private static final int EMPTY_MSG = 3;
private static final float TEXT_SIZE = 20.0f;
private static final int MARGIN_SIZE = 20;
private static final long TIMEOUT_IN_MS = 10000L;
@@ -85,6 +85,9 @@
case SHOW_STATUS:
mTips.setText(msg.obj.toString());
break;
+ case EMPTY_MSG:
+ mNewMessage.setText("");
+ break;
default:
Log.d(TAG, "unknown msg:" + msg.what);
break;
@@ -134,7 +137,7 @@
ChatActivity.this.getResources().getString(R.string.session_timeout)),
TIMEOUT_IN_MS);
ChatManager.getInstance(getApplicationContext(), mSubId).initChatSession(
- TELURI_PREFIX + mDestNumber, new SessionStateCallback() {
+ mDestNumber, new SessionStateCallback() {
@Override
public void onSuccess() {
Log.i(TAG, "session init succeeded");
@@ -176,7 +179,8 @@
ChatManager.getInstance(getApplicationContext(), mSubId).addNewMessage(
mNewMessage.getText().toString(), ChatManager.SELF, mDestNumber);
ChatManager.getInstance(getApplicationContext(), mSubId).sendMessage(
- TELURI_PREFIX + mDestNumber, mNewMessage.getText().toString());
+ mDestNumber, mNewMessage.getText().toString());
+ mHandler.sendMessage(mHandler.obtainMessage(EMPTY_MSG));
}
});
});
@@ -259,8 +263,7 @@
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
- ChatManager.getInstance(getApplicationContext(), mSubId).terminateSession(
- TELURI_PREFIX + mDestNumber);
+ ChatManager.getInstance(getApplicationContext(), mSubId).terminateSession(mDestNumber);
}
@Override
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java
index aa90487..0c2996c 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -32,7 +33,11 @@
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -47,15 +52,27 @@
public class ProvisioningActivity extends AppCompatActivity {
private static final String TAG = "TestRcsApp.ProvisioningActivity";
+ private static final String UP_10 = "UP_1.0";
+ private static final String UP_23 = "UP_2.3";
+ private static final String V_6 = "6.0";
+ private static final String V_9 = "9.0";
+ private static final String RCS_CONFIG = "CONFIG";
+ private static final String RCS_PROFILE = "RCS_PROFILE";
+ private static final String RCS_VERSION = "RCS_VERSION";
private static final int MSG_RESULT = 1;
+
private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private int mDefaultSmsSubId;
private ProvisioningManager mProvisioningManager;
+ private Spinner mRcsProfileSpinner;
+ private String mRcsVersion;
+ private String mRcsProfile;
private Button mRegisterButton;
private Button mUnRegisterButton;
private Button mIsCapableButton;
private TextView mSingleRegResult;
private TextView mCallbackResult;
+ private SharedPreferences mPref;
private SingleRegCapabilityReceiver mSingleRegCapabilityReceiver;
private boolean mIsRegistered = false;
private Handler mHandler;
@@ -85,10 +102,10 @@
};
// Static configuration.
- private static RcsClientConfiguration getDefaultClientConfiguration() {
+ private RcsClientConfiguration getDefaultClientConfiguration() {
return new RcsClientConfiguration(
- /*rcsVersion=*/ "6.0",
- /*rcsProfile=*/ "UP_1.0",
+ /*rcsVersion=*/ mRcsVersion,
+ /*rcsProfile=*/ mRcsProfile,
/*clientVendor=*/ "Goog",
/*clientVersion=*/ "RCSAndrd-1.0");
}
@@ -112,6 +129,8 @@
}
}
};
+ mPref = getSharedPreferences(RCS_CONFIG, MODE_PRIVATE);
+ initRcsProfile();
}
@Override
@@ -130,7 +149,7 @@
super.onDestroy();
this.unregisterReceiver(mSingleRegCapabilityReceiver);
if (mIsRegistered) {
- mProvisioningManager.unregisterRcsProvisioningChangedCallback(mCallback);
+ mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);
}
}
@@ -157,9 +176,9 @@
Log.i(TAG, "Using configuration: " + getDefaultClientConfiguration());
try {
Log.i(TAG, "setRcsClientConfiguration()");
- Log.i(TAG, "registerRcsProvisioningChangedCallback()");
+ Log.i(TAG, "registerRcsProvisioningCallback()");
mProvisioningManager.setRcsClientConfiguration(getDefaultClientConfiguration());
- mProvisioningManager.registerRcsProvisioningChangedCallback(mExecutorService,
+ mProvisioningManager.registerRcsProvisioningCallback(mExecutorService,
mCallback);
mIsRegistered = true;
} catch (ImsException e) {
@@ -173,7 +192,7 @@
});
mUnRegisterButton.setOnClickListener(view -> {
if (mProvisioningManager != null) {
- mProvisioningManager.unregisterRcsProvisioningChangedCallback(mCallback);
+ mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);
setClickable(mRegisterButton, false);
setClickable(mRegisterButton, true);
mIsRegistered = false;
@@ -206,6 +225,44 @@
return SubscriptionManager.isValidSubscriptionId(mDefaultSmsSubId);
}
+ private void initRcsProfile() {
+ mRcsProfileSpinner = findViewById(R.id.rcs_profile_list);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
+ R.array.rcs_profile, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mRcsProfileSpinner.setAdapter(adapter);
+ mRcsProfileSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ Log.i(TAG, "rcs profile position:" + position);
+ switch (position) {
+ case 0:
+ mRcsProfile = UP_10;
+ mRcsVersion = V_6;
+ break;
+ case 1:
+ mRcsProfile = UP_23;
+ mRcsVersion = V_9;
+ break;
+ default:
+ Log.e(TAG, "invalid position:" + position);
+ return;
+ }
+ mPref.edit().putString(RCS_PROFILE, mRcsProfile)
+ .putString(RCS_VERSION, mRcsVersion)
+ .commit();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // TODO Auto-generated method stub
+ }
+ });
+ mRcsProfile = mPref.getString(RCS_PROFILE, UP_10);
+ mRcsVersion = mPref.getString(RCS_VERSION, V_6);
+ mRcsProfileSpinner.setSelection(mRcsProfile.equals(UP_10) ? 0 : 1);
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java
index bbecbc2..0fae8f6 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java
@@ -46,6 +46,7 @@
public class UceActivity extends AppCompatActivity {
private static final String TAG = "TestRcsApp.UceActivity";
+ private static final String TELURI_PREFIX = "tel:";
private Button mCapabilityButton;
private Button mAvailabilityButton;
private TextView mCapabilityResult;
@@ -106,7 +107,7 @@
public void onComplete() {
Log.i(TAG, "onComplete()");
- mCapabilityResult.append("complete");
+ mCapabilityResult.append("onComplete");
}
@@ -146,7 +147,7 @@
public void onComplete() {
Log.i(TAG, "onComplete()");
- mCapabilityResult.append("complete");
+ mCapabilityResult.append("onComplete");
}
@@ -174,7 +175,7 @@
for (String number : numbers) {
String formattedNumber = NumberUtils.formatNumber(this, number);
if (formattedNumber != null) {
- contactList.add(Uri.parse(ChatActivity.TELURI_PREFIX + formattedNumber));
+ contactList.add(Uri.parse(TELURI_PREFIX + formattedNumber));
} else {
Log.w(TAG, "number formatted improperly, skipping: " + number);
}
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
index 4489349..399a860 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
@@ -55,6 +55,7 @@
public class ChatManager {
public static final String SELF = "self";
private static final String TAG = "TestRcsApp.ChatManager";
+ private static final String TELURI_PREFIX = "tel:";
private static AddressFactory sAddressFactory = new AddressFactoryImpl();
private static HashMap<Integer, ChatManager> sChatManagerInstances = new HashMap<>();
private final ExecutorService mFixedThreadPool = Executors.newFixedThreadPool(5);
@@ -65,13 +66,14 @@
private SimpleRcsClient mSimpleRcsClient;
private State mState;
private int mSubId;
- private HashMap<URI, SimpleChatSession> mContactSessionMap = new HashMap<>();
+ private HashMap<String, SimpleChatSession> mContactSessionMap = new HashMap<>();
private RcsStateChangedCallback mRcsStateChangedCallback;
private ChatManager(Context context, int subId) {
mContext = context;
mSubId = subId;
- mProvisioningController = StaticConfigProvisioningController.createForSubscriptionId(subId);
+ mProvisioningController = StaticConfigProvisioningController.createForSubscriptionId(subId,
+ context);
ImsManager imsManager = mContext.getSystemService(ImsManager.class);
mRegistrationController = new RegistrationControllerImpl(subId, mFixedThreadPool,
imsManager);
@@ -89,15 +91,14 @@
mRcsStateChangedCallback.notifyStateChange(oldState, newState);
});
mImsService.setListener((session) -> {
- Log.i(TAG, "onIncomingSession()");
- mContactSessionMap.put(session.getRemoteUri(), session);
+ Log.i(TAG, "onIncomingSession():" + session.getRemoteUri());
+ String phoneNumber = getNumberFromUri(session.getRemoteUri().toString());
+ mContactSessionMap.put(phoneNumber, session);
session.setListener(
// implement onMessageReceived()
(message) -> {
mFixedThreadPool.execute(() -> {
String msg = message.content();
- String phoneNumber = getNumberFromUri(
- session.getRemoteUri().toString());
if (TextUtils.isEmpty(phoneNumber)) {
Log.i(TAG, "dest number is empty, uri:"
+ session.getRemoteUri());
@@ -172,33 +173,34 @@
/**
* Initiate 1 to 1 chat session.
- * @param telUriContact destination tel Uri.
+ *
+ * @param contact destination phone number.
* @param callback callback for session state.
*/
- public void initChatSession(String telUriContact, SessionStateCallback callback) {
+ public void initChatSession(String contact, SessionStateCallback callback) {
if (mState != State.REGISTERED) {
Log.i(TAG, "Could not init session due to State = " + mState);
return;
}
- URI uri = createUri(telUriContact);
- if (mContactSessionMap.containsKey(uri)) {
+ Log.i(TAG, "initChatSession contact: " + contact);
+ if (mContactSessionMap.containsKey(contact)) {
callback.onSuccess();
- Log.i(TAG, "uri exists");
+ Log.i(TAG, "contact exists");
return;
}
Futures.addCallback(
- mImsService.startOriginatingChatSession(telUriContact),
+ mImsService.startOriginatingChatSession(TELURI_PREFIX + contact),
new FutureCallback<SimpleChatSession>() {
@Override
public void onSuccess(SimpleChatSession chatSession) {
- mContactSessionMap.put(chatSession.getRemoteUri(), chatSession);
+ String phoneNumber = getNumberFromUri(
+ chatSession.getRemoteUri().toString());
+ mContactSessionMap.put(phoneNumber, chatSession);
chatSession.setListener(
// implement onMessageReceived()
(message) -> {
mFixedThreadPool.execute(() -> {
String msg = message.content();
- String phoneNumber = getNumberFromUri(
- chatSession.getRemoteUri().toString());
if (TextUtils.isEmpty(phoneNumber)) {
Log.i(TAG, "dest number is empty, uri:"
+ chatSession.getRemoteUri());
@@ -221,13 +223,14 @@
/**
* Send a chat message.
- * @param telUriContact destination tel Uri.
+ *
+ * @param contact destination phone number.
* @param message chat message.
*/
- public void sendMessage(String telUriContact, String message) {
- SimpleChatSession chatSession = mContactSessionMap.get(createUri(telUriContact));
+ public void sendMessage(String contact, String message) {
+ SimpleChatSession chatSession = mContactSessionMap.get(contact);
if (chatSession == null) {
- Log.i(TAG, "session is unavailable for telUriContact = " + telUriContact);
+ Log.i(TAG, "session is unavailable for contact = " + contact);
return;
}
chatSession.sendMessage(message);
@@ -239,22 +242,23 @@
/**
* Terminate the chat session.
- * @param telUriContact destination tel Uri
+ *
+ * @param contact destination phone number.
*/
- public void terminateSession(String telUriContact) {
+ public void terminateSession(String contact) {
Log.i(TAG, "terminateSession");
- URI uri = createUri(telUriContact);
- SimpleChatSession chatSession = mContactSessionMap.get(uri);
+ SimpleChatSession chatSession = mContactSessionMap.get(contact);
if (chatSession == null) {
- Log.i(TAG, "session is unavailable for telUriContact = " + telUriContact);
+ Log.i(TAG, "session is unavailable for contact = " + contact);
return;
}
chatSession.terminate();
- mContactSessionMap.remove(uri);
+ mContactSessionMap.remove(contact);
}
/**
* Insert chat information into database.
+ *
* @param message chat message.
* @param src source phone number.
* @param dest destination phone number.
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
index 81abe89..58a6eef 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
@@ -31,17 +31,19 @@
/** Provides creating and managing {@link MsrpSession} */
public class MsrpManager {
private final ImsPdnNetworkFetcher imsPdnNetworkFetcher;
+ private Context context;
public MsrpManager(Context context) {
+ this.context = context;
imsPdnNetworkFetcher = new ImsPdnNetworkFetcher(context);
}
- private static MsrpSession createMsrpSession(ConnectivityManager manager,
+ private MsrpSession createMsrpSession(ConnectivityManager manager,
Network network, String host, int port, String localIp, int localPort,
MsrpSessionListener listener) throws IOException {
Socket socket = network.getSocketFactory().createSocket(host, port,
InetAddress.getByName(localIp), localPort);
- MsrpSession msrpSession = new MsrpSession(manager,
+ MsrpSession msrpSession = new MsrpSession(manager, context,
network, socket, listener);
Thread thread = new Thread(msrpSession::run);
thread.start();
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
index 59a0c0e..1c461fe 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
@@ -19,6 +19,7 @@
import static com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Method.SEND;
import static com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Method.UNKNOWN;
+import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.QosCallback;
@@ -27,6 +28,7 @@
import android.net.QosSessionAttributes;
import android.net.QosSocketInfo;
import android.util.Log;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.concurrent.futures.CallbackToFutureAdapter;
@@ -49,6 +51,8 @@
* Provides MSRP sending and receiving messages ability.
*/
public class MsrpSession {
+ private static final String DEDICATED_BEARER_SUCCESS = "Dedicated bearer succeeded";
+ private static final String DEDICATED_BEARER_ERROR = "Dedicated bearer error";
private final Network network;
private final Socket socket;
private final InputStream input;
@@ -59,11 +63,13 @@
private final MsrpSessionListener listener;
private final ConnectivityManager connectivityManager;
private final String LOG_TAG = MsrpSession.class.getSimpleName();
+ private final Context context;
/** Creates a new MSRP session on the given listener and the provided streams. */
- MsrpSession(ConnectivityManager connectivityManager, Network network, Socket socket,
- MsrpSessionListener listener) throws IOException {
+ MsrpSession(ConnectivityManager connectivityManager, Context context, Network network,
+ Socket socket, MsrpSessionListener listener) throws IOException {
this.connectivityManager = connectivityManager;
+ this.context = context;
this.network = network;
this.socket = socket;
this.input = socket.getInputStream();
@@ -76,6 +82,7 @@
private final QosCallback qosCallback = new QosCallback() {
@Override
public void onError(@NonNull QosCallbackException exception) {
+ Toast.makeText(context, DEDICATED_BEARER_ERROR, Toast.LENGTH_SHORT).show();
Log.e(LOG_TAG, "onError: " + exception.toString());
super.onError(exception);
}
@@ -83,6 +90,7 @@
@Override
public void onQosSessionAvailable(@NonNull QosSession session,
@NonNull QosSessionAttributes sessionAttributes) {
+ Toast.makeText(context, DEDICATED_BEARER_SUCCESS, Toast.LENGTH_SHORT).show();
Log.d(LOG_TAG, "onQosSessionAvailable: " + session.toString() + ", "
+ sessionAttributes.toString());
super.onQosSessionAvailable(session, sessionAttributes);
@@ -90,6 +98,7 @@
@Override
public void onQosSessionLost(@NonNull QosSession session) {
+ Toast.makeText(context, DEDICATED_BEARER_ERROR, Toast.LENGTH_SHORT).show();
Log.e(LOG_TAG, "onQosSessionLost: " + session.toString());
super.onQosSessionLost(session);
}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java
index 350f43c..b8b1f21 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java
@@ -16,6 +16,8 @@
package com.android.libraries.rcs.simpleclient.provisioning;
+import android.content.Context;
+import android.content.SharedPreferences;
import android.os.Build.VERSION_CODES;
import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsException;
@@ -24,15 +26,15 @@
import android.telephony.ims.RcsClientConfiguration;
import android.util.Log;
-import java.util.Optional;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.annotation.VisibleForTesting;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
/**
* "Fake" provisioning implementation for supplying a static config when testing ProvisioningManager
* is unnecessary. State changes are invoked manually.
@@ -45,29 +47,35 @@
private Optional<RcsProvisioningCallback> storedCallback = Optional.empty();
private Optional<ProvisioningStateChangeCallback> stateChangeCallback = Optional.empty();
private Optional<byte[]> configXmlData = Optional.empty();
+ private Context context;
- private StaticConfigProvisioningController(int subId) {
+ private StaticConfigProvisioningController(int subId, Context context) {
this.provisioningManager = ProvisioningManager.createForSubscriptionId(subId);
+ this.context = context;
}
@RequiresApi(api = VERSION_CODES.R)
- public static StaticConfigProvisioningController createWithDefaultSubscriptionId() {
+ public static StaticConfigProvisioningController createWithDefaultSubscriptionId(
+ Context context) {
return new StaticConfigProvisioningController(
- SubscriptionManager.getActiveDataSubscriptionId());
+ SubscriptionManager.getActiveDataSubscriptionId(), context);
}
- public static StaticConfigProvisioningController createForSubscriptionId(int subscriptionId) {
- return new StaticConfigProvisioningController(subscriptionId);
+ /** Create ProvisioningController */
+ public static StaticConfigProvisioningController createForSubscriptionId(int subscriptionId,
+ Context context) {
+ return new StaticConfigProvisioningController(subscriptionId, context);
}
// Static configuration.
- private static RcsClientConfiguration getDefaultClientConfiguration() {
+ private RcsClientConfiguration getDefaultClientConfiguration() {
+ SharedPreferences pref = context.getSharedPreferences("CONFIG", context.MODE_PRIVATE);
return new RcsClientConfiguration(
- /*rcsVersion=*/ "6.0",
- /*rcsProfile=*/ "UP_2.3",
+ /*rcsVersion=*/ pref.getString("RCS_VERSION", "6.0"),
+ /*rcsProfile=*/ pref.getString("RCS_PROFILE", "UP_1.0"),
/*clientVendor=*/ "Goog",
- /*clientVersion=*/ "RCSAndrd-1.0");//"RCS fake library 1.0");
+ /*clientVersion=*/ "RCSAndrd-1.0");
}
@Override
@@ -136,7 +144,7 @@
Log.i(TAG, "Registering the callback.");
synchronized (this) {
- provisioningManager.registerRcsProvisioningChangedCallback(executorService, callback);
+ provisioningManager.registerRcsProvisioningCallback(executorService, callback);
storedCallback = Optional.of(callback);
}
}
@@ -147,7 +155,7 @@
RcsProvisioningCallback callback =
storedCallback.orElseThrow(
() -> new IllegalStateException("No callback present."));
- provisioningManager.unregisterRcsProvisioningChangedCallback(callback);
+ provisioningManager.unregisterRcsProvisioningCallback(callback);
storedCallback = Optional.empty();
}
}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/ChatServiceException.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/ChatServiceException.java
index 94850fd..bc2c611 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/ChatServiceException.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/ChatServiceException.java
@@ -31,6 +31,7 @@
public final class ChatServiceException extends Exception {
public static final int CODE_ERROR_UNSPECIFIED = 0;
+ public static final int CODE_ERROR_SEND_MESSAGE_FAILED = 1;
private int mCode = CODE_ERROR_UNSPECIFIED;
/**
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
index 4cc474c..fbeb205 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
@@ -17,6 +17,7 @@
package com.android.libraries.rcs.simpleclient.service.chat;
import static com.android.libraries.rcs.simpleclient.protocol.cpim.CpimUtils.CPIM_CONTENT_TYPE;
+import static com.android.libraries.rcs.simpleclient.service.chat.ChatServiceException.CODE_ERROR_SEND_MESSAGE_FAILED;
import static com.android.libraries.rcs.simpleclient.service.chat.ChatServiceException.CODE_ERROR_UNSPECIFIED;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -101,11 +102,12 @@
}
/** Send a text message via MSRP session associated with this session. */
- public void sendMessage(String msg) {
+ public ListenableFuture<Void> sendMessage(String msg) {
MsrpSession session = mMsrpSession;
if (session == null || mRemoteSdp == null || mLocalSdp == null) {
Log.e(TAG, "Session is not established");
- return;
+ return Futures.immediateFailedFuture(
+ new IllegalStateException("Session is not established"));
}
// Build a new CPIM message and send it out through the MSRP session.
@@ -133,27 +135,21 @@
.build();
Log.i(TAG, "Send a MSRP chunk: " + msrpChunk);
- Futures.addCallback(
- session.send(msrpChunk),
- new FutureCallback<MsrpChunk>() {
- @Override
- public void onSuccess(MsrpChunk result) {
- if (result.responseCode() != 200) {
- Log.d(
- TAG,
- "Received error response id="
- + result.transactionId()
- + " code="
- + result.responseCode());
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- Log.d(TAG, "Failed to send msrp chunk", t);
- }
- },
- MoreExecutors.directExecutor());
+ return Futures.transformAsync(session.send(msrpChunk), result -> {
+ if (result == null) {
+ return Futures.immediateFailedFuture(
+ new ChatServiceException("Failed to send a chunk",
+ CODE_ERROR_SEND_MESSAGE_FAILED));
+ }
+ if (result.responseCode() != 200) {
+ Log.d(TAG, "Received error response id=" + result.transactionId()
+ + " code=" + result.responseCode());
+ return Futures.immediateFailedFuture(
+ new ChatServiceException("Msrp response code: " + result.responseCode(),
+ CODE_ERROR_SEND_MESSAGE_FAILED));
+ }
+ return Futures.immediateFuture(null);
+ }, MoreExecutors.directExecutor());
}
/** Start outgoing chat session. */
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index f77dd55..28c4390 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -475,13 +475,13 @@
public void testRegisterThenUnregisterCallback() throws Exception {
createMonitor(1);
- boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
assertTrue(result);
verify(mIImsConfig, times(1)).addRcsConfigCallback(eq(mCallback));
- result = mRcsProvisioningMonitor.unregisterRcsProvisioningChangedCallback(
+ result = mRcsProvisioningMonitor.unregisterRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
assertTrue(result);
@@ -494,7 +494,7 @@
public void testCallbackRemovedWhenSubInfoChanged() throws Exception {
createMonitor(1);
- boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
makeFakeActiveSubIds(0);
mExecutor.execute(() -> mSubChangedListener.onSubscriptionsChanged());
@@ -510,7 +510,7 @@
public void testCallbackRemovedWhenDmaChanged() throws Exception {
createMonitor(1);
- boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
processAllMessages();
@@ -524,7 +524,7 @@
@SmallTest
public void testRcsConnectedAndDisconnected() throws Exception {
createMonitor(1);
- mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ mRcsProvisioningMonitor.registerRcsProvisioningCallback(
FAKE_SUB_ID_BASE, mCallback);
verify(mIImsConfig, times(1))
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
index eecbd2e..da614fc 100644
--- a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -58,6 +58,8 @@
@RunWith(AndroidJUnit4.class)
public class RcsFeatureControllerTest extends TelephonyTestBase {
+ private static final int TEST_SUB_ID = 1;
+
private static final ImsReasonInfo REASON_DISCONNECTED = new ImsReasonInfo(
ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, 0, "test");
@@ -96,7 +98,7 @@
// Connect the RcsFeatureManager
mConnectorListener.getValue().connectionReady(mFeatureManager);
- verify(mFeatureManager).updateCapabilities();
+ verify(mFeatureManager).updateCapabilities(TEST_SUB_ID);
verify(mFeatureManager).registerImsRegistrationCallback(any());
verify(mMockFeature).onRcsConnected(mFeatureManager);
@@ -132,16 +134,16 @@
mConnectorListener.getValue().connectionReady(mFeatureManager);
try {
- controller.registerImsRegistrationCallback(0 /*subId*/, regCb);
- controller.registerRcsAvailabilityCallback(0 /*subId*/, capCb);
+ controller.registerImsRegistrationCallback(TEST_SUB_ID, regCb);
+ controller.registerRcsAvailabilityCallback(TEST_SUB_ID, capCb);
controller.isCapable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
controller.isAvailable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
controller.getRegistrationTech(integer -> {
});
- verify(mFeatureManager).registerImsRegistrationCallback(0, regCb);
- verify(mFeatureManager).registerRcsAvailabilityCallback(0, capCb);
+ verify(mFeatureManager).registerImsRegistrationCallback(TEST_SUB_ID, regCb);
+ verify(mFeatureManager).registerRcsAvailabilityCallback(TEST_SUB_ID, capCb);
verify(mFeatureManager).isCapable(
RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
@@ -153,10 +155,10 @@
fail("ImsException not expected.");
}
- controller.unregisterImsRegistrationCallback(0, regCb);
- controller.unregisterRcsAvailabilityCallback(0, capCb);
- verify(mFeatureManager).unregisterImsRegistrationCallback(0, regCb);
- verify(mFeatureManager).unregisterRcsAvailabilityCallback(0, capCb);
+ controller.unregisterImsRegistrationCallback(TEST_SUB_ID, regCb);
+ controller.unregisterRcsAvailabilityCallback(TEST_SUB_ID, capCb);
+ verify(mFeatureManager).unregisterImsRegistrationCallback(TEST_SUB_ID, regCb);
+ verify(mFeatureManager).unregisterRcsAvailabilityCallback(TEST_SUB_ID, capCb);
}
@Test
@@ -216,13 +218,13 @@
FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED);
try {
- controller.registerImsRegistrationCallback(0 /*subId*/, null /*callback*/);
+ controller.registerImsRegistrationCallback(TEST_SUB_ID, null /*callback*/);
fail("ImsException expected for IMS registration.");
} catch (ImsException e) {
//expected
}
try {
- controller.registerRcsAvailabilityCallback(0 /*subId*/, null /*callback*/);
+ controller.registerRcsAvailabilityCallback(TEST_SUB_ID, null /*callback*/);
fail("ImsException expected for availability");
} catch (ImsException e) {
//expected
@@ -245,10 +247,25 @@
assertNotNull(integer);
assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, integer.intValue());
});
- controller.unregisterImsRegistrationCallback(0, regCb);
- controller.unregisterRcsAvailabilityCallback(0, capCb);
- verify(mFeatureManager, never()).unregisterImsRegistrationCallback(0, regCb);
- verify(mFeatureManager, never()).unregisterRcsAvailabilityCallback(0, capCb);
+ controller.unregisterImsRegistrationCallback(TEST_SUB_ID, regCb);
+ controller.unregisterRcsAvailabilityCallback(TEST_SUB_ID, capCb);
+ verify(mFeatureManager, never()).unregisterImsRegistrationCallback(TEST_SUB_ID, regCb);
+ verify(mFeatureManager, never()).unregisterRcsAvailabilityCallback(TEST_SUB_ID, capCb);
+ }
+
+ @Test
+ public void testCarrierConfigChanged() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+ verify(mFeatureManager).updateCapabilities(TEST_SUB_ID);
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+ controller.onCarrierConfigChangedForSubscription();
+
+ verify(mFeatureManager, times(2)).updateCapabilities(TEST_SUB_ID);
+ verify(mMockFeature).onCarrierConfigChanged();
+ verify(mMockFeature, never()).onAssociatedSubscriptionUpdated(anyInt());
}
@Test
@@ -256,13 +273,13 @@
RcsFeatureController controller = createFeatureController();
// Connect the RcsFeatureManager
mConnectorListener.getValue().connectionReady(mFeatureManager);
- verify(mFeatureManager).updateCapabilities();
+ verify(mFeatureManager).updateCapabilities(TEST_SUB_ID);
controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
- controller.updateAssociatedSubscription(1 /*new sub id*/);
+ controller.updateAssociatedSubscription(2 /*new subId*/);
- verify(mFeatureManager, times(2)).updateCapabilities();
- verify(mMockFeature).onAssociatedSubscriptionUpdated(1 /*new sub id*/);
+ verify(mFeatureManager).updateCapabilities(2 /*new subId*/);
+ verify(mMockFeature).onAssociatedSubscriptionUpdated(2 /*new subId*/);
}
@Test
@@ -281,7 +298,7 @@
private RcsFeatureController createFeatureController() {
RcsFeatureController controller = new RcsFeatureController(mContext, 0 /*slotId*/,
- mRegistrationFactory);
+ TEST_SUB_ID, mRegistrationFactory);
controller.setFeatureConnectorFactory(mFeatureFactory);
doReturn(mFeatureConnector).when(mFeatureFactory).create(any(), anyInt(),
mConnectorListener.capture(), any(), any());
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
index c367af3..39469b6 100644
--- a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -67,10 +67,12 @@
super.setUp();
doReturn(mFeatureConnector).when(mFeatureConnectorFactory).create(any(), anyInt(),
any(), any(), any());
- mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/);
- mFeatureControllerSlot1 = createFeatureController(1 /*slotId*/);
- doReturn(mFeatureControllerSlot0).when(mFeatureFactory).createController(any(), eq(0));
- doReturn(mFeatureControllerSlot1).when(mFeatureFactory).createController(any(), eq(1));
+ mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/, 1 /*subId*/);
+ mFeatureControllerSlot1 = createFeatureController(1 /*slotId*/, 2 /*subId*/);
+ doReturn(mFeatureControllerSlot0).when(mFeatureFactory).createController(any(), eq(0),
+ anyInt());
+ doReturn(mFeatureControllerSlot1).when(mFeatureFactory).createController(any(), eq(1),
+ anyInt());
doReturn(mMockUceSlot0).when(mFeatureFactory).createUceControllerManager(any(), eq(0),
anyInt());
doReturn(mMockUceSlot1).when(mFeatureFactory).createUceControllerManager(any(), eq(1),
@@ -227,7 +229,7 @@
}
@Test
- public void testCarrierConfigUpdate() {
+ public void testCarrierConfigUpdateAssociatedSub() {
setCarrierConfig(1 /*subId*/,
CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL,
true /*isEnabled*/);
@@ -251,6 +253,26 @@
}
@Test
+ public void testCarrierConfigNotifyFeatures() {
+ setCarrierConfig(1 /*subId*/,
+ CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL,
+ true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UceControllerManager.class);
+ verify(mFeatureControllerSlot0).connect();
+
+
+ // Send carrier config update twice with no update to subId
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ verify(mFeatureControllerSlot0, never()).onCarrierConfigChangedForSubscription();
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0, times(1)).updateAssociatedSubscription(1);
+ // carrier config changed should be sent here
+ verify(mFeatureControllerSlot0).onCarrierConfigChangedForSubscription();
+ }
+
+ @Test
public void testCarrierConfigUpdateUceToNoUce() {
setCarrierConfig(1 /*subId*/,
CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL,
@@ -334,10 +356,10 @@
return service;
}
- private RcsFeatureController createFeatureController(int slotId) {
+ private RcsFeatureController createFeatureController(int slotId, int subId) {
// Create a spy instead of a mock because TelephonyRcsService relies on state provided by
// RcsFeatureController.
- RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId,
+ RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId, subId,
mRegistrationFactory));
controller.setFeatureConnectorFactory(mFeatureConnectorFactory);
return controller;
diff --git a/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java b/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
index 4148d13..82687f8 100644
--- a/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.net.Uri;
@@ -94,11 +95,15 @@
}
@Test
- public void testSubscriptionUpdated() throws Exception {
+ public void testSubIdAndCarrierConfigUpdate() throws Exception {
UceControllerManager uceCtrlManager = getUceControllerManager();
- uceCtrlManager.onAssociatedSubscriptionUpdated(mSubId);
+ // Updates with the same subId should not destroy the UceController
+ uceCtrlManager.onCarrierConfigChanged();
+ verify(mUceController, never()).onDestroy();
+ // Updates with different subIds should trigger the creation of a new controller.
+ uceCtrlManager.onAssociatedSubscriptionUpdated(mSubId + 1);
verify(mUceController).onDestroy();
}