Merge "Add command to restart the modem"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 37e009d..18e8d04 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -40,6 +40,7 @@
<protected-broadcast android:name="android.provider.Telephony.SIM_FULL" />
<protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
<protected-broadcast android:name="com.android.internal.telephony.data-stall" />
+ <protected-broadcast android:name="com.android.internal.telephony.provisioning_apn_alarm" />
<protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" />
diff --git a/res/values/config.xml b/res/values/config.xml
index e6c578a..7dd26bb 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -306,4 +306,8 @@
<!-- Whether or not to support RCS VoLTE single registration -->
<bool name="config_rcsVolteSingleRegistrationEnabled">true</bool>
+
+ <!-- Whether or not to support device to device communication using RTP and DTMF communication
+ transports. -->
+ <bool name="config_use_device_to_device_communication">false</bool>
</resources>
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 12c8cda..2c87f7c 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -263,10 +263,6 @@
public void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
List<Uri> contactNumbers, IRcsUceControllerCallback c) {
enforceReadPrivilegedPermission("requestCapabilities");
- if (!isUceSettingEnabled(subId, callingPackage, callingFeatureId)) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "The user has not enabled UCE for this subscription.");
- }
final long token = Binder.clearCallingIdentity();
try {
UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
@@ -284,13 +280,9 @@
}
@Override
- public void requestNetworkAvailability(int subId, String callingPackage,
+ public void requestAvailability(int subId, String callingPackage,
String callingFeatureId, Uri contactNumber, IRcsUceControllerCallback c) {
- enforceReadPrivilegedPermission("requestNetworkAvailability");
- if (!isUceSettingEnabled(subId, callingPackage, callingFeatureId)) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "The user has not enabled UCE for this subscription.");
- }
+ enforceReadPrivilegedPermission("requestAvailability");
final long token = Binder.clearCallingIdentity();
try {
UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index ce8e9b3..5c97597 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -69,6 +69,8 @@
import com.android.internal.telephony.dataconnection.DataConnectionReasons;
import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
import com.android.internal.telephony.ims.ImsResolver;
+import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.util.IndentingPrintWriter;
import com.android.phone.settings.SettingsConstants;
import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
@@ -360,6 +362,24 @@
defaultImsRcsPackage, PhoneFactory.getPhones().length,
new ImsFeatureBinderRepository());
mImsResolver.initialize();
+
+ // With the IMS phone created, load static config.xml values from the phone process
+ // so that it can be provided to the ImsPhoneCallTracker.
+ for (Phone p : PhoneFactory.getPhones()) {
+ Phone imsPhone = p.getImsPhone();
+ if (imsPhone != null && imsPhone instanceof ImsPhone) {
+ ImsPhone theImsPhone = (ImsPhone) imsPhone;
+ if (theImsPhone.getCallTracker() instanceof ImsPhoneCallTracker) {
+ ImsPhoneCallTracker ict = (ImsPhoneCallTracker)
+ theImsPhone.getCallTracker();
+
+ ImsPhoneCallTracker.Config config = new ImsPhoneCallTracker.Config();
+ config.isD2DCommunicationSupported = getResources().getBoolean(
+ R.bool.config_use_device_to_device_communication);
+ ict.setConfig(config);
+ }
+ }
+ }
RcsProvisioningMonitor.make(this);
}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index b8f87ea..10b8bc8 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -87,8 +87,11 @@
import android.telephony.PhoneNumberRange;
import android.telephony.RadioAccessFamily;
import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioInterfaceCapabilities;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.SignalStrengthUpdateRequest;
+import android.telephony.SignalThresholdInfo;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
@@ -127,6 +130,7 @@
import com.android.ims.ImsManager;
import com.android.ims.internal.IImsServiceFeatureCallback;
+import com.android.ims.rcs.uce.eab.EabUtil;
import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.CallManager;
import com.android.internal.telephony.CallStateException;
@@ -201,6 +205,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@@ -312,6 +317,10 @@
private static final int EVENT_SET_DATA_THROTTLING_DONE = 100;
private static final int CMD_SET_SIM_POWER = 101;
private static final int EVENT_SET_SIM_POWER_DONE = 102;
+ private static final int CMD_SET_SIGNAL_STRENGTH_UPDATE_REQUEST = 103;
+ private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE = 104;
+ private static final int CMD_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST = 105;
+ private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE = 106;
// Parameters of select command.
private static final int SELECT_COMMAND = 0xA4;
@@ -1791,6 +1800,60 @@
}
break;
}
+ case CMD_SET_SIGNAL_STRENGTH_UPDATE_REQUEST: {
+ request = (MainThreadRequest) msg.obj;
+
+ final Phone phone = getPhoneFromRequest(request);
+ if (phone == null || phone.getServiceStateTracker() == null) {
+ request.result = new IllegalStateException("Phone or SST is null");
+ notifyRequester(request);
+ break;
+ }
+
+ Pair<Integer, SignalStrengthUpdateRequest> pair =
+ (Pair<Integer, SignalStrengthUpdateRequest>) request.argument;
+ onCompleted = obtainMessage(EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE,
+ request);
+ phone.getServiceStateTracker().setSignalStrengthUpdateRequest(
+ request.subId, pair.first /*callingUid*/,
+ pair.second /*request*/, onCompleted);
+ break;
+ }
+ case EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE: {
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ // request.result will be the exception of ar if present, true otherwise.
+ // Be cautious not to leave result null which will wait() forever
+ request.result = ar.exception != null ? ar.exception : true;
+ notifyRequester(request);
+ break;
+ }
+ case CMD_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST: {
+ request = (MainThreadRequest) msg.obj;
+
+ Phone phone = getPhoneFromRequest(request);
+ if (phone == null || phone.getServiceStateTracker() == null) {
+ request.result = new IllegalStateException("Phone or SST is null");
+ notifyRequester(request);
+ break;
+ }
+
+ Pair<Integer, SignalStrengthUpdateRequest> pair =
+ (Pair<Integer, SignalStrengthUpdateRequest>) request.argument;
+ onCompleted = obtainMessage(EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE,
+ request);
+ phone.getServiceStateTracker().clearSignalStrengthUpdateRequest(
+ request.subId, pair.first /*callingUid*/,
+ pair.second /*request*/, onCompleted);
+ break;
+ }
+ case EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE: {
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ request.result = ar.exception != null ? ar.exception : true;
+ notifyRequester(request);
+ break;
+ }
default:
Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
@@ -3015,7 +3078,7 @@
*
* @throws SecurityException if the caller is not system.
*/
- private void enforceSystemCaller() {
+ private static void enforceSystemCaller() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Caller must be system");
}
@@ -3228,7 +3291,9 @@
String authorizedPackage = NumberVerificationManager.getAuthorizedPackage(mApp);
if (!TextUtils.equals(callingPackage, authorizedPackage)) {
- throw new SecurityException("Calling package must be configured in the device config");
+ throw new SecurityException("Calling package must be configured in the device config: "
+ + "calling package: " + callingPackage
+ + ", configured package: " + authorizedPackage);
}
if (range == null) {
@@ -5493,12 +5558,20 @@
}
}
- public void setImsRegistrationState(boolean registered) {
+ /**
+ * Sets the ims registration state on all valid {@link Phone}s.
+ */
+ public void setImsRegistrationState(final boolean registered) {
enforceModifyPermission();
final long identity = Binder.clearCallingIdentity();
try {
- getDefaultPhone().setImsRegistrationState(registered);
+ // NOTE: Before S, this method only set the default phone.
+ for (final Phone phone : PhoneFactory.getPhones()) {
+ if (SubscriptionManager.isValidSubscriptionId(phone.getSubId())) {
+ phone.setImsRegistrationState(registered);
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9255,6 +9328,18 @@
}
@Override
+ public boolean isRadioInterfaceCapabilitySupported(
+ @NonNull @TelephonyManager.RadioInterfaceCapability String capability) {
+ RadioInterfaceCapabilities radioInterfaceCapabilities =
+ mPhoneConfigurationManager.getRadioInterfaceCapabilities();
+ if (radioInterfaceCapabilities == null) {
+ throw new RuntimeException("radio interface capabilities are not available");
+ } else {
+ return radioInterfaceCapabilities.isSupported(capability);
+ }
+ }
+
+ @Override
public void bootstrapAuthenticationRequest(int subId, int appType, Uri nafUrl,
UaSecurityProtocolIdentifier securityProtocol,
boolean forceBootStrapping, IBootstrapAuthenticationCallback callback)
@@ -9353,8 +9438,8 @@
switch (thermalMitigationAction) {
case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_DATA_THROTTLING:
thermalMitigationResult =
- handleDataThrottlingRequest(subId,
- thermalMitigationRequest.getDataThrottlingRequest());
+ handleDataThrottlingRequest(subId,
+ thermalMitigationRequest.getDataThrottlingRequest());
break;
case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_VOICE_ONLY:
if (thermalMitigationRequest.getDataThrottlingRequest() != null) {
@@ -9387,14 +9472,14 @@
Phone phone = getPhone(subId);
if (phone == null) {
thermalMitigationResult =
- TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
break;
}
if (PhoneConstantConversions.convertCallState(phone.getState())
- != TelephonyManager.CALL_STATE_IDLE
- || phone.isInEmergencySmsMode() || phone.isInEcm()
- || (service != null && service.isEmergencyCallPending())) {
+ != TelephonyManager.CALL_STATE_IDLE
+ || phone.isInEmergencySmsMode() || phone.isInEcm()
+ || (service != null && service.isEmergencyCallPending())) {
String errorMessage = "Phone state is not valid. call state = "
+ PhoneConstantConversions.convertCallState(phone.getState())
+ " isInEmergencySmsMode = " + phone.isInEmergencySmsMode()
@@ -9405,7 +9490,7 @@
+ service.isEmergencyCallPending();
Log.e(LOG_TAG, errorMessage);
thermalMitigationResult =
- TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE;
+ TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE;
break;
}
} else {
@@ -9422,7 +9507,7 @@
break;
}
thermalMitigationResult =
- TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
+ TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
break;
default:
throw new IllegalArgumentException("the requested thermalMitigationAction does "
@@ -9571,10 +9656,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .addRcsProvisioningCallbackForSubscription(callback, subId);
- } catch (ImsException e) {
- throw new ServiceSpecificException(e.getCode());
+ if (!RcsProvisioningMonitor.getInstance()
+ .registerRcsProvisioningChangedCallback(subId, callback)) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "Service not available for the subscription.");
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9598,11 +9684,8 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeRcsProvisioningCallbackForSubscription(callback, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterRcsProvisioningChangedCallback: " + subId
- + "is inactive, ignoring unregister.");
+ RcsProvisioningMonitor.getInstance()
+ .unregisterRcsProvisioningChangedCallback(subId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9677,6 +9760,32 @@
}
/**
+ * Sends a device to device communication message. Only usable via shell.
+ * @param message message to send.
+ * @param value message value.
+ */
+ @Override
+ public void sendDeviceToDeviceMessage(int message, int value) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "setCarrierSingleRegistrationEnabledOverride");
+ enforceModifyPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ TelephonyConnectionService service =
+ TelecomAccountRegistry.getInstance(null).getTelephonyConnectionService();
+ if (service == null) {
+ Rlog.e(LOG_TAG, "sendDeviceToDeviceMessage: not in a call.");
+ return;
+ }
+ service.sendTestDeviceToDeviceMessage(message, value);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+
+ /**
* Gets the config of RCS VoLTE single registration enabled for the device.
*/
@Override
@@ -9723,4 +9832,107 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ /**
+ * Remove the EAB contacts from the EAB database.
+ */
+ @Override
+ public int removeContactFromEab(int subId, String contacts) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "removeCapabilitiesFromEab");
+ enforceModifyPermission();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return EabUtil.removeContactFromEab(subId, contacts, getDefaultPhone().getContext());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void setSignalStrengthUpdateRequest(int subId, SignalStrengthUpdateRequest request,
+ String callingPackage) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "setSignalStrengthUpdateRequest");
+
+ final int callingUid = Binder.getCallingUid();
+ // Verify that tha callingPackage belongs to the calling UID
+ mApp.getSystemService(AppOpsManager.class)
+ .checkPackage(callingUid, callingPackage);
+
+ validateSignalStrengthUpdateRequest(request, callingUid);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Object result = sendRequest(CMD_SET_SIGNAL_STRENGTH_UPDATE_REQUEST,
+ new Pair<Integer, SignalStrengthUpdateRequest>(callingUid, request), subId);
+
+ if (result instanceof IllegalStateException) {
+ throw (IllegalStateException) result;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void clearSignalStrengthUpdateRequest(int subId, SignalStrengthUpdateRequest request,
+ String callingPackage) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "clearSignalStrengthUpdateRequest");
+
+ final int callingUid = Binder.getCallingUid();
+ // Verify that tha callingPackage belongs to the calling UID
+ mApp.getSystemService(AppOpsManager.class)
+ .checkPackage(callingUid, callingPackage);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Object result = sendRequest(CMD_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST,
+ new Pair<Integer, SignalStrengthUpdateRequest>(callingUid, request), subId);
+
+ if (result instanceof IllegalStateException) {
+ throw (IllegalStateException) result;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private static void validateSignalStrengthUpdateRequest(SignalStrengthUpdateRequest request,
+ int callingUid) {
+ if (callingUid == Process.PHONE_UID || callingUid == Process.SYSTEM_UID) {
+ // phone/system process do not have further restriction on request
+ return;
+ }
+
+ // Applications has restrictions on how to use the request:
+ // Only system caller can set mIsSystemThresholdReportingRequestedWhileIdle
+ if (request.isSystemThresholdReportingRequestedWhileIdle()) {
+ // This is not system caller which has been checked above
+ throw new IllegalArgumentException(
+ "Only system can set isSystemThresholdReportingRequestedWhileIdle");
+ }
+
+ for (SignalThresholdInfo info : request.getSignalThresholdInfos()) {
+ // Only system caller can set mHysteresisMs/mHysteresisDb/mIsEnabled.
+ if (info.getHysteresisMs() != SignalThresholdInfo.HYSTERESIS_MS_DISABLED
+ || info.getHysteresisDb() != SignalThresholdInfo.HYSTERESIS_DB_DISABLED
+ || info.isEnabled()) {
+ throw new IllegalArgumentException(
+ "Only system can set hide fields in SignalThresholdInfo");
+ }
+
+ // Thresholds length for each RAN need in range. This has been validated in
+ // SignalThresholdInfo#Builder#setThreshold. Here we prevent apps calling hide method
+ // setThresholdUnlimited (e.g. through reflection) with too short or too long thresholds
+ final int[] thresholds = info.getThresholds();
+ Objects.requireNonNull(thresholds);
+ if (thresholds.length < SignalThresholdInfo.getMinimumNumberOfThresholdsAllowed()
+ || thresholds.length
+ > SignalThresholdInfo.getMaximumNumberOfThresholdsAllowed()) {
+ throw new IllegalArgumentException(
+ "thresholds length is out of range: " + thresholds.length);
+ }
+ }
+ }
}
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 98003bd..7b51eeb 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -36,19 +36,20 @@
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsConfig;
import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.ImsFeature;
import android.text.TextUtils;
-import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.telephony.Rlog;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
+import java.util.Iterator;
+import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
/**
* Class to monitor RCS Provisioning Status
@@ -67,10 +68,8 @@
private final PhoneGlobals mPhone;
private final Handler mHandler;
- //cache the rcs config per sub id
- private final Map<Integer, byte[]> mConfigs = Collections.synchronizedMap(new HashMap<>());
- //cache the single registration config per sub id
- private final ConcurrentHashMap<Integer, Integer> mSingleRegistrations =
+ // Cache the RCS provsioning info and related sub id
+ private final ConcurrentHashMap<Integer, RcsProvisioningInfo> mRcsProvisioningInfos =
new ConcurrentHashMap<>();
private Boolean mDeviceSingleRegistrationEnabledOverride;
private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride =
@@ -81,6 +80,7 @@
private final DmaChangedListener mDmaChangedListener;
private final SubscriptionManager mSubscriptionManager;
private final TelephonyRegistryManager mTelephonyRegistryManager;
+ private final RoleManagerAdapter mRoleManager;
private static RcsProvisioningMonitor sInstance;
@@ -111,8 +111,6 @@
};
private final class DmaChangedListener implements OnRoleHoldersChangedListener {
- private RoleManager mRoleManager;
-
@Override
public void onRoleHoldersChanged(String role, UserHandle user) {
if (RoleManager.ROLE_SMS.equals(role)) {
@@ -123,24 +121,19 @@
}
public void register() {
- mRoleManager = mPhone.getSystemService(RoleManager.class);
- if (mRoleManager != null) {
- try {
- mRoleManager.addOnRoleHoldersChangedListenerAsUser(
- mPhone.getMainExecutor(), this, UserHandle.SYSTEM);
- } catch (RuntimeException e) {
- loge("Could not register dma change listener due to " + e);
- }
+ try {
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(
+ mPhone.getMainExecutor(), this, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ loge("Could not register dma change listener due to " + e);
}
}
public void unregister() {
- if (mRoleManager != null) {
- try {
- mRoleManager.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.SYSTEM);
- } catch (RuntimeException e) {
- loge("Could not unregister dma change listener due to " + e);
- }
+ try {
+ mRoleManager.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ loge("Could not unregister dma change listener due to " + e);
}
}
}
@@ -189,13 +182,113 @@
}
}
+ private final class RcsProvisioningInfo {
+ private int mSubId;
+ private volatile int mSingleRegistrationCapability;
+ private volatile byte[] mConfig;
+ private HashSet<IRcsConfigCallback> mRcsConfigCallbacks;
+
+ RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config) {
+ mSubId = subId;
+ mSingleRegistrationCapability = singleRegistrationCapability;
+ mConfig = config;
+ mRcsConfigCallbacks = new HashSet<>();
+ }
+
+ void setSingleRegistrationCapability(int singleRegistrationCapability) {
+ mSingleRegistrationCapability = singleRegistrationCapability;
+ }
+
+ int getSingleRegistrationCapability() {
+ return mSingleRegistrationCapability;
+ }
+
+ void setConfig(byte[] config) {
+ mConfig = config;
+ }
+
+ byte[] getConfig() {
+ return mConfig;
+ }
+
+ boolean addRcsConfigCallback(IRcsConfigCallback cb) {
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+ if (imsConfig == null) {
+ logd("fail to addRcsConfigCallback as imsConfig is null");
+ return false;
+ }
+
+ synchronized (mRcsConfigCallbacks) {
+ try {
+ imsConfig.addRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to addRcsConfigCallback due to " + e);
+ return false;
+ }
+ mRcsConfigCallbacks.add(cb);
+ }
+ return true;
+ }
+
+ boolean removeRcsConfigCallback(IRcsConfigCallback cb) {
+ boolean result = true;
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+
+ synchronized (mRcsConfigCallbacks) {
+ if (imsConfig != null) {
+ try {
+ imsConfig.removeRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to removeRcsConfigCallback due to " + e);
+ }
+ } else {
+ // Return false but continue to remove the callback
+ result = false;
+ }
+
+ try {
+ cb.onRemoved();
+ } catch (RemoteException e) {
+ logd("Failed to notify onRemoved due to dead binder of " + cb);
+ }
+ mRcsConfigCallbacks.remove(cb);
+ }
+ return result;
+ }
+
+ void clear() {
+ setConfig(null);
+ synchronized (mRcsConfigCallbacks) {
+ IImsConfig imsConfig = getIImsConfig(mSubId, ImsFeature.FEATURE_RCS);
+ Iterator<IRcsConfigCallback> it = mRcsConfigCallbacks.iterator();
+ while (it.hasNext()) {
+ IRcsConfigCallback cb = it.next();
+ if (imsConfig != null) {
+ try {
+ imsConfig.removeRcsConfigCallback(cb);
+ } catch (RemoteException e) {
+ loge("fail to removeRcsConfigCallback due to " + e);
+ }
+ }
+ try {
+ cb.onRemoved();
+ } catch (RemoteException e) {
+ logd("Failed to notify onRemoved due to dead binder of " + cb);
+ }
+ it.remove();
+ }
+ }
+ }
+ }
+
@VisibleForTesting
- public RcsProvisioningMonitor(PhoneGlobals app, Looper looper) {
+ public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager) {
mPhone = app;
mHandler = new MyHandler(looper);
mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class);
mSubscriptionManager = mPhone.getSystemService(SubscriptionManager.class);
mTelephonyRegistryManager = mPhone.getSystemService(TelephonyRegistryManager.class);
+ mRoleManager = roleManager;
mDmaPackageName = getDmaPackageName();
logv("DMA is " + mDmaPackageName);
IntentFilter filter = new IntentFilter();
@@ -217,7 +310,8 @@
logd("RcsProvisioningMonitor created.");
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
- sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper());
+ sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper(),
+ new RoleManagerAdapterImpl(app));
}
return sInstance;
}
@@ -254,15 +348,19 @@
*/
@VisibleForTesting
public byte[] getConfig(int subId) {
- return mConfigs.get(subId);
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return mRcsProvisioningInfos.get(subId).getConfig();
+ }
+ return null;
}
/**
* Returns whether Rcs Volte single registration is enabled for the sub.
*/
public boolean isRcsVolteSingleRegistrationEnabled(int subId) {
- if (mSingleRegistrations.containsKey(subId)) {
- return mSingleRegistrations.get(subId) == ProvisioningManager.STATUS_CAPABLE;
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
+ == ProvisioningManager.STATUS_CAPABLE;
}
return false;
}
@@ -283,6 +381,34 @@
}
/**
+ * Called when the application registers rcs provisioning changed callback
+ */
+ public boolean registerRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ // should not happen in normal case
+ if (info == null) {
+ logd("fail to register rcs provisioning changed due to subscription unavailable");
+ return false;
+ }
+
+ return info.addRcsConfigCallback(cb);
+ }
+
+ /**
+ * Called when the application unregisters rcs provisioning changed callback
+ */
+ public boolean unregisterRcsProvisioningChangedCallback(int subId, IRcsConfigCallback cb) {
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ // should not happen in normal case
+ if (info == null) {
+ logd("fail to unregister rcs provisioning changed due to subscription unavailable");
+ return false;
+ }
+
+ return info.removeRcsConfigCallback(cb);
+ }
+
+ /**
* override the device config whether single registration is enabled
*/
public void overrideDeviceSingleRegistrationEnabled(Boolean enabled) {
@@ -293,7 +419,7 @@
* Overrides the carrier config whether single registration is enabled
*/
public boolean overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled) {
- if (!mSingleRegistrations.containsKey(subId)) {
+ if (!mRcsProvisioningInfos.containsKey(subId)) {
return false;
}
mHandler.sendMessage(mHandler.obtainMessage(
@@ -305,8 +431,9 @@
* Returns the device config whether single registration is enabled
*/
public boolean getDeviceSingleRegistrationEnabled() {
- for (int val : mSingleRegistrations.values()) {
- return (val & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
+ for (RcsProvisioningInfo info : mRcsProvisioningInfos.values()) {
+ return (info.getSingleRegistrationCapability()
+ & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
}
return false;
}
@@ -315,8 +442,8 @@
* Returns the carrier config whether single registration is enabled
*/
public boolean getCarrierSingleRegistrationEnabled(int subId) {
- if (mSingleRegistrations.containsKey(subId)) {
- return (mSingleRegistrations.get(subId)
+ if (mRcsProvisioningInfos.containsKey(subId)) {
+ return (mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability()
& ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE) == 0;
}
return false;
@@ -325,20 +452,21 @@
private void onDefaultMessagingApplicationChanged() {
final String packageName = getDmaPackageName();
if (!TextUtils.equals(mDmaPackageName, packageName)) {
- //clear old callbacks
- ImsManager.getInstance(mPhone, mPhone.getPhone().getPhoneId())
- .clearRcsProvisioningCallbacks();
mDmaPackageName = packageName;
logv("new default messaging application " + mDmaPackageName);
- mConfigs.forEach((k, v) -> {
+
+ mRcsProvisioningInfos.forEach((k, v) -> {
+ byte[] cachedConfig = v.getConfig();
+ //clear old callbacks
+ v.clear();
if (isAcsUsed(k)) {
logv("acs used, trigger to re-configure.");
- mConfigs.put(k, null);
notifyRcsAutoConfigurationRemoved(k);
triggerRcsReconfiguration(k);
} else {
+ v.setConfig(cachedConfig);
logv("acs not used, notify.");
- notifyRcsAutoConfigurationReceived(k, v, false);
+ notifyRcsAutoConfigurationReceived(k, v.getConfig(), false);
}
});
}
@@ -427,58 +555,68 @@
private void onCarrierConfigChange() {
logv("onCarrierConfigChange");
- mConfigs.forEach((subId, config) -> {
+ mRcsProvisioningInfos.forEach((subId, info) -> {
int value = getSingleRegistrationCapableValue(subId);
- if (value != mSingleRegistrations.get(subId)) {
- mSingleRegistrations.put(subId, value);
- notifyDmaForSub(subId);
+ if (value != info.getSingleRegistrationCapability()) {
+ info.setSingleRegistrationCapability(value);
+ notifyDmaForSub(subId, value);
}
});
}
private void onSubChanged() {
final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList();
- final HashSet<Integer> subsToBeDeactivated = new HashSet<>(mConfigs.keySet());
+ final HashSet<Integer> subsToBeDeactivated = new HashSet<>(mRcsProvisioningInfos.keySet());
for (int i : activeSubs) {
subsToBeDeactivated.remove(i);
- if (!mConfigs.containsKey(i)) {
+ if (!mRcsProvisioningInfos.containsKey(i)) {
byte[] data = RcsConfig.loadRcsConfigForSub(mPhone, i, false);
- logv("new config is created for sub : " + i);
- mConfigs.put(i, data);
+ int capability = getSingleRegistrationCapableValue(i);
+ logv("new info is created for sub : " + i + ", single registration capability :"
+ + capability + ", rcs config : " + data);
+ mRcsProvisioningInfos.put(i, new RcsProvisioningInfo(i, capability, data));
notifyRcsAutoConfigurationReceived(i, data, false);
- mSingleRegistrations.put(i, getSingleRegistrationCapableValue(i));
- notifyDmaForSub(i);
+ notifyDmaForSub(i, capability);
}
}
subsToBeDeactivated.forEach(i -> {
- mConfigs.remove(i);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.remove(i);
notifyRcsAutoConfigurationRemoved(i);
+ if (info != null) {
+ info.clear();
+ }
});
}
private void onConfigReceived(int subId, byte[] config, boolean isCompressed) {
logv("onConfigReceived, subId:" + subId + ", config:"
+ config + ", isCompressed:" + isCompressed);
- mConfigs.put(subId, isCompressed ? RcsConfig.decompressGzip(config) : config);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ if (info != null) {
+ info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config);
+ }
RcsConfig.updateConfigForSub(mPhone, subId, config, isCompressed);
notifyRcsAutoConfigurationReceived(subId, config, isCompressed);
}
private void onReconfigRequest(int subId) {
logv("onReconfigRequest, subId:" + subId);
- mConfigs.put(subId, null);
+ RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
+ if (info != null) {
+ info.setConfig(null);
+ }
notifyRcsAutoConfigurationRemoved(subId);
triggerRcsReconfiguration(subId);
}
- private void notifyDmaForSub(int subId) {
+ private void notifyDmaForSub(int subId, int capability) {
final Intent intent = new Intent(
ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
intent.setPackage(mDmaPackageName);
intent.putExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID, subId);
- intent.putExtra(ProvisioningManager.EXTRA_STATUS, mSingleRegistrations.get(subId));
+ intent.putExtra(ProvisioningManager.EXTRA_STATUS, capability);
logv("notify " + intent);
mPhone.sendBroadcast(intent);
}
@@ -490,8 +628,7 @@
private String getDmaPackageName() {
try {
- return CollectionUtils.firstOrNull(mPhone.getSystemService(RoleManager.class)
- .getRoleHolders(RoleManager.ROLE_SMS));
+ return CollectionUtils.firstOrNull(mRoleManager.getRoleHolders(RoleManager.ROLE_SMS));
} catch (RuntimeException e) {
loge("Could not get dma name due to " + e);
return null;
@@ -517,4 +654,44 @@
private static void loge(String msg) {
Rlog.e(TAG, msg);
}
+
+ /**
+ * {@link RoleManager} is final so we have to wrap the implementation for testing.
+ */
+ @VisibleForTesting
+ public interface RoleManagerAdapter {
+ /** See {@link RoleManager#getRoleHolders(String)} */
+ List<String> getRoleHolders(String roleName);
+ /** See {@link RoleManager#addOnRoleHoldersChangedListenerAsUser} */
+ void addOnRoleHoldersChangedListenerAsUser(Executor executor,
+ OnRoleHoldersChangedListener listener, UserHandle user);
+ /** See {@link RoleManager#removeOnRoleHoldersChangedListenerAsUser} */
+ void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener,
+ UserHandle user);
+ }
+
+ private static class RoleManagerAdapterImpl implements RoleManagerAdapter {
+ private final RoleManager mRoleManager;
+
+ private RoleManagerAdapterImpl(Context context) {
+ mRoleManager = context.getSystemService(RoleManager.class);
+ }
+
+ @Override
+ public List<String> getRoleHolders(String roleName) {
+ return mRoleManager.getRoleHolders(roleName);
+ }
+
+ @Override
+ public void addOnRoleHoldersChangedListenerAsUser(Executor executor,
+ OnRoleHoldersChangedListener listener, UserHandle user) {
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, listener, user);
+ }
+
+ @Override
+ public void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener,
+ UserHandle user) {
+ mRoleManager.removeOnRoleHoldersChangedListenerAsUser(listener, user);
+ }
+ }
}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index c64c375..d526e2f 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -16,6 +16,11 @@
package com.android.phone;
+import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_AUDIO_CODEC;
+import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE;
+import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_BATTERY_STATE;
+import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE;
+
import android.content.Context;
import android.os.Binder;
import android.os.PersistableBundle;
@@ -27,11 +32,13 @@
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.feature.ImsFeature;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.d2d.Communicator;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.modules.utils.BasicShellCommandHandler;
@@ -95,6 +102,12 @@
private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled";
private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
+ private static final String D2D_SUBCOMMAND = "d2d";
+ private static final String D2D_SEND = "send";
+
+ private static final String RCS_UCE_COMMAND = "uce";
+ private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact";
+
// Take advantage of existing methods that already contain permissions checks when possible.
private final ITelephony mInterface;
@@ -164,6 +177,8 @@
case IMS_SUBCOMMAND: {
return handleImsCommand();
}
+ case RCS_UCE_COMMAND:
+ return handleRcsUceCommand();
case NUMBER_VERIFICATION_SUBCOMMAND:
return handleNumberVerificationCommand();
case EMERGENCY_NUMBER_TEST_MODE:
@@ -177,6 +192,8 @@
return handleEndBlockSuppressionCommand();
case GBA_SUBCOMMAND:
return handleGbaCommand();
+ case D2D_SUBCOMMAND:
+ return handleD2dCommand();
case SINGLE_REGISTATION_CONFIG:
return handleSingleRegistrationConfigCommand();
case RESTART_MODEM:
@@ -195,6 +212,8 @@
pw.println(" Print this help text.");
pw.println(" ims");
pw.println(" IMS Commands.");
+ pw.println(" uce");
+ pw.println(" RCS User Capability Exchange Commands.");
pw.println(" emergency-number-test-mode");
pw.println(" Emergency Number Test Mode Commands.");
pw.println(" end-block-suppression");
@@ -210,12 +229,30 @@
pw.println(" restart-modem");
pw.println(" Restart modem command.");
onHelpIms();
+ onHelpUce();
onHelpEmergencyNumber();
onHelpEndBlockSupperssion();
onHelpDataTestMode();
onHelpCc();
onHelpGba();
onHelpSrc();
+ onHelpD2D();
+ }
+
+ private void onHelpD2D() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("D2D Comms Commands:");
+ pw.println(" d2d send TYPE VALUE");
+ pw.println(" Sends a D2D message of specified type and value.");
+ pw.println(" Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - "
+ + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE));
+ pw.println(" Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString(
+ MESSAGE_CALL_AUDIO_CODEC));
+ pw.println(" Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - "
+ + Communicator.messageToString(
+ MESSAGE_DEVICE_BATTERY_STATE));
+ pw.println(" Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - "
+ + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE));
}
private void onHelpIms() {
@@ -254,6 +291,17 @@
pw.println(" enables or disables handling or network conference event package data.");
}
+ private void onHelpUce() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("User Capability Exchange Commands:");
+ pw.println(" uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]");
+ pw.println(" Remove the EAB contacts from the EAB database.");
+ 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(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
+ }
+
private void onHelpNumberVerification() {
PrintWriter pw = getOutPrintWriter();
pw.println("Number verification commands");
@@ -546,6 +594,64 @@
return -1;
}
+ private int handleD2dCommand() {
+ String arg = getNextArg();
+ if (arg == null) {
+ onHelpD2D();
+ return 0;
+ }
+
+ switch (arg) {
+ case D2D_SEND: {
+ return handleD2dSendCommand();
+ }
+ }
+
+ return -1;
+ }
+
+ private int handleD2dSendCommand() {
+ PrintWriter errPw = getErrPrintWriter();
+ String opt;
+ int messageType = -1;
+ int messageValue = -1;
+
+
+ String arg = getNextArg();
+ if (arg == null) {
+ onHelpD2D();
+ return 0;
+ }
+ try {
+ messageType = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ errPw.println("message type must be a valid integer");
+ return -1;
+ }
+
+ arg = getNextArg();
+ if (arg == null) {
+ onHelpD2D();
+ return 0;
+ }
+ try {
+ messageValue = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ errPw.println("message value must be a valid integer");
+ return -1;
+ }
+
+ try {
+ mInterface.sendDeviceToDeviceMessage(messageType, messageValue);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "d2d send error: " + e.getMessage());
+ errPw.println("Exception: " + e.getMessage());
+ return -1;
+ }
+
+ return 0;
+ }
+
// ims set-ims-service
private int handleImsSetServiceCommand() {
PrintWriter errPw = getErrPrintWriter();
@@ -1496,6 +1602,45 @@
return -1;
}
+ private int handleRcsUceCommand() {
+ String arg = getNextArg();
+ if (arg == null) {
+ Log.w(LOG_TAG, "cannot get uce parameter");
+ return -1;
+ }
+
+ switch (arg) {
+ case UCE_REMOVE_EAB_CONTACT:
+ return handleRemovingEabContactCommand();
+ }
+ return -1;
+ }
+
+ private int handleRemovingEabContactCommand() {
+ int subId = getSubId("uce remove-eab-contact");
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ String phoneNumber = getNextArgRequired();
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return -1;
+ }
+ int result = 0;
+ try {
+ result = mInterface.removeContactFromEab(subId, phoneNumber);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ }
+
+ if (VDBG) {
+ Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result);
+ }
+ return result;
+ }
+
private int handleSrcSetDeviceEnabledCommand() {
String enabledStr = getNextArg();
if (enabledStr == null) {
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index 37212cf..ad3f133 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -122,8 +122,12 @@
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
boolean isRoaming = tm.isNetworkRoaming(
SubscriptionManager.getDefaultVoiceSubscriptionId());
+ boolean alwaysAllowWhileRoaming = isCarrierAllowRttWhenRoaming(
+ SubscriptionManager.getDefaultVoiceSubscriptionId());
- boolean shouldDisableBecauseRoamingOffWfc = isRoaming && !isOnWfc();
+ boolean shouldDisableBecauseRoamingOffWfc =
+ (isRoaming && !isOnWfc()) && !alwaysAllowWhileRoaming;
+
if (shouldDisableBecauseRoamingOffWfc) {
mButtonRtt.setSummary(TextUtils.concat(getText(R.string.rtt_mode_summary), "\n",
getText(R.string.no_rtt_when_roaming)));
@@ -277,4 +281,13 @@
return configManager.getConfig().getBoolean(
CarrierConfigManager.KEY_TTY_SUPPORTED_BOOL);
}
+
+ /**
+ * Determines from carrier config whether to always allow RTT while roaming.
+ */
+ private boolean isCarrierAllowRttWhenRoaming(int subId) {
+ PersistableBundle b =
+ PhoneGlobals.getInstance().getCarrierConfigForSubId(subId);
+ return b.getBoolean(CarrierConfigManager.KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL);
+ }
}
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 016da87..9d4edfd 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -743,6 +743,15 @@
}
/**
+ * Determines from carrier config whether to always allow RTT while roaming.
+ */
+ private boolean isCarrierAllowRttWhenRoaming() {
+ PersistableBundle b =
+ PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+ return b.getBoolean(CarrierConfigManager.KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL);
+ }
+
+ /**
* Where a device supports instant lettering and call subjects, retrieves the necessary
* PhoneAccount extras for those features.
*
@@ -894,11 +903,15 @@
boolean isRoaming = mTelephonyManager.isNetworkRoaming(mPhone.getSubId());
boolean isOnWfc = mPhone.getImsRegistrationTech()
== ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
+ boolean alwaysAllowWhileRoaming = isCarrierAllowRttWhenRoaming();
- boolean shouldDisableBecauseRoamingOffWfc = isRoaming && !isOnWfc;
+ boolean shouldDisableBecauseRoamingOffWfc =
+ (isRoaming && !isOnWfc) && !alwaysAllowWhileRoaming;
+
Log.i(this, "isRttCurrentlySupported -- regular acct,"
+ " hasVoiceAvailability: " + hasVoiceAvailability + "\n"
+ " isRttSupported: " + isRttSupported + "\n"
+ + " alwaysAllowWhileRoaming: " + alwaysAllowWhileRoaming + "\n"
+ " isRoaming: " + isRoaming + "\n"
+ " isOnWfc: " + isOnWfc + "\n");
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3e7f29c..45c00e4 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -46,6 +46,8 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.RtpHeaderExtension;
+import android.telephony.ims.RtpHeaderExtensionType;
import android.text.TextUtils;
import android.util.Pair;
@@ -61,6 +63,9 @@
import com.android.internal.telephony.Connection.PostDialListener;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.d2d.Communicator;
+import com.android.internal.telephony.d2d.RtpAdapter;
+import com.android.internal.telephony.d2d.RtpTransport;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
@@ -85,7 +90,7 @@
/**
* Base class for CDMA and GSM connections.
*/
-abstract class TelephonyConnection extends Connection implements Holdable {
+abstract class TelephonyConnection extends Connection implements Holdable, Communicator.Callback {
private static final String LOG_TAG = "TelephonyConnection";
private static final int MSG_PRECISE_CALL_STATE_CHANGED = 1;
@@ -487,6 +492,19 @@
public void onRingbackRequested(Connection c, boolean ringback) {}
}
+ public static class D2DCallStateAdapter extends TelephonyConnectionListener {
+ private Communicator mCommunicator;
+
+ D2DCallStateAdapter(Communicator communicator) {
+ mCommunicator = communicator;
+ }
+
+ @Override
+ public void onStateChanged(android.telecom.Connection c, int state) {
+ mCommunicator.onStateChanged(c, state);
+ }
+ }
+
private final PostDialListener mPostDialListener = new PostDialListener() {
@Override
public void onPostDialWait() {
@@ -701,6 +719,20 @@
public void onIsNetworkEmergencyCallChanged(boolean isEmergencyCall) {
setIsNetworkIdentifiedEmergencyCall(isEmergencyCall);
}
+
+ /**
+ * Indicates data from an RTP header extension has been received from the network.
+ * @param extensionData The extension data.
+ */
+ @Override
+ public void onReceivedRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> extensionData) {
+ if (mRtpTransport == null) {
+ return;
+ }
+ Log.i(this, "onReceivedRtpHeaderExtensions: received %d extensions",
+ extensionData.size());
+ mRtpTransport.onRtpHeaderExtensionsReceived(extensionData);
+ }
};
private TelephonyConnectionService mTelephonyConnectionService;
@@ -805,6 +837,18 @@
private int mHangupDisconnectCause = DisconnectCause.NOT_VALID;
/**
+ * Provides a means for a {@link Communicator} to be informed of call state changes.
+ */
+ private D2DCallStateAdapter mD2DCallStateAdapter;
+
+ private RtpTransport mRtpTransport;
+
+ /**
+ * Facilitates device to device communication.
+ */
+ private Communicator mCommunicator;
+
+ /**
* Listeners to our TelephonyConnection specific callbacks
*/
private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -1404,6 +1448,9 @@
if (isImsConnection()) {
mWasImsConnection = true;
}
+ if (originalConnection instanceof ImsPhoneConnection) {
+ maybeConfigureDeviceToDeviceCommunication();
+ }
mIsMultiParty = mOriginalConnection.isMultiparty();
Bundle extrasToPut = new Bundle();
@@ -2218,6 +2265,10 @@
case DISCONNECTING:
break;
}
+
+ if (mCommunicator != null) {
+ mCommunicator.onStateChanged(this, getState());
+ }
}
}
@@ -3112,6 +3163,77 @@
}
/**
+ * Where device to device communication is available and this is an IMS call, configures the
+ * D2D communication infrastructure for operation.
+ */
+ private void maybeConfigureDeviceToDeviceCommunication() {
+ if (!getPhone().getContext().getResources().getBoolean(
+ R.bool.config_use_device_to_device_communication)) {
+ Log.d(this, "maybeConfigureDeviceToDeviceCommunication: not using D2D.");
+ return;
+ }
+ if (!isImsConnection()) {
+ Log.d(this, "maybeConfigureDeviceToDeviceCommunication: not an IMS connection.");
+ return;
+ }
+ // Implement abstracted out RTP functionality the RTP transport depends on.
+ RtpAdapter rtpAdapter = new RtpAdapter() {
+ @Override
+ public Set<RtpHeaderExtensionType> getAcceptedRtpHeaderExtensions() {
+ if (!isImsConnection()) {
+ return Collections.EMPTY_SET;
+ }
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ return originalConnection.getAcceptedRtpHeaderExtensions();
+ }
+
+ @Override
+ public void sendRtpHeaderExtensions(
+ @NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
+ if (!isImsConnection()) {
+ Log.w(TelephonyConnection.this, "sendRtpHeaderExtensions: not an ims conn.");
+ }
+ Log.d(TelephonyConnection.this, "sendRtpHeaderExtensions: sending %d messages",
+ rtpHeaderExtensions.size());
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ originalConnection.sendRtpHeaderExtensions(rtpHeaderExtensions);
+ }
+ };
+ mRtpTransport = new RtpTransport(rtpAdapter, null /* TODO: not needed yet */, mHandler);
+ mCommunicator = new Communicator(List.of(mRtpTransport), this);
+ mD2DCallStateAdapter = new D2DCallStateAdapter(mCommunicator);
+ addTelephonyConnectionListener(mD2DCallStateAdapter);
+ }
+
+ /**
+ * @return The D2D communication class, or {@code null} if not set up.
+ */
+ public @Nullable Communicator getCommunicator() {
+ return mCommunicator;
+ }
+
+ /**
+ * Called by {@link Communicator} associated with this {@link TelephonyConnection} when there
+ * are incoming device-to-device messages received.
+ * @param messages the incoming messages.
+ */
+ @Override
+ public void onMessagesReceived(@NonNull Set<Communicator.Message> messages) {
+ Log.i(this, "onMessagesReceived: got d2d messages: %s", messages);
+ // TODO: Actually do something WITH the messages.
+
+ // TODO: Remove this prior to launch.
+ // This is just here for debug purposes; send as a connection event so that it
+ // will be output in the Telecom logs.
+ for (Communicator.Message msg : messages) {
+ sendConnectionEvent("D2D_" + Communicator.messageToString(msg.getType())
+ + "_" + Communicator.valueToString(msg.getType(), msg.getValue()), null);
+ }
+ }
+
+ /**
* Called by a {@link ConnectionService} to notify Telecom that a {@link Conference#onMerge()}
* operation has started.
*/
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 56012c8..2877326 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -63,6 +63,7 @@
import com.android.internal.telephony.PhoneSwitcher;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.SubscriptionController;
+import com.android.internal.telephony.d2d.Communicator;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
@@ -77,6 +78,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -1078,7 +1080,8 @@
if (state == ServiceState.STATE_OUT_OF_SERVICE) {
int dataNetType = phone.getServiceState().getDataNetworkType();
if (dataNetType == TelephonyManager.NETWORK_TYPE_LTE ||
- dataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ dataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA ||
+ dataNetType == TelephonyManager.NETWORK_TYPE_NR) {
state = phone.getServiceState().getDataRegistrationState();
}
}
@@ -2484,6 +2487,31 @@
conference.addTelephonyConferenceListener(mTelephonyConferenceListener);
}
+ /**
+ * Sends a test device to device message on the active call which supports it.
+ * Used exclusively from the telephony shell command to send a test message.
+ *
+ * @param message the message
+ * @param value the value
+ */
+ public void sendTestDeviceToDeviceMessage(int message, int value) {
+ getAllConnections().stream()
+ .filter(f -> f instanceof TelephonyConnection)
+ .forEach(t -> {
+ TelephonyConnection tc = (TelephonyConnection) t;
+ Communicator c = tc.getCommunicator();
+ if (c == null) {
+ Log.w(this, "sendTestDeviceToDeviceMessage: D2D not enabled");
+ return;
+ }
+
+ c.sendMessages(new HashSet<Communicator.Message>() {{
+ add(new Communicator.Message(message, value));
+ }});
+
+ });
+ }
+
private PhoneAccountHandle adjustAccountHandle(Phone phone,
PhoneAccountHandle origAccountHandle) {
int origSubId = PhoneUtils.getSubIdForPhoneAccountHandle(origAccountHandle);
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 1d8fa3b..18ad98e 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -163,8 +163,8 @@
public void dump(PrintWriter printWriter) {
printWriter.println("Last reg state: " + mLastRegState);
printWriter.println("Denied tags: " + mDelegateDeniedTags);
- printWriter.println("Most recent logs: ");
printWriter.println();
+ printWriter.println("Most recent logs: ");
mLocalLog.dump(printWriter);
}
diff --git a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
index 0691ae5..c42472d 100644
--- a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
+++ b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
@@ -343,6 +343,7 @@
/** Dump state about this tracker that should be included in the dumpsys */
public void dump(PrintWriter printWriter) {
+ printWriter.println("Most recent logs:");
mLocalLog.dump(printWriter);
}
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 4b3176a..2d6d4f0 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -376,14 +376,23 @@
IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
pw.println("SipDelegateController" + "[" + mSubId + "]:");
pw.increaseIndent();
+ pw.println("Most recent logs:");
+ pw.increaseIndent();
+ mLocalLog.dump(pw);
+ pw.decreaseIndent();
+
+ pw.println();
pw.println("DelegateStateTracker:");
pw.increaseIndent();
- mDelegateStateTracker.dump(printWriter);
+ mDelegateStateTracker.dump(pw);
pw.decreaseIndent();
+
+ pw.println();
pw.println("MessageStateTracker:");
pw.increaseIndent();
- mMessageTransportStateTracker.dump(printWriter);
+ mMessageTransportStateTracker.dump(pw);
pw.decreaseIndent();
+
pw.decreaseIndent();
}
diff --git a/src/com/android/services/telephony/rcs/UceControllerManager.java b/src/com/android/services/telephony/rcs/UceControllerManager.java
index d1f91d1..09288f1 100644
--- a/src/com/android/services/telephony/rcs/UceControllerManager.java
+++ b/src/com/android/services/telephony/rcs/UceControllerManager.java
@@ -51,6 +51,7 @@
private final ExecutorService mExecutorService;
private volatile UceController mUceController;
+ private volatile RcsFeatureManager mRcsFeatureManager;
public UceControllerManager(Context context, int slotId, int subId) {
Log.d(LOG_TAG, "create: slotId=" + slotId + ", subId=" + subId);
@@ -74,12 +75,18 @@
@Override
public void onRcsConnected(RcsFeatureManager manager) {
- mExecutorService.submit(() -> mUceController.onRcsConnected(manager));
+ mExecutorService.submit(() -> {
+ mRcsFeatureManager = manager;
+ mUceController.onRcsConnected(manager);
+ });
}
@Override
public void onRcsDisconnected() {
- mExecutorService.submit(() -> mUceController.onRcsDisconnected());
+ mExecutorService.submit(() -> {
+ mRcsFeatureManager = null;
+ mUceController.onRcsDisconnected();
+ });
}
@Override
@@ -103,6 +110,12 @@
// Destroy existing UceController and create a new one.
mUceController.onDestroy();
mUceController = new UceController(mContext, subId);
+
+ // The RCS should be connected when the mRcsFeatureManager is not null. Set it to the
+ // new UceController instance.
+ if (mRcsFeatureManager != null) {
+ mUceController.onRcsConnected(mRcsFeatureManager);
+ }
});
}
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index 5035284..02d2f8a 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -24,18 +24,15 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.role.IOnRoleHoldersChangedListener;
-import android.app.role.IRoleManager;
+import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -46,12 +43,8 @@
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IInterface;
import android.os.Looper;
import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Telephony.SimInfo;
import android.telephony.CarrierConfigManager;
@@ -60,6 +53,7 @@
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RcsConfig;
import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.ImsFeature;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -76,15 +70,12 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.Executor;
/**
@@ -100,7 +91,7 @@
+ "\t\t<GroupChatAuth>1</GroupChatAuth>\n"
+ "\t\t<ftAuth>1</ftAuth>\n"
+ "\t\t<standaloneMsgAuth>1</standaloneMsgAuth>\n"
- + "\t\t<geolocPushAuth>1<geolocPushAuth>\n"
+ + "\t\t<geolocPushAuth>1</geolocPushAuth>\n"
+ "\t\t<Ext>\n"
+ "\t\t\t<DataOff>\n"
+ "\t\t\t\t<rcsMessagingDataOff>1</rcsMessagingDataOff>\n"
@@ -115,7 +106,6 @@
private static final String DEFAULT_MESSAGING_APP1 = "DMA1";
private static final String DEFAULT_MESSAGING_APP2 = "DMA2";
- private MockitoSession mSession;
private RcsProvisioningMonitor mRcsProvisioningMonitor;
private Handler mHandler;
private HandlerThread mHandlerThread;
@@ -133,10 +123,9 @@
private TelephonyRegistryManager mTelephonyRegistryManager;
@Mock
private CarrierConfigManager mCarrierConfigManager;
- private IOnRoleHoldersChangedListener.Stub mRoleHolderChangedListener;
- private RoleManager mRoleManager;
+ private OnRoleHoldersChangedListener mRoleHolderChangedListener;
@Mock
- private IRoleManager.Stub mIRoleManager;
+ private RcsProvisioningMonitor.RoleManagerAdapter mRoleManager;
@Mock
private ITelephony.Stub mITelephony;
@Mock
@@ -147,6 +136,8 @@
private Resources mResources;
@Mock
private PhoneGlobals mPhone;
+ @Mock
+ private IRcsConfigCallback mCallback;
private Executor mExecutor = new Executor() {
@Override
@@ -189,8 +180,6 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- replaceService(Context.ROLE_SERVICE, mIRoleManager);
- mRoleManager = new RoleManager(mPhone);
when(mPhone.getResources()).thenReturn(mResources);
when(mResources.getBoolean(
eq(R.bool.config_rcsVolteSingleRegistrationEnabled))).thenReturn(true);
@@ -209,8 +198,6 @@
.thenReturn(mSubscriptionManager);
when(mPhone.getSystemService(eq(Context.TELEPHONY_REGISTRY_SERVICE)))
.thenReturn(mTelephonyRegistryManager);
- when(mPhone.getSystemService(eq(Context.ROLE_SERVICE)))
- .thenReturn(mRoleManager);
mBundle = new PersistableBundle();
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle);
@@ -237,15 +224,15 @@
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
- mRoleHolderChangedListener = (IOnRoleHoldersChangedListener.Stub)
- invocation.getArguments()[0];
+ mRoleHolderChangedListener = (OnRoleHoldersChangedListener)
+ invocation.getArguments()[1];
return null;
}
- }).when(mIRoleManager).addOnRoleHoldersChangedListenerAsUser(
- any(IOnRoleHoldersChangedListener.Stub.class), anyInt());
+ }).when(mRoleManager).addOnRoleHoldersChangedListenerAsUser(any(Executor.class),
+ any(OnRoleHoldersChangedListener.class), any(UserHandle.class));
List<String> dmas = new ArrayList<>();
dmas.add(DEFAULT_MESSAGING_APP1);
- when(mIRoleManager.getRoleHoldersAsUser(any(), anyInt())).thenReturn(dmas);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_SMS))).thenReturn(dmas);
mProvider = new SimInfoContentProvider(mPhone);
mProvider.setCursor(mCursor);
@@ -268,9 +255,6 @@
mRcsProvisioningMonitor = null;
}
- if (mSession != null) {
- mSession.finishMocking();
- }
if (mLooper != null) {
mLooper.destroy();
mLooper = null;
@@ -452,7 +436,6 @@
verify(mIImsConfig, times(1)).triggerRcsReconfiguration();
}
-
@Test
@SmallTest
public void testIsRcsVolteSingleRegistrationEnabled() throws Exception {
@@ -482,12 +465,63 @@
assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
}
+ @Test
+ @SmallTest
+ public void testRegisterThenUnregisterCallback() throws Exception {
+ createMonitor(1);
+
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).addRcsConfigCallback(eq(mCallback));
+
+ result = mRcsProvisioningMonitor.unregisterRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
+ verify(mCallback, times(1)).onRemoved();
+ }
+
+ @Test
+ @SmallTest
+ public void testCallbackRemovedWhenSubInfoChanged() throws Exception {
+ createMonitor(1);
+
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+ makeFakeActiveSubIds(0);
+ mExecutor.execute(() -> mSubChangedListener.onSubscriptionsChanged());
+ processAllMessages();
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
+ verify(mCallback, times(1)).onRemoved();
+ }
+
+ @Test
+ @SmallTest
+ public void testCallbackRemovedWhenDmaChanged() throws Exception {
+ createMonitor(1);
+
+ boolean result = mRcsProvisioningMonitor.registerRcsProvisioningChangedCallback(
+ FAKE_SUB_ID_BASE, mCallback);
+ updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
+ processAllMessages();
+
+ assertTrue(result);
+ verify(mIImsConfig, times(1)).removeRcsConfigCallback(eq(mCallback));
+ verify(mCallback, times(1)).onRemoved();
+ }
+
private void createMonitor(int subCount) {
if (Looper.myLooper() == null) {
Looper.prepare();
}
makeFakeActiveSubIds(subCount);
- mRcsProvisioningMonitor = new RcsProvisioningMonitor(mPhone, mHandlerThread.getLooper());
+ mRcsProvisioningMonitor = new RcsProvisioningMonitor(mPhone, mHandlerThread.getLooper(),
+ mRoleManager);
mHandler = mRcsProvisioningMonitor.getHandler();
try {
mLooper = new TestableLooper(mHandler.getLooper());
@@ -512,27 +546,12 @@
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(subIds);
}
- private void updateDefaultMessageApplication(String packageName) throws Exception {
+ private void updateDefaultMessageApplication(String packageName) {
List<String> dmas = new ArrayList<>();
dmas.add(packageName);
- when(mIRoleManager.getRoleHoldersAsUser(any(), anyInt())).thenReturn(dmas);
- mExecutor.execute(() -> {
- try {
- mRoleHolderChangedListener.onRoleHoldersChanged(
- RoleManager.ROLE_SMS, UserHandle.USER_ALL);
- } catch (RemoteException e) {
- logd("exception to call onRoleHoldersChanged " + e);
- }
- });
- }
-
- private void replaceService(final String serviceName,
- final IInterface serviceInstance) throws Exception {
- IBinder binder = mock(IBinder.class);
- when(binder.queryLocalInterface(anyString())).thenReturn(serviceInstance);
- Field field = ServiceManager.class.getDeclaredField("sCache");
- field.setAccessible(true);
- ((Map<String, IBinder>) field.get(null)).put(serviceName, binder);
+ when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_SMS))).thenReturn(dmas);
+ mExecutor.execute(() -> mRoleHolderChangedListener.onRoleHoldersChanged(
+ RoleManager.ROLE_SMS, UserHandle.ALL));
}
private void processAllMessages() {