Merge "Revert^2 "Hearing Aid: Connect route when right HA is connected first"" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 28c85e1..c6f5e9c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -318,18 +318,6 @@
              android:exported="false"
              android:process=":ui"/>
 
-        <service android:name=".components.BluetoothPhoneService"
-             android:singleUser="true"
-             android:process="system"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.bluetooth.IBluetoothHeadsetPhone"/>
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.bluetooth.IBluetoothLeCallControlCallback" />
-            </intent-filter>
-        </service>
-
         <service android:name=".components.TelecomService"
              android:singleUser="true"
              android:process="system"
diff --git a/flags/Android.bp b/flags/Android.bp
index 7e2b31d..6fa147a 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -29,10 +29,13 @@
       "telecom_incallservice_flags.aconfig",
       "telecom_default_phone_account_flags.aconfig",
       "telecom_callaudioroutestatemachine_flags.aconfig",
+      "telecom_calls_manager_flags.aconfig",
       "telecom_anomaly_report_flags.aconfig",
       "telecom_callaudiomodestatemachine_flags.aconfig",
       "telecom_calllog_flags.aconfig",
-      "telecom_resolve_hidden_dependencies.aconfig"
+      "telecom_resolve_hidden_dependencies.aconfig",
+      "telecom_bluetoothroutemanager_flags.aconfig",
+      "telecom_work_profile_flags.aconfig"
     ],
 }
 
diff --git a/flags/telecom_bluetoothroutemanager_flags.aconfig b/flags/telecom_bluetoothroutemanager_flags.aconfig
new file mode 100644
index 0000000..ddd8571
--- /dev/null
+++ b/flags/telecom_bluetoothroutemanager_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.telecom.flags"
+
+flag {
+  name: "use_actual_address_to_enter_connecting_state"
+  namespace: "telecom"
+  description: "Fix bugs that may add bluetooth device with null address."
+  bug: "306113816"
+}
+
diff --git a/flags/telecom_callaudioroutestatemachine_flags.aconfig b/flags/telecom_callaudioroutestatemachine_flags.aconfig
index b0f14a4..6f2c7fc 100644
--- a/flags/telecom_callaudioroutestatemachine_flags.aconfig
+++ b/flags/telecom_callaudioroutestatemachine_flags.aconfig
@@ -40,4 +40,25 @@
   namespace: "telecom"
   description: "Refactor call audio set/clear communication device and include unsupported routes."
   bug: "308968392"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "communication_device_protected_by_lock"
+  namespace: "telecom"
+  description: "Protect set/clear communication device operation with lock to avoid race condition."
+  bug: "303001133"
+}
+
+flag {
+  name: "reset_mute_when_entering_quiescent_bt_route"
+  namespace: "telecom"
+  description: "Reset mute state when entering quiescent bluetooth route."
+  bug: "311313250"
+}
+
+flag {
+  name: "update_route_mask_when_bt_connected"
+  namespace: "telecom"
+  description: "Update supported route mask when Bluetooth devices audio connected."
+  bug: "301695370"
+}
diff --git a/flags/telecom_calllog_flags.aconfig b/flags/telecom_calllog_flags.aconfig
index 075e1f3..3ce7b63 100644
--- a/flags/telecom_calllog_flags.aconfig
+++ b/flags/telecom_calllog_flags.aconfig
@@ -5,4 +5,11 @@
   namespace: "telecom"
   description: "log external call if current device is a wearable one"
   bug: "292600751"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "telecom_skip_log_based_on_extra"
+  namespace: "telecom"
+  description: "skipping logging a call based on passed extra"
+  bug: "295530944"
+}
diff --git a/flags/telecom_calls_manager_flags.aconfig b/flags/telecom_calls_manager_flags.aconfig
new file mode 100644
index 0000000..1a19480
--- /dev/null
+++ b/flags/telecom_calls_manager_flags.aconfig
@@ -0,0 +1,15 @@
+package: "com.android.server.telecom.flags"
+
+flag {
+  name: "use_improved_listener_order"
+  namespace: "telecom"
+  description: "Make InCallController the first listener to trigger"
+  bug: "24244713"
+}
+
+flag {
+  name: "fix_audio_flicker_for_outgoing_calls"
+  namespace: "telecom"
+  description: "This fix ensures the MO calls won't switch from Active to Quite b/c setDialing was not called"
+  bug: "309540769"
+}
diff --git a/flags/telecom_work_profile_flags.aconfig b/flags/telecom_work_profile_flags.aconfig
new file mode 100644
index 0000000..cc78b30
--- /dev/null
+++ b/flags/telecom_work_profile_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.telecom.flags"
+
+flag {
+  name: "work_profile_associated_user"
+  namespace: "telecom"
+  description: "Redefines the associated user for calls in the context of work profile support (U+)"
+  bug: "294699269"
+}
\ No newline at end of file
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index fff7257..4eead66 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -73,7 +73,7 @@
     <string name="non_primary_user" msgid="315564589279622098">"Det er kun ejeren af en enhed, der kan se og administrere blokerede numre."</string>
     <string name="delete_icon_description" msgid="5335959254954774373">"Fjern blokering"</string>
     <string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"Blokering er midlertidigt slået fra"</string>
-    <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Når du har ringet eller sendt en sms-besked til alarmcentralen, bliver blokering slået fra for at sikre, at alarmcentralen kan komme i kontakt med dig."</string>
+    <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Når du har ringet eller sendt en besked til alarmcentralen, bliver blokering slået fra for at sikre, at alarmcentralen kan komme i kontakt med dig."</string>
     <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Genaktiver nu"</string>
     <string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> blev blokeret"</string>
     <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Blokeringen af <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> blev ophævet"</string>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 6e4dc3c..7ef2a12 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -72,6 +73,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.IVideoProvider;
 import com.android.internal.util.Preconditions;
+import com.android.server.telecom.flags.FeatureFlags;
 import com.android.server.telecom.stats.CallFailureCause;
 import com.android.server.telecom.stats.CallStateChangedAtomWriter;
 import com.android.server.telecom.ui.ToastFactory;
@@ -324,6 +326,7 @@
                 }
             };
 
+    private final boolean mIsModifyStatePermissionGranted;
     /**
      * One of CALL_DIRECTION_INCOMING, CALL_DIRECTION_OUTGOING, or CALL_DIRECTION_UNKNOWN
      */
@@ -786,6 +789,8 @@
      */
     private CompletableFuture<Boolean> mDisconnectFuture;
 
+    private FeatureFlags mFlags;
+
     /**
      * Persists the specified parameters and initializes the new instance.
      * @param context The context.
@@ -817,11 +822,12 @@
             boolean shouldAttachToExistingConnection,
             boolean isConference,
             ClockProxy clockProxy,
-            ToastFactory toastFactory) {
+            ToastFactory toastFactory,
+            FeatureFlags featureFlags) {
         this(callId, context, callsManager, lock, repository, phoneNumberUtilsAdapter,
                handle, null, gatewayInfo, connectionManagerPhoneAccountHandle,
                targetPhoneAccountHandle, callDirection, shouldAttachToExistingConnection,
-               isConference, clockProxy, toastFactory);
+               isConference, clockProxy, toastFactory, featureFlags);
 
     }
 
@@ -841,8 +847,10 @@
             boolean shouldAttachToExistingConnection,
             boolean isConference,
             ClockProxy clockProxy,
-            ToastFactory toastFactory) {
+            ToastFactory toastFactory,
+            FeatureFlags featureFlags) {
 
+        mFlags = featureFlags;
         mId = callId;
         mConnectionId = callId;
         mState = (isConference && callDirection != CALL_DIRECTION_INCOMING &&
@@ -873,6 +881,8 @@
         mStartRingTime = 0;
 
         mCallStateChangedAtomWriter.setExistingCallCount(callsManager.getCalls().size());
+        mIsModifyStatePermissionGranted =
+                isModifyPhoneStatePermissionGranted(getDelegatePhoneAccountHandle());
     }
 
     /**
@@ -892,6 +902,7 @@
      * connection, regardless of whether it's incoming or outgoing.
      * @param connectTimeMillis The connection time of the call.
      * @param clockProxy
+     * @param featureFlags The telecom feature flags.
      */
     Call(
             String callId,
@@ -910,11 +921,13 @@
             long connectTimeMillis,
             long connectElapsedTimeMillis,
             ClockProxy clockProxy,
-            ToastFactory toastFactory) {
+            ToastFactory toastFactory,
+            FeatureFlags featureFlags) {
         this(callId, context, callsManager, lock, repository,
                 phoneNumberUtilsAdapter, handle, gatewayInfo,
                 connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection,
-                shouldAttachToExistingConnection, isConference, clockProxy, toastFactory);
+                shouldAttachToExistingConnection, isConference, clockProxy, toastFactory,
+                featureFlags);
 
         mConnectTimeMillis = connectTimeMillis;
         mConnectElapsedTimeMillis = connectElapsedTimeMillis;
@@ -1766,8 +1779,12 @@
                     accountHandle.getComponentName().getPackageName(),
                     mContext.getPackageManager());
             // Set the associated user for the call for MT calls based on the target phone account.
