Ensure transactional accounts cannot be call capable.

Similar to self-managed phone accounts, accounts with
CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS should also not be allowed
to have CAPABILITY_CALL_PROVIDER, CAPABILITY_CONNECTION_MANAGER, or
CAPABILITY_SIM_SUBSCRIPTION.

Test: Added new CTS test android.telecom.cts.PhoneAccountOperationsTest#testRegisterPhoneAccountBadCapabilitiesCombo
Fixes: 376936125
Flag: com.android.server.telecom.flags.enforce_transactional_exclusivity
Change-Id: If9f44c41f28ad1069021a95eab546b8bc478d1b4
diff --git a/flags/telecom_non_critical_security_flags.aconfig b/flags/telecom_non_critical_security_flags.aconfig
index 37929a8..e492073 100644
--- a/flags/telecom_non_critical_security_flags.aconfig
+++ b/flags/telecom_non_critical_security_flags.aconfig
@@ -7,4 +7,15 @@
   namespace: "telecom"
   description: "When set, Telecom will unregister accounts if the service is not resolvable"
   bug: "281061708"
+}
+
+# OWNER=tgunn TARGET=25Q2
+flag {
+  name: "enforce_transactional_exclusivity"
+  namespace: "telecom"
+  description: "When set, ensure that transactional accounts cannot also be call capable"
+  bug: "376936125"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
\ No newline at end of file
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index f0423c3..796a62b 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -1284,12 +1284,15 @@
         boolean isNewAccount;
 
         // add self-managed capability for transactional accounts that are missing it
-        if (hasTransactionalCallCapabilities(account) &&
-                !account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
+        if (hasTransactionalCallCapabilities(account)
+                && !account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
             account = account.toBuilder()
                     .setCapabilities(account.getCapabilities()
                             | PhoneAccount.CAPABILITY_SELF_MANAGED)
                     .build();
+            // Note: below we will automatically remove CAPABILITY_CONNECTION_MANAGER,
+            // CAPABILITY_CALL_PROVIDER, and CAPABILITY_SIM_SUBSCRIPTION if this magically becomes
+            // a self-managed phone account here.
         }
 
         PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle());
@@ -1310,6 +1313,12 @@
         if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
             // Turn off bits we don't want to be able to set (TelecomServiceImpl protects against
             // this but we'll also prevent it from happening here, just to be safe).
+            if ((account.getCapabilities() & (PhoneAccount.CAPABILITY_CALL_PROVIDER
+                    | PhoneAccount.CAPABILITY_CONNECTION_MANAGER
+                    | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) > 0) {
+                Log.w(this, "addOrReplacePhoneAccount: attempt to register a "
+                        + "VoIP phone account with call provider/cm/sim sub capabilities.");
+            }
             int newCapabilities = account.getCapabilities() &
                     ~(PhoneAccount.CAPABILITY_CALL_PROVIDER |
                         PhoneAccount.CAPABILITY_CONNECTION_MANAGER |
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index e6a6dd6..602f014 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -882,16 +882,20 @@
                     try {
                         enforcePhoneAccountModificationForPackage(
                                 account.getAccountHandle().getComponentName().getPackageName());
-                        if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
+                        if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
+                                || (mFeatureFlags.enforceTransactionalExclusivity()
+                                && account.hasCapabilities(
+                                PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS))) {
                             enforceRegisterSelfManaged();
                             if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
                                     account.hasCapabilities(
                                             PhoneAccount.CAPABILITY_CONNECTION_MANAGER) ||
                                     account.hasCapabilities(
                                             PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
-                                throw new SecurityException("Self-managed ConnectionServices " +
-                                        "cannot also be call capable, connection managers, or " +
-                                        "SIM accounts.");
+                                throw new SecurityException("Self-managed ConnectionServices and "
+                                        + "transactional voip apps "
+                                        + "cannot also be call capable, connection managers, or "
+                                        + "SIM accounts.");
                             }
 
                             // For self-managed CS, the phone account registrar will override the