Merge "Fix USSD Api test app"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 503cd91..49882b0 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -28,10 +28,10 @@
     <string name="notification_missedCall_message" msgid="3049928912736917988">"Poruka"</string>
     <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvuk poziva je isključen."</string>
     <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Zvučnik je omogućen."</string>
-    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ne mogu sada pričati. Šta ima?"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ne mogu sada pričati. O čemu se radi?"</string>
     <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Nazvat ću te uskoro."</string>
     <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Nazvat ću te kasnije."</string>
-    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ne mogu pričati. Nazovi kasnije?"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ne mogu pričati. Nazovi me kasnije."</string>
     <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Brzi odgovori"</string>
     <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Uredi brze odgovore"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 992df6f..5497d76 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,7 +29,7 @@
     <string name="accessibility_call_muted" msgid="2776111226185342220">"Llamada silenciada"</string>
     <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altavoz habilitado"</string>
     <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"No puedo hablar ahora. ¿Todo bien?"</string>
-    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Te llamo enseguida."</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Te llamo en seguida."</string>
     <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Te llamo más tarde."</string>
     <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"No puedo hablar ahora. ¿Me llamas más tarde?"</string>
     <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respuestas rápidas"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 358b106..eefd65f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
     <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Je t\'appellerai plus tard."</string>
     <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Peux pas parler. On se rappelle ?"</string>
     <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Réponses rapides"</string>
-    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Modifier réponses rapides"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Modifier les réponses rapides"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Réponse rapide"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message envoyé à <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 9e76715..e5bcb91 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -29,9 +29,9 @@
     <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvuk poziva isključen."</string>
     <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Zvučnik je omogućen."</string>
     <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Sada ne mogu razgovarati. Što ima?"</string>
-    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Nazvat ću vas odmah."</string>
-    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Zvat ću vas kasnije."</string>
-    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Sada ne mogu razgovarati. Nazovite me kasnije."</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Zovem čim stignem."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Nazvat ću kasnije."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Sad ne mogu razgovarati. Čujemo se kasnije."</string>
     <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Brzi odgovori"</string>
     <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Uređivanje brzih odgovora"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index e8fe522..b56255a 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -54,7 +54,7 @@
     <string name="block_number" msgid="1101252256321306179">"Ավելացնել համար"</string>
     <string name="unblock_dialog_body" msgid="1614238499771862793">"Արգելաբացե՞լ <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g> համարը:"</string>
     <string name="unblock_button" msgid="3078048901972674170">"Արգելաբացել"</string>
-    <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Արգելափակել այս համարից ուղարկված զանգերն ու հաղորդագրությունները՝"</string>
+    <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Արգելափակել զանգերն ու հաղորդագրությունները այս համարից"</string>
     <string name="add_blocked_number_hint" msgid="6847675097085433553">"Հեռախոսահամարը"</string>
     <string name="block_button" msgid="8822290682524373357">"Արգելափակել"</string>
     <string name="non_primary_user" msgid="5180129233352533459">"Միայն սարքի սեփականատերը կարող է դիտել և կառավարել արգելափակված համարները:"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 36b2473..4ee9c3f 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -49,8 +49,8 @@
     <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"မူရင်း သတ်မှတ်ရန်"</string>
     <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"မလုပ်တော့"</string>
     <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> သည် ခေါ်ဆိုမှုများကို ဘက်စုံပြုလုပ်ထိန်းချုပ်သွားနိုင်မည်ဖြစ်သည်။ သင်ယုံကြည်သော အက်ပ်များကိုသာ မူရင်း Phone အက်ပ်အဖြစ် သတ်မှတ်သင့်ပါသည်။"</string>