-            if (isIncoming() && !accountHandle.getUserHandle().equals(mAssociatedUser)) {
-                setAssociatedUser(accountHandle.getUserHandle());
+            UserHandle associatedUser = UserUtil.getAssociatedUserForCall(
+                    mFlags.workProfileAssociatedUser(),
+                    mCallsManager.getPhoneAccountRegistrar(), mCallsManager.getCurrentUserHandle(),
+                    accountHandle);
+            if (isIncoming() && !associatedUser.equals(mAssociatedUser)) {
+                setAssociatedUser(associatedUser);
             }
         }
     }
@@ -3098,6 +3115,12 @@
                     Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE));
         }
 
+        if (mExtras.containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL)) {
+            if (source != SOURCE_CONNECTION_SERVICE || !mIsModifyStatePermissionGranted) {
+                mExtras.remove(TelecomManager.EXTRA_DO_NOT_LOG_CALL);
+            }
+        }
+
         // If the change originated from an InCallService, notify the connection service.
         if (source == SOURCE_INCALL_SERVICE) {
             Log.addEvent(this, LogUtils.Events.ICS_EXTRAS_CHANGED);
@@ -3112,6 +3135,15 @@
         }
     }
 
+    private boolean isModifyPhoneStatePermissionGranted(PhoneAccountHandle phoneAccountHandle) {
+        if (phoneAccountHandle == null) {
+            return false;
+        }
+        String packageName = phoneAccountHandle.getComponentName().getPackageName();
+        return PackageManager.PERMISSION_GRANTED == mContext.getPackageManager().checkPermission(
+                android.Manifest.permission.MODIFY_PHONE_STATE, packageName);
+    }
+
     /**
      * Removes extras from the extras bundle associated with this {@link Call}.
      *
@@ -4092,7 +4124,7 @@
      * @param associatedUser
      */
     public void setAssociatedUser(UserHandle associatedUser) {
-        Log.i(this, "Setting associated user for call");
+        Log.i(this, "Setting associated user for call: %s", associatedUser);
         Preconditions.checkNotNull(associatedUser);
         mAssociatedUser = associatedUser;
     }
diff --git a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
index 38a96eb..5fc2414 100644
--- a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
+++ b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
@@ -24,10 +24,12 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.flags.Flags;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Semaphore;
 
 /**
  * Helper class used to keep track of the requested communication device within Telecom for audio
@@ -50,6 +52,7 @@
     private int mAudioDeviceType = sAUDIO_DEVICE_TYPE_INVALID;
     // Keep track of the locally requested BT audio device if set
     private String mBtAudioDevice = null;
+    private final Semaphore mLock =  new Semaphore(1);
 
     public CallAudioCommunicationDeviceTracker(Context context) {
         mAudioManager = context.getSystemService(AudioManager.class);
@@ -94,6 +97,9 @@
      */
     public boolean setCommunicationDevice(int audioDeviceType,
             BluetoothDevice btDevice) {
+        if (Flags.communicationDeviceProtectedByLock()) {
+            mLock.tryAcquire();
+        }
         // There is only one audio device type associated with each type of BT device.
         boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType);
         Log.i(this, "setCommunicationDevice: type = %s, isBtDevice = %s, btDevice = %s",
@@ -153,8 +159,16 @@
                 if (audioDeviceType == AudioDeviceInfo.TYPE_BLE_HEADSET) {
                     mBluetoothRouteManager.onAudioOn(mBtAudioDevice);
                 }
+            } else if (Flags.communicationDeviceProtectedByLock()) {
+                // Clear BT device if it's still stored. Handles race condition for when a non-BT
+                // device is set for communication shortly after a BT (LE) device is set for
+                // communication but the selection hasn't been cleared yet.
+                mBtAudioDevice = null;
             }
         }
+        if (Flags.communicationDeviceProtectedByLock()) {
+            mLock.release();
+        }
         return result;
     }
 
@@ -164,6 +178,9 @@
      * @param audioDeviceTypes The supported audio device types for the device.
      */
     public void clearCommunicationDevice(int audioDeviceType) {
+        if (Flags.communicationDeviceProtectedByLock()) {
+            mLock.tryAcquire();
+        }
         // There is only one audio device type associated with each type of BT device.
         boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType);
         Log.i(this, "clearCommunicationDevice: type = %s, isBtDevice = %s",
@@ -195,6 +212,9 @@
             mBluetoothRouteManager.onAudioLost(mBtAudioDevice);
             mBtAudioDevice = null;
         }
+        if (Flags.communicationDeviceProtectedByLock()) {
+            mLock.release();
+        }
     }
 
     private boolean isUsbHeadsetType(int audioDeviceType, int sourceType) {
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index cc5ee05..c0bb50e 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -17,7 +17,6 @@
 package com.android.server.telecom;
 
 
-import android.annotation.FlaggedApi;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
@@ -840,6 +839,9 @@
             if (mFeatureFlags.callAudioCommunicationDeviceRefactor()) {
                 setBluetoothOn(null);
             }
+            if (mFeatureFlags.updateRouteMaskWhenBtConnected()) {
+                mAvailableRoutes |= ROUTE_BLUETOOTH;
+            }
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH,
                     mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(),
                     mBluetoothRouteManager.getConnectedDevices());
@@ -945,7 +947,7 @@
                             mBluetoothRouteManager.disconnectAudio();
                         } else {
                             mBluetoothRouteManager.disconnectAudio();
-                            transitionTo(mQuiescentBluetoothRoute);
+                            reinitialize();
                         }
                         mCallAudioManager.notifyAudioOperationsComplete();
                     } else if (msg.arg1 == RINGING_FOCUS
@@ -1071,6 +1073,9 @@
         public void enter() {
             super.enter();
             mHasUserExplicitlyLeftBluetooth = false;
+            if (mFeatureFlags.resetMuteWhenEnteringQuiescentBtRoute()) {
+                setMuteOn(false);
+            }
             updateInternalCallAudioState();
         }
 
@@ -1839,7 +1844,7 @@
                         AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
             }
         } else {
-            processLegacySpeakerCommunicationDevice(on);
+            speakerOn = processLegacySpeakerCommunicationDevice(on);
         }
         mStatusBarNotifier.notifySpeakerphone(hasAnyCalls && speakerOn);
     }
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index cfa2eb4..fc4e05d 100644
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -170,6 +170,7 @@
      * Call was NOT in the "choose account" phase when disconnected
      * Call is NOT a conference call which had children (unless it was remotely hosted).
      * Call is NOT a child call from a conference which was remotely hosted.
+     * Call has NOT indicated it should be skipped for logging in its extras
      * Call is NOT simulating a single party conference.
      * Call was NOT explicitly canceled, except for disconnecting from a conference.
      * Call is NOT an external call or an external call on watch.
@@ -201,6 +202,11 @@
             return false;
         }
 
+        if (mFeatureFlags.telecomSkipLogBasedOnExtra() && call.getExtras() != null
+                && call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL)) {
+            return false;
+        }
+
         // A child call of a conference which was remotely hosted; these didn't originate on this
         // device and should not be logged.
         if (call.getParentCall() != null && call.hasProperty(Connection.PROPERTY_REMOTELY_HOSTED)) {
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 7fea8e0..5db59c4 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -685,10 +685,15 @@
         mCallStreamingNotification = callStreamingNotification;
         mFeatureFlags = featureFlags;
 
-        mListeners.add(mInCallController);
+        if (mFeatureFlags.useImprovedListenerOrder()) {
+            mListeners.add(mInCallController);
+        }
         mListeners.add(mInCallWakeLockController);
         mListeners.add(statusBarNotifier);
         mListeners.add(mCallLogManager);
+        if (!mFeatureFlags.useImprovedListenerOrder()) {
+            mListeners.add(mInCallController);
+        }
         mListeners.add(mCallEndpointController);
         mListeners.add(mCallDiagnosticServiceController);
         mListeners.add(mCallAudioManager);
@@ -767,6 +772,10 @@
         call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp(
                 call.getAssociatedUser()));
 
+        if (!mFeatureFlags.fixAudioFlickerForOutgoingCalls()) {
+            setCallState(call, callState, "successful outgoing call");
+        }
+
         if (!mCalls.contains(call)) {
             // Call was not added previously in startOutgoingCall due to it being a potential MMI
             // code, so add it now.
@@ -778,11 +787,16 @@
             listener.onConnectionServiceChanged(call, null, call.getConnectionService());
         }
 
-        // Allow the ConnectionService to start the call in the active state. This case is helpful
-        // for conference calls or meetings that can skip the dialing stage.
-        if (callState == CallState.ACTIVE) {
-            setCallState(call, callState, "skipping the dialing state and setting active");
-        } else {
+        if (mFeatureFlags.fixAudioFlickerForOutgoingCalls()) {
+            // Allow the ConnectionService to start the call in the active state. This case is
+            // helpful for conference calls or meetings that can skip the dialing stage.
+            if (callState == CallState.ACTIVE) {
+                setCallState(call, callState, "skipping the dialing state and setting active");
+            } else {
+                markCallAsDialing(call);
+            }
+        }
+        else{
             markCallAsDialing(call);
         }
     }
@@ -1468,7 +1482,8 @@
                 false /* forceAttachToExistingConnection */,
                 isConference, /* isConference */
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
         // 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
@@ -1495,7 +1510,10 @@
                 }
             }
             // Incoming address was set via EXTRA_INCOMING_CALL_ADDRESS above.
