Add self-managed connection service API.
Beginning of required changes to support self-managed CS.
1. Ensure self-managed connections have PROPERTY_SELF_MANAGED set.
2. Plumb through setAudioRoute API from connection.
3. Ensure self-managed phone accounts are auto-enabled.
4. Stub out new TelecomManager APIs.
Test: Manual; cts and unit tests will come in future CLs.
Bug: 34159263
Change-Id: I8352b2e2e3f9424ac1b612280c1b0cdca006afdb
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index d4142fd..1530c0f 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -373,7 +373,6 @@
// Set to true once the NewOutgoingCallIntentBroadcast comes back and is processed.
private boolean mIsNewOutgoingCallIntentBroadcastDone = false;
-
/**
* Indicates whether the call is remotely held. A call is considered remotely held when
* {@link #onConnectionEvent(String)} receives the {@link Connection#EVENT_ON_HOLD_TONE_START}
@@ -382,6 +381,12 @@
private boolean mIsRemotelyHeld = false;
/**
+ * Indicates whether the {@link PhoneAccount} associated with this call is self-managed.
+ * See {@link PhoneAccount#CAPABILITY_SELF_MANAGED} for more information.
+ */
+ private boolean mIsSelfManaged = false;
+
+ /**
* Indicates whether the {@link PhoneAccount} associated with this call supports video calling.
* {@code True} if the phone account supports video calling, {@code false} otherwise.
*/
@@ -934,6 +939,17 @@
return mIsVideoCallingSupported;
}
+ public boolean isSelfManaged() {
+ return mIsSelfManaged;
+ }
+
+ public void setIsSelfManaged(boolean isSelfManaged) {
+ mIsSelfManaged = isSelfManaged;
+
+ // Connection properties will add/remove the PROPERTY_SELF_MANAGED.
+ setConnectionProperties(getConnectionProperties());
+ }
+
private void configureIsWorkCall() {
PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
boolean isWorkCall = false;
@@ -1051,6 +1067,14 @@
void setConnectionProperties(int connectionProperties) {
Log.v(this, "setConnectionProperties: %s", Connection.propertiesToString(
connectionProperties));
+
+ // Ensure the ConnectionService can't change the state of the self-managed property.
+ if (isSelfManaged()) {
+ connectionProperties |= Connection.PROPERTY_SELF_MANAGED;
+ } else {
+ connectionProperties &= ~Connection.PROPERTY_SELF_MANAGED;
+ }
+
if (mConnectionProperties != connectionProperties) {
int previousProperties = mConnectionProperties;
mConnectionProperties = connectionProperties;
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 2aacfab..5d5115b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -694,6 +694,16 @@
false /* isConference */
);
+ // Ensure new calls related to self-managed calls/connections are set as such. This will
+ // be overridden when the actual connection is returned in startCreateConnection, however
+ // doing this now ensures the logs and any other logic will treat this call as self-managed
+ // from the moment it is created.
+ PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
+ phoneAccountHandle);
+ if (phoneAccount != null) {
+ call.setIsSelfManaged(phoneAccount.isSelfManaged());
+ }
+
call.initAnalytics();
if (getForegroundCall() != null) {
getForegroundCall().getAnalytics().setCallIsInterrupted(true);
@@ -782,6 +792,9 @@
boolean isReusedCall = true;
Call call = reuseOutgoingCall(handle);
+ PhoneAccount account =
+ mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
+
// Create a call with original handle. The handle may be changed when the call is attached
// to a connection service, but in most cases will remain the same.
if (call == null) {
@@ -802,6 +815,14 @@
);
call.initAnalytics();
+ // Ensure new calls related to self-managed calls/connections are set as such. This
+ // will be overridden when the actual connection is returned in startCreateConnection,
+ // however doing this now ensures the logs and any other logic will treat this call as
+ // self-managed from the moment it is created.
+ if (account != null) {
+ call.setIsSelfManaged(account.isSelfManaged());
+ }
+
call.setInitiatingUser(initiatingUser);
isReusedCall = false;
@@ -818,9 +839,6 @@
// Also, ensure we don't try to place an outgoing call with video if video is not
// supported.
if (VideoProfile.isVideo(videoState)) {
- PhoneAccount account =
- mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
-
if (call.isEmergencyCall() && account != null &&
!account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
// Phone account doesn't support emergency video calling, so fallback to
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index b30f52d..277a851 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -511,6 +511,22 @@
}
@Override
+ public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, "CSW.sAR");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ logIncoming("setAudioRoute %s %s", callId,
+ CallAudioState.audioRouteToString(audioRoute));
+ mCallsManager.setAudioRoute(audioRoute);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
+
+ @Override
public void setStatusHints(String callId, StatusHints statusHints,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, "CSW.sSH");
@@ -793,7 +809,9 @@
call.getHandle(),
extras,
call.getVideoState(),
- callId),
+ callId,
+ false), // TODO(3pcalls): pass in true/false based on whether ux
+ // should show.
call.shouldAttachToExistingConnection(),
call.isUnknown(),
Log.getExternalSession());
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 213ae06..d536ffb 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -643,9 +643,11 @@
// Set defaults and replace based on the group Id.
maybeReplaceOldAccount(account);
// Reset enabled state to whatever the value was if the account was already registered,
- // or _true_ if this is a SIM-based account. All SIM-based accounts are always enabled.
+ // or _true_ if this is a SIM-based account. All SIM-based accounts are always enabled,
+ // as are all self-managed phone accounts.
account.setIsEnabled(
- isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION));
+ isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+ || account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED));
write();
fireAccountsChanged();
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 9214447..2b03539 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -351,6 +351,9 @@
try {
enforcePhoneAccountModificationForPackage(
account.getAccountHandle().getComponentName().getPackageName());
+ if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
+ enforceRegisterSelfManaged();
+ }
if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
enforceRegisterSimSubscriptionPermission();
}
@@ -1178,6 +1181,51 @@
public Intent createManageBlockedNumbersIntent() {
return BlockedNumbersActivity.getIntentForStartingActivity();
}
+
+ /**
+ * @see android.telecom.TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)
+ */
+ @Override
+ public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+ try {
+ Log.startSession("TSI.iICP");
+ enforcePermission(android.Manifest.permission.MANAGE_OWN_CALLS);
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ // TODO(3pcalls) - Implement body.
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ return true;
+ }
+
+ /**
+ * @see android.telecom.TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)
+ */
+ @Override
+ public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+ try {
+ Log.startSession("TSI.iOCP");
+ enforcePermission(android.Manifest.permission.MANAGE_OWN_CALLS);
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ // TODO(3pcalls) - Implement body.
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+
+ return true;
+ }
};
private Context mContext;
@@ -1351,6 +1399,10 @@
mContext.enforceCallingOrSelfPermission(permission, null);
}
+ private void enforceRegisterSelfManaged() {
+ mContext.enforceCallingPermission(android.Manifest.permission.MANAGE_OWN_CALLS, null);
+ }
+
private void enforceRegisterMultiUser() {
if (!isCallerSystemApp()) {
throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");