-    <string name="blocked_numbers" msgid="2751843139572970579">"ပိတ်ဆို့ထားသည့် နံပါတ်များ"</string>
-    <string name="blocked_numbers_msg" msgid="1045015186124965643">"သင်သည် ဘလော့ခ်လုပ်ထားသော နံပါတ်များမှ ဖုန်းခေါ်ခြင်း (သို့) စာသားပို့ခြင်းတို့ကို လက်ခံရရှိမည် မဟုတ်ပါ။"</string>
+    <string name="blocked_numbers" msgid="2751843139572970579">"ပိတ်ထားသည့် နံပါတ်များ"</string>
+    <string name="blocked_numbers_msg" msgid="1045015186124965643">"ပိတ်ထားသော နံပါတ်များမှ ဖုန်းခေါ်ခြင်း (သို့) စာသားပို့ခြင်းတို့ကို သင်လက်ခံရရှိမည် မဟုတ်ပါ။"</string>
     <string name="block_number" msgid="1101252256321306179">"နံပါတ်တစ်ခု ထည့်ပါ"</string>
     <string name="unblock_dialog_body" msgid="1614238499771862793">"<xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g> ကို ပိတ်ဆို့မှုပြန်ဖွင့်မလား။"</string>
     <string name="unblock_button" msgid="3078048901972674170">"ပိတ်ဆို့မှုပြန်ဖွင့်ပါ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 2fd44a5..d57efdc 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -50,7 +50,7 @@
     <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Anuluj"</string>
     <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> uzyska możliwość nawiązywania połączeń i kontrolowania wszystkich ich aspektów. Tylko zaufane aplikacje powinny być ustawiane jako domyślna aplikacja telefoniczna."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Zablokowane numery"</string>
-    <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nie będziesz otrzymywać połączeń ani SMS-ów z zablokowanych numerów."</string>
+    <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nie będziesz otrzymywać połączeń ani SMS-ów z zablokowanych numerów."</string>
     <string name="block_number" msgid="1101252256321306179">"Dodaj numer"</string>
     <string name="unblock_dialog_body" msgid="1614238499771862793">"Odblokować <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
     <string name="unblock_button" msgid="3078048901972674170">"Odblokuj"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 11d688a..3952f30 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -28,10 +28,10 @@
     <string name="notification_missedCall_message" msgid="3049928912736917988">"簡訊"</string>
     <string name="accessibility_call_muted" msgid="2776111226185342220">"通話已靜音。"</string>
     <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"喇叭已啟用"</string>
-    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"我現在不方便通話,有什麼事?"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"我現在不方便講話,有什麼事?"</string>
     <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"我待會就回電。"</string>
     <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"我晚點回電。"</string>
-    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"我現在不方便通話,晚點再打來好嗎?"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"我現在不方便講話,晚點再打來好嗎?"</string>
     <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"快速回應"</string>
     <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"編輯快速回應"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 0dd2cca..a71770f 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -128,7 +128,8 @@
         void onExternalCallChanged(Call call, boolean isExternalCall);
         void onRttInitiationFailure(Call call, int reason);
         void onRemoteRttRequest(Call call, int requestId);
-        void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState);
+        void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState,
+                                 Bundle extras);
     }
 
     public abstract static class ListenerBase implements Listener {
@@ -201,7 +202,8 @@
         @Override
         public void onRemoteRttRequest(Call call, int requestId) {}
         @Override
-        public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState) {}
+        public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState,
+                                        Bundle extras) {}
     }
 
     private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener =
@@ -1015,6 +1017,30 @@
         return phoneAccount.getLabel();
     }
 
+    /**
+     * Determines if this Call should be written to the call log.
+     * @return {@code true} for managed calls or for self-managed calls which have the
+     * {@link PhoneAccount#EXTRA_LOG_SELF_MANAGED_CALLS} extra set.
+     */
+    public boolean isLoggedSelfManaged() {
+        if (!isSelfManaged()) {
+            // Managed calls are always logged.
+            return true;
+        }
+        if (getTargetPhoneAccount() == null) {
+            return false;
+        }
+        PhoneAccount phoneAccount = mCallsManager.getPhoneAccountRegistrar()
+                .getPhoneAccountUnchecked(getTargetPhoneAccount());
+
+        if (phoneAccount == null) {
+            return false;
+        }
+
+        return phoneAccount.getExtras() != null && phoneAccount.getExtras().getBoolean(
+                PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, false);
+    }
+
     @VisibleForTesting
     public boolean isIncoming() {
         return mCallDirection == CALL_DIRECTION_INCOMING;
@@ -1044,6 +1070,27 @@
         setConnectionProperties(getConnectionProperties());
     }
 
