Merge "Don't send thermal mitigation request to modem if not supported."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 488326c..a6c1ec5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -100,6 +100,7 @@
<protected-broadcast android:name= "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" />
<protected-broadcast android:name= "android.intent.action.ACTION_MANAGED_ROAMING_IND" />
+ <protected-broadcast android:name= "android.intent.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE" />
<!-- Allows granting runtime permissions to telephony related components. -->
<uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
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 cc61eac..69c2b8a 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;
@@ -862,6 +865,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);
@@ -2094,6 +2101,7 @@
PreferenceManager.getDefaultSharedPreferences(mApp);
mNetworkScanRequestTracker = new NetworkScanRequestTracker();
mPhoneConfigurationManager = PhoneConfigurationManager.getInstance();
+ mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
mNotifyUserActivity = new AtomicBoolean(false);
publish();
@@ -2801,9 +2809,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);
}
@@ -6050,9 +6056,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);
@@ -6079,6 +6084,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 {
@@ -6101,6 +6111,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 {
@@ -6114,28 +6128,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.
*
@@ -6155,10 +6147,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(
@@ -7234,15 +7231,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);
}
@@ -9309,7 +9305,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 {
@@ -9639,10 +9635,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);
@@ -9657,7 +9653,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.");
}
@@ -9670,10 +9666,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);
@@ -9688,7 +9684,7 @@
final long identity = Binder.clearCallingIdentity();
try {
RcsProvisioningMonitor.getInstance()
- .unregisterRcsProvisioningChangedCallback(subId, callback);
+ .unregisterRcsProvisioningCallback(subId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9913,6 +9909,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/chat_layout.xml b/testapps/TestRcsApp/TestApp/res/layout/chat_layout.xml
index 5dbf6b0..df80e54 100644
--- a/testapps/TestRcsApp/TestApp/res/layout/chat_layout.xml
+++ b/testapps/TestRcsApp/TestApp/res/layout/chat_layout.xml
@@ -4,11 +4,19 @@
android:layout_height="match_parent"
android:orientation="vertical">
+ <TextView
+ android:id="@+id/session_tips"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="15dp"
+ android:textStyle="bold" />
+
<LinearLayout
android:id="@id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:layout_below="@+id/session_tips">
<TextView
android:layout_width="wrap_content"
@@ -59,4 +67,4 @@
android:text="@string/send" />
</RelativeLayout>
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/testapps/TestRcsApp/TestApp/res/layout/contact_list.xml b/testapps/TestRcsApp/TestApp/res/layout/contact_list.xml
index 44f6d3c..eb4d1fa 100644
--- a/testapps/TestRcsApp/TestApp/res/layout/contact_list.xml
+++ b/testapps/TestRcsApp/TestApp/res/layout/contact_list.xml
@@ -4,6 +4,13 @@
android:layout_height="match_parent"
android:orientation="vertical">
+ <TextView
+ android:id="@+id/tips"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="15dp"
+ android:textStyle="bold" />
+
<Button
android:id="@+id/start_chat_btn"
android:layout_width="match_parent"
@@ -19,4 +26,4 @@
android:layout_height="match_parent"
android:layout_alignParentBottom="true" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
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/layout/uce_layout.xml b/testapps/TestRcsApp/TestApp/res/layout/uce_layout.xml
index 305c88e..5cf2da2 100644
--- a/testapps/TestRcsApp/TestApp/res/layout/uce_layout.xml
+++ b/testapps/TestRcsApp/TestApp/res/layout/uce_layout.xml
@@ -44,18 +44,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:layout_marginBottom="10dp"
android:text="@string/request_capability"
android:textAllCaps="false" />
- <TextView
- android:id="@+id/capability_result"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/result"
- android:textSize="15dp"
- android:textStyle="bold" />
-
<Button
android:id="@+id/availability_btn"
android:layout_width="match_parent"
@@ -66,11 +57,12 @@
android:textAllCaps="false" />
<TextView
- android:id="@+id/availability_result"
+ android:id="@+id/capability_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/result"
+ android:scrollbars="vertical"
android:textSize="15dp"
android:textStyle="bold" />
</LinearLayout>
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml b/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
index 3528add..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>
@@ -14,16 +18,18 @@
multiple ones.</string>
<string name="number">Number: </string>
<string name="request_capability">requestCapability</string>
- <string name="request_availability">requestNetworkAvailability</string>
+ <string name="request_availability">requestNetworkAvailability (1st number)</string>
<string name="gba_bootstrap">bootstrapAuthenticationRequest</string>
<string name="start_chat">Start Chat</string>
<string name="to">To:</string>
<string name="chat_message">Chat Message</string>
<string name="send">Send</string>
<string name="ok">OK</string>
- <string name="session_succeeded">Session init succeeded</string>
- <string name="session_failed">Session init failed</string>
- <string name="session_not_ready">Session not ready</string>
+ <string name="session_initiating">Initializing chat session..</string>
+ <string name="session_timeout">Session initialization timeout</string>
+ <string name="session_succeeded">Session initialization succeeded</string>
+ <string name="session_failed">Session initialization failed</string>
+ <string name="session_broken_or_not_ready">Session broken or not ready</string>
<string name="organization">Organization:</string>
<string name="uicc_type">UICC Type:</string>
<string name="protocol">Protocol:</string>
@@ -39,10 +45,18 @@
<string name="chatbot_session">Chatbot Session</string>
<string name="chatbot_standalone">Chatbot Standalone</string>
<string name="chatbot_version">Chatbot Version</string>
- <string name="provisioning_done">Provisioning Done</string>
- <string name="registration_done">Registration Done</string>
+ <string name="start_provisioning">Start Provisioning....</string>
+ <string name="provisioning_timeout">Provisioning timeout.</string>
+ <string name="provisioning_done">Provisioning done, Start registering...</string>
+ <string name="registration_timeout">Registration timeout</string>
+ <string name="registration_done">Registration done. Enjoy chat!</string>
+ <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 0531209..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,20 +49,22 @@
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_TOAST = 2;
+ 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;
private final ExecutorService mFixedThreadPool = Executors.newFixedThreadPool(3);
private boolean mSessionInitResult = false;
private Button mSend;
private String mDestNumber;
- private TextView mDestNumberView;
+ private TextView mDestNumberView, mTips;
private EditText mNewMessage;
private ChatObserver mChatObserver;
private Handler mHandler;
+ private int mSubId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -80,9 +82,11 @@
case INIT_LIST:
initChatMessageLayout((Cursor) msg.obj);
break;
- case SHOW_TOAST:
- Toast.makeText(ChatActivity.this, msg.obj.toString(),
- Toast.LENGTH_SHORT).show();
+ case SHOW_STATUS:
+ mTips.setText(msg.obj.toString());
+ break;
+ case EMPTY_MSG:
+ mNewMessage.setText("");
break;
default:
Log.d(TAG, "unknown msg:" + msg.what);
@@ -92,6 +96,7 @@
}
};
mDestNumberView = findViewById(R.id.destNum);
+ mTips = findViewById(R.id.session_tips);
initDestNumber();
mChatObserver = new ChatObserver(mHandler);
}
@@ -115,9 +120,9 @@
mNewMessage = findViewById(R.id.new_msg);
mSend = findViewById(R.id.chat_btn);
- int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- Log.e(TAG, "invalid subId:" + subId);
+ mSubId = SubscriptionManager.getDefaultSmsSubscriptionId();
+ if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
+ Log.e(TAG, "invalid subId:" + mSubId);
return;
}
try {
@@ -127,43 +132,55 @@
mDestNumber = formattedNumber;
}
mDestNumberView.setText(mDestNumber);
- ChatManager.getInstance(getApplicationContext(), subId).initChatSession(
- TELURI_PREFIX + mDestNumber, new SessionStateCallback() {
+ mTips.setText(ChatActivity.this.getResources().getString(R.string.session_initiating));
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(SHOW_STATUS,
+ ChatActivity.this.getResources().getString(R.string.session_timeout)),
+ TIMEOUT_IN_MS);
+ ChatManager.getInstance(getApplicationContext(), mSubId).initChatSession(
+ mDestNumber, new SessionStateCallback() {
@Override
public void onSuccess() {
Log.i(TAG, "session init succeeded");
- mHandler.sendMessage(mHandler.obtainMessage(SHOW_TOAST,
- ChatActivity.this.getResources().getString(
- R.string.session_succeeded)));
+ String success = ChatActivity.this.getResources().getString(
+ R.string.session_succeeded);
+ if (mHandler.hasMessages(SHOW_STATUS)) {
+ mHandler.removeMessages(SHOW_STATUS);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, success));
mSessionInitResult = true;
}
@Override
public void onFailure() {
Log.i(TAG, "session init failed");
- mHandler.sendMessage(mHandler.obtainMessage(SHOW_TOAST,
- ChatActivity.this.getResources().getString(
- R.string.session_failed)));
+ String failure = ChatActivity.this.getResources().getString(
+ R.string.session_failed);
+ if (mHandler.hasMessages(SHOW_STATUS)) {
+ mHandler.removeMessages(SHOW_STATUS);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, failure));
mSessionInitResult = false;
}
});
mSend.setOnClickListener(view -> {
- if (!mSessionInitResult) {
+ if (!ChatManager.getInstance(getApplicationContext(), mSubId).isRegistered()
+ || !mSessionInitResult) {
Toast.makeText(ChatActivity.this,
- getResources().getString(R.string.session_not_ready),
+ getResources().getString(R.string.session_broken_or_not_ready),
Toast.LENGTH_SHORT).show();
- Log.i(TAG, "session not ready");
+ Log.i(TAG, "session broken or not ready");
return;
}
mFixedThreadPool.execute(() -> {
if (TextUtils.isEmpty(mDestNumber)) {
Log.i(TAG, "Destination number is empty");
} else {
- ChatManager.getInstance(getApplicationContext(), subId).addNewMessage(
+ ChatManager.getInstance(getApplicationContext(), mSubId).addNewMessage(
mNewMessage.getText().toString(), ChatManager.SELF, mDestNumber);
- ChatManager.getInstance(getApplicationContext(), subId).sendMessage(
- TELURI_PREFIX + mDestNumber, mNewMessage.getText().toString());
+ ChatManager.getInstance(getApplicationContext(), mSubId).sendMessage(
+ mDestNumber, mNewMessage.getText().toString());
+ mHandler.sendMessage(mHandler.obtainMessage(EMPTY_MSG));
}
});
});
@@ -246,16 +263,7 @@
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
- }
-
- private void dispose() {
- int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- Log.e(TAG, "invalid subId:" + subId);
- return;
- }
- ChatManager chatManager = ChatManager.getInstance(this, subId);
- chatManager.deregister();
+ ChatManager.getInstance(getApplicationContext(), mSubId).terminateSession(mDestNumber);
}
@Override
@@ -277,5 +285,4 @@
queryChatData();
}
}
-
}
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ContactListActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ContactListActivity.java
index 70715f0..b641606 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ContactListActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ContactListActivity.java
@@ -32,7 +32,6 @@
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
-import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@@ -51,13 +50,17 @@
private static final String TAG = "TestRcsApp.ContactListActivity";
private static final int RENDER_LISTVIEW = 1;
- private static final int SHOW_TOAST = 2;
+ private static final int SHOW_STATUS = 2;
+ private static final long TIMEOUT_IN_MS = 10000L;
private final ExecutorService mSingleThread = Executors.newSingleThreadExecutor();
+ private TextView mTips;
private Button mStartChatButton;
private Handler mHandler;
private SummaryObserver mSummaryObserver;
private ArrayAdapter mAdapter;
private ListView mListview;
+ private State mState;
+ private ArrayList<ContactAttributes> mContactList;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -68,22 +71,25 @@
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
+ mContactList = new ArrayList<>();
+ mTips = findViewById(R.id.tips);
+ mListview = findViewById(R.id.listview);
mStartChatButton = findViewById(R.id.start_chat_btn);
mStartChatButton.setOnClickListener(view -> {
Intent intent = new Intent(ContactListActivity.this, PhoneNumberActivity.class);
ContactListActivity.this.startActivity(intent);
});
+ setButtonClickable(false);
mHandler = new Handler() {
public void handleMessage(Message message) {
Log.i(TAG, "handleMessage:" + message.what);
switch (message.what) {
case RENDER_LISTVIEW:
- renderListView((ArrayList<ContactAttributes>) message.obj);
+ renderListView();
break;
- case SHOW_TOAST:
- Toast.makeText(ContactListActivity.this, message.obj.toString(),
- Toast.LENGTH_SHORT).show();
+ case SHOW_STATUS:
+ mTips.setText(message.obj.toString());
break;
default:
Log.i(TAG, "unknown msg:" + message.what);
@@ -91,6 +97,7 @@
}
};
initListView();
+ initSipDelegate();
mSummaryObserver = new SummaryObserver(mHandler);
}
@@ -98,7 +105,6 @@
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart");
- initSipDelegate();
querySummaryData();
getContentResolver().registerContentObserver(ChatProvider.SUMMARY_URI, false,
mSummaryObserver);
@@ -130,7 +136,6 @@
private void initListView() {
Log.i(TAG, "initListView");
- mListview = findViewById(R.id.listview);
mAdapter = new ArrayAdapter<ContactAttributes>(this,
android.R.layout.simple_list_item_2,
@@ -159,28 +164,34 @@
ChatProvider.SummaryColumns.LATEST_MESSAGE,
ChatProvider.SummaryColumns.IS_READ}, null, null, null);
- ArrayList<ContactAttributes> contactList = new ArrayList<>();
+ mContactList.clear();
while (cursor.moveToNext()) {
String phoneNumber = getPhoneNumber(cursor);
String latestMessage = getLatestMessage(cursor);
boolean isRead = getIsRead(cursor);
- contactList.add(new ContactAttributes(phoneNumber, latestMessage, isRead));
+ mContactList.add(new ContactAttributes(phoneNumber, latestMessage, isRead));
}
- mHandler.sendMessage(mHandler.obtainMessage(RENDER_LISTVIEW, contactList));
+ mHandler.sendMessage(mHandler.obtainMessage(RENDER_LISTVIEW));
cursor.close();
});
}
- private void renderListView(ArrayList<ContactAttributes> contactList) {
+ private void renderListView() {
mAdapter.clear();
- mAdapter.addAll(contactList);
- mListview.setOnItemClickListener((parent, view, position, id) -> {
- Intent intent = new Intent(ContactListActivity.this, ChatActivity.class);
- intent.putExtra(ChatActivity.EXTRA_REMOTE_PHONE_NUMBER,
- contactList.get(position).phoneNumber);
- ContactListActivity.this.startActivity(intent);
- });
+ mAdapter.addAll(mContactList);
+ }
+ private void setListViewClickable(boolean clickable) {
+ if (clickable) {
+ mListview.setOnItemClickListener((parent, view, position, id) -> {
+ Intent intent = new Intent(ContactListActivity.this, ChatActivity.class);
+ intent.putExtra(ChatActivity.EXTRA_REMOTE_PHONE_NUMBER,
+ mContactList.get(position).phoneNumber);
+ ContactListActivity.this.startActivity(intent);
+ });
+ } else {
+ mListview.setOnItemClickListener(null);
+ }
}
private void initSipDelegate() {
@@ -193,21 +204,56 @@
ChatManager chatManager = ChatManager.getInstance(this, subId);
chatManager.setRcsStateChangedCallback((oldState, newState) -> {
//Show toast when provisioning or registration is done.
- if (newState == State.REGISTERING) {
- mHandler.sendMessage(mHandler.obtainMessage(SHOW_TOAST,
- ContactListActivity.this.getResources().getString(
- R.string.provisioning_done)));
- } else if (newState == State.REGISTERED) {
- mHandler.sendMessage(mHandler.obtainMessage(SHOW_TOAST,
- ContactListActivity.this.getResources().getString(
- R.string.registration_done)));
- }
+ mState = newState;
+ String tips = "";
+ String timeoutTips = "";
+ switch (newState) {
+ case PROVISIONING:
+ tips = ContactListActivity.this.getResources().getString(
+ R.string.start_provisioning);
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, tips));
+ timeoutTips = ContactListActivity.this.getResources().getString(
+ R.string.provisioning_timeout);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(SHOW_STATUS, timeoutTips),
+ TIMEOUT_IN_MS);
+ break;
+ case REGISTERING:
+ tips = ContactListActivity.this.getResources().getString(
+ R.string.provisioning_done);
+ if (mHandler.hasMessages(SHOW_STATUS)) {
+ mHandler.removeMessages(SHOW_STATUS);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, tips));
+ timeoutTips = ContactListActivity.this.getResources().getString(
+ R.string.registration_timeout);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(SHOW_STATUS, timeoutTips),
+ TIMEOUT_IN_MS);
+ break;
+ case REGISTERED:
+ tips = ContactListActivity.this.getResources().getString(
+ R.string.registration_done);
+ if (mHandler.hasMessages(SHOW_STATUS)) {
+ mHandler.removeMessages(SHOW_STATUS);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, tips));
+ setButtonClickable(true);
+ setListViewClickable(true);
+ break;
+ case NOT_REGISTERED:
+ tips = ContactListActivity.this.getResources().getString(
+ R.string.registration_failed);
+ mHandler.sendMessage(mHandler.obtainMessage(SHOW_STATUS, tips));
+ setButtonClickable(false);
+ setListViewClickable(false);
+ break;
+ default:
+ Log.i(TAG, "unknown state:" + newState);
+ }
});
chatManager.register();
}
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
@@ -230,6 +276,16 @@
return 1 == cursor.getInt(cursor.getColumnIndex(ChatProvider.SummaryColumns.IS_READ));
}
+ private void setButtonClickable(boolean clickable) {
+ if (clickable) {
+ mStartChatButton.setAlpha(1);
+ mStartChatButton.setClickable(true);
+ } else {
+ mStartChatButton.setAlpha(.5f);
+ mStartChatButton.setClickable(false);
+ }
+ }
+
class ContactAttributes {
public String phoneNumber;
public String message;
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 10f588c..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
@@ -19,6 +19,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsRcsManager;
@@ -26,6 +27,7 @@
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter;
import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Button;
@@ -44,10 +46,10 @@
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;
- private TextView mAvailabilityResult;
private EditText mNumbers;
private int mDefaultSmsSubId;
private ImsRcsManager mImsRcsManager;
@@ -63,15 +65,25 @@
initLayout();
}
- private void initLayout() {
+ @Override
+ protected void onStart() {
+ super.onStart();
mDefaultSmsSubId = SmsManager.getDefaultSmsSubscriptionId();
+ Log.i(TAG, "defaultSmsSubId:" + mDefaultSmsSubId);
+ if (SubscriptionManager.isValidSubscriptionId(mDefaultSmsSubId)) {
+ mImsRcsManager = getImsRcsManager(mDefaultSmsSubId);
+ if (mImsRcsManager != null) {
+ initLayout();
+ }
+ }
+ }
+ private void initLayout() {
mCapabilityButton = findViewById(R.id.capability_btn);
mAvailabilityButton = findViewById(R.id.availability_btn);
mCapabilityResult = findViewById(R.id.capability_result);
- mAvailabilityResult = findViewById(R.id.capability_result);
+ mCapabilityResult.setMovementMethod(new ScrollingMovementMethod());
- mImsRcsManager = getImsRcsManager(mDefaultSmsSubId);
mCapabilityButton.setOnClickListener(view -> {
List<Uri> contactList = getContectList();
if (contactList.size() == 0) {
@@ -84,26 +96,27 @@
new RcsUceAdapter.CapabilitiesCallback() {
public void onCapabilitiesReceived(
List<RcsContactUceCapability> contactCapabilities) {
- Log.i(TAG, "onCapabilitiesReceived()");
StringBuilder b = new StringBuilder("onCapabilitiesReceived:\n");
for (RcsContactUceCapability c : contactCapabilities) {
b.append(getReadableCapability(c));
b.append("\n");
}
mCapabilityResult.append(b.toString() + "\n");
+ Log.i(TAG, b.toString());
}
public void onComplete() {
Log.i(TAG, "onComplete()");
- mCapabilityResult.append("complete");
+ mCapabilityResult.append("onComplete");
}
public void onError(int errorCode, long retryAfterMilliseconds) {
- Log.i(TAG, "onError() errorCode:" + errorCode + " retryAfterMs:"
- + retryAfterMilliseconds);
- mCapabilityResult.append("error - errorCode:" + errorCode
- + " retryAfterMs:" + retryAfterMilliseconds);
+ String result =
+ "onError() errorCode:" + errorCode + " retryAfterMs:"
+ + retryAfterMilliseconds + "\n";
+ Log.i(TAG, result);
+ mCapabilityResult.append(result);
}
});
} catch (ImsException e) {
@@ -117,36 +130,37 @@
Log.i(TAG, "empty contact list");
return;
}
- mAvailabilityResult.setText("pending...\n");
+ mCapabilityResult.setText("pending...\n");
try {
mImsRcsManager.getUceAdapter().requestAvailability(contactList.get(0),
getMainExecutor(), new RcsUceAdapter.CapabilitiesCallback() {
public void onCapabilitiesReceived(
List<RcsContactUceCapability> contactCapabilities) {
- Log.i(TAG, "onCapabilitiesReceived()");
StringBuilder b = new StringBuilder("onCapabilitiesReceived:\n");
for (RcsContactUceCapability c : contactCapabilities) {
b.append(getReadableCapability(c));
b.append("\n");
}
- mAvailabilityResult.append(b.toString() + "\n");
+ mCapabilityResult.append(b.toString() + "\n");
+ Log.i(TAG, b.toString());
}
public void onComplete() {
Log.i(TAG, "onComplete()");
- mAvailabilityResult.append("complete");
+ mCapabilityResult.append("onComplete");
}
public void onError(int errorCode, long retryAfterMilliseconds) {
- Log.i(TAG, "onError() errorCode:" + errorCode + " retryAfterMs:"
- + retryAfterMilliseconds);
- mAvailabilityResult.append("error - errorCode:" + errorCode
- + " retryAfterMs:" + retryAfterMilliseconds);
+ String result =
+ "onError() errorCode:" + errorCode + " retryAfterMs:"
+ + retryAfterMilliseconds + "\n";
+ Log.i(TAG, result);
+ mCapabilityResult.append(result);
}
});
} catch (ImsException e) {
- mAvailabilityResult.setText("ImsException:" + e);
+ mCapabilityResult.setText("ImsException:" + e);
}
});
}
@@ -161,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 0447d1a..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);
@@ -79,8 +81,8 @@
mSimpleRcsClient = SimpleRcsClient.newBuilder()
.registrationController(mRegistrationController)
.provisioningController(mProvisioningController)
- .imsService(mImsService)
- .executor(mFixedThreadPool).build();
+ .imsService(mImsService).build();
+
mState = State.NEW;
// register callback for state change
mSimpleRcsClient.onStateChanged((oldState, newState) -> {
@@ -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,31 +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, "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());
@@ -219,24 +223,42 @@
/**
* 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) {
- if (mState != State.REGISTERED) {
- Log.i(TAG, "Could not send msg due to State = " + mState);
- return;
- }
- 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);
}
+ public boolean isRegistered() {
+ return (mState == State.REGISTERED);
+ }
+
+ /**
+ * Terminate the chat session.
+ *
+ * @param contact destination phone number.
+ */
+ public void terminateSession(String contact) {
+ Log.i(TAG, "terminateSession");
+ SimpleChatSession chatSession = mContactSessionMap.get(contact);
+ if (chatSession == null) {
+ Log.i(TAG, "session is unavailable for contact = " + contact);
+ return;
+ }
+ chatSession.terminate();
+ 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/SimpleRcsClient.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/SimpleRcsClient.java
index c299cc9..0469bc0 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/SimpleRcsClient.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/SimpleRcsClient.java
@@ -24,14 +24,10 @@
import com.android.libraries.rcs.simpleclient.protocol.sip.SipSession;
import com.android.libraries.rcs.simpleclient.provisioning.ProvisioningController;
-import com.android.libraries.rcs.simpleclient.provisioning.StaticConfigProvisioningController;
import com.android.libraries.rcs.simpleclient.registration.RegistrationController;
+import com.android.libraries.rcs.simpleclient.registration.RegistrationStateChangeCallback;
import com.android.libraries.rcs.simpleclient.service.ImsService;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-
-import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -46,7 +42,6 @@
private ProvisioningController provisioningController;
private RegistrationController registrationController;
private ImsService imsService;
- private Executor executor;
private SimpleRcsClientContext context;
private StateChangedCallback stateChangedCallback;
@@ -108,23 +103,31 @@
return;
}
- Futures.addCallback(registrationController.register(imsService),
- new FutureCallback<SipSession>() {
+ registrationController.register(imsService,
+ new RegistrationStateChangeCallback() {
@Override
- public void onSuccess(SipSession result) {
- Log.i(TAG, "onSuccess:" + result);
- registered(result);
+ public void notifyRegStateChanged(ImsService imsService) {
+
}
@Override
- public void onFailure(Throwable t) {
- Log.i(TAG, "onFailure:" + t);
+ public void onSuccess(SipSession sipSession) {
+ Log.i(TAG, "onSuccess");
+ registered(sipSession);
}
- }, executor);
+
+ @Override
+ public void onFailure(String reason) {
+ Log.i(TAG, "onFailure reason:" + reason);
+ notRegistered();
+ }
+ });
}
private void registered(SipSession session) {
- enterState(State.REGISTERING, State.REGISTERED);
+ if (state.get().equals(State.REGISTERING) || state.get().equals(State.NOT_REGISTERED)) {
+ enterState(state.get(), State.REGISTERED);
+ }
context = new SimpleRcsClientContext(provisioningController, registrationController,
imsService,
@@ -133,6 +136,10 @@
imsService.start(context);
}
+ private void notRegistered() {
+ enterState(State.REGISTERED, State.NOT_REGISTERED);
+ }
+
/**
* Possible client states.
*/
@@ -141,6 +148,7 @@
PROVISIONING,
REGISTERING,
REGISTERED,
+ NOT_REGISTERED,
}
/**
@@ -151,7 +159,6 @@
private ProvisioningController provisioningController;
private RegistrationController registrationController;
private ImsService imsService;
- private Executor executor;
public Builder provisioningController(ProvisioningController controller) {
this.provisioningController = controller;
@@ -168,17 +175,11 @@
return this;
}
- public Builder executor(Executor executor) {
- this.executor = executor;
- return this;
- }
-
public SimpleRcsClient build() {
SimpleRcsClient client = new SimpleRcsClient();
client.registrationController = registrationController;
client.provisioningController = provisioningController;
client.imsService = imsService;
- client.executor = executor;
return client;
}
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 3f8b986..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);
}
@@ -98,7 +107,7 @@
private void listenForBearer() {
try {
connectivityManager.registerQosCallback(new QosSocketInfo(network, socket),
- qosCallback, MoreExecutors.directExecutor());
+ MoreExecutors.directExecutor(), qosCallback);
} catch (IOException e) {
throw new RuntimeException(e);
}
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/registration/RegistrationController.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationController.java
index 64d93b2..8bbe327 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationController.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationController.java
@@ -16,21 +16,18 @@
package com.android.libraries.rcs.simpleclient.registration;
-import com.android.libraries.rcs.simpleclient.protocol.sip.SipSession;
import com.android.libraries.rcs.simpleclient.service.ImsService;
-import com.google.common.util.concurrent.ListenableFuture;
-
/**
* Access to registration functionality.
*/
public interface RegistrationController {
/**
- * Registers the given ImsService with the backend and returns a SipSession for sending and
- * receiving SIP messages.
+ * Register the given ImsService with the backend and use the callback to return a SipSession
+ * for sending and receiving SIP messages.
*/
- ListenableFuture<SipSession> register(ImsService imsService);
+ void register(ImsService imsService, RegistrationStateChangeCallback callback);
void deregister();
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
index f1868fc..9ababc3 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
@@ -68,6 +68,7 @@
private final int subscriptionId;
private SipDelegateManager sipDelegateManager;
private RegistrationContext context;
+ private RegistrationStateChangeCallback callback;
public RegistrationControllerImpl(int subscriptionId, Executor executor,
ImsManager imsManager) {
@@ -77,11 +78,11 @@
}
@Override
- public ListenableFuture<SipSession> register(ImsService imsService) {
+ public void register(ImsService imsService, RegistrationStateChangeCallback callback) {
Log.i(TAG, "register");
+ this.callback = callback;
context = new RegistrationContext(this, imsService);
context.register();
- return context.getFuture();
}
@Override
@@ -101,7 +102,7 @@
/**
* Envelopes the registration data for a single ImsService instance.
*/
- private static class RegistrationContext implements SipSession, SipSessionConfiguration {
+ private class RegistrationContext implements SipSession, SipSessionConfiguration {
private final RegistrationControllerImpl controller;
private final ImsService imsService;
@@ -139,12 +140,17 @@
.getRegisteredFeatureTags()
.containsAll(imsService.getFeatureTags())) {
// registered;
- sessionFuture.set(RegistrationContext.this);
+ callback.onSuccess(RegistrationContext.this);
+ } else {
+ callback.onFailure("feature tag not registered");
}
}
@Override
public void onDestroyed(int reason) {
+ Log.d(TAG, "onDestroyed:" + reason);
+ callback.onFailure("delegate destroyed");
+
}
};
private SipSessionListener sipSessionListener;
@@ -167,10 +173,13 @@
@Override
public void onMessageSendFailure(@NonNull String viaTransactionId, int reason) {
+ Log.i(TAG, "onMessageSendFailure: viaTransactionId:"
+ + viaTransactionId + ", reason:" + reason);
}
@Override
public void onMessageSent(@NonNull String viaTransactionId) {
+ Log.i(TAG, "onMessageSent: viaTransactionId:" + viaTransactionId);
}
};
@@ -435,7 +444,7 @@
* for now.
* @return A SipMessage with the corrected header section.
*/
- private static SipMessage repairHeaderSection(SipMessage message) {
+ private SipMessage repairHeaderSection(SipMessage message) {
String headers = message.getHeaderSection();
if (headers.startsWith("ia:")) {
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationStateChangeCallback.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationStateChangeCallback.java
index 4f36ce5..570b313 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationStateChangeCallback.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationStateChangeCallback.java
@@ -16,6 +16,7 @@
package com.android.libraries.rcs.simpleclient.registration;
+import com.android.libraries.rcs.simpleclient.protocol.sip.SipSession;
import com.android.libraries.rcs.simpleclient.service.ImsService;
/**
@@ -30,4 +31,10 @@
* @param imsService the newly registered service.
*/
void notifyRegStateChanged(ImsService imsService);
+
+ /**callback for successful session creation */
+ void onSuccess(SipSession sipSession);
+
+ /**callback for failed session creation. */
+ void onFailure(String reason);
}
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();
}