-            call.setAssociatedUser(phoneAccountHandle.getUserHandle());
+            UserHandle associatedUser = UserUtil.getAssociatedUserForCall(
+                    mFeatureFlags.workProfileAssociatedUser(),
+                    getPhoneAccountRegistrar(), getCurrentUserHandle(), phoneAccountHandle);
+            call.setAssociatedUser(associatedUser);
         }
 
         if (phoneAccount != null) {
@@ -1615,15 +1633,19 @@
         // Check if the target phone account is possibly in ECBM.
         call.setIsInECBM(getEmergencyCallHelper()
                 .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount()));
-        // If the phone account user profile is paused or the call isn't visible to the secondary/
-        // guest user, reject the non-emergency incoming call. When the current user is the admin,
-        // we need to allow the calls to go through if the work profile isn't paused. We should
-        // always allow emergency calls and also allow non-emergency calls when ECBM is active for
-        // the phone account.
-        if ((mUserManager.isQuietModeEnabled(call.getAssociatedUser())
-                || (!mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier())
-                && !isCallVisibleForUser(call, mCurrentUserHandle)))
-                && !call.isEmergencyCall() && !call.isInECBM()) {
+
+        // Check if call is visible to the current user.
+        boolean isCallHiddenFromProfile = !isCallVisibleForUser(call, mCurrentUserHandle);
+        // For admins, we should check if the work profile is paused in order to reject
+        // the call.
+        if (mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier())) {
+            isCallHiddenFromProfile &= mUserManager.isQuietModeEnabled(
+                call.getAssociatedUser());
+        }
+
+        // We should always allow emergency calls and also allow non-emergency calls when ECBM
+        // is active for the phone account.
+        if (isCallHiddenFromProfile && !call.isEmergencyCall() && !call.isInECBM()) {
             Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.",
                     phoneAccountHandle.getUserHandle());
             call.setMissedReason(USER_MISSED_NOT_RUNNING);
@@ -1696,11 +1718,15 @@
                 true /* forceAttachToExistingConnection */,
                 false, /* isConference */
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
         call.initAnalytics();
 
         // For unknown calls, base the associated user off of the target phone account handle.
-        call.setAssociatedUser(phoneAccountHandle.getUserHandle());
+        UserHandle associatedUser = UserUtil.getAssociatedUserForCall(
+                mFeatureFlags.workProfileAssociatedUser(),
+                getPhoneAccountRegistrar(), getCurrentUserHandle(), phoneAccountHandle);
+        call.setAssociatedUser(associatedUser);
         setIntentExtrasAndStartTime(call, extras);
         call.addListener(this);
         notifyStartCreateConnection(call);
@@ -1814,7 +1840,8 @@
                     false /* forceAttachToExistingConnection */,
                     isConference, /* isConference */
                     mClockProxy,
-                    mToastFactory);
+                    mToastFactory,
+                    mFeatureFlags);
 
             if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) {
                 call.setIsTransactionalCall(true);
@@ -4221,7 +4248,8 @@
                 connectTime,
                 connectElapsedTime,
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
 
         // Unlike connections, conferences are not created first and then notified as create
         // connection complete from the CS.  They originate from the CS and are reported directly to
@@ -4239,7 +4267,10 @@
         call.setStatusHints(parcelableConference.getStatusHints());
         call.putConnectionServiceExtras(parcelableConference.getExtras());
         // For conference calls, set the associated user from the target phone account user handle.
-        call.setAssociatedUser(phoneAccount.getUserHandle());
+        UserHandle associatedUser = UserUtil.getAssociatedUserForCall(
+                mFeatureFlags.workProfileAssociatedUser(), getPhoneAccountRegistrar(),
+                getCurrentUserHandle(), phoneAccount);
+        call.setAssociatedUser(associatedUser);
         // In case this Conference was added via a ConnectionManager, keep track of the original
         // Connection ID as created by the originating ConnectionService.
         Bundle extras = parcelableConference.getExtras();
@@ -5277,7 +5308,8 @@
                 connection.getConnectTimeMillis() /* connectTimeMillis */,
                 connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
 
         call.initAnalytics();
         call.getAnalytics().setCreatedFromExistingConnection(true);
@@ -5292,7 +5324,10 @@
                 connection.getCallerDisplayNamePresentation());
         // For existing connections, use the phone account user handle to determine the user
         // association with the call.
-        call.setAssociatedUser(connection.getPhoneAccount().getUserHandle());
+        UserHandle associatedUser = UserUtil.getAssociatedUserForCall(
+                mFeatureFlags.workProfileAssociatedUser(), getPhoneAccountRegistrar(),
+                getCurrentUserHandle(), connection.getPhoneAccount());
+        call.setAssociatedUser(associatedUser);
         call.addListener(this);
         call.putConnectionServiceExtras(connection.getExtras());
 
@@ -5937,7 +5972,7 @@
                 handoverFromCall.getHandle(), null,
                 null, null,
                 Call.CALL_DIRECTION_OUTGOING, false,
-                false, mClockProxy, mToastFactory);
+                false, mClockProxy, mToastFactory, mFeatureFlags);
         call.initAnalytics();
 
         // Set self-managed and voipAudioMode if destination is self-managed CS
@@ -6144,7 +6179,8 @@
                 false /* forceAttachToExistingConnection */,
                 false, /* isConference */
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
 
         if (fromCall == null || isHandoverInProgress() ||
                 !isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount()) ||
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index c11ee6e..07b048d 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -525,8 +525,6 @@
                         .validateAccountIconUserBoundary(icon, callingUserHandle));
             }
 