+    /**
+     * Marks a handover as being completed, either as a result of failing to handover or completion
+     * of handover.
+     */
+    public void markHandoverFinished() {
+        if (mHandoverFromCall != null) {
+            mHandoverFromCall.setHandoverFromCall(null);
+            mHandoverFromCall.setHandoverToCall(null);
+            mHandoverFromCall = null;
+        } else if (mHandoverToCall != null) {
+            mHandoverToCall.setHandoverFromCall(null);
+            mHandoverToCall.setHandoverToCall(null);
+            mHandoverToCall = null;
+        }
+
+    }
+
+    public boolean isHandoverInProgress() {
+        return mHandoverFromCall != null || mHandoverToCall != null;
+    }
+
     public Call getHandoverToCall() {
         return mHandoverToCall;
     }
@@ -1895,7 +1942,13 @@
                 PhoneAccountHandle phoneAccountHandle = (PhoneAccountHandle) parcelable;
                 int videoState = extras.getInt(android.telecom.Call.EXTRA_HANDOVER_VIDEO_STATE,
                         VideoProfile.STATE_AUDIO_ONLY);
-                requestHandover(phoneAccountHandle, videoState);
+                Parcelable handoverExtras = extras.getParcelable(
+                        android.telecom.Call.EXTRA_HANDOVER_EXTRAS);
+                Bundle handoverExtrasBundle = null;
+                if (handoverExtras instanceof Bundle) {
+                    handoverExtrasBundle = (Bundle) handoverExtras;
+                }
+                requestHandover(phoneAccountHandle, videoState, handoverExtrasBundle);
             } else {
                 Log.addEvent(this, LogUtils.Events.CALL_EVENT, event);
                 mConnectionService.sendCallEvent(this, event, extras);
@@ -2583,10 +2636,13 @@
      * Initiates a handover of this {@link Call} to another {@link PhoneAccount}.
      * @param handoverToHandle The {@link PhoneAccountHandle} to handover to.
      * @param videoState The video state of the call when handed over.
+     * @param extras Optional extras {@link Bundle} provided by the initiating
+     *      {@link android.telecom.InCallService}.
      */
-    private void requestHandover(PhoneAccountHandle handoverToHandle, int videoState) {
+    private void requestHandover(PhoneAccountHandle handoverToHandle, int videoState,
+                                 Bundle extras) {
         for (Listener l : mListeners) {
-            l.onHandoverRequested(this, handoverToHandle, videoState);
+            l.onHandoverRequested(this, handoverToHandle, videoState, extras);
         }
     }
 }
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 5f732e6..f778e30 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -637,7 +637,7 @@
     private void playToneForDisconnectedCall(Call call) {
         // If this call is being disconnected as a result of being handed over to another call,
         // we will not play a disconnect tone.
-        if (call.getHandoverToCall() != null || call.getHandoverFromCall() != null) {
+        if (call.isHandoverInProgress()) {
             Log.i(LOG_TAG, "Omitting tone because %s is being handed over.", call);
             return;
         }
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index c9569d7..8057afc 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.location.Country;
 import android.location.CountryDetector;
-import android.location.CountryListener;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Looper;
@@ -146,13 +145,15 @@
         // 2) It is a conference call
         // 3) Call was not explicitly canceled
         // 4) Call is not an external call
-        // 5) Call is not a self-managed call
+        // 5) Call is not a self-managed call OR call is a self-managed call which has indicated it
+        //    should be logged in its PhoneAccount
         if (isNewlyDisconnected &&
                 (oldState != CallState.SELECT_PHONE_ACCOUNT &&
                  !call.isConference() &&
                  !isCallCanceled) &&
                 !call.isExternalCall() &&
-                !call.isSelfManaged()) {
+                (!call.isSelfManaged() ||
+                call.isLoggedSelfManaged())) {
             int type;
             if (!call.isIncoming()) {
                 type = Calls.OUTGOING_TYPE;
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 2b3529b..8f97b1b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -711,10 +711,12 @@
      * @param call The call.
      * @param handoverTo The {@link PhoneAccountHandle} to handover the call to.
      * @param videoState The desired video state of the call after handover.
+     * @param extras
      */
     @Override
-    public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState) {
-        requestHandover(call, handoverTo, videoState);
+    public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState,
+                                    Bundle extras) {
+        requestHandover(call, handoverTo, videoState, extras);
     }
 
     @VisibleForTesting
@@ -884,7 +886,6 @@
         if (isHandover) {
             if (!isHandoverInProgress() &&
                     isHandoverToPhoneAccountSupported(phoneAccountHandle)) {
-                Log.w(this, "processIncomingCallIntent: To account doesn't support handover.");
                 final String handleScheme = handle.getSchemeSpecificPart();
                 Call fromCall = mCalls.stream()
                         .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber(
@@ -906,7 +907,14 @@
                     // Link the calls so we know we're handing over.
                     fromCall.setHandoverToCall(call);
                     call.setHandoverFromCall(fromCall);
+                    Log.addEvent(fromCall, LogUtils.Events.START_HANDOVER,
+                            "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId());
+                    Log.addEvent(call, LogUtils.Events.START_HANDOVER,
+                            "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId());
                 }
+            } else {
+                Log.w(this, "processIncomingCallIntent: To account doesn't support handover.");
+                isHandoverAllowed = false;
             }
         }
         if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
@@ -1713,8 +1721,7 @@
      * Removes an existing disconnected call, and notifies the in-call app.
      */
     void markCallAsRemoved(Call call) {
-        call.setHandoverToCall(null);
-        call.setHandoverFromCall(null);
+        call.markHandoverFinished();
 
         removeCall(call);
         Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
@@ -2149,22 +2156,49 @@
                 if (newState == CallState.ACTIVE) {
                     Call handoverFrom = call.getHandoverFromCall();
                     Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
-                            call.getId(), handoverFrom.getId());
+                            handoverFrom.getId(), call.getId());
                     Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
-                            call.getId(), handoverFrom.getId());
+                            handoverFrom.getId(), call.getId());
+                    handoverFrom.onConnectionEvent(
+                            android.telecom.Connection.EVENT_HANDOVER_COMPLETE, null);
                     markCallAsDisconnected(handoverFrom,
                             new DisconnectCause(DisconnectCause.LOCAL));
                     markCallAsRemoved(handoverFrom);
                     call.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
+                    call.markHandoverFinished();
                 } else if (newState == CallState.DISCONNECTED) {
                     Call handoverFrom = call.getHandoverFromCall();
                     Log.i(this, "Call %s failed to handover from %s.",
                             call.getId(), handoverFrom.getId());
                     Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s",
                             call.getId(), handoverFrom.getId());
-                    handoverFrom.sendCallEvent(
-                            android.telecom.Call.EVENT_HANDOVER_FAILED, null);
+                    // Inform the "from" Call (ie the source call) that the handover from it has
+                    // failed; this allows the InCallService to be notified that a handover it
+                    // initiated failed.
+                    handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null);
+                    // Inform the "to" ConnectionService that handover to it has failed.  This
+                    // allows the ConnectionService the call was being handed over
+                    call.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null);
+                    call.markHandoverFinished();
                 }
