Merge "InCallTonePlayer concurrency improvements." into tm-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a3c75a6..d376b6a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -263,7 +263,7 @@
         <activity android:name=".RespondViaSmsSettings"
              android:label="@string/respond_via_sms_setting_title"
              android:configChanges="orientation|screenSize|keyboardHidden"
-             android:theme="@style/Theme.Telecom.DialerSettings"
+             android:theme="@style/CallSettingsWithoutDividerTheme"
              android:process=":ui"
              android:exported="true">
             <intent-filter>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5ba0a3f..64dfabd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -92,4 +92,9 @@
         <item name="android:lineSpacingExtra">@dimen/blocked_numbers_secondary_line_spacing</item>
         <item name="android:capitalize">sentences</item>
     </style>
+
+    <style name="CallSettingsWithoutDividerTheme" parent="Theme.Telecom.DialerSettings">
+        <item name="android:listDivider">@null</item>
+    </style>
+
 </resources>
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 6a1f5aa..5d2edaa 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -542,9 +542,9 @@
         mCallAudioModeStateMachine.dump(pw);
         pw.decreaseIndent();
 
-        pw.println("CallAudioRouteStateMachine pending messages:");
+        pw.println("CallAudioRouteStateMachine:");
         pw.increaseIndent();
-        mCallAudioRouteStateMachine.dumpPendingMessages(pw);
+        mCallAudioRouteStateMachine.dump(pw);
         pw.decreaseIndent();
 
         pw.println("BluetoothDeviceManager:");
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 50baf58..ad68571 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -411,6 +411,8 @@
                         Log.w(this, "Ignoring switch to headset command. Not available.");
                     }
                     return HANDLED;
+                case CONNECT_DOCK:
+                    // fall through; we want to switch to speaker mode when docked and in a call.
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
                     setSpeakerphoneOn(true);
@@ -486,6 +488,8 @@
                         Log.w(this, "Ignoring switch to headset command. Not available.");
                     }
                     return HANDLED;
+                case CONNECT_DOCK:
+                    // fall through; we want to go to the quiescent speaker route when out of a call
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
                     transitionTo(mQuiescentSpeakerRoute);
@@ -537,10 +541,6 @@
                 case BT_AUDIO_DISCONNECTED:
                     // This may be sent as a confirmation by the BT stack after switch off BT.
                     return HANDLED;
-                case CONNECT_DOCK:
-                    setSpeakerphoneOn(true);
-                    sendInternalMessage(SWITCH_SPEAKER);
-                    return HANDLED;
                 case DISCONNECT_DOCK:
                     // Nothing to do here
                     return HANDLED;
@@ -1273,6 +1273,8 @@
                 case SPEAKER_ON:
                     // Nothing to do
                     return HANDLED;
+                case DISCONNECT_DOCK:
+                    // Fall-through; same as if speaker goes off, we want to switch baseline.
                 case SPEAKER_OFF:
                     sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
                     return HANDLED;
@@ -1619,6 +1621,15 @@
         quitNow();
     }
 
+    public void dump(IndentingPrintWriter pw) {
+        pw.print("Current state: ");
+        pw.println(getCurrentState().getName());
+        pw.println("Pending messages:");
+        pw.increaseIndent();
+        dumpPendingMessages(pw);
+        pw.decreaseIndent();
+    }
+
     public void dumpPendingMessages(IndentingPrintWriter pw) {
         getHandler().getLooper().dump(pw::println, "");
     }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 9d6dd07..5a01be7 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -3987,6 +3987,19 @@
         return false;
     }
 
+    /**
+     * Determines if there are any ongoing self managed calls for the given package/user.
+     * @param packageName The package name to check.
+     * @param userHandle The userhandle to check.
+     * @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
+     */
+    public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) {
+        return mCalls.stream().anyMatch(
+                c -> c.isSelfManaged()
+                && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
+                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle));
+    }
+
     @VisibleForTesting
     public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
                                     PhoneAccountHandle phoneAccountHandle, int... states) {
diff --git a/src/com/android/server/telecom/DockManager.java b/src/com/android/server/telecom/DockManager.java
index 46b2efc..dda5711 100644
--- a/src/com/android/server/telecom/DockManager.java
+++ b/src/com/android/server/telecom/DockManager.java
@@ -29,7 +29,12 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-/** Listens for and caches car dock state. */
+/**
+ * Listens for and caches car dock state.
+ * Testing; you can enable/disable dock with adb commands:
+ *   adb shell dumpsys DockObserver set state 3
+ *   adb shell dumpsys DockObserver set state 0
+ */
 @VisibleForTesting
 public class DockManager {
     @VisibleForTesting
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 6e952e3..ec87555 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -944,6 +944,15 @@
         }
     };
 