-            if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return;
-
             if (parcelableConference.getConnectElapsedTimeMillis() != 0
                     && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
                             != PackageManager.PERMISSION_GRANTED) {
@@ -941,9 +939,6 @@
         public void addExistingConnection(String callId, ParcelableConnection connection,
                 Session.Info sessionInfo) {
             Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation);
-
-            if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return;
-
             UserHandle userHandle = Binder.getCallingUserHandle();
             // Check that the Calling Package matches PhoneAccountHandle's Component Package
             PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount();
@@ -1358,7 +1353,6 @@
     private final CallsManager mCallsManager;
     private final AppOpsManager mAppOpsManager;
     private final Context mContext;
-    public boolean mIsRemoteConnectionService = false;
 
     private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener;
 
@@ -2548,13 +2542,13 @@
     private void logIncoming(String msg, Object... params) {
         // Keep these as debug; the incoming logging is traced on a package level through the
         // session logging.
-        Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]:"
-                + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params);
+        Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+                + msg, params);
     }
 
     private void logOutgoing(String msg, Object... params) {
-        Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]:"
-                + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params);
+        Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+                + msg, params);
     }
 
     private void queryRemoteConnectionServices(final UserHandle userHandle,
@@ -2581,7 +2575,6 @@
             ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
                     handle.getComponentName(), handle.getUserHandle());
             if (service != null && service != this) {
-                service.mIsRemoteConnectionService = true;
                 simServices.add(service);
             } else {
                 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 184eadd..1aee25c 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -82,6 +82,7 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it
@@ -1406,17 +1407,31 @@
     @Override
     public void onCallRemoved(Call call) {
         Log.i(this, "onCallRemoved: %s", call);
-        if (mCallsManager.getCalls().isEmpty()) {
+        // Instead of checking if there are no active calls, we should check if there any calls with
+        // the same associated user returned from getUserFromCall. For instance, it's possible to
+        // have calls coexist on the personal profile and work profile, in which case, we would only
+        // remove the ICS connection for the user associated with the call to be disconnected.
+        UserHandle userFromCall = getUserFromCall(call);
+        Stream<Call> callsAssociatedWithUserFromCall = mCallsManager.getCalls().stream()
+                .filter((c) -> getUserFromCall(c).equals(userFromCall));
+        boolean isCallCountZero = mFeatureFlags.workProfileAssociatedUser()
+                ? callsAssociatedWithUserFromCall.count() == 0
+                : mCallsManager.getCalls().isEmpty();
+        if (isCallCountZero) {
             /** Let's add a 2 second delay before we send unbind to the services to hopefully
              *  give them enough time to process all the pending messages.
              */
             mHandler.postDelayed(new Runnable("ICC.oCR", mLock) {
                 @Override
                 public void loggedRun() {
-                    // Check again to make sure there are no active calls.
-                    if (mCallsManager.getCalls().isEmpty()) {
-                        unbindFromServices(getUserFromCall(call));
-
+                    // Check again to make sure there are no active calls for the associated user.
+                    Stream<Call> callsAssociatedWithUserFromCall = mCallsManager.getCalls().stream()
+                            .filter((c) -> getUserFromCall(c).equals(userFromCall));
+                    boolean isCallCountZero = mFeatureFlags.workProfileAssociatedUser()
+                            ? callsAssociatedWithUserFromCall.count() == 0
+                            : mCallsManager.getCalls().isEmpty();
+                    if (isCallCountZero) {
+                        unbindFromServices(userFromCall);
                         mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
                     }
                 }
@@ -1832,6 +1847,7 @@
      * Unbinds an existing bound connection to the in-call app.
      */
     public void unbindFromServices(UserHandle userHandle) {
+        Log.i(this, "Unbinding from services for user %s", userHandle);
         try {
             mContext.unregisterReceiver(mPackageChangedReceiver);
         } catch (IllegalArgumentException e) {
@@ -2320,7 +2336,9 @@
         }
 
         // Upon successful connection, send the state of the world to the service.
-        List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls());
+        List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls().stream().filter(
+                call -> getUserFromCall(call).equals(userHandle))
+                .collect(Collectors.toUnmodifiableList()));
         Log.i(this, "Adding %s calls to InCallService after onConnected: %s, including external " +
                 "calls", calls.size(), info.getComponentName());
         int numCallsSent = 0;
@@ -2463,6 +2481,9 @@
                 }
             }
             Log.i(this, "Components updated: %s", componentsUpdated);
+        } else {
+            Log.i(this,
+                    "Unable to update call. InCallService not found for user: %s", userFromCall);
         }
     }
 
@@ -2901,8 +2922,11 @@
         } else {
             UserHandle userFromCall = call.getAssociatedUser();
             UserManager userManager = mContext.getSystemService(UserManager.class);
-            // Emergency call should never be blocked, so if the user associated with call is in
-            // quite mode, use the primary user for the emergency call.
+            // Emergency call should never be blocked, so if the user associated with the target
+            // phone account handle user is in quiet mode, use the current user for the ecall.
+            // Note, that this only applies to incoming calls that are received on assigned
+            // sims (i.e. work sim), where the associated user would be the target phone account
+            // handle user.
             if ((call.isEmergencyCall() || call.isInECBM())
                     && (userManager.isQuietModeEnabled(userFromCall)
                     // We should also account for secondary/guest users where the profile may not
diff --git a/src/com/android/server/telecom/UserUtil.java b/src/com/android/server/telecom/UserUtil.java
index d0a561a..670ad34 100644
--- a/src/com/android/server/telecom/UserUtil.java
+++ b/src/com/android/server/telecom/UserUtil.java
@@ -24,8 +24,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.Log;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 
 import com.android.server.telecom.components.ErrorDialogActivity;
+import com.android.server.telecom.flags.FeatureFlags;
 
 public final class UserUtil {
 
@@ -99,4 +102,37 @@
         }
         return false;
     }
+
+    /**
+     * Gets the associated user for the given call. Note: this is applicable to all calls except
+     * outgoing calls as the associated user is already based off of the user placing the
+     * call.
+     *
+     * @param phoneAccountRegistrar
+     * @param currentUser Current user profile (this can either be the admin or a secondary/guest
+     *                    user). Note that work profile users fall under the admin user.
+     * @param targetPhoneAccount The phone account to retrieve the {@link UserHandle} from.
+     * @return current user if it isn't the admin or if the work profile is paused for the target
+     * phone account handle user, otherwise return the target phone account handle user. If the
+     * flag is disabled, return the legacy {@link UserHandle}.
+     */
+    public static UserHandle getAssociatedUserForCall(boolean isAssociatedUserFlagEnabled,
+            PhoneAccountRegistrar phoneAccountRegistrar, UserHandle currentUser,
+            PhoneAccountHandle targetPhoneAccount) {
+        if (!isAssociatedUserFlagEnabled) {
+            return targetPhoneAccount.getUserHandle();
+        }
+        // For multi-user phone accounts, associate the call with the profile receiving/placing
+        // the call. For SIM accounts (that are assigned to specific users), the user association
+        // will be placed on the target phone account handle user.
+        PhoneAccount account = phoneAccountRegistrar.getPhoneAccountUnchecked(targetPhoneAccount);
+        if (account != null) {
+            return account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)
+                    ? currentUser
+                    : targetPhoneAccount.getUserHandle();
+        }
+        // If target phone account handle is null or account cannot be found,
+        // return the current user.
+        return currentUser;
+    }
 }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index c5e56b3..27e5a7d 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.AudioDeviceInfo;
+import android.media.audio.common.AudioDevice;
 import android.os.Bundle;
 import android.telecom.Log;
 import android.util.ArraySet;
@@ -40,13 +41,13 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.concurrent.Executor;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.Executor;
 
 public class BluetoothDeviceManager {
 
@@ -458,8 +459,8 @@
             disconnectSco();
         } else {
             disconnectSco();
-            clearLeAudioOrSpeakerCommunicationDevice();
-            clearHearingAidOrSpeakerCommunicationDevice();
+            clearLeAudioCommunicationDevice();
+            clearHearingAidCommunicationDevice();
         }
     }
 
@@ -479,9 +480,13 @@
         return mHearingAidSetAsCommunicationDevice;
     }
 
-    public void clearLeAudioOrSpeakerCommunicationDevice() {
+    public void clearLeAudioCommunicationDevice() {
         Log.i(this, "clearLeAudioCommunicationDevice: mLeAudioSetAsCommunicationDevice = " +
                 mLeAudioSetAsCommunicationDevice + " device = " + mLeAudioDevice);
+        if (!mLeAudioSetAsCommunicationDevice) {
+            return;
+        }
+        mLeAudioSetAsCommunicationDevice = false;
         if (mLeAudioDevice != null) {
             mBluetoothRouteManager.onAudioLost(mLeAudioDevice);
             mLeAudioDevice = null;
@@ -493,22 +498,20 @@
         }
 
         AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice();
-        if (audioDeviceInfo != null) {
-            if (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) {
-                Log.i(this, "clearLeAudioCommunicationDevice: clearing le audio");
-                mBluetoothRouteManager.onAudioLost(audioDeviceInfo.getAddress());
-                mAudioManager.clearCommunicationDevice();
-            } else if (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
-                Log.i(this, "clearLeAudioCommunicationDevice: clearing speaker");
-                mAudioManager.clearCommunicationDevice();
-            }
+        if (audioDeviceInfo != null && audioDeviceInfo.getType()
+                == AudioDeviceInfo.TYPE_BLE_HEADSET) {
+            mBluetoothRouteManager.onAudioLost(audioDeviceInfo.getAddress());
+            mAudioManager.clearCommunicationDevice();
         }
-        mLeAudioSetAsCommunicationDevice = false;
     }
 
-    public void clearHearingAidOrSpeakerCommunicationDevice() {
+    public void clearHearingAidCommunicationDevice() {
         Log.i(this, "clearHearingAidCommunicationDevice: mHearingAidSetAsCommunicationDevice = "
                 + mHearingAidSetAsCommunicationDevice);
+        if (!mHearingAidSetAsCommunicationDevice) {
+            return;
+        }
+        mHearingAidSetAsCommunicationDevice = false;
         if (mHearingAidDevice != null) {
             mBluetoothRouteManager.onAudioLost(mHearingAidDevice);
             mHearingAidDevice = null;
@@ -520,17 +523,10 @@
         }
 
         AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice();
-        if (audioDeviceInfo != null) {
-            if (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
-                Log.i(this, "clearHearingAidCommunicationDevice: clearing hearing aid");
-                mBluetoothRouteManager.onAudioLost(audioDeviceInfo.getAddress());
-                mAudioManager.clearCommunicationDevice();
-            } else if (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
-                Log.i(this, "clearHearingAidCommunicationDevice: clearing speaker");
-                mAudioManager.clearCommunicationDevice();
-            }
+        if (audioDeviceInfo != null && audioDeviceInfo.getType()
+                == AudioDeviceInfo.TYPE_HEARING_AID) {
+            mAudioManager.clearCommunicationDevice();
         }
-        mHearingAidSetAsCommunicationDevice = false;
     }
 
     public boolean setLeAudioCommunicationDevice() {
@@ -567,7 +563,7 @@
         }
 
         // clear hearing aid communication device if set
-        clearHearingAidOrSpeakerCommunicationDevice();
+        clearHearingAidCommunicationDevice();
 
         // Turn BLE_OUT_HEADSET ON.
         boolean result = mAudioManager.setCommunicationDevice(bleHeadset);
@@ -616,7 +612,7 @@
         }
 
         // clear LE audio communication device if set
-        clearLeAudioOrSpeakerCommunicationDevice();
+        clearLeAudioCommunicationDevice();
 
         // Turn hearing aid ON.
         boolean result = mAudioManager.setCommunicationDevice(hearingAid);
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 941d2ec..235ba56 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -21,8 +21,8 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothLeAudio;
 import android.content.Context;
 import android.media.AudioDeviceInfo;
 import android.os.Message;
@@ -40,10 +40,12 @@
 import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.flags.FeatureFlags;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.List;
 import java.util.Objects;
@@ -140,7 +142,7 @@
                 Log.w(LOG_TAG, "Entering AudioOff state but device %s appears to be connected. " +
                         "Switching to audio-on state for that device.", erroneouslyConnectedDevice);
                 // change this to just transition to the new audio on state
-                transitionToActualState(null /* excludeAddress */);
+                transitionToActualState();
             }
             cleanupStatesForDisconnectedDevices();
             if (mListener != null) {
@@ -284,7 +286,7 @@
                     case LOST_DEVICE:
                         removeDevice((String) args.arg2);
                         if (Objects.equals(address, mDeviceAddress)) {
-                            transitionToActualState(null /* excludeAddress */);
+                            transitionToActualState();
                         }
                         break;
                     case CONNECT_BT:
@@ -324,7 +326,7 @@
                     case CONNECTION_TIMEOUT:
                         Log.i(LOG_TAG, "Connection with device %s timed out.",
                                 mDeviceAddress);
-                        transitionToActualState(null /* excludeAddress */);
+                        transitionToActualState();
                         break;
                     case BT_AUDIO_IS_ON:
                         if (Objects.equals(mDeviceAddress, address)) {
@@ -341,7 +343,7 @@
                         if (Objects.equals(mDeviceAddress, address) || address == null) {
                             Log.i(LOG_TAG, "Connection with device %s failed.",
                                     mDeviceAddress);
-                            transitionToActualState(address);
+                            transitionToActualState();
                         } else {
                             Log.w(LOG_TAG, "Got BT lost message for device %s while" +
                                     " connecting to %s.", address, mDeviceAddress);
@@ -401,7 +403,7 @@
                     case LOST_DEVICE:
                         removeDevice((String) args.arg2);
                         if (Objects.equals(address, mDeviceAddress)) {
-                            transitionToActualState(null /* excludeAddress */);
+                            transitionToActualState();
                         }
                         break;
                     case CONNECT_BT:
@@ -416,8 +418,13 @@
                         String actualAddress = connectBtAudio(address,
                             true /* switchingBtDevices*/);
                         if (actualAddress != null) {
-                            transitionTo(getConnectingStateForAddress(address,
-                                    "AudioConnected/CONNECT_BT"));
+                            if (mFeatureFlags.useActualAddressToEnterConnectingState()) {
+                                transitionTo(getConnectingStateForAddress(actualAddress,
+                                        "AudioConnected/CONNECT_BT"));
+                            } else {
+                                transitionTo(getConnectingStateForAddress(address,
+                                        "AudioConnected/CONNECT_BT"));
+                            }
                         } else {
                             Log.w(LOG_TAG, "Tried to connect to %s but failed" +
                                     " to connect to any BT device.", (String) args.arg2);
@@ -458,7 +465,7 @@
                     case BT_AUDIO_LOST:
                         if (Objects.equals(mDeviceAddress, address) || address == null) {
                             Log.i(LOG_TAG, "BT connection with device %s lost.", mDeviceAddress);
-                            transitionToActualState(address);
+                            transitionToActualState();
                         } else {
                             Log.w(LOG_TAG, "Got BT lost message for device %s while" +
                                     " connected to %s.", address, mDeviceAddress);
@@ -656,7 +663,7 @@
                     mCommunicationDeviceTracker.clearCommunicationDevice(
                             AudioDeviceInfo.TYPE_BLE_HEADSET);
                 } else {
-                    mDeviceManager.clearLeAudioOrSpeakerCommunicationDevice();
+                    mDeviceManager.clearLeAudioCommunicationDevice();
                 }
             }
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) {
@@ -666,7 +673,7 @@
                     mCommunicationDeviceTracker.clearCommunicationDevice(
                             AudioDeviceInfo.TYPE_HEARING_AID);
                 } else {
-                    mDeviceManager.clearHearingAidOrSpeakerCommunicationDevice();
+                    mDeviceManager.clearHearingAidCommunicationDevice();
                 }
             }
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) {
@@ -791,7 +798,7 @@
                 actualAddress)) {
             Log.i(this, "trying to connect to already connected device -- skipping connection"
                     + " and going into the actual connected state.");
-            transitionToActualState(null /* excludeAddress */);
+            transitionToActualState();
             return null;
         }
 
@@ -827,10 +834,9 @@
         return null;
     }
 