+            // If this call was disconnected because it was handed over TO another call, report the
+            // handover as complete.
+            } else if (call.getHandoverToCall() != null && newState == CallState.DISCONNECTED) {
+                Call handoverTo = call.getHandoverToCall();
+
+                Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
+                        call.getId(), handoverTo.getId());
+                Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
+                        call.getId(), handoverTo.getId());
+
+                // Inform the "from" Call (ie the source call) that the handover from it has
+                // completed; this allows the InCallService to be notified that a handover it
+                // initiated completed.
+                call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null);
+                // Inform the "to" ConnectionService that handover to it has completed.
+                handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
+                answerCall(handoverTo, handoverTo.getVideoState());
+                call.markHandoverFinished();
             }
 
             // Only broadcast state change for calls that are being tracked.
@@ -2843,9 +2877,11 @@
      * @param handoverFromCall The {@link Call} to be handed over.
      * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to.
      * @param videoState The desired video state of {@link Call} after handover.
+     * @param initiatingExtras Extras associated with the handover, to be passed to the handover
+     *               {@link android.telecom.ConnectionService}.
      */
     private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle,
-                                 int videoState) {
+                                 int videoState, Bundle initiatingExtras) {
 
         boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported(
                 handoverFromCall.getTargetPhoneAccount());
@@ -2861,6 +2897,11 @@
         Bundle extras = new Bundle();
         extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
         extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
+        if (initiatingExtras != null) {
+            extras.putAll(initiatingExtras);
+        }
+        extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE,
+                mCallAudioManager.getCallAudioState());
         Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle,
                 extras, getCurrentUserHandle());
         Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER,