+    private final BroadcastReceiver mUserAddedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
+                restrictPhoneCallOps();
+            }
+        }
+    };
+
     private final SystemStateListener mSystemStateListener = new SystemStateListener() {
         @Override
         public void onCarModeChanged(int priority, String packageName, boolean isCarMode) {
@@ -1052,6 +1061,7 @@
         mSystemStateHelper.addListener(mSystemStateListener);
         mClockProxy = clockProxy;
         restrictPhoneCallOps();
+        mContext.registerReceiver(mUserAddedReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
     }
 
     private void restrictPhoneCallOps() {
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index e65a651..9597403 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -47,6 +47,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -1413,7 +1414,7 @@
 
         public final UserHandle userHandle;
 
-        public final PhoneAccountHandle phoneAccountHandle;
+        public PhoneAccountHandle phoneAccountHandle;
 
         public final String groupId;
 
@@ -1555,6 +1556,7 @@
             XmlPullParser parser = Xml.resolvePullParser(is);
             parser.nextTag();
             mState = readFromXml(parser, mContext);
+            migratePhoneAccountHandle(mState);
             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
 
         } catch (IOException | XmlPullParserException e) {
@@ -1599,6 +1601,50 @@
         return s != null ? s : new State();
     }
 
+    /**
+     * Try to migrate the ID of default phone account handle from IccId to SubId.
+     */
+    @VisibleForTesting
+    public void migratePhoneAccountHandle(State state) {
+        if (mSubscriptionManager == null) {
+            return;
+        }
+        // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId
+        // from the subscription database
+        List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager
+                .getAllSubscriptionInfoList();
+        Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+                = state.defaultOutgoingAccountHandles;
+        for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry
+                : defaultPhoneAccountHandles.entrySet()) {
+            DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue();
+
+            // Migrate Telephony PhoneAccountHandle only
+            String telephonyComponentName =
+                    "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
+            if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName()
+                    .flattenToString().equals(telephonyComponentName)) {
+                continue;
+            }
+            // Migrate from IccId to SubId
+            for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
+                String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId();
+                // Some phone account handle would store phone account handle id with the IccId
+                // string plus "F", and the getIccId() returns IccId string itself without "F",
+                // so here need to use "startsWith" to match.
+                if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith(
+                        subscriptionInfo.getIccId())) {
+                    Log.i(this, "Found subscription ID to migrate: "
+                            + subscriptionInfo.getSubscriptionId());
+                    defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle(
+                            defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(),
+                                    Integer.toString(subscriptionInfo.getSubscriptionId()));
+                    break;
+                }
+            }
+        }
+    }
+
     ////////////////////////////////////////////////////////////////////////////////////////////////
     //
     // XML serialization
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 455fe85..5684612 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -530,12 +530,6 @@
             try {
                 Log.startSession("TSI.rPA");
                 synchronized (mLock) {
-                    if (!((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                                .isVoiceCapable()) {
-                        Log.w(this,
-                                "registerPhoneAccount not allowed on non-voice capable device.");
-                        return;
-                    }
                     try {
                         enforcePhoneAccountModificationForPackage(
                                 account.getAccountHandle().getComponentName().getPackageName());
@@ -2093,6 +2087,39 @@
                 Log.endSession();
             }
         }
+
+        /**
+         * Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
+         * calls for a given {@code packageName} and {@code userHandle}.
+         *
+         * @param packageName the package name of the app to check calls for.
+         * @param userHandle the user handle on which to check for calls.
+         * @param callingPackage The caller's package name.
+         * @return {@code true} if there are ongoing calls, {@code false} otherwise.
+         */
+        @Override
+        public boolean isInSelfManagedCall(String packageName, UserHandle userHandle,
+                String callingPackage) {
+            try {
+                if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                    throw new SecurityException("Only the system can call this API");
+                }
+                mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+                        "READ_PRIVILEGED_PHONE_STATE required.");
+
+                Log.startSession("TSI.iISMC", Log.getPackageAbbreviation(callingPackage));
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        return mCallsManager.isInSelfManagedCall(packageName, userHandle);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
     };
 
     /**
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 2785739..e5706d2 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -382,16 +382,8 @@
     }
 
     public void disconnectAudio() {
-        if (mBluetoothAdapter != null) {
-            for (BluetoothDevice device: mBluetoothAdapter.getActiveDevices(
-                        BluetoothProfile.HEARING_AID)) {
-                if (device != null) {
-                    mBluetoothAdapter.removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
-                }
-            }
-            disconnectSco();
-            clearLeAudioCommunicationDevice();
-        }
+        disconnectSco();
+        clearLeAudioCommunicationDevice();
     }
 
     public void disconnectSco() {
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index ae76708..cad7b4c 100755
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -80,11 +80,6 @@
      */
     public void processIntent(Intent intent, String callingPackageName,
             boolean canCallNonEmergency, boolean isLocalInvocation) {
-        // Ensure call intents are not processed on devices that are not capable of calling.
-        if (!isVoiceCapable()) {
-            return;
-        }
-
         String action = intent.getAction();
 
         if (Intent.ACTION_CALL.equals(action) ||
@@ -160,16 +155,6 @@
     }
 
     /**
-     * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
-     *
-     * @return {@code True} if the device is voice-capable.
-     */
-    private boolean isVoiceCapable() {
-        return ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                .isVoiceCapable();
-    }
-
-    /**
      * Potentially trampolines the intent to Telecom via TelecomServiceImpl.
      * If the caller is local to the Telecom service, we send the intent to Telecom without
      * sending it through TelecomServiceImpl.
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 03a5b43..6b97f97 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -268,7 +268,9 @@
                     createClearMissedCallsPendingIntent(userHandle))
             .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, missedCallCount)
             .putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
-                    callInfo == null ? null : callInfo.getPhoneNumber());
+                    callInfo == null ? null : callInfo.getPhoneNumber())
+            .putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                    callInfo == null ? null : callInfo.getPhoneAccountHandle());
 
         if (missedCallCount == 1 && callInfo != null) {
             final Uri handleUri = callInfo.getHandle();
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index f011f0c..a9851bf 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -367,7 +367,6 @@
                 .thenReturn(Arrays.asList(device2, null));
 
         mBluetoothDeviceManager.disconnectAudio();
-        verify(mAdapter).removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
         verify(mBluetoothHeadset).disconnectAudio();
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 91ec7f3..19e6327 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -505,6 +505,37 @@
 
     @SmallTest
     @Test
+    public void testDockWhenInQuiescentState() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+                mThreadHandler.getLooper());
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
+        stateMachine.initialize(initState);
+
+        // Raise a dock connect event.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_DOCK);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+        assertTrue(!stateMachine.isInActiveState());
+        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(true));
+
+        // Raise a dock disconnect event.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.DISCONNECT_DOCK);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+        assertTrue(!stateMachine.isInActiveState());
+        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(false));
+    }
+
+    @SmallTest
+    @Test
     public void testFocusChangeFromQuiescentSpeaker() {
         CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
                 mContext,
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 879ed0f..0ad966e 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -823,6 +823,30 @@
                 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
         ));
 
+        params.add(new RoutingTestParameters(
+                "Connect dock from earpiece", // name
+                CallAudioState.ROUTE_EARPIECE, // initialRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
+                ON, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.CONNECT_DOCK, // action
+                CallAudioState.ROUTE_SPEAKER, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Disconnect dock from speaker", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.DISCONNECT_DOCK, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+        ));
+
         return params;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index da72933..6fd8334 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -1625,6 +1625,57 @@
         verify(callSpy, never()).setDisconnectCause(any(DisconnectCause.class));
     }
 
+    @Test
+    public void testIsInSelfManagedCallOnlyManaged() {
+        Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+        managedCall.setIsSelfManaged(false);
+        mCallsManager.addCall(managedCall);
+
+        // Certainly nothing from the self managed handle.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        // And nothing in a random other package.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                "com.foo",
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        // And this method is only checking self managed not managed.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+    }
+
+    @Test
+    public void testIsInSelfManagedCallOnlySelfManaged() {
+        Call selfManagedCall = createCall(SELF_MANAGED_HANDLE, CallState.ACTIVE);
+        selfManagedCall.setIsSelfManaged(true);
+        mCallsManager.addCall(selfManagedCall);
+
+        assertTrue(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                "com.foo",
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+
+        Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+        managedCall.setIsSelfManaged(false);
+        mCallsManager.addCall(managedCall);
+
+        // Still not including managed
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+
+        // Also shouldn't be something in another user's version of the same package.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                new UserHandle(90210)));
+    }
+
     private Call addSpyCall() {
         return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
     }
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 47a6177..023b368 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -540,7 +540,7 @@
     private final NotificationManager mNotificationManager = mock(NotificationManager.class);
     private final UserManager mUserManager = mock(UserManager.class);
     private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
-    private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
+    private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
     private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
     private final CountryDetector mCountryDetector = mock(CountryDetector.class);
     private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>();
@@ -735,6 +735,10 @@
         mTelecomManager = telecomManager;
     }
 
+    public void setSubscriptionManager(SubscriptionManager subscriptionManager) {
+        mSubscriptionManager = subscriptionManager;
+    }
+
     public TelephonyManager getTelephonyManager() {
         return mTelephonyManager;
     }
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 8cdb66e..ffa08e2 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -51,6 +51,8 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Xml;
@@ -83,6 +85,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -98,6 +101,7 @@
     private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService";
     private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
     private PhoneAccountRegistrar mRegistrar;
+    @Mock private SubscriptionManager mSubscriptionManager;
     @Mock private TelecomManager mTelecomManager;
     @Mock private DefaultDialerCache mDefaultDialerCache;
     @Mock private AppLabelProxy mAppLabelProxy;
@@ -108,6 +112,7 @@
         super.setUp();
         MockitoAnnotations.initMocks(this);
         mComponentContextFixture.setTelecomManager(mTelecomManager);
+        mComponentContextFixture.setSubscriptionManager(mSubscriptionManager);
         new File(
                 mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
                 FILE_NAME)
@@ -1226,6 +1231,29 @@
         clearInvocations(mComponentContextFixture.getTelephonyManager());
     }
 
+    /**
+     * Test PhoneAccountHandle Migration Logic.
+     */
+    @Test
+    public void testPhoneAccountMigration() throws Exception {
+        PhoneAccountRegistrar.State testState = makeQuickStateWithTelephonyPhoneAccountHandle();
+        final int mTestPhoneAccountHandleSubIdInt = 123;
+        // Mock SubscriptionManager
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo(
+                mTestPhoneAccountHandleSubIdInt, "id0", 1, "a", "b", 1, 1, "test",
+                        1, null, null, null, null, false, null, null);
+        List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>();
+        subscriptionInfoList.add(subscriptionInfo);
+        when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(subscriptionInfoList);
+        mRegistrar.migratePhoneAccountHandle(testState);
+        Collection<DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+                = testState.defaultOutgoingAccountHandles.values();
+        DefaultPhoneAccountHandle defaultPhoneAccountHandle
+                = defaultPhoneAccountHandles.iterator().next();
+        assertEquals(Integer.toString(mTestPhoneAccountHandleSubIdInt),
+                defaultPhoneAccountHandle.phoneAccountHandle.getId());
+    }
+
     private static ComponentName makeQuickConnectionServiceComponentName() {
         return new ComponentName(
                 "com.android.server.telecom.tests",
@@ -1447,6 +1475,25 @@
         }
     }
 
+    private PhoneAccountRegistrar.State makeQuickStateWithTelephonyPhoneAccountHandle() {
+        PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
+        s.accounts.add(makeQuickAccount("id0", 0));
+        s.accounts.add(makeQuickAccount("id1", 1));
+        s.accounts.add(makeQuickAccount("id2", 2));
+        PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(new ComponentName(
+                "com.android.phone",
+                        "com.android.services.telephony.TelephonyConnectionService"), "id0");
+        UserHandle userHandle = phoneAccountHandle.getUserHandle();
+        when(UserManager.get(mContext).getSerialNumberForUser(userHandle))
+            .thenReturn(0L);
+        when(UserManager.get(mContext).getUserForSerialNumber(0L))
+            .thenReturn(userHandle);
+        s.defaultOutgoingAccountHandles
+            .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
+                "testGroup"));
+        return s;
+    }
+
     private PhoneAccountRegistrar.State makeQuickState() {
         PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
         s.accounts.add(makeQuickAccount("id0", 0));
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index b4f0c4b..210f80e 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -199,10 +199,6 @@
         super.setUp();
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
 
-        TelephonyManager mockTelephonyManager =
-                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        when(mockTelephonyManager.isVoiceCapable()).thenReturn(true);
-
         doReturn(mContext).when(mContext).getApplicationContext();
         doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
         doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class),
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 0991f36..d6ff196 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -573,9 +573,6 @@
                 com.android.server.telecom.R.string.incall_default_class,
                 mInCallServiceComponentNameX.getClassName());
 
-        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
-                .isVoiceCapable();
-
         mInCallServiceFixtureX = new InCallServiceFixture();
         mInCallServiceFixtureY = new InCallServiceFixture();