-    private void transitionToActualState(String excludeAddress) {
+    private void transitionToActualState() {
         BluetoothDevice possiblyAlreadyConnectedDevice = getBluetoothAudioConnectedDevice();
-        if (possiblyAlreadyConnectedDevice != null
-                && !possiblyAlreadyConnectedDevice.getAddress().equals(excludeAddress)) {
+        if (possiblyAlreadyConnectedDevice != null) {
             Log.i(LOG_TAG, "Device %s is already connected; going to AudioConnected.",
                     possiblyAlreadyConnectedDevice);
             transitionTo(getConnectedStateForAddress(
diff --git a/testapps/transactionalVoipApp/res/values-ca/strings.xml b/testapps/transactionalVoipApp/res/values-ca/strings.xml
index 06f1655..5500444 100644
--- a/testapps/transactionalVoipApp/res/values-ca/strings.xml
+++ b/testapps/transactionalVoipApp/res/values-ca/strings.xml
@@ -31,7 +31,7 @@
     <string name="request_earpiece_endpoint" msgid="6649571985089296573">"Auricular"</string>
     <string name="request_speaker_endpoint" msgid="1033259535289845405">"Altaveu"</string>
     <string name="request_bluetooth_endpoint" msgid="5933254250623451836">"Bluetooth"</string>
-    <string name="start_stream" msgid="3567634786280097431">"inicia la reproducció en continu"</string>
+    <string name="start_stream" msgid="3567634786280097431">"inicia la reproducció en línia"</string>
     <string name="crash_app" msgid="2548690390730057704">"llança una excepció"</string>
     <string name="update_notification" msgid="8677916482672588779">"actualitza la notificació a l\'estil de trucada en curs"</string>
 </resources>
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 14065ca..d2937e2 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -69,6 +69,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.telecom.IInCallAdapter;
+import com.android.server.telecom.InCallController;
+
 import android.telecom.CallerInfo;
 
 import com.google.common.base.Predicate;
@@ -624,6 +626,48 @@
 
     @LargeTest
     @Test
+    public void testIncomingThenOutgoingCalls_AssociatedUsersNotEqual() throws Exception {
+        when(mFeatureFlags.workProfileAssociatedUser()).thenReturn(true);
+        InCallServiceFixture.setIgnoreOverrideAdapterFlag(true);
+
+        // Receive incoming call via mPhoneAccountMultiUser
+        IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
+                mPhoneAccountMultiUser.getAccountHandle(), mConnectionServiceFixtureA);
+        waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(),
+                TEST_TIMEOUT);
+        // Make outgoing call on mPhoneAccountMultiUser (unassociated sim to simulate guest/
+        // secondary user scenario where both MO/MT calls exist).
+        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
+                mPhoneAccountMultiUser.getAccountHandle(), mConnectionServiceFixtureA);
+        waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(),
+                TEST_TIMEOUT);
+
+        // Outgoing call should be on hold while incoming call is made active
+        mConnectionServiceFixtureA.mConnectionById.get(incoming.mConnectionId).state =
+                Connection.STATE_HOLDING;
+
+        // Swap calls and verify that outgoing call is now the active call while the incoming call
+        // is the held call.
+        mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId);
+        waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(),
+                TEST_TIMEOUT);
+        assertEquals(Call.STATE_HOLDING,
+                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE,
+                mInCallServiceFixtureX.getCall(incoming.mCallId).getState());
+
+        // Ensure no issues with call disconnect.
+        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId);
+        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
+        assertEquals(Call.STATE_DISCONNECTING,
+                mInCallServiceFixtureX.getCall(incoming.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTING,
+                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
+        InCallServiceFixture.setIgnoreOverrideAdapterFlag(false);
+    }
+
+    @LargeTest
+    @Test
     public void testAudioManagerOperations() throws Exception {
         AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
                 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index 86d2bee..e3d4ec2 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -425,7 +425,6 @@
         List<AudioDeviceInfo> devices = new ArrayList<>();
         devices.add(mockAudioDeviceInfo);
 
-        when(mockAudioManager.getCommunicationDevice()).thenReturn(mSpeakerInfo);
         when(mockAudioManager.getAvailableCommunicationDevices())
                 .thenReturn(devices);
         when(mockAudioManager.setCommunicationDevice(eq(mockAudioDeviceInfo)))
@@ -461,7 +460,6 @@
         List<AudioDeviceInfo> devices = new ArrayList<>();
         devices.add(mockAudioDeviceInfo);
 
-        when(mockAudioManager.getCommunicationDevice()).thenReturn(mSpeakerInfo);
         when(mockAudioManager.getAvailableCommunicationDevices())
                         .thenReturn(devices);
         when(mockAudioManager.setCommunicationDevice(mockAudioDeviceInfo))
@@ -781,10 +779,10 @@
             assertFalse(mCommunicationDeviceTracker.isAudioDeviceSetForType(device_type));
         } else {
             if (device_type == AudioDeviceInfo.TYPE_BLE_HEADSET) {
-                mBluetoothDeviceManager.clearLeAudioOrSpeakerCommunicationDevice();
+                mBluetoothDeviceManager.clearLeAudioCommunicationDevice();
                 assertFalse(mBluetoothDeviceManager.isLeAudioCommunicationDevice());
             } else {
-                mBluetoothDeviceManager.clearHearingAidOrSpeakerCommunicationDevice();
+                mBluetoothDeviceManager.clearHearingAidCommunicationDevice();
                 assertFalse(mBluetoothDeviceManager.isHearingAidSetAsCommunicationDevice());
             }
         }
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index 45a2581..e1ef08a 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -248,6 +248,33 @@
         sm.quitNow();
     }
 
