Merge "callforwarding: Add checking response NPE"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 39daea8..d75e484 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1447,6 +1447,17 @@
<string name="alert_dialog_no">No</string>
<!-- ECM: ECM exit dialog choice -->
<string name="alert_dialog_dismiss">Dismiss</string>
+ <!-- ECM: Notification body wihout data restriction hint -->
+ <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint">The phone is in emergency callback mode</string>
+ <!-- ECM: Displays the time when ECM will end without data restriction hint, Example: "Until 10:45 AM" -->
+ <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint">Until <xliff:g id="completeTime">%s</xliff:g></string>
+ <!-- ECM: Dialog box message without data restriction hint for exiting from the notifications screen -->
+ <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint">
+ <!-- number of minutes is one -->
+ <item quantity="one">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minute.\nDo you want to exit now?</item>
+ <!-- number of minutes is not equal to one -->
+ <item quantity="other">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minutes.\nDo you want to exit now?</item>
+ </plurals>
<!-- For incoming calls, this is a string we can get from a CDMA network instead of
the actual phone number, to indicate there's no number present. DO NOT TRANSLATE. -->
diff --git a/src/com/android/phone/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index 4541926..5d83de1 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -35,6 +35,7 @@
import android.widget.TextView;
import android.widget.Toast;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
@@ -108,7 +109,7 @@
if (!skipReading) {
// Query call barring status
mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage(
- MyHandler.MESSAGE_GET_CALL_BARRING), 0);
+ MyHandler.MESSAGE_GET_CALL_BARRING), CommandsInterface.SERVICE_CLASS_VOICE);
if (mTcpListener != null) {
mTcpListener.onStarted(this, true);
}
@@ -202,7 +203,8 @@
}
// Send set call barring message to RIL layer.
mPhone.setCallBarring(mFacility, !mIsActivated, password,
- mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0);
+ mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING),
+ CommandsInterface.SERVICE_CLASS_VOICE);
if (mTcpListener != null) {
mTcpListener.onStarted(this, false);
}
@@ -326,7 +328,7 @@
"",
obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING,
ar.exception),
- 0);
+ CommandsInterface.SERVICE_CLASS_VOICE);
}
}
}
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index dcfa024..6edc155 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -300,8 +300,14 @@
return String.format(getResources().getQuantityText(
R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
case EXIT_ECM_DIALOG:
- return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
- minutes).toString(), time);
+ boolean shouldRestrictData = mPhone.getImsPhone() != null
+ && mPhone.getImsPhone().isInImsEcm();
+ return String.format(getResources().getQuantityText(
+ // During IMS ECM, data restriction hint should be removed.
+ shouldRestrictData
+ ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
+ : R.plurals.alert_dialog_exit_ecm,
+ minutes).toString(), time);
}
return null;
}
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index 41d83c4..012a670 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -194,7 +194,11 @@
// Format notification string
String text = null;
if(mInEmergencyCall) {
- text = getText(R.string.phone_in_ecm_call_notification_text).toString();
+ text = getText(
+ // During IMS ECM, data restriction hint should be removed.
+ (imsPhone != null && imsPhone.isInImsEcm())
+ ? R.string.phone_in_ecm_call_notification_text_without_data_restriction_hint
+ : R.string.phone_in_ecm_call_notification_text).toString();
} else {
// Calculate the time in ms when the notification will be finished.
long finishedCountMs = millisUntilFinished + System.currentTimeMillis();
@@ -205,7 +209,11 @@
String completeTime = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
finishedCountMs);
- text = getResources().getString(R.string.phone_in_ecm_notification_complete_time,
+ text = getResources().getString(
+ // During IMS ECM, data restriction hint should be removed.
+ (imsPhone != null && imsPhone.isInImsEcm())
+ ? R.string.phone_in_ecm_notification_complete_time_without_data_restriction_hint
+ : R.string.phone_in_ecm_notification_complete_time,
completeTime);
}
builder.setContentText(text);
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 6b1b5e3..3ea8df2 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -361,8 +361,8 @@
int slotId = phone.getPhoneId();
RcsFeatureController c = mRcsService.getFeatureController(slotId);
if (c == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
- "Cannot find RcsFeatureController instance for sub: " + subId);
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "The requested operation is not supported for subId " + subId);
}
return c;
}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index fe55335..fccceec 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -470,7 +470,7 @@
private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
String dialerPackage = mContext.getSystemService(TelecomManager.class)
- .getDefaultDialerPackage(userHandle.getIdentifier());
+ .getDefaultDialerPackage(userHandle);
return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
.setPackage(dialerPackage);
}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 4eb1788..8e6e7c8 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -35,7 +35,6 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Binder;
@@ -3210,8 +3209,8 @@
@Override
public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
throws RemoteException {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "registerImsRegistrationCallback");
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -3236,8 +3235,8 @@
*/
@Override
public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "unregisterImsRegistrationCallback");
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
@@ -3293,8 +3292,8 @@
*/
@Override
public void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("getImsMmTelRegistrationTransportType");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getImsMmTelRegistrationTransportType");
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"IMS not available on device.");
@@ -3333,8 +3332,8 @@
@Override
public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
throws RemoteException {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "registerMmTelCapabilityCallback");
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"IMS not available on device.");
@@ -3358,8 +3357,8 @@
*/
@Override
public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "unregisterMmTelCapabilityCallback");
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
@@ -3455,8 +3454,8 @@
*/
@Override
public boolean isAdvancedCallingSettingEnabled(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("isAdvancedCallingSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isAdvancedCallingSettingEnabled");
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
final long token = Binder.clearCallingIdentity();
@@ -3492,8 +3491,8 @@
*/
@Override
public boolean isVtSettingEnabled(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("isVtSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVtSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3526,8 +3525,8 @@
*/
@Override
public boolean isVoWiFiSettingEnabled(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("isVoWiFiSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVoWiFiSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3561,8 +3560,8 @@
*/
@Override
public boolean isVoWiFiRoamingSettingEnabled(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("isVoWiFiRoamingSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVoWiFiRoamingSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3613,8 +3612,8 @@
*/
@Override
public int getVoWiFiModeSetting(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("getVoWiFiModeSetting");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getVoWiFiModeSetting");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3695,8 +3694,8 @@
*/
@Override
public boolean isTtyOverVolteEnabled(int subId) {
- //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
- enforceReadPrivilegedPermission("isTtyOverVolteEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isTtyOverVolteEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -7158,33 +7157,6 @@
}
/**
- * Get aggregated video call data usage since boot.
- *
- * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
- * @return Snapshot of video call data usage
- * {@hide}
- */
- @Override
- public NetworkStats getVtDataUsage(int subId, boolean perUidStats) {
- mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_NETWORK_USAGE_HISTORY,
- null);
-
- final long identity = Binder.clearCallingIdentity();
- try {
- // NetworkStatsService keeps tracking the active network interface and identity. It
- // records the delta with the corresponding network identity.
- // We just return the total video call data usage snapshot since boot.
- Phone phone = getPhone(subId);
- if (phone != null) {
- return phone.getVtDataUsage(perUidStats);
- }
- return null;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
* Policy control of data connection. Usually used when data limit is passed.
* @param enabled True if enabling the data, otherwise disabling.
* @param subId Subscription index
@@ -7701,7 +7673,8 @@
@Override
public int getCdmaRoamingMode(int subId) {
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
mApp, subId, "getCdmaRoamingMode");
final long identity = Binder.clearCallingIdentity();
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
index 32badd0..7458195 100644
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -17,6 +17,7 @@
package com.android.services.telephony;
import android.content.Context;
+import android.net.Uri;
import android.os.PersistableBundle;
import android.telecom.Connection;
import android.telecom.PhoneAccountHandle;
@@ -73,6 +74,12 @@
}
@Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+ " for CDMA conference call.");
+ }
+
+ @Override
public void onAnswer(int videoState) {
Log.e(this, new Exception(), "Answer not supported for CDMA conference call.");
}
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index ac3928f..b7ecd48 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -19,13 +19,13 @@
import android.net.Uri;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
-import com.android.telephony.Rlog;
import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import com.android.ims.internal.ConferenceParticipant;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.telephony.Rlog;
/**
* Represents a participant in a conference call.
@@ -215,7 +215,7 @@
sb.append(" connectTime:");
sb.append(getConnectTimeMillis());
sb.append(" connectElapsedTime:");
- sb.append(getConnectElapsedTimeMillis());
+ sb.append(getConnectionStartElapsedRealtimeMillis());
sb.append("]");
return sb.toString();
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index f5f5c66..c11a1ca 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -30,7 +30,6 @@
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
import android.util.Pair;
import com.android.ims.internal.ConferenceParticipant;
@@ -42,6 +41,7 @@
import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -313,10 +313,10 @@
long connectTime = conferenceHost.getOriginalConnection().getConnectTime();
long connectElapsedTime = conferenceHost.getOriginalConnection().getConnectTimeReal();
setConnectionTime(connectTime);
- setConnectionStartElapsedRealTime(connectElapsedTime);
+ setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
// Set the connectTime in the connection as well.
conferenceHost.setConnectTimeMillis(connectTime);
- conferenceHost.setConnectionStartElapsedRealTime(connectElapsedTime);
+ conferenceHost.setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
mTelephonyConnectionService = telephonyConnectionService;
setConferenceHost(conferenceHost);
@@ -374,6 +374,10 @@
Connection.CAPABILITY_CAN_PAUSE_VIDEO,
mConferenceHost.getVideoPauseSupported() && isVideoCapable());
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT,
+ (capabilities & Connection.CAPABILITY_ADD_PARTICIPANT) != 0);
+
return conferenceCapabilities;
}
@@ -522,6 +526,19 @@
}
/**
+ * Supports adding participants to an existing conference call
+ *
+ * @param participants that are pulled to existing conference call
+ */
+ @Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ if (mConferenceHost == null) {
+ return;
+ }
+ mConferenceHost.performAddConferenceParticipants(participants);
+ }
+
+ /**
* Invoked when the conference is answered.
*/
@Override
@@ -741,7 +758,8 @@
setAddress(mConferenceHost.getAddress(), mConferenceHost.getAddressPresentation());
setCallerDisplayName(mConferenceHost.getCallerDisplayName(),
mConferenceHost.getCallerDisplayNamePresentation());
- setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+ setConnectionStartElapsedRealtimeMillis(
+ mConferenceHost.getConnectionStartElapsedRealtimeMillis());
setConnectionTime(mConferenceHost.getConnectTimeMillis());
}
@@ -959,7 +977,8 @@
Log.d(this,
"stopEmulatingSinglePartyCall: restored lone participant connect time");
loneParticipant.setConnectTimeMillis(getConnectionTime());
- loneParticipant.setConnectionStartElapsedRealTime(getConnectionStartElapsedRealTime());
+ loneParticipant.setConnectionStartElapsedRealtimeMillis(
+ getConnectionStartElapsedRealtimeMillis());
}
// Tell Telecom its a conference again.
@@ -999,7 +1018,8 @@
setAddress(entry.getAddress(), entry.getAddressPresentation());
setCallerDisplayName(entry.getCallerDisplayName(),
entry.getCallerDisplayNamePresentation());
- setConnectionStartElapsedRealTime(entry.getConnectElapsedTimeMillis());
+ setConnectionStartElapsedRealtimeMillis(
+ entry.getConnectionStartElapsedRealtimeMillis());
setConnectionTime(entry.getConnectTimeMillis());
mLoneParticipantIdentity = new Pair<>(entry.getUserEntity(), entry.getEndpoint());
@@ -1043,10 +1063,11 @@
!isConferenceHost() /* isRemotelyHosted */);
if (participant.getConnectTime() == 0) {
connection.setConnectTimeMillis(parent.getConnectTimeMillis());
- connection.setConnectionStartElapsedRealTime(parent.getConnectElapsedTimeMillis());
+ connection.setConnectionStartElapsedRealtimeMillis(
+ parent.getConnectionStartElapsedRealtimeMillis());
} else {
connection.setConnectTimeMillis(participant.getConnectTime());
- connection.setConnectionStartElapsedRealTime(participant.getConnectElapsedTime());
+ connection.setConnectionStartElapsedRealtimeMillis(participant.getConnectElapsedTime());
}
// Indicate whether this is an MT or MO call to Telecom; the participant has the cached
// data from the time of merge.
@@ -1212,7 +1233,8 @@
c.updateState();
// Copy the connect time from the conferenceHost
c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
- c.setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+ c.setConnectionStartElapsedRealtimeMillis(
+ mConferenceHost.getConnectionStartElapsedRealtimeMillis());
mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, c);
mTelephonyConnectionService.addConnectionToConferenceController(c);
} // CDMA case not applicable for SRVCC
diff --git a/src/com/android/services/telephony/TelephonyConference.java b/src/com/android/services/telephony/TelephonyConference.java
index d720639..7e4693f 100644
--- a/src/com/android/services/telephony/TelephonyConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -16,6 +16,7 @@
package com.android.services.telephony;
+import android.net.Uri;
import android.telecom.Connection;
import android.telecom.PhoneAccountHandle;
@@ -103,6 +104,12 @@
}
@Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+ " for GSM conference call.");
+ }
+
+ @Override
public void onMerge(Connection connection) {
try {
Phone phone = ((TelephonyConnection) connection).getPhone();
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
old mode 100644
new mode 100755
index 29b65d0..fd9de4f
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -40,7 +40,6 @@
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RilRadioTechnology;
import android.telephony.SubscriptionManager;
@@ -51,6 +50,7 @@
import android.util.Pair;
import com.android.ims.ImsCall;
+import com.android.ims.ImsException;
import com.android.ims.internal.ConferenceParticipant;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
@@ -63,12 +63,14 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
import com.android.phone.ImsUtil;
import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -870,6 +872,11 @@
}
@Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ performAddConferenceParticipants(participants);
+ }
+
+ @Override
public void onAbort() {
Log.v(this, "onAbort");
mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.LOCAL).sendToTarget();
@@ -949,6 +956,58 @@
}
@Override
+ public void onTransfer(Uri number, boolean isConfirmationRequired) {
+ Log.v(this, "onTransfer");
+ if (mOriginalConnection != null) {
+ if (number == null) {
+ Log.w(this, "call transfer uri is null");
+ return;
+ }
+ String scheme = number.getScheme();
+ String transferNumber = "";
+ String uriString = number.getSchemeSpecificPart();
+ if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+ if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
+ Log.w(this, "onTransfer, number scheme is not of type tel instead: "
+ + scheme);
+ return;
+ }
+ if (PhoneNumberUtils.isUriNumber(uriString)) {
+ Log.w(this, "Invalid transfer address. Not a legal PSTN number.");
+ return;
+ }
+ transferNumber = PhoneNumberUtils.convertAndStrip(uriString);
+ if (TextUtils.isEmpty(transferNumber)) {
+ Log.w(this, "Empty transfer number obtained from uri");
+ return;
+ }
+ } else {
+ Log.w(this, "Cannot transfer to voicemail uri");
+ return;
+ }
+
+ try {
+ mOriginalConnection.transfer(transferNumber, isConfirmationRequired);
+ } catch (CallStateException e) {
+ Log.e(this, e, "Failed to transfer call.");
+ }
+ }
+ }
+
+ @Override
+ public void onTransfer(Connection otherConnection) {
+ Log.v(this, "onConsultativeTransfer");
+ if (mOriginalConnection != null && (otherConnection instanceof TelephonyConnection)) {
+ try {
+ mOriginalConnection.consultativeTransfer(
+ ((TelephonyConnection) otherConnection).getOriginalConnection());
+ } catch (CallStateException e) {
+ Log.e(this, e, "Failed to transfer call.");
+ }
+ }
+ }
+
+ @Override
public void onPostDialContinue(boolean proceed) {
Log.v(this, "onPostDialContinue, proceed: " + proceed);
if (mOriginalConnection != null) {
@@ -1120,6 +1179,29 @@
}
}
+ private String[] getAddConferenceParticipants(List<Uri> participants) {
+ String[] addConfParticipants = new String[participants.size()];
+ int i = 0;
+ for (Uri participant : participants) {
+ addConfParticipants[i] = participant.getSchemeSpecificPart();
+ i++;
+ }
+ return addConfParticipants;
+ }
+
+ public void performAddConferenceParticipants(List<Uri> participants) {
+ Log.v(this, "performAddConferenceParticipants");
+ if (mOriginalConnection.getCall() instanceof ImsPhoneCall) {
+ ImsPhoneCall imsPhoneCall = (ImsPhoneCall)mOriginalConnection.getCall();
+ try {
+ imsPhoneCall.getImsCall().inviteParticipants(
+ getAddConferenceParticipants(participants));
+ } catch(ImsException e) {
+ Log.e(this, e, "failed to add conference participants");
+ }
+ }
+ }
+
/**
* Builds connection capabilities common to all TelephonyConnections. Namely, apply IMS-based
* capabilities.
@@ -1154,6 +1236,12 @@
newCapabilities = changeBitmask(newCapabilities, CAPABILITY_SUPPORT_DEFLECT,
isImsConnection() && canDeflectImsCalls());
+ newCapabilities = applyAddParticipantCapabilities(newCapabilities);
+ newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER_CONSULTATIVE,
+ isImsConnection() && canConsultativeTransfer());
+ newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER,
+ isImsConnection() && canTransferToNumber());
+
if (getConnectionCapabilities() != newCapabilities) {
setConnectionCapabilities(newCapabilities);
notifyConnectionCapabilitiesChanged(newCapabilities);
@@ -1186,7 +1274,7 @@
isExternalConnection());
newProperties = changeBitmask(newProperties, PROPERTY_HAS_CDMA_VOICE_PRIVACY,
mIsCdmaVoicePrivacyEnabled);
- newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING_USED,
+ newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING,
mIsUsingAssistedDialing);
newProperties = changeBitmask(newProperties, PROPERTY_IS_RTT, isRtt());
newProperties = changeBitmask(newProperties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
@@ -1580,6 +1668,75 @@
|| !VideoProfile.isVideo(getVideoState()));
}
+ private boolean isConferenceHosted() {
+ boolean isHosted = false;
+ if (getTelephonyConnectionService() != null) {
+ for (Conference current : getTelephonyConnectionService().getAllConferences()) {
+ if (current instanceof ImsConference) {
+ ImsConference other = (ImsConference) current;
+ if (getState() == current.getState()) {
+ continue;
+ }
+ if (other.isConferenceHost()) {
+ isHosted = true;
+ break;
+ }
+ }
+ }
+ }
+ return isHosted;
+ }
+
+ private boolean isAddParticipantCapable() {
+ // not add participant capable for non ims phones
+ if (getPhone() == null || getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
+ return false;
+ }
+
+ if (!getCarrierConfig()
+ .getBoolean(CarrierConfigManager.KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL)) {
+ return false;
+ }
+
+ boolean isCapable = !mTreatAsEmergencyCall && (mConnectionState == Call.State.ACTIVE ||
+ mConnectionState == Call.State.HOLDING);
+
+ // add participant capable if current connection is a host connection or
+ // if conference is not hosted on the device
+ isCapable = isCapable && ((mOriginalConnection != null &&
+ mOriginalConnection.isConferenceHost()) ||
+ !isConferenceHosted());
+
+ /**
+ * For individual IMS calls, if the extra for remote conference support is
+ * - indicated, then consider the same for add participant capability
+ * - not indicated, then the add participant capability is same as before.
+ */
+ if (isCapable && (mOriginalConnection != null) && !mIsMultiParty) {
+ isCapable = mOriginalConnectionExtras.getBoolean(
+ ImsCallProfile.EXTRA_CONFERENCE_AVAIL, isCapable);
+ }
+ return isCapable;
+ }
+
+ /**
+ * Applies the add participant capabilities to the {@code CallCapabilities} bit-mask.
+ *
+ * @param callCapabilities The {@code CallCapabilities} bit-mask.
+ * @return The capabilities with the add participant capabilities applied.
+ */
+ private int applyAddParticipantCapabilities(int callCapabilities) {
+ int currentCapabilities = callCapabilities;
+ if (isAddParticipantCapable()) {
+ currentCapabilities = changeBitmask(currentCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT, true);
+ } else {
+ currentCapabilities = changeBitmask(currentCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT, false);
+ }
+ return currentCapabilities;
+ }
+
@VisibleForTesting
public PersistableBundle getCarrierConfig() {
Phone phone = getPhone();
@@ -1600,6 +1757,50 @@
return false;
}
+ private boolean isCallTransferSupported() {
+ PersistableBundle b = getCarrierConfig();
+ // Return false if the CarrierConfig is unavailable
+ if (b != null) {
+ return b.getBoolean(CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
+ }
+ return false;
+ }
+
+ private boolean canTransfer(TelephonyConnection c) {
+ com.android.internal.telephony.Connection connection = c.getOriginalConnection();
+ return (connection != null && !connection.isMultiparty()
+ && (c.getState() == STATE_ACTIVE || c.getState() == STATE_HOLDING));
+ }
+
+ private boolean canTransferToNumber() {
+ if (!isCallTransferSupported()) {
+ return false;
+ }
+ return canTransfer(this);
+ }
+
+ private boolean canConsultativeTransfer() {
+ if (!isCallTransferSupported()) {
+ return false;
+ }
+ if (!canTransfer(this)) {
+ return false;
+ }
+ boolean canConsultativeTransfer = false;
+ if (getTelephonyConnectionService() != null) {
+ for (Connection current : getTelephonyConnectionService().getAllConnections()) {
+ if (current != this && current instanceof TelephonyConnection) {
+ TelephonyConnection other = (TelephonyConnection) current;
+ if (canTransfer(other)) {
+ canConsultativeTransfer = true;
+ break;
+ }
+ }
+ }
+ }
+ return canConsultativeTransfer;
+ }
+
/**
* Determines if the device will respect the value of the
* {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.
@@ -1842,6 +2043,12 @@
// Ensure extras are propagated to Telecom.
putTelephonyExtras(mOriginalConnectionExtras);
+ // If extras contain Conference support information,
+ // then ensure capabilities are updated.
+ if (mOriginalConnectionExtras.containsKey(
+ ImsCallProfile.EXTRA_CONFERENCE_AVAIL)) {
+ updateConnectionCapabilities();
+ }
} else {
Log.d(this, "Extras update not required");
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 73ea98d..c5eff69 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1706,7 +1706,7 @@
return true;
}
return cfgManager.getConfigForSubId(phone.getSubId()).getBoolean(
- CarrierConfigManager.KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
+ CarrierConfigManager.KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
}
private boolean shouldHoldForEmergencyCall(Phone phone) {
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index f451e9b..5094c57 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -125,7 +125,7 @@
public void connectionReady(RcsFeatureManager manager)
throws com.android.ims.ImsException {
if (manager == null) {
- Log.w(LOG_TAG, "connectionReady returned null RcsFeatureManager");
+ logw("connectionReady returned null RcsFeatureManager");
return;
}
try {
@@ -192,6 +192,7 @@
*/
public void connect() {
synchronized (mLock) {
+ if (mFeatureConnector != null) return;
mFeatureConnector = mFeatureFactory.create(mContext, mSlotId, mFeatureConnectorListener,
mContext.getMainExecutor(), LOG_TAG);
mFeatureConnector.connect();
@@ -224,6 +225,25 @@
}
/**
+ * Removes the feature associated with this class.
+ */
+ public <T> void removeFeature(Class<T> clazz) {
+ synchronized (mLock) {
+ RcsFeatureController.Feature feature = mFeatures.remove(clazz);
+ feature.onDestroy();
+ }
+ }
+
+ /**
+ * @return true if this controller has features it is actively tracking.
+ */
+ public boolean hasActiveFeatures() {
+ synchronized (mLock) {
+ return mFeatures.size() > 0;
+ }
+ }
+
+ /**
* Update the subscription associated with this controller.
*/
public void updateAssociatedSubscription(int newSubId) {
@@ -247,7 +267,10 @@
*/
public void destroy() {
synchronized (mLock) {
- mFeatureConnector.disconnect();
+ Log.i(LOG_TAG, "destroy: slotId=" + mSlotId);
+ if (mFeatureConnector != null) {
+ mFeatureConnector.disconnect();
+ }
for (Feature c : mFeatures.values()) {
c.onRcsDisconnected();
c.onDestroy();
@@ -406,4 +429,15 @@
pw.println(mFeatureManager != null);
}
}
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder sb = new StringBuilder("[");
+ sb.append(mSlotId);
+ sb.append("] ");
+ return sb;
+ }
}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index b4223d3..c85e9a9 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -28,6 +28,7 @@
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConfigurationManager;
@@ -35,8 +36,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* Singleton service setup to manage RCS related services that the platform provides such as User
@@ -85,8 +84,8 @@
private final Object mLock = new Object();
private int mNumSlots;
- // Index corresponds to the slot ID.
- private List<RcsFeatureController> mFeatureControllers;
+ // Maps slot ID -> RcsFeatureController.
+ private SparseArray<RcsFeatureController> mFeatureControllers;
private BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() {
@Override
@@ -99,8 +98,10 @@
if (bundle == null) {
return;
}
- int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX);
- int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX);
+ int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX,
+ SubscriptionManager.INVALID_PHONE_INDEX);
+ int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
updateFeatureControllerSubscription(slotId, subId);
}
}
@@ -125,10 +126,9 @@
});
public TelephonyRcsService(Context context, int numSlots) {
- Log.i(LOG_TAG, "initialize");
mContext = context;
mNumSlots = numSlots;
- mFeatureControllers = new ArrayList<>(numSlots);
+ mFeatureControllers = new SparseArray<>(numSlots);
}
/**
@@ -145,11 +145,7 @@
* system callbacks.
*/
public void initialize() {
- synchronized (mLock) {
- for (int i = 0; i < mNumSlots; i++) {
- mFeatureControllers.add(constructFeatureController(i));
- }
- }
+ updateFeatureControllerSize(mNumSlots);
PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
HANDLER_MSIM_CONFIGURATION_CHANGE, null);
@@ -173,15 +169,24 @@
if (oldNumSlots == newNumSlots) {
return;
}
+ Log.i(LOG_TAG, "updateFeatureControllers: oldSlots=" + oldNumSlots + ", newNumSlots="
+ + newNumSlots);
mNumSlots = newNumSlots;
if (oldNumSlots < newNumSlots) {
for (int i = oldNumSlots; i < newNumSlots; i++) {
- mFeatureControllers.add(constructFeatureController(i));
+ RcsFeatureController c = constructFeatureController(i);
+ // Do not add feature controllers for inactive subscriptions
+ if (c.hasActiveFeatures()) {
+ mFeatureControllers.put(i, c);
+ }
}
} else {
for (int i = (oldNumSlots - 1); i > (newNumSlots - 1); i--) {
- RcsFeatureController controller = mFeatureControllers.remove(i);
- controller.destroy();
+ RcsFeatureController c = mFeatureControllers.get(i);
+ if (c != null) {
+ mFeatureControllers.remove(i);
+ c.destroy();
+ }
}
}
}
@@ -190,24 +195,62 @@
private void updateFeatureControllerSubscription(int slotId, int newSubId) {
synchronized (mLock) {
RcsFeatureController f = mFeatureControllers.get(slotId);
- if (f == null) {
- Log.w(LOG_TAG, "unexpected null FeatureContainer for slot " + slotId);
- return;
+ Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId + " newSubId="
+ + newSubId + ", existing feature=" + (f != null));
+ if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+ if (f == null) {
+ // A controller doesn't exist for this slot yet.
+ f = mFeatureFactory.createController(mContext, slotId);
+ updateSupportedFeatures(f, slotId, newSubId);
+ if (f.hasActiveFeatures()) mFeatureControllers.put(slotId, f);
+ } else {
+ updateSupportedFeatures(f, slotId, newSubId);
+ // Do not keep an empty container around.
+ if (!f.hasActiveFeatures()) {
+ f.destroy();
+ mFeatureControllers.remove(slotId);
+ }
+ }
}
- f.updateAssociatedSubscription(newSubId);
+ if (f != null) f.updateAssociatedSubscription(newSubId);
}
}
private RcsFeatureController constructFeatureController(int slotId) {
RcsFeatureController c = mFeatureFactory.createController(mContext, slotId);
- // TODO: integrate user setting into whether or not this feature is added as well as logic
- // to listen for changes in user setting.
- c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId,
- getSubscriptionFromSlot(slotId)), UserCapabilityExchangeImpl.class);
- c.connect();
+ int subId = getSubscriptionFromSlot(slotId);
+ updateSupportedFeatures(c, slotId, subId);
return c;
}
+ private void updateSupportedFeatures(RcsFeatureController c, int slotId, int subId) {
+ if (doesSubscriptionSupportPresence(subId)) {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) == null) {
+ c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId, subId),
+ UserCapabilityExchangeImpl.class);
+ }
+ } else {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) != null) {
+ c.removeFeature(UserCapabilityExchangeImpl.class);
+ }
+ }
+ // Only start the connection procedure if we have active features.
+ if (c.hasActiveFeatures()) c.connect();
+ }
+
+ private boolean doesSubscriptionSupportPresence(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+ CarrierConfigManager carrierConfigManager =
+ mContext.getSystemService(CarrierConfigManager.class);
+ if (carrierConfigManager == null) return false;
+ boolean supportsUce = carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+ supportsUce |= carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL);
+ return supportsUce;
+ }
+
+
private int getSubscriptionFromSlot(int slotId) {
SubscriptionManager manager = mContext.getSystemService(SubscriptionManager.class);
if (manager == null) {
@@ -229,7 +272,8 @@
pw.println("RcsFeatureControllers:");
pw.increaseIndent();
synchronized (mLock) {
- for (RcsFeatureController f : mFeatureControllers) {
+ for (int i = 0; i < mNumSlots; i++) {
+ RcsFeatureController f = mFeatureControllers.get(i);
pw.increaseIndent();
f.dump(fd, printWriter, args);
pw.decreaseIndent();
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
index 7521205..d488dff 100644
--- a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
+++ b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
@@ -44,7 +44,7 @@
public class UserCapabilityExchangeImpl implements RcsFeatureController.Feature, SubscribePublisher,
PresencePublisher {
- private static final String LOG_TAG = "UserCapabilityExchangeImpl";
+ private static final String LOG_TAG = "RcsUceImpl";
private int mSlotId;
private int mSubId;
@@ -58,6 +58,7 @@
UserCapabilityExchangeImpl(Context context, int slotId, int subId) {
mSlotId = slotId;
mSubId = subId;
+ logi("created");
String[] volteError = context.getResources().getStringArray(
R.array.config_volte_provision_error_on_publish_response);
@@ -78,7 +79,7 @@
// Runs on main thread.
@Override
public void onRcsConnected(RcsFeatureManager rcsFeatureManager) {
- Log.i(LOG_TAG, "onRcsConnected: slotId=" + mSlotId + ", subId=" + mSubId);
+ logi("onRcsConnected");
mPresencePublication.updatePresencePublisher(this);
mPresenceSubscriber.updatePresenceSubscriber(this);
}
@@ -86,7 +87,7 @@
// Runs on main thread.
@Override
public void onRcsDisconnected() {
- Log.i(LOG_TAG, "onRcsDisconnected: phoneId=" + mSlotId + ", subId=" + mSubId);
+ logi("onRcsDisconnected");
mPresencePublication.removePresencePublisher();
mPresenceSubscriber.removePresenceSubscriber();
}
@@ -127,7 +128,7 @@
new ContactCapabilityResponse() {
@Override
public void onSuccess(int reqId) {
- Log.i(LOG_TAG, "onSuccess called for reqId:" + reqId);
+ logi("onSuccess called for reqId:" + reqId);
}
@Override
@@ -137,16 +138,16 @@
if (c != null) {
c.onError(toUceError(resultCode));
} else {
- Log.w(LOG_TAG, "onError called for unknown reqId:" + reqId);
+ logw("onError called for unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
@Override
public void onFinish(int reqId) {
- Log.i(LOG_TAG, "onFinish called for reqId:" + reqId);
+ logi("onFinish called for reqId:" + reqId);
}
@Override
@@ -156,10 +157,10 @@
if (c != null) {
c.onError(RcsUceAdapter.ERROR_REQUEST_TIMEOUT);
} else {
- Log.w(LOG_TAG, "onTimeout called for unknown reqId:" + reqId);
+ logw("onTimeout called for unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
@@ -172,10 +173,10 @@
if (c != null) {
c.onCapabilitiesReceived(contactCapabilities);
} else {
- Log.w(LOG_TAG, "onCapabilitiesUpdated, unknown reqId:" + reqId);
+ logw("onCapabilitiesUpdated, unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.w(LOG_TAG, "onCapabilitiesUpdated on dead service");
+ logw("onCapabilitiesUpdated on dead service");
}
}
});
@@ -184,7 +185,7 @@
c.onError(toUceError(taskId));
return;
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
mPendingCapabilityRequests.put(taskId, c);
@@ -272,4 +273,21 @@
return RcsUceAdapter.ERROR_GENERIC_FAILURE;
}
}
+
+ private void logi(String log) {
+ Log.i(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(mSlotId);
+ builder.append("->");
+ builder.append(mSubId);
+ builder.append("] ");
+ return builder;
+ }
}
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
index cfede94..fbb270d 100644
--- a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -107,7 +107,7 @@
}
@Test
- public void testFeatureManagerConnectedAddFeature() throws Exception {
+ public void testFeatureManagerConnectedAddRemoveFeature() throws Exception {
RcsFeatureController controller = createFeatureController();
// Connect the RcsFeatureManager
mConnectorListener.getValue().connectionReady(mFeatureManager);
@@ -115,6 +115,10 @@
verify(mMockFeature).onRcsConnected(mFeatureManager);
assertEquals(mMockFeature, controller.getFeature(RcsFeatureController.Feature.class));
+
+ controller.removeFeature(RcsFeatureController.Feature.class);
+ verify(mMockFeature).onDestroy();
+ assertNull(controller.getFeature(RcsFeatureController.Feature.class));
}
@Test
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
index 68b08a7..cfb68b7 100644
--- a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -21,16 +21,21 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.BroadcastReceiver;
import android.content.Intent;
+import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
import org.junit.After;
import org.junit.Before;
@@ -45,20 +50,31 @@
@Captor ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
@Mock TelephonyRcsService.FeatureFactory mFeatureFactory;
- @Mock RcsFeatureController mFeatureControllerSlot0;
- @Mock RcsFeatureController mFeatureControllerSlot1;
@Mock UserCapabilityExchangeImpl mMockUceSlot0;
@Mock UserCapabilityExchangeImpl mMockUceSlot1;
+ @Mock RcsFeatureController.RegistrationHelperFactory mRegistrationFactory;
+ @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureConnectorFactory;
+ @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+
+ private RcsFeatureController mFeatureControllerSlot0;
+ private RcsFeatureController mFeatureControllerSlot1;
@Before
public void setUp() throws Exception {
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));
doReturn(mMockUceSlot0).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(0),
anyInt());
doReturn(mMockUceSlot1).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(1),
anyInt());
+ //set up default slot-> sub ID mappings.
+ setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
+ setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
}
@After
@@ -67,14 +83,46 @@
}
@Test
- public void testUserCapabilityExchangeConnected() {
+ public void testUserCapabilityExchangePresenceConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
createRcsService(1 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0).connect();
}
@Test
+ public void testUserCapabilityExchangeOptionsConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabled() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabledCarrierConfigChanged() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+
+ sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(anyInt());
+ }
+
+
+ @Test
public void testSlotUpdates() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
TelephonyRcsService service = createRcsService(1 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0).connect();
@@ -94,8 +142,7 @@
verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0, times(1)).connect();
- verify(mFeatureControllerSlot1, times(1)).addFeature(mMockUceSlot1,
- UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot1, times(1)).connect();
// Remove a slot.
@@ -116,6 +163,7 @@
@Test
public void testCarrierConfigUpdate() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
createRcsService(2 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
@@ -132,6 +180,37 @@
verify(mFeatureControllerSlot1, times(1)).updateAssociatedSubscription(2);
}
+ @Test
+ public void testCarrierConfigUpdateUceToNoUce() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).removeFeature(UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
+ @Test
+ public void testCarrierConfigUpdateNoUceToUce() {
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
private void sendCarrierConfigChanged(int slotId, int subId) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, slotId);
@@ -139,6 +218,18 @@
mReceiverCaptor.getValue().onReceive(mContext, intent);
}
+ private void setCarrierConfig(String key, boolean value) {
+ PersistableBundle bundle = mContext.getCarrierConfig();
+ bundle.putBoolean(key, value);
+ }
+
+ private void setSlotToSubIdMapping(int slotId, int loadedSubId) {
+ SubscriptionManager m = mContext.getSystemService(SubscriptionManager.class);
+ int [] subIds = new int[1];
+ subIds[0] = loadedSubId;
+ doReturn(subIds).when(m).getSubscriptionIds(eq(slotId));
+ }
+
private TelephonyRcsService createRcsService(int numSlots) {
TelephonyRcsService service = new TelephonyRcsService(mContext, numSlots);
service.setFeatureFactory(mFeatureFactory);
@@ -146,4 +237,13 @@
verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
return service;
}
+
+ private RcsFeatureController createFeatureController(int slotId) {
+ // Create a spy instead of a mock because TelephonyRcsService relies on state provided by
+ // RcsFeatureController.
+ RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId,
+ mRegistrationFactory));
+ controller.setFeatureConnectorFactory(mFeatureConnectorFactory);
+ return controller;
+ }
}