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.");