@@ -2880,7 +2921,7 @@
      * @return {@code true} if handover is currently allowed, {@code false} otherwise.
      */
     private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) {
-        return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO);
+        return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM);
     }
 
     /**
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index dc90787..d445bd6 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -919,6 +919,12 @@
                       mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
                 }
 
+                // Call is incoming and added because we're handing over from another; tell CS
+                // that its expected to handover.
+                if (call.isIncoming() && call.getHandoverFromCall() != null) {
+                    extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
+                }
+
                 Log.addEvent(call, LogUtils.Events.START_CONNECTION,
                         Log.piiHandle(call.getHandle()));
 
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 8cdec30..074f325 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -73,6 +73,7 @@
 import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -1089,6 +1090,52 @@
         }
     }
 
+    private void sortPhoneAccounts() {
+        if (mState.accounts.size() > 1) {
+            // Sort the phone accounts using sort order:
+            // 1) SIM accounts first, followed by non-sim accounts
+            // 2) Sort order, with those specifying no sort order last.
+            // 3) Label
+
+            // Comparator to sort SIM subscriptions before non-sim subscriptions.
+            Comparator<PhoneAccount> bySimCapability = (p1, p2) -> {
+                if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                        && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                    return -1;
+                } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                        && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            };
+
+            // Create a string comparator which will sort strings, placing nulls last.
+            Comparator<String> nullSafeStringComparator = Comparator.nullsLast(
+                    String::compareTo);
+
+            // Comparator which places PhoneAccounts with a specified sort order first, followed by
+            // those with no sort order.
+            Comparator<PhoneAccount> bySortOrder = (p1, p2) -> {
+                String sort1 = p1.getExtras() == null ? null :
+                        p1.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
+                String sort2 = p2.getExtras() == null ? null :
+                        p2.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
+                return nullSafeStringComparator.compare(sort1, sort2);
+            };
+
+            // Comparator which sorts PhoneAccounts by label.
+            Comparator<PhoneAccount> byLabel = (p1, p2) -> {
+                String s1 = p1.getLabel() == null ? null : p1.getLabel().toString();
+                String s2 = p2.getLabel() == null ? null : p2.getLabel().toString();
+                return nullSafeStringComparator.compare(s1, s2);
+            };
+
+            // Sort the phone accounts.
+            mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel)));
+        }
+    }
+
     ////////////////////////////////////////////////////////////////////////////////////////////////
     //
     // State management
@@ -1115,6 +1162,7 @@
 
     private void write() {
         try {
+            sortPhoneAccounts();
             ByteArrayOutputStream os = new ByteArrayOutputStream();
             XmlSerializer serializer = new FastXmlSerializer();
             serializer.setOutput(os, "utf-8");
@@ -1870,4 +1918,8 @@
             return null;
         }
     };
+
+    private String nullToEmpty(String str) {
+        return str == null ? "" : str;
+    }
 }
diff --git a/src/com/android/server/telecom/ui/IncomingCallNotifier.java b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
index a4c56d2..ea3105d 100644
--- a/src/com/android/server/telecom/ui/IncomingCallNotifier.java
+++ b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
@@ -133,7 +133,7 @@
     private void updateIncomingCall() {
         Optional<Call> incomingCallOp = mCalls.stream()
                 .filter(call -> call.isSelfManaged() && call.isIncoming() &&
-                        call.getState() == CallState.RINGING)
+                        call.getState() == CallState.RINGING && !call.isHandoverInProgress())
                 .findFirst();
         Call incomingCall = incomingCallOp.orElse(null);
         if (incomingCall != null && mCallsManagerProxy != null &&
@@ -263,7 +263,7 @@
         builder.setContentTitle(incomingCallText);
         builder.setContentText(disconnectText);
         builder.setSmallIcon(R.drawable.ic_phone);
-        builder.setChannel(NotificationChannelManager.CHANNEL_ID_INCOMING_CALLS);
+        builder.setChannelId(NotificationChannelManager.CHANNEL_ID_INCOMING_CALLS);
         // Ensures this is a heads up notification.  A heads-up notification is typically only shown
         // if there is a fullscreen intent.  However since this notification doesn't have that we
         // will use this trick to get it to show as one anyways.
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 1081c98..bbacd36 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -332,7 +332,7 @@
                 // notification is shown on the user's lock screen and they have chosen to hide
                 // sensitive notification information.
                 .setPublicVersion(publicBuilder.build())
-                .setChannel(NotificationChannelManager.CHANNEL_ID_MISSED_CALLS);
+                .setChannelId(NotificationChannelManager.CHANNEL_ID_MISSED_CALLS);
 
         Uri handleUri = callInfo.getHandle();
         String handle = callInfo.getHandleSchemeSpecificPart();
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index e30ef42..e55de33 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -92,6 +92,11 @@
             android:layout_height="wrap_content"
             android:text="Incoming Call"
             android:id="@+id/placeIncomingCallButton" />
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Handover From"
+            android:id="@+id/handoverFrom" />
     </LinearLayout>
 
     <ListView
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index 83efba4..f9bce35 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -93,16 +93,20 @@
 
     public void registerPhoneAccounts(Context context) {
         registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_1, SELF_MANAGED_ADDRESS_1,
-                SELF_MANAGED_NAME_1);
+                SELF_MANAGED_NAME_1, true /* areCallsLogged */);
         registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_2, SELF_MANAGED_ADDRESS_2,