+    @SmallTest
+    @Test
+    public void testConnectBtWithoutAddress() {
+        when(mFeatureFlags.useActualAddressToEnterConnectingState()).thenReturn(true);
+        BluetoothRouteManager sm = setupStateMachine(
+                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
+        setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null, null,
+                null);
+        when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
+                nullable(ContentResolver.class))).thenReturn(0L);
+        when(mBluetoothHeadset.connectAudio()).thenReturn(BluetoothStatusCodes.ERROR_UNKNOWN);
+        executeRoutingAction(sm, BluetoothRouteManager.CONNECT_BT, null);
+        // Wait 3 times: the first connection attempt is accounted for in executeRoutingAction,
+        // so wait twice for the retry attempt, again to make sure there are only three attempts,
+        // and once more for good luck.
+        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+        verifyConnectionAttempt(DEVICE1, 1);
+        assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
+                        + ":" + DEVICE1.getAddress(),
+                sm.getCurrentState().getName());
+        sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT);
+        sm.quitNow();
+    }
+
     private BluetoothRouteManager setupStateMachine(String initialState,
             BluetoothDevice initialDevice) {
         resetMocks();
diff --git a/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java b/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
index 7e197fe..86d24f9 100644
--- a/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
@@ -27,6 +27,7 @@
 
 import android.content.ComponentName;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -123,6 +124,7 @@
         mCallAnomalyWatchdog = new CallAnomalyWatchdog(mTestScheduledExecutorService, mLock,
                 mTimeouts, mMockClockProxy, mMockEmergencyCallDiagnosticLogger);
         mCallAnomalyWatchdog.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
+        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
     }
 
     @Override
@@ -862,6 +864,7 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
     }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 19dfe83..1fa14a5 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -883,16 +883,6 @@
         verify(mockBluetoothRouteManager, atLeastOnce())
                 .connectBluetoothAudio(eq(bluetoothDevice1.getAddress()));
         assertTrue(stateMachine.isInActiveState());
-
-        // Switch to inactive, pretending that the call disconnected.
-        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
-                CallAudioRouteStateMachine.NO_FOCUS);
-        waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT);
-
-        // Make sure that we've successfully switched to the quiescent BT route
-        assertEquals(CallAudioState.ROUTE_BLUETOOTH,
-                stateMachine.getCurrentCallAudioState().getRoute());
-        assertFalse(stateMachine.isInActiveState());
     }
 
     @SmallTest
@@ -1238,6 +1228,86 @@
         assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
     }
 
+    @SmallTest
+    @Test
+    public void testQuiescentBluetoothRouteResetMute() {
+        when(mFeatureFlags.resetMuteWhenEnteringQuiescentBtRoute()).thenReturn(true);
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+                mThreadHandler.getLooper(),
+                Runnable::run /** do async stuff sync for test purposes */,
+                mCommunicationDeviceTracker,
+                mFeatureFlags);
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+
+        CallAudioState initState = new CallAudioState(false,
+                CallAudioState.ROUTE_BLUETOOTH, CallAudioState.ROUTE_SPEAKER
+                | CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
+        stateMachine.initialize(initState);
+
+        // Switch to active and mute
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);
+        waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT);
+        assertTrue(stateMachine.isInActiveState());
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.MUTE_ON);
+        waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT);
+        CallAudioState expectedState = new CallAudioState(true,
+                CallAudioState.ROUTE_BLUETOOTH, CallAudioState.ROUTE_SPEAKER
+                | CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
+        assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.NO_FOCUS);
+        waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT);
+
+        expectedState = new CallAudioState(false,
+                CallAudioState.ROUTE_BLUETOOTH, CallAudioState.ROUTE_SPEAKER
+                | CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
+        // TODO: Re-enable this part of the test; this is now failing because we have to
+        // revert ag/23783145.
+        // assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
+    }
+
+    @SmallTest
+    @Test
+    public void testSupportRouteMaskUpdateWhenBtAudioConnected() {
+        when(mFeatureFlags.updateRouteMaskWhenBtConnected()).thenReturn(true);
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+                mThreadHandler.getLooper(),
+                Runnable::run /** do async stuff sync for test purposes */,
+                mCommunicationDeviceTracker,
+                mFeatureFlags);
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+
+        CallAudioState initState = new CallAudioState(false,
+                CallAudioState.ROUTE_EARPIECE,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
+        stateMachine.initialize(initState);
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);
+        waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT);
+        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER
+                        | CallAudioState.ROUTE_BLUETOOTH);
+        assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
+    }
+
     private void initializationTestHelper(CallAudioState expectedState,
             int earpieceControl) {
         when(mockWiredHeadsetManager.isPluggedIn()).thenReturn(
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index 83d1043..c09d138 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -967,6 +967,56 @@
 
     @SmallTest
     @Test
+    public void testDoNotLogCallExtra() {
+        when(mFeatureFlags.telecomSkipLogBasedOnExtra()).thenReturn(true);
+        Call fakeCall = makeFakeCall(
+                DisconnectCause.LOCAL, // disconnectCauseCode
+                false, // isConference
+                true, // isIncoming
+                1L, // creationTimeMillis
+                1000L, // ageMillis
+                TEL_PHONEHANDLE, // callHandle
+                mDefaultAccountHandle, // phoneAccountHandle
+                NO_VIDEO_STATE, // callVideoState
+                POST_DIAL_STRING, // postDialDigits
+                VIA_NUMBER_STRING, // viaNumber
+                UserHandle.of(CURRENT_USER_ID)
+        );
+        Bundle extras = new Bundle();
+        extras.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
+        when(fakeCall.getExtras()).thenReturn(extras);
+
+        assertFalse(mCallLogManager.shouldLogDisconnectedCall(fakeCall, CallState.DISCONNECTED,
+                false /* isCanceled */));
+    }
+
+    @SmallTest
+    @Test
+    public void testIgnoresDoNotLogCallExtra_whenFlagDisabled() {
+        when(mFeatureFlags.telecomSkipLogBasedOnExtra()).thenReturn(false);
+        Call fakeCall = makeFakeCall(
+                DisconnectCause.LOCAL, // disconnectCauseCode
+                false, // isConference
+                true, // isIncoming
+                1L, // creationTimeMillis
+                1000L, // ageMillis
+                TEL_PHONEHANDLE, // callHandle
+                mDefaultAccountHandle, // phoneAccountHandle
+                NO_VIDEO_STATE, // callVideoState
+                POST_DIAL_STRING, // postDialDigits
+                VIA_NUMBER_STRING, // viaNumber
+                UserHandle.of(CURRENT_USER_ID)
+        );
+        Bundle extras = new Bundle();
+        extras.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
+        when(fakeCall.getExtras()).thenReturn(extras);
+
+        assertTrue(mCallLogManager.shouldLogDisconnectedCall(fakeCall, CallState.DISCONNECTED,
+                false /* isCanceled */));
+    }
+
+    @SmallTest
+    @Test
     public void testDoNotLogConferenceWithChildren() {
         Call fakeCall = makeFakeCall(
                 DisconnectCause.LOCAL, // disconnectCauseCode
diff --git a/tests/src/com/android/server/telecom/tests/CallTest.java b/tests/src/com/android/server/telecom/tests/CallTest.java
index 997e7dd..7a77374 100644
--- a/tests/src/com/android/server/telecom/tests/CallTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -34,10 +33,12 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.telecom.CallAttributes;
 import android.telecom.CallerInfo;
 import android.telecom.Connection;
@@ -117,6 +118,7 @@
         doReturn(new ComponentName(mContext, CallTest.class))
                 .when(mMockConnectionService).getComponentName();
         doReturn(mMockToast).when(mMockToastProxy).makeText(any(), anyInt(), anyInt());
+        doReturn(UserHandle.CURRENT).when(mMockCallsManager).getCurrentUserHandle();
     }
 
     @After
@@ -200,7 +202,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
 
         // To start with connection creation isn't complete.
         assertFalse(call.isCreateConnectionComplete());
@@ -338,7 +341,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 true /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
 
         assertFalse(call.wasDndCheckComputedForCall());
         assertFalse(call.isCallSuppressedByDoNotDisturb());
@@ -364,7 +368,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 true /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
 
         assertNull(call.getConnectionServiceWrapper());
         assertFalse(call.isTransactionalCall());
@@ -394,7 +399,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 true /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
 
         // setup
         call.setIsTransactionalCall(true);
@@ -728,6 +734,52 @@
                 }));
     }
 
+    @Test
+    @SmallTest
+    public void testExcludesInCallServiceFromDoNotLogCallExtra() {
+        Call call = createCall("any");
+        Bundle extra = new Bundle();
+        extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
+
+        call.putInCallServiceExtras(extra, "packageName");
+
+        assertFalse(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
+    }
+
+    @Test
+    @SmallTest
+    public void testExcludesConnectionServiceWithoutModifyStatePermissionFromDoNotLogCallExtra() {
+        PackageManager packageManager = mContext.getPackageManager();
+        Bundle extra = new Bundle();
+        extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
+        String packageName = SIM_1_HANDLE.getComponentName().getPackageName();
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(packageManager)
+                .checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, packageName);
+        Call call = createCall("any");
+
+        call.putConnectionServiceExtras(extra);
+
+        assertFalse(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
+    }
+
+    @Test
+    @SmallTest
+    public void testDoesNotExcludeConnectionServiceWithModifyStatePermissionFromDoNotLogCallExtra() {
+        String packageName = SIM_1_HANDLE.getComponentName().getPackageName();
+        Bundle extra = new Bundle();
+        extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
+        PackageManager packageManager = mContext.getPackageManager();
+        doReturn(PackageManager.PERMISSION_GRANTED)
+                .when(packageManager)
+                .checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, packageName);
+        Call call = createCall("any");
+
+        call.putConnectionServiceExtras(extra);
+
+        assertTrue(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
+    }
+
     private Call createCall(String id) {
         return createCall(id, Call.CALL_DIRECTION_UNDEFINED);
     }
@@ -748,6 +800,7 @@
                 false,
                 false,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index fe94da4..649f435 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -415,7 +415,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
         ongoingCall.setState(CallState.ACTIVE, "just cuz");
         return ongoingCall;
     }