-                SELF_MANAGED_NAME_2);
+                SELF_MANAGED_NAME_2, false /* areCallsLogged */);
     }
 
-    public void registerPhoneAccount(Context context, String id, Uri address, String name) {
+    public void registerPhoneAccount(Context context, String id, Uri address, String name,
+                                     boolean areCallsLogged) {
         PhoneAccountHandle handle = new PhoneAccountHandle(COMPONENT_NAME, id);
         mPhoneAccounts.put(id, handle);
         Bundle extras = new Bundle();
         extras.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO, true);
+        if (areCallsLogged) {
+            extras.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true);
+        }
         PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index 4dfa012..6139e33 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -47,6 +47,7 @@
     private CheckBox mCheckIfPermittedBeforeCalling;
     private Button mPlaceOutgoingCallButton;
     private Button mPlaceIncomingCallButton;
+    private Button mHandoverFrom;
     private RadioButton mUseAcct1Button;
     private RadioButton mUseAcct2Button;
     private RadioButton mVideoCallButton;
@@ -100,9 +101,13 @@
         mPlaceIncomingCallButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                placeIncomingCall();
+                placeIncomingCall(false /* isHandoverFrom */);
             }
         });
+        mHandoverFrom = (Button) findViewById(R.id.handoverFrom);
+        mHandoverFrom.setOnClickListener((v -> {
+            placeIncomingCall(true /* isHandoverFrom */);
+        }));
 
         mUseAcct1Button = (RadioButton) findViewById(R.id.useAcct1Button);
         mUseAcct2Button = (RadioButton) findViewById(R.id.useAcct2Button);
@@ -148,7 +153,7 @@
         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
     }
 
-    private void placeIncomingCall() {
+    private void placeIncomingCall(boolean isHandoverFrom) {
         TelecomManager tm = TelecomManager.from(this);
         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
 
@@ -166,6 +171,9 @@
             extras.putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE,
                     VideoProfile.STATE_BIDIRECTIONAL);
         }
+        if (isHandoverFrom) {
+            extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
+        }
         tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
     }
 }
\ No newline at end of file
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
index 72a6184..82967c4 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
@@ -82,6 +82,9 @@
 
     @Override
     public void onShowIncomingCallUi() {
+        if (isHandover()) {
+            return;
+        }
         // Create the fullscreen intent used to show the fullscreen incoming call UX.
         Intent intent = new Intent(Intent.ACTION_MAIN, null);
         intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
index 4f28848..7ef9c26 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
@@ -84,11 +84,15 @@
         if (requestExtras != null) {
             connection.setIsHandover(requestExtras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER,
                     false));
-            Intent intent = new Intent(Intent.ACTION_MAIN, null);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
-            intent.setClass(this, HandoverActivity.class);
-            intent.putExtra(HandoverActivity.EXTRA_CALL_ID, connection.getCallId());
-            startActivity(intent);
+            if (!isIncoming && connection.isHandover()) {
+                Intent intent = new Intent(Intent.ACTION_MAIN, null);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.setClass(this, HandoverActivity.class);
+                intent.putExtra(HandoverActivity.EXTRA_CALL_ID, connection.getCallId());
+                startActivity(intent);
+            } else {
+                Log.i(this, "Handover incoming call created.");
+            }
         }
 
         // Track the phone account handle which created this connection so we can distinguish them
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 2898457..a98712c 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -51,6 +51,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 import static org.mockito.Matchers.anyInt;
@@ -577,6 +578,192 @@
         assertEquals(PhoneAccount.CAPABILITY_SELF_MANAGED, registeredAccount.getCapabilities());
     }
 