@@ -2559,6 +2560,7 @@
     @SmallTest
     @Test
     public void testOutgoingCallStateIsSetToAPreviousStateAndIgnored() {
+        when(mFeatureFlags.fixAudioFlickerForOutgoingCalls()).thenReturn(true);
         Call outgoingCall = addSpyCall(CallState.CONNECTING);
         mCallsManager.onSuccessfulOutgoingCall(outgoingCall, CallState.NEW);
         verify(outgoingCall, never()).setState(eq(CallState.NEW), any());
@@ -2571,6 +2573,7 @@
     @SmallTest
     @Test
     public void testOutgoingCallStateCanAvoidDialingAndGoStraightToActive() {
+        when(mFeatureFlags.fixAudioFlickerForOutgoingCalls()).thenReturn(true);
         Call outgoingCall = addSpyCall(CallState.CONNECTING);
         mCallsManager.onSuccessfulOutgoingCall(outgoingCall, CallState.ACTIVE);
         verify(outgoingCall, never()).setState(eq(CallState.DIALING), any());
@@ -2586,9 +2589,7 @@
                 WORK_HANDLE.getUserHandle(), service);
 
         UserManager um = mContext.getSystemService(UserManager.class);
-        UserHandle newUser = new UserHandle(11);
-        when(mCallsManager.getCurrentUserHandle()).thenReturn(newUser);
-        when(um.isUserAdmin(eq(newUser.getIdentifier()))).thenReturn(false);
+        when(um.isUserAdmin(anyInt())).thenReturn(false);
         when(um.isQuietModeEnabled(eq(WORK_HANDLE.getUserHandle()))).thenReturn(false);
         when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(WORK_HANDLE)))
                 .thenReturn(WORK_ACCOUNT);
@@ -2604,14 +2605,17 @@
     @Test
     public void testRejectIncomingCallOnPAHInactive_ProfilePaused() throws Exception {
         ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
-        doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
-        mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
-                SIM_2_HANDLE.getUserHandle(), service);
+        doReturn(WORK_HANDLE.getComponentName()).when(service).getComponentName();
+        mCallsManager.addConnectionServiceRepositoryCache(WORK_HANDLE.getComponentName(),
+                WORK_HANDLE.getUserHandle(), service);
 
         UserManager um = mContext.getSystemService(UserManager.class);
-        when(um.isQuietModeEnabled(eq(SIM_2_HANDLE.getUserHandle()))).thenReturn(true);
+        when(um.isUserAdmin(anyInt())).thenReturn(true);
+        when(um.isQuietModeEnabled(eq(WORK_HANDLE.getUserHandle()))).thenReturn(true);
+        when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(WORK_HANDLE)))
+                .thenReturn(WORK_ACCOUNT);
         Call newCall = mCallsManager.processIncomingCallIntent(
-                SIM_2_HANDLE, new Bundle(), false);
+                WORK_HANDLE, new Bundle(), false);
 
         verify(service, timeout(TEST_TIMEOUT)).createConnectionFailed(any());
         assertFalse(newCall.isInECBM());
@@ -2648,9 +2652,7 @@
         when(mEmergencyCallHelper.isLastOutgoingEmergencyCallPAH(eq(WORK_HANDLE)))
                 .thenReturn(true);
         UserManager um = mContext.getSystemService(UserManager.class);
-        UserHandle newUser = new UserHandle(11);
-        when(mCallsManager.getCurrentUserHandle()).thenReturn(newUser);
-        when(um.isUserAdmin(eq(newUser.getIdentifier()))).thenReturn(false);
+        when(um.isUserAdmin(anyInt())).thenReturn(false);
         when(um.isQuietModeEnabled(eq(WORK_HANDLE.getUserHandle()))).thenReturn(false);
         when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(WORK_HANDLE)))
                 .thenReturn(WORK_ACCOUNT);
@@ -3427,7 +3429,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
         ongoingCall.setState(initialState, "just cuz");
         if (targetPhoneAccount == SELF_MANAGED_HANDLE
                 || targetPhoneAccount == SELF_MANAGED_2_HANDLE) {
diff --git a/tests/src/com/android/server/telecom/tests/EmergencyCallDiagnosticLoggerTest.java b/tests/src/com/android/server/telecom/tests/EmergencyCallDiagnosticLoggerTest.java
index 3cb8196..c63a3d5 100644
--- a/tests/src/com/android/server/telecom/tests/EmergencyCallDiagnosticLoggerTest.java
+++ b/tests/src/com/android/server/telecom/tests/EmergencyCallDiagnosticLoggerTest.java
@@ -35,6 +35,7 @@
 import android.net.Uri;
 import android.os.BugreportManager;
 import android.os.DropBoxManager;
+import android.os.UserHandle;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -128,6 +129,7 @@
         when(mTimeouts.getDaysBackToSearchEmergencyDiagnosticEntries()).
                 thenReturn(DAYS_BACK_TO_SEARCH_EMERGENCY_DIAGNOSTIC_ENTRIES);
         when(mClockProxy.currentTimeMillis()).thenReturn(System.currentTimeMillis());
+        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
 
         mEmergencyCallDiagnosticLogger = new EmergencyCallDiagnosticLogger(mTm, mBrm,
                 mTimeouts, mDbm, Runnable::run, mClockProxy);
@@ -171,7 +173,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mMockClockProxy,
-                mMockToastProxy);
+                mMockToastProxy,
+                mFeatureFlags);
     }
 
     /**
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 1b5677e..cd8431a 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -141,6 +141,8 @@
     @Mock PackageManager mMockPackageManager;
     @Mock PermissionCheckerManager mMockPermissionCheckerManager;
     @Mock Call mMockCall;
+    @Mock Call mMockSystemCall1;
+    @Mock Call mMockSystemCall2;
     @Mock Resources mMockResources;
     @Mock AppOpsManager mMockAppOpsManager;
     @Mock MockContext mMockContext;
@@ -586,6 +588,7 @@
         when(mMockCall.isEmergencyCall()).thenReturn(true);
         when(mMockCall.isIncoming()).thenReturn(true);
         when(mMockCall.getAssociatedUser()).thenReturn(DUMMY_USER_HANDLE);
+        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockContext.getSystemService(eq(UserManager.class)))
             .thenReturn(mMockUserManager);
         when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
@@ -615,6 +618,7 @@
         when(mMockCall.isInECBM()).thenReturn(true);
         when(mMockCall.isIncoming()).thenReturn(true);
         when(mMockCall.getAssociatedUser()).thenReturn(DUMMY_USER_HANDLE);
+        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockContext.getSystemService(eq(UserManager.class)))
                 .thenReturn(mMockUserManager);
         when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
@@ -645,6 +649,7 @@
         when(mMockCall.isInECBM()).thenReturn(true);
         when(mMockCall.isIncoming()).thenReturn(true);
         when(mMockCall.getAssociatedUser()).thenReturn(DUMMY_USER_HANDLE);
+        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockContext.getSystemService(eq(UserManager.class)))
                 .thenReturn(mMockUserManager);
         when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
@@ -1837,6 +1842,67 @@
         assertNull(mInCallController.getInCallServiceConnections().get(testUser));
     }
 
+    @Test
+    public void testRemoveAllServiceConnections_MultiUser() throws Exception {
+        when(mFeatureFlags.workProfileAssociatedUser()).thenReturn(true);
+        setupMocks(false /* isExternalCall */);
+        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+        UserHandle workUser = new UserHandle(12);
+        UserManager um = mContext.getSystemService(UserManager.class);
+        when(um.getUserInfo(anyInt())).thenReturn(mMockUserInfo);
+        when(mMockUserInfo.isManagedProfile()).thenReturn(false);
+        when(mMockCall.getAssociatedUser()).thenReturn(workUser);
+        setupFakeSystemCall(mMockSystemCall1, 1);
+        setupFakeSystemCall(mMockSystemCall2, 2);
+
+        // Add "work" call to service. The mapping should've been inserted
+        // with the workUser as the key.
+        mInCallController.onCallAdded(mMockCall);
+        // Add system call to service. The mapping should've been
+        // inserted with the system user as the key.
+        mInCallController.onCallAdded(mMockSystemCall1);
+
+        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        // Make sure we bound to the system call as well as the work call.
+        verify(mMockContext, times(2)).bindServiceAsUser(
+                bindIntentCaptor.capture(),
+                any(ServiceConnection.class),
+                eq(serviceBindingFlags),
+                eq(UserHandle.CURRENT));
+        assertTrue(mInCallController.getInCallServiceConnections().containsKey(workUser));
+        assertTrue(mInCallController.getInCallServiceConnections().containsKey(UserHandle.SYSTEM));
+
+        // Remove the work call. This leverages getUserFromCall to remove the ICS mapping.
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockSystemCall1));
+        mInCallController.onCallRemoved(mMockCall);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        // Verify that the mapping was properly removed.
+        assertNull(mInCallController.getInCallServiceConnections().get(workUser));
+        // Verify mapping for system user is still present.
+        assertNotNull(mInCallController.getInCallServiceConnections().get(UserHandle.SYSTEM));
+
+        // Add another system call
+        mInCallController.onCallAdded(mMockSystemCall2);
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockSystemCall2));
+        // Remove first system call and verify that mapping is present
+        mInCallController.onCallRemoved(mMockSystemCall1);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        // Verify mapping for system user is still present.
+        assertNotNull(mInCallController.getInCallServiceConnections().get(UserHandle.SYSTEM));
+        // Remove last system call and verify that connection isn't present in ICS mapping.
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList());
+        mInCallController.onCallRemoved(mMockSystemCall2);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        assertNull(mInCallController.getInCallServiceConnections().get(UserHandle.SYSTEM));
+    }
+
+    private void setupFakeSystemCall(@Mock Call call, int id) {
+        when(call.getAssociatedUser()).thenReturn(UserHandle.SYSTEM);
+        when(call.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
+        when(call.getAnalytics()).thenReturn(new Analytics.CallInfo());
+        when(call.getId()).thenReturn("TC@" + id);
+    }
+
     private void setupMocksForWorkProfileTest() {
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockCallsManager.isInEmergencyCall()).thenReturn(false);
diff --git a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
index 88b5bb5..39381e6 100644
--- a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.tests;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.IInCallAdapter;
 import com.android.internal.telecom.IInCallService;
 
@@ -39,7 +40,7 @@
  * Controls a test {@link IInCallService} as would be provided by an InCall UI on a system.
  */
 public class InCallServiceFixture implements TestFixture<IInCallService> {
-
+    public static boolean sIgnoreOverrideAdapterFlag = false;
     public String mLatestCallId;
     public IInCallAdapter mInCallAdapter;
     public CallAudioState mCallAudioState;
@@ -53,10 +54,17 @@
     public CountDownLatch mUpdateCallLock = new CountDownLatch(1);
     public CountDownLatch mAddCallLock = new CountDownLatch(1);
 
+    @VisibleForTesting
+    public static void setIgnoreOverrideAdapterFlag(boolean flag) {
+        sIgnoreOverrideAdapterFlag = flag;
+    }
+
     public class FakeInCallService extends IInCallService.Stub {
         @Override
         public void setInCallAdapter(IInCallAdapter inCallAdapter) throws RemoteException {
-            if (mInCallAdapter != null && inCallAdapter != null) {
+            // sIgnoreOverrideAdapterFlag is being used to verify a scenario where the InCallAdapter
+            // gets set twice (secondary user places MO/MT call).
+            if (mInCallAdapter != null && inCallAdapter != null && !sIgnoreOverrideAdapterFlag) {
                 throw new RuntimeException("Adapter is already set");
             }
             if (mInCallAdapter == null && inCallAdapter == null) {
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
index 753c847..f28966e 100644
--- a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -153,6 +153,8 @@
         setUpEmergencyCall();
         when(mEmergencyCall.getAssociatedUser()).
                 thenReturn(mPhoneAccountA0.getAccountHandle().getUserHandle());
+        when(mEmergencyCall.getTargetPhoneAccount())
+                .thenReturn(mPhoneAccountA0.getAccountHandle());
         mCallsManager.addCall(mEmergencyCall);
         assertTrue(mCallsManager.isInEmergencyCall());
 
@@ -418,7 +420,7 @@
                 null, mCallsManager.getPhoneNumberUtilsAdapter(), null,
                 null, null, mPhoneAccountA0.getAccountHandle(),
                 Call.CALL_DIRECTION_INCOMING, false, false,
-                mClockProxy, null));
+                mClockProxy, null, mFeatureFlags));
         doReturn(1L).when(mIncomingCall).getStartRingTime();
         doAnswer((x) -> {
             mCountDownLatch.countDown();
diff --git a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
index fed8084..57c6191 100644
--- a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
+++ b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
@@ -13,6 +13,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.telecom.Connection;
 import android.telecom.ParcelableCall;
 import android.telecom.PhoneAccountHandle;
@@ -57,6 +58,7 @@
         when(mClockProxy.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
         when(mCallsManager.getCallerInfoLookupHelper()).thenReturn(mCallerInfoLookupHelper);
         when(mCallsManager.getPhoneAccountRegistrar()).thenReturn(mPhoneAccountRegistrar);
+        when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
         when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any())).thenReturn(null);
         when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
                 .thenReturn(false);
@@ -75,7 +77,8 @@
                 false /* shouldAttachToExistingConnection */,
                 false /* isConference */,
                 mClockProxy /* ClockProxy */,
-                mToastProxy);
+                mToastProxy,
+                mFeatureFlags);
     }
 
     @Override
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index baa4f90..ee42c2a 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -147,6 +147,8 @@
         when(mockCall2.getState()).thenReturn(CallState.RINGING);
         when(mockCall1.getAssociatedUser()).thenReturn(PA_HANDLE.getUserHandle());
         when(mockCall2.getAssociatedUser()).thenReturn(PA_HANDLE.getUserHandle());
+        when(mockCall1.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
+        when(mockCall2.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         // Set BT active state in tests to ensure that we do not end up blocking tests for 1 sec
         // waiting for BT to connect in unit tests by default.
         asyncRingtonePlayer.updateBtActiveState(true);
@@ -180,9 +182,9 @@
         when(mFeatureFlags.useDeviceProvidedSerializedRingerVibration()).thenReturn(true);
         mockVibrationResourceValues(
                 """
-                    <vibration>
+                    <vibration-effect>
                         <predefined-effect name="click"/>
-                    </vibration>
+                    </vibration-effect>
                 """,
                 /* useSimpleVibration= */ true);
         when(mockVibratorInfo.areVibrationFeaturesSupported(any())).thenReturn(true);
@@ -199,7 +201,7 @@
         when(mFeatureFlags.useDeviceProvidedSerializedRingerVibration()).thenReturn(false);
         mockVibrationResourceValues(
                 """
-                    <vibration>
+                    <vibration-effect>
                         <waveform-effect>
                             <waveform-entry durationMs="100" amplitude="0"/>
                             <repeating>
@@ -207,7 +209,7 @@
                                 <waveform-entry durationMs="700" amplitude="0"/>
                             </repeating>
                         </waveform-effect>
-                    </vibration>
+                    </vibration-effect>
                 """,
                 /* useSimpleVibration= */ false);
         when(mockVibratorInfo.areVibrationFeaturesSupported(any())).thenReturn(true);
@@ -223,7 +225,7 @@
         when(mFeatureFlags.useDeviceProvidedSerializedRingerVibration()).thenReturn(true);
         mockVibrationResourceValues(
                 """
-                    <vibration>
+                    <vibration-effect>
                         <waveform-effect>
                             <waveform-entry durationMs="100" amplitude="0"/>
                             <repeating>
@@ -231,7 +233,7 @@
                                 <waveform-entry durationMs="700" amplitude="0"/>
                             </repeating>
                         </waveform-effect>
-                    </vibration>
+                    </vibration-effect>
                 """,
                 /* useSimpleVibration= */ false);
         when(mockVibratorInfo.areVibrationFeaturesSupported(any())).thenReturn(true);
@@ -249,9 +251,9 @@
         when(mFeatureFlags.useDeviceProvidedSerializedRingerVibration()).thenReturn(true);
         mockVibrationResourceValues(
                 """
-                    <vibration>
+                    <vibration-effect>
                         <predefined-effect name="click"/>
-                    </vibration>
+                    </vibration-effect>
                 """,
                 /* useSimpleVibration= */ false);
         when(mockVibratorInfo.areVibrationFeaturesSupported(any())).thenReturn(true);
@@ -278,9 +280,9 @@
         when(mFeatureFlags.useDeviceProvidedSerializedRingerVibration()).thenReturn(true);
         mockVibrationResourceValues(
                 """
-                    <vibration>
+                    <vibration-effect>
                         <predefined-effect name="click"/>
-                    </vibration>
+                    </vibration-effect>
                 """,
                 /* useSimpleVibration= */ false);
         when(mockVibratorInfo.areVibrationFeaturesSupported(
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 33b0068..aa2cf56 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -327,6 +327,20 @@
                                     PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
                     .build();
 
+    final PhoneAccount mPhoneAccountMultiUser =
+            PhoneAccount.builder(
+                            new PhoneAccountHandle(
+                                    mConnectionServiceComponentNameA,
+                                    "id MU", UserHandle.of(12)),
+                            "Phone account service MU")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING |
+                                    PhoneAccount.CAPABILITY_MULTI_USER)
+                    .build();
+
     ConnectionServiceFixture mConnectionServiceFixtureA;
     ConnectionServiceFixture mConnectionServiceFixtureB;
     Timeouts.Adapter mTimeoutsAdapter;
@@ -601,6 +615,7 @@
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0);
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1);
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountMultiUser);
 
         mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
                 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle());
diff --git a/tests/src/com/android/server/telecom/tests/TransactionTests.java b/tests/src/com/android/server/telecom/tests/TransactionTests.java
index d733d9d..b35f88e 100644
--- a/tests/src/com/android/server/telecom/tests/TransactionTests.java
+++ b/tests/src/com/android/server/telecom/tests/TransactionTests.java
@@ -338,7 +338,8 @@
                 false /* shouldAttachToExistingConnection*/,
                 false /* isConference */,
                 mClockProxy,
-                mToastFactory);
+                mToastFactory,
+                mFeatureFlags);
 
         Call callSpy = Mockito.spy(call);