+    @MediumTest
+    public void testSortSimFirst() throws Exception {
+        ComponentName componentA = new ComponentName("a", "a");
+        ComponentName componentB = new ComponentName("b", "b");
+        mComponentContextFixture.addConnectionService(componentA,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentB,
+                Mockito.mock(IConnectionService.class));
+
+        PhoneAccount simAccount = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentB, "2"), "2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                .setIsEnabled(true)
+                .build();
+
+        PhoneAccount nonSimAccount = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentA, "1"), "1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setIsEnabled(true)
+                .build();
+
+        registerAndEnableAccount(nonSimAccount);
+        registerAndEnableAccount(simAccount);
+
+        List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle());
+        assertTrue(accounts.get(0).getLabel().toString().equals("2"));
+        assertTrue(accounts.get(1).getLabel().toString().equals("1"));
+    }
+
+    @MediumTest
+    public void testSortBySortOrder() throws Exception {
+        ComponentName componentA = new ComponentName("a", "a");
+        ComponentName componentB = new ComponentName("b", "b");
+        ComponentName componentC = new ComponentName("c", "c");
+        mComponentContextFixture.addConnectionService(componentA,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentB,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentC,
+                Mockito.mock(IConnectionService.class));
+
+        PhoneAccount account1 = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentA, "c"), "c")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "A"))
+                .build();
+
+        PhoneAccount account2 = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentB, "b"), "b")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "B"))
+                .build();
+
+        PhoneAccount account3 = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentC, "c"), "a")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        registerAndEnableAccount(account3);
+        registerAndEnableAccount(account2);
+        registerAndEnableAccount(account1);
+
+        List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle());
+        assertTrue(accounts.get(0).getLabel().toString().equals("c"));
+        assertTrue(accounts.get(1).getLabel().toString().equals("b"));
+        assertTrue(accounts.get(2).getLabel().toString().equals("a"));
+    }
+
+    @MediumTest
+    public void testSortByLabel() throws Exception {
+        ComponentName componentA = new ComponentName("a", "a");
+        ComponentName componentB = new ComponentName("b", "b");
+        ComponentName componentC = new ComponentName("c", "c");
+        mComponentContextFixture.addConnectionService(componentA,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentB,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentC,
+                Mockito.mock(IConnectionService.class));
+
+        PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(componentA, "c"),
+                "c")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(componentB, "b"),
+                "b")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(componentC, "a"),
+                "a")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        registerAndEnableAccount(account1);
+        registerAndEnableAccount(account2);
+        registerAndEnableAccount(account3);
+
+        List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle());
+        assertTrue(accounts.get(0).getLabel().toString().equals("a"));
+        assertTrue(accounts.get(1).getLabel().toString().equals("b"));
+        assertTrue(accounts.get(2).getLabel().toString().equals("c"));
+    }
+
+    @MediumTest
+    public void testSortAll() throws Exception {
+        ComponentName componentA = new ComponentName("a", "a");
+        ComponentName componentB = new ComponentName("b", "b");
+        ComponentName componentC = new ComponentName("c", "c");
+        ComponentName componentW = new ComponentName("w", "w");
+        ComponentName componentX = new ComponentName("x", "x");
+        ComponentName componentY = new ComponentName("y", "y");
+        ComponentName componentZ = new ComponentName("z", "z");
+        mComponentContextFixture.addConnectionService(componentA,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentB,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentC,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentW,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentX,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentY,
+                Mockito.mock(IConnectionService.class));
+        mComponentContextFixture.addConnectionService(componentZ,
+                Mockito.mock(IConnectionService.class));
+        PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "y"), "y")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "2"))
+                .build();
+
+        PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "z"), "z")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "1"))
+                .build();
+
+        PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "x"), "x")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                .build();
+
+        PhoneAccount account4 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "w"), "w")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                .build();
+
+        PhoneAccount account5 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "b"), "b")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        PhoneAccount account6 = new PhoneAccount.Builder(makeQuickAccountHandle(
+                makeQuickConnectionServiceComponentName(), "c"), "a")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+
+        registerAndEnableAccount(account1);
+        registerAndEnableAccount(account2);
+        registerAndEnableAccount(account3);
+        registerAndEnableAccount(account4);
+        registerAndEnableAccount(account5);
+        registerAndEnableAccount(account6);
+
+        List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle());
+        // Sim accts ordered by sort order first
+        assertTrue(accounts.get(0).getLabel().toString().equals("z"));
+        assertTrue(accounts.get(1).getLabel().toString().equals("y"));
+
+        // Sim accts with no sort order next
+        assertTrue(accounts.get(2).getLabel().toString().equals("w"));
+        assertTrue(accounts.get(3).getLabel().toString().equals("x"));
+
+        // Other accts sorted by label next
+        assertTrue(accounts.get(4).getLabel().toString().equals("a"));
+        assertTrue(accounts.get(5).getLabel().toString().equals("b"));
+    }
+
     private static ComponentName makeQuickConnectionServiceComponentName() {
         return new ComponentName(
                 "com.android.server.telecom.tests",