Merge "Support CDMA emergency callback. (2/2)" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 43a1f5e..1fcfd23 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -71,7 +71,7 @@
              URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
              contacts provider entries. Any data not fitting the schema described is ignored. -->
         <activity android:name="CallActivity"
-                android:theme="@android:style/Theme.NoDisplay"
+                android:theme="@style/Theme.Telecomm.Transparent"
                 android:permission="android.permission.CALL_PHONE"
                 android:excludeFromRecents="true">
             <!-- CALL action intent filters for the various ways of initiating an outgoing call. -->
@@ -202,12 +202,19 @@
 
         <activity android:name=".PhoneAccountPreferencesActivity"
                   android:label="@string/phone_account_preferences_title"
-                  android:configChanges="orientation|screenSize|keyboardHidden">
-                  android:exported="true" >
+                  android:configChanges="orientation|screenSize|keyboardHidden"
+                  android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
         </activity>
 
+        <activity android:name=".ErrorDialogActivity"
+                android:configChanges="orientation|screenSize|keyboardHidden"
+                android:excludeFromRecents="true"
+                android:launchMode="singleInstance"
+                android:theme="@style/Theme.Telecomm.Transparent">
+        </activity>
+
     </application>
 </manifest>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b9f3999..b9ffa44 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Бърз отговор"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"Възст. на станд. настройки"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"До <xliff:g id="PHONE_NUMBER">%s</xliff:g> бе изпратено съобщение."</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"Настройки на профила за телефона"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"Стандартен профил за изходящи обаждания"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Профил за обаждане през Wi-Fi"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"Извеждане на запитване всеки път"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 364dcbc..92ef8a6 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -41,5 +41,5 @@
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Konto für WLAN-Anrufe"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"Jedes Mal fragen"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"Keine WLAN-Anrufe nutzen"</string>
-    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"Dieser Nutzer darf abgesehen von Notrufen keine Telefonanrufe tätigen."</string>
+    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"Dieser Nutzer darf abgesehen von Notrufen keine Anrufe tätigen."</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 2083071..b7344f9 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Pikavastaukset"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"Palauta oletussovellus"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Viesti lähetetty numeroon <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"Puhelintilin asetukset"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"Lähtevien puheluiden oletustili"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Wi-Fi-puhelutili"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"Kysy aina"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index b5f7def..a5b7315 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"სწრაფი პასუხი"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"ნაგულისხმევი აპის ისევ დაყენება"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"შეტყობინება გაიგზავნა <xliff:g id="PHONE_NUMBER">%s</xliff:g>-თან."</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"ტელეფონის ანგარიშის პარამეტრები"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"ნაგულისხმევი გამავალი ანგარიში"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"ანგარიში Wi-Fi დარეკვისთვის"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"მკითხე ყოველ ჯერზე"</string>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 882c775..a3c49cc 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Respons pantas"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"Tetapkan semula apl lalai"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesej dihantar ke <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"Tetapan akaun telefon"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"Akaun keluar lalai"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Akaun panggilan Wi-Fi"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"Tanya setiap kali"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 37e185e..0fe8775 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -36,11 +36,10 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"द्रुत प्रतिक्रिया"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"पूर्वनिर्धारित अनुप्रयोग पुनःसेट गर्नुहोस्"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> लाई सन्देश पठाइयो।"</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"फोन खाता सेटिङहरू"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"बहिर्गमन पूर्वनिर्धारित खाता"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"वाइफाइ कल गर्ने खाता"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"प्रत्येक चोटि सोध्नुहोस्"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"वाइफाइ कल प्रयोग नगर्नुहोस्"</string>
-    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"यो प्रयोगकर्ता लाई गैर-आकस्मिक फोन कल गर्न अनुमति छैन"</string>
+    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"यो प्रयोगकर्तालाई गैर-आकस्मिक फोन कल गर्न अनुमति छैन"</string>
 </resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 95e06e2..91f9f29 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ක්ෂණික ප්‍රතිචාරය"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"සුපුරුදු යෙදුම යළි සකසන්න"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> හට පණිවිඩය යවන්න."</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"දුරකථන ගිණුම සැකසීම"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"සුපුරුදු එළියට යෑමේ ගිණුම"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Wi-Fi ඇමතුම් ගැනීමේ ගිණුම"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"සෑම වේලාවේම අසන්න"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 76f1ee8..4a5ad27 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -36,8 +36,7 @@
     <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回复"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"重置默认应用"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"讯息已发送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
-    <!-- no translation found for phone_account_preferences_title (5042332049625236956) -->
-    <skip />
+    <string name="phone_account_preferences_title" msgid="5042332049625236956">"电话帐户设置"</string>
     <string name="default_outgoing_account_title" msgid="8261079649574578970">"默认拨出帐户"</string>
     <string name="sim_call_manager_account" msgid="2559930293628077755">"WLAN通话帐户"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"每次都询问"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 650776d..26516e4 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -41,5 +41,5 @@
     <string name="sim_call_manager_account" msgid="2559930293628077755">"Wi-Fi 通話帳戶"</string>
     <string name="account_ask_every_time" msgid="944077828070287407">"每次都詢問"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"不要使用 Wi-Fi 通話功能"</string>
-    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"這位使用者只能撥打緊急電話"</string>
+    <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"這位使用者只可撥打緊急電話"</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f4a2e8..d50d830 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -95,6 +95,17 @@
          due to a user restriction -->
     <string name="outgoing_call_not_allowed">This user is not allowed to make non-emergency phone calls</string>
 
+    <!-- Call failure message displayed in an error dialog used to indicate that a phone number was not provided -->
+    <string name="outgoing_call_error_no_phone_number_supplied">Call not sent, no valid number entered.</string>
+
+    <!-- missing voicemail number -->
+    <!-- Title of the "Missing voicemail number" dialog -->
+    <string name="no_vm_number">Missing voicemail number</string>
+    <!-- Body text of the "Missing voicemail number" dialog -->
+    <string name="no_vm_number_msg">No voicemail number is stored on the SIM card.</string>
+    <!-- Button label on the "Missing voicemail number" dialog -->
+    <string name="add_vm_number_str">Add number</string>
+
     <!-- DO NOT TRANSLATE. Label for test Subscription 0. -->
     <string name="test_account_0_label">Q Mobile</string>
     <!-- DO NOT TRANSLATE. Label for test Subscription 1. -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..6b6c1bb
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="Theme.Telecomm.Transparent" parent="@android:style/Theme.Material.Light">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+    </style>
+</resources>
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 4fa39e8..dc3fa07 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -616,7 +616,9 @@
     }
 
     @Override
-    public void handleCreateConnectionSuccess(ParcelableConnection connection) {
+    public void handleCreateConnectionSuccess(
+            CallIdMapper idMapper,
+            ParcelableConnection connection) {
         Log.v(this, "handleCreateConnectionSuccessful %s", connection);
         mCreateConnectionProcessor = null;
         setTargetPhoneAccount(connection.getPhoneAccount());
@@ -630,6 +632,11 @@
         setAudioModeIsVoip(connection.getAudioModeIsVoip());
         setStatusHints(connection.getStatusHints());
 
+        mConferenceableCalls.clear();
+        for (String id : connection.getConferenceableConnectionIds()) {
+            mConferenceableCalls.add(idMapper.getCall(id));
+        }
+
         if (mIsIncoming) {
             // We do not handle incoming calls immediately when they are verified by the connection
             // service. We allow the caller-info-query code to execute first so that we can read the
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index 95dee18..0d36c8a 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -26,6 +26,7 @@
 import android.os.UserManager;
 import android.telecomm.PhoneAccountHandle;
 import android.telecomm.TelecommManager;
+import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.widget.Toast;
@@ -47,6 +48,7 @@
  * non-emergency numbers just like it did pre-L.
  */
 public class CallActivity extends Activity {
+
     private CallsManager mCallsManager = CallsManager.getInstance();
     private boolean mIsVoiceCapable;
 
@@ -149,9 +151,11 @@
 
         NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                 mCallsManager, call, intent, isDefaultDialer());
-        final boolean success = broadcaster.processIntent();
+        final int result = broadcaster.processIntent();
+        final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
+
         if (!success && call != null) {
-            call.disconnect();
+            disconnectCallAndShowErrorDialog(call, result);
         }
         setResult(success ? RESULT_OK : RESULT_CANCELED);
     }
@@ -209,4 +213,23 @@
         return getApplicationContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_voice_capable);
     }
+
+    private void disconnectCallAndShowErrorDialog(Call call, int errorCode) {
+        call.disconnect();
+        final Intent errorIntent = new Intent(this, ErrorDialogActivity.class);
+        int errorMessageId = -1;
+        switch (errorCode) {
+            case DisconnectCause.INVALID_NUMBER:
+                errorMessageId = R.string.outgoing_call_error_no_phone_number_supplied;
+                break;
+            case DisconnectCause.VOICEMAIL_NUMBER_MISSING:
+                errorIntent.putExtra(ErrorDialogActivity.SHOW_MISSING_VOICEMAIL_NO_DIALOG_EXTRA,
+                        true);
+                break;
+        }
+        if (errorMessageId != -1) {
+            errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId);
+        }
+        startActivity(errorIntent);
+    }
 }
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index 7d1f01a..5fcb9bd 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -894,7 +894,8 @@
         } else {
             // Successful connection
             if (mPendingResponses.containsKey(callId)) {
-                mPendingResponses.remove(callId).handleCreateConnectionSuccess(connection);
+                mPendingResponses.remove(callId)
+                        .handleCreateConnectionSuccess(mCallIdMapper, connection);
             }
         }
     }
diff --git a/src/com/android/telecomm/CreateConnectionProcessor.java b/src/com/android/telecomm/CreateConnectionProcessor.java
index d8fd00a..cc2e8c0 100644
--- a/src/com/android/telecomm/CreateConnectionProcessor.java
+++ b/src/com/android/telecomm/CreateConnectionProcessor.java
@@ -272,7 +272,9 @@
         }
 
         @Override
-        public void handleCreateConnectionSuccess(ParcelableConnection connection) {
+        public void handleCreateConnectionSuccess(
+                CallIdMapper idMapper,
+                ParcelableConnection connection) {
             if (mResponse == null) {
                 // Nobody is listening for this connection attempt any longer; ask the responsible
                 // ConnectionService to tear down any resources associated with the call
@@ -280,7 +282,7 @@
             } else {
                 // Success -- share the good news and remember that we are no longer interested
                 // in hearing about any more attempts
-                mResponse.handleCreateConnectionSuccess(connection);
+                mResponse.handleCreateConnectionSuccess(idMapper, connection);
                 mResponse = null;
             }
         }
diff --git a/src/com/android/telecomm/CreateConnectionResponse.java b/src/com/android/telecomm/CreateConnectionResponse.java
index b907e3a..13d1573 100644
--- a/src/com/android/telecomm/CreateConnectionResponse.java
+++ b/src/com/android/telecomm/CreateConnectionResponse.java
@@ -22,6 +22,6 @@
  * A callback for providing the result of creating a connection.
  */
 interface CreateConnectionResponse {
-    void handleCreateConnectionSuccess(ParcelableConnection connection);
+    void handleCreateConnectionSuccess(CallIdMapper idMapper, ParcelableConnection connection);
     void handleCreateConnectionFailure(int code, String message);
 }
diff --git a/src/com/android/telecomm/ErrorDialogActivity.java b/src/com/android/telecomm/ErrorDialogActivity.java
new file mode 100644
index 0000000..098a15f
--- /dev/null
+++ b/src/com/android/telecomm/ErrorDialogActivity.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecomm.TelecommManager;
+
+/**
+ * Used to display an error dialog from within the Telecomm service when an outgoing call fails
+ */
+public class ErrorDialogActivity extends Activity {
+    private static final String TAG = ErrorDialogActivity.class.getSimpleName();
+
+    public static final String SHOW_MISSING_VOICEMAIL_NO_DIALOG_EXTRA = "show_missing_voicemail";
+    public static final String ERROR_MESSAGE_ID_EXTRA = "error_message_id";
+
+    /**
+     * Intent action to bring up Voicemail Provider settings.
+     */
+    public static final String ACTION_ADD_VOICEMAIL =
+            "com.android.phone.CallFeaturesSetting.ADD_VOICEMAIL";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final boolean showVoicemailDialog = getIntent().getBooleanExtra(
+                SHOW_MISSING_VOICEMAIL_NO_DIALOG_EXTRA, false);
+
+        if (showVoicemailDialog) {
+            showMissingVoicemailErrorDialog();
+        } else {
+            final int error = getIntent().getIntExtra(ERROR_MESSAGE_ID_EXTRA, -1);
+            if (error == -1) {
+                Log.w(TAG, "ErrorDialogActivity called with no error type extra.");
+                finish();
+            } else {
+                showGenericErrorDialog(error);
+            }
+        }
+    }
+
+    private void showGenericErrorDialog(int resid) {
+        final CharSequence msg = getResources().getText(resid);
+        final DialogInterface.OnClickListener clickListener;
+        final DialogInterface.OnCancelListener cancelListener;
+
+        clickListener = new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                finish();
+            }
+        };
+
+        cancelListener = new DialogInterface.OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface dialog) {
+                finish();
+            }
+        };
+
+        final AlertDialog errorDialog = new AlertDialog.Builder(this)
+                .setMessage(msg).setPositiveButton(android.R.string.ok, clickListener)
+                        .setOnCancelListener(cancelListener).create();
+
+        errorDialog.show();
+    }
+
+    private void showMissingVoicemailErrorDialog() {
+        new AlertDialog.Builder(this)
+                .setTitle(R.string.no_vm_number)
+                .setMessage(R.string.no_vm_number_msg)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            finish();
+                        }})
+                .setNegativeButton(R.string.add_vm_number_str,
+                        new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    addVoiceMailNumberPanel(dialog);
+                                }})
+                .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface dialog) {
+                            finish();
+                        }}).show();
+    }
+
+
+    private void addVoiceMailNumberPanel(DialogInterface dialog) {
+        if (dialog != null) {
+            dialog.dismiss();
+        }
+
+        // Navigate to the Voicemail setting in the Call Settings activity.
+        Intent intent = new Intent(ACTION_ADD_VOICEMAIL);
+        startActivity(intent);
+        finish();
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+        // Don't show the return to previous task animation to avoid showing a black screen.
+        // Just dismiss the dialog and undim the previous activity immediately.
+        overridePendingTransition(0, 0);
+    }
+}
diff --git a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
index a45f4ef..1c44fb2 100644
--- a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
@@ -26,6 +26,7 @@
 import android.telecomm.GatewayInfo;
 import android.telecomm.TelecommManager;
 import android.telecomm.VideoProfile;
+import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
@@ -66,6 +67,7 @@
 
     private static final String SCHEME_TEL = "tel";
     private static final String SCHEME_SIP = "sip";
+    private static final String SCHEME_VOICEMAIL = "voicemail";
 
     private final CallsManager mCallsManager;
     private final Call mCall;
@@ -150,9 +152,10 @@
      * - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer)
      * - CALL_EMERGENCY (intent launched by lock screen emergency dialer)
      *
-     * @return whether or not the caller was allowed to start the outgoing call.
+     * @return {@link CallActivity#OUTGOING_CALL_SUCCEEDED} if the call succeeded, and an
+     *         appropriate {@link DisconnectCause} if the call did not, describing why it failed.
      */
-    boolean processIntent() {
+    int processIntent() {
         Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");
 
         final Context context = TelecommApp.getInstance();
@@ -161,8 +164,14 @@
         String handle = PhoneNumberUtils.getNumberFromIntent(intent, context);
 
         if (TextUtils.isEmpty(handle)) {
-            Log.w(this, "Empty handle obtained from the call intent.");
-            return false;
+            final Uri data = intent.getData();
+            if (data != null && SCHEME_VOICEMAIL.equals(data.getScheme())) {
+                Log.w(this, "Voicemail scheme provided but no voicemail number set.");
+                return DisconnectCause.VOICEMAIL_NUMBER_MISSING;
+            } else {
+                Log.w(this, "Empty handle obtained from the call intent.");
+                return DisconnectCause.INVALID_NUMBER;
+            }
         }
 
         boolean isUriNumber = PhoneNumberUtils.isUriNumber(handle);
@@ -187,7 +196,7 @@
                     Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
                             + "unless caller is system or default dialer.", handle, intent);
                     launchSystemDialer(context, intent.getData());
-                    return false;
+                    return DisconnectCause.OUTGOING_CANCELED;
                 } else {
                     callImmediately = true;
                 }
@@ -196,12 +205,12 @@
             if (!isPotentialEmergencyNumber) {
                 Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
                         + "Intent %s.", handle, intent);
-                return false;
+                return DisconnectCause.OUTGOING_CANCELED;
             }
             callImmediately = true;
         } else {
             Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
-            return false;
+            return DisconnectCause.INVALID_NUMBER;
         }
 
         if (callImmediately) {
@@ -223,7 +232,7 @@
         }
 
         broadcastIntent(intent, handle, context, !callImmediately);
-        return true;
+        return DisconnectCause.NOT_DISCONNECTED;
     }
 
     /**
diff --git a/src/com/android/telecomm/PhoneAccountPreferencesActivity.java b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java
index 9d30b87..7b64631 100644
--- a/src/com/android/telecomm/PhoneAccountPreferencesActivity.java
+++ b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java
@@ -57,7 +57,7 @@
             mDefaultOutgoingAccount.setModel(
                     registrar,
                     registrar.getOutgoingPhoneAccounts(),
-                    registrar.getDefaultOutgoingPhoneAccount(),
+                    registrar.getUserSelectedOutgoingPhoneAccount(),
                     getString(R.string.account_ask_every_time));
 
             mSimCallManagerAccount.setModel(
diff --git a/src/com/android/telecomm/PhoneAccountRegistrar.java b/src/com/android/telecomm/PhoneAccountRegistrar.java
index db05fff..f7cce27 100644
--- a/src/com/android/telecomm/PhoneAccountRegistrar.java
+++ b/src/com/android/telecomm/PhoneAccountRegistrar.java
@@ -65,6 +65,9 @@
  */
 public final class PhoneAccountRegistrar {
 
+    public static final PhoneAccountHandle NO_ACCOUNT_SELECTED =
+            new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED");
+
     public abstract static class Listener {
         public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
         public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
@@ -92,16 +95,9 @@
     }
 
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount() {
-        if (mState.defaultOutgoing != null) {
-            // Return the registered outgoing default iff it still exists (we keep a sticky
-            // default to survive account deletion and re-addition)
-            for (int i = 0; i < mState.accounts.size(); i++) {
-                if (mState.accounts.get(i).getAccountHandle().equals(mState.defaultOutgoing)) {
-                    return mState.defaultOutgoing;
-                }
-            }
-            // At this point, there was a registered default but it has been deleted; proceed
-            // as though there were no default
+        final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount();
+        if (userSelected != null) {
+            return userSelected;
         }
 
         List<PhoneAccountHandle> outgoing = getOutgoingPhoneAccounts();
@@ -118,6 +114,21 @@
         }
     }
 
+    PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
+        if (mState.defaultOutgoing != null) {
+            // Return the registered outgoing default iff it still exists (we keep a sticky
+            // default to survive account deletion and re-addition)
+            for (int i = 0; i < mState.accounts.size(); i++) {
+                if (mState.accounts.get(i).getAccountHandle().equals(mState.defaultOutgoing)) {
+                    return mState.defaultOutgoing;
+                }
+            }
+            // At this point, there was a registered default but it has been deleted; proceed
+            // as though there were no default
+        }
+        return null;
+    }
+
     public void setDefaultOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
         if (accountHandle == null) {
             // Asking to clear the default outgoing is a valid request
@@ -164,8 +175,11 @@
                 Log.d(this, "setSimCallManager: Not a call manager: %s", callManagerAccount);
                 return;
             }
+        } else {
+            callManager = NO_ACCOUNT_SELECTED;
         }
         mState.simCallManager = callManager;
+
         write();
         fireSimCallManagerChanged();
     }
@@ -176,6 +190,9 @@
         }
 
         if (mState.simCallManager != null) {
+            if (NO_ACCOUNT_SELECTED.equals(mState.simCallManager)) {
+                return null;
+            }
             // Return the registered sim call manager iff it still exists (we keep a sticky
             // setting to survive account deletion and re-addition)
             for (int i = 0; i < mState.accounts.size(); i++) {
diff --git a/src/com/android/telecomm/ProximitySensorManager.java b/src/com/android/telecomm/ProximitySensorManager.java
index c6b018a..287c6d4 100644
--- a/src/com/android/telecomm/ProximitySensorManager.java
+++ b/src/com/android/telecomm/ProximitySensorManager.java
@@ -74,7 +74,7 @@
         if (mProximityWakeLock.isHeld()) {
             Log.i(this, "Releasing proximity wake lock");
             int flags =
-                (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
+                (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_DISTANT_PROXIMITY);
             mProximityWakeLock.release(flags);
         } else {
             Log.i(this, "Proximity wake lock already released");
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index 7af1534..05f0e0a 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -29,7 +29,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ServiceManager;
-import android.phone.PhoneManager;
+import android.os.UserHandle;
 import android.telecomm.CallState;
 import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneAccountHandle;
@@ -250,10 +250,10 @@
     }
 
     /**
-     * @see TelecommManager#isInAPhoneCall
+     * @see TelecommManager#isInCall
      */
     @Override
-    public boolean isInAPhoneCall() {
+    public boolean isInCall() {
         enforceReadPermission();
         // Do not use sendRequest() with this method since it could cause a deadlock with
         // audio service, which we call into from the main thread: AudioManager.setMode().
@@ -288,16 +288,16 @@
     }
 
     /**
-     * @see PhoneManager#showCallScreen
+     * @see TelecommManager#showInCallScreen
      */
     @Override
-    public void showCallScreen(boolean showDialpad) {
+    public void showInCallScreen(boolean showDialpad) {
         enforceReadPermissionOrDefaultDialer();
         sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
     }
 
     /**
-     * @see PhoneManager#cancelMissedCallsNotification
+     * @see TelecommManager#cancelMissedCallsNotification
      */
     @Override
     public void cancelMissedCallsNotification() {
@@ -306,7 +306,7 @@
     }
 
     /**
-     * @see PhoneManager#handlePinMmi
+     * @see TelecommManager#handleMmi
      */
     @Override
     public boolean handlePinMmi(String dialString) {
@@ -356,7 +356,7 @@
             }
 
             long token = Binder.clearCallingIdentity();
-            TelecommApp.getInstance().startActivity(intent);
+            TelecommApp.getInstance().startActivityAsUser(intent, UserHandle.CURRENT);
             Binder.restoreCallingIdentity(token);
         }
     }
@@ -441,10 +441,6 @@
         mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
     }
 
-    private void showCallScreenInternal(boolean showDialpad) {
-        CallsManager.getInstance().getInCallController().bringToForeground(showDialpad);
-    }
-
     private boolean isDefaultDialerCalling() {
         ComponentName defaultDialerComponent = getDefaultPhoneApp();
         if (defaultDialerComponent != null) {
diff --git a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
index e941c2d..fb44069 100644
--- a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
+++ b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
@@ -70,7 +70,7 @@
     private void sendIncomingCallIntent(Context context, boolean isVideoCall) {
         PhoneAccountHandle phoneAccount = new PhoneAccountHandle(
                 new ComponentName(context, TestConnectionService.class),
-                CallServiceNotifier.CALL_PROVIDER_ID);
+                CallServiceNotifier.SIM_SUBSCRIPTION_ID);
 
         // For the purposes of testing, indicate whether the incoming call is a video call by
         // stashing an indicator in the EXTRA_INCOMING_CALL_EXTRAS.
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionManager.java b/tests/src/com/android/telecomm/testapps/TestConnectionManager.java
index 902ace7..95f0718 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionManager.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionManager.java
@@ -19,28 +19,28 @@
 import android.app.PendingIntent;
 import android.net.Uri;
 import android.telecomm.AudioState;
+import android.telecomm.Conference;
 import android.telecomm.Connection;
 import android.telecomm.ConnectionRequest;
 import android.telecomm.ConnectionService;
 import android.telecomm.PhoneAccountHandle;
+import android.telecomm.RemoteConference;
 import android.telecomm.RemoteConnection;
 import android.telecomm.StatusHints;
 import android.util.Log;
 
-import java.util.Random;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Service which acts as a fake ConnectionManager if so configured.
  * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
  */
 public class TestConnectionManager extends ConnectionService {
-    /**
-     * Random number generator used to generate phone numbers.
-     */
-    private Random mRandom = new Random();
-
-    private final class TestManagedConnection extends Connection {
-        private final RemoteConnection.Listener mProxyListener = new RemoteConnection.Listener() {
+    public final class TestManagedConnection extends Connection {
+        private final RemoteConnection.Listener mRemoteListener = new RemoteConnection.Listener() {
             @Override
             public void onStateChanged(RemoteConnection connection, int state) {
                 setState(state);
@@ -103,62 +103,76 @@
             @Override
             public void onDestroyed(RemoteConnection connection) {
                 destroy();
+                mManagedConnectionByRemote.remove(mRemote);
+            }
+
+            @Override
+            public void onConferenceableConnectionsChanged(
+                    RemoteConnection connect,
+                    List<RemoteConnection> conferenceable) {
+                List<Connection> c = new ArrayList<>();
+                for (RemoteConnection remote : conferenceable) {
+                    if (mManagedConnectionByRemote.containsKey(remote)) {
+                        c.add(mManagedConnectionByRemote.get(remote));
+                    }
+                }
+                setConferenceableConnections(c);
             }
         };
 
-        private final RemoteConnection mRemoteConnection;
+        private final RemoteConnection mRemote;
         private final boolean mIsIncoming;
 
-        TestManagedConnection(RemoteConnection remoteConnection, boolean isIncoming) {
-            mRemoteConnection = remoteConnection;
+        TestManagedConnection(RemoteConnection remote, boolean isIncoming) {
+            mRemote = remote;
             mIsIncoming = isIncoming;
-            mRemoteConnection.addListener(mProxyListener);
-            setState(mRemoteConnection.getState());
+            mRemote.addListener(mRemoteListener);
+            setState(mRemote.getState());
         }
 
         @Override
         public void onAbort() {
-            mRemoteConnection.abort();
+            mRemote.abort();
         }
 
         /** ${inheritDoc} */
         @Override
         public void onAnswer(int videoState) {
-            mRemoteConnection.answer(videoState);
+            mRemote.answer(videoState);
         }
 
         /** ${inheritDoc} */
         @Override
         public void onDisconnect() {
-            mRemoteConnection.disconnect();
+            mRemote.disconnect();
         }
 
         @Override
         public void onPlayDtmfTone(char c) {
-            mRemoteConnection.playDtmfTone(c);
+            mRemote.playDtmfTone(c);
         }
 
         /** ${inheritDoc} */
         @Override
         public void onHold() {
-            mRemoteConnection.hold();
+            mRemote.hold();
         }
 
         /** ${inheritDoc} */
         @Override
         public void onReject() {
-            mRemoteConnection.reject();
+            mRemote.reject();
         }
 
         /** ${inheritDoc} */
         @Override
         public void onUnhold() {
-            mRemoteConnection.unhold();
+            mRemote.unhold();
         }
 
         @Override
         public void onSetAudioState(AudioState state) {
-            mRemoteConnection.setAudioState(state);
+            mRemote.setAudioState(state);
         }
 
         private void setState(int state) {
@@ -180,29 +194,125 @@
         }
     }
 
+    public final class TestManagedConference extends Conference {
+        private final RemoteConference.Listener mRemoteListener = new RemoteConference.Listener() {
+            @Override
+            public void onStateChanged(RemoteConference conference, int oldState, int newState) {
+                switch (newState) {
+                    case Connection.STATE_DISCONNECTED:
+                        // See onDisconnected below
+                        break;
+                    case Connection.STATE_HOLDING:
+                        setOnHold();
+                        break;
+                    case Connection.STATE_ACTIVE:
+                        setActive();
+                        break;
+                    default:
+                        log("unrecognized state for Conference: " + newState);
+                        break;
+                }
+            }
+
+            @Override
+            public void onDisconnected(RemoteConference conference, int cause, String message) {
+                setDisconnected(cause, message);
+            }
+
+            @Override
+            public void onConnectionAdded(
+                    RemoteConference conference,
+                    RemoteConnection connection) {
+                TestManagedConnection c = mManagedConnectionByRemote.get(connection);
+                if (c == null) {
+                    log("onConnectionAdded cannot find remote connection: " + connection);
+                } else {
+                    addConnection(c);
+                }
+            }
+
+            @Override
+            public void onConnectionRemoved(
+                    RemoteConference conference,
+                    RemoteConnection connection) {
+                TestManagedConnection c = mManagedConnectionByRemote.get(connection);
+                if (c == null) {
+                    log("onConnectionRemoved cannot find remote connection: " + connection);
+                } else {
+                    removeConnection(c);
+                }
+            }
+
+            @Override
+            public void onCapabilitiesChanged(RemoteConference conference, int capabilities) {
+                setCapabilities(capabilities);
+            }
+
+            @Override
+            public void onDestroyed(RemoteConference conference) {
+                destroy();
+                mRemote.removeListener(mRemoteListener);
+                mManagedConferenceByRemote.remove(mRemote);
+            }
+        };
+
+        private final RemoteConference mRemote;
+
+        public TestManagedConference(RemoteConference remote) {
+            super(null);
+            mRemote = remote;
+            remote.addListener(mRemoteListener);
+            setActive();
+            for (RemoteConnection r : remote.getConnections()) {
+                TestManagedConnection c = mManagedConnectionByRemote.get(r);
+                if (c != null) {
+                    addConnection(c);
+                }
+            }
+        }
+    }
+
     private static void log(String msg) {
         Log.w("telecomtestcs", "[TestConnectionManager] " + msg);
     }
 
+    private final Map<RemoteConference, TestManagedConference> mManagedConferenceByRemote
+            = new HashMap<>();
+    private final Map<RemoteConnection, TestManagedConnection> mManagedConnectionByRemote
+            = new HashMap<>();
+
     @Override
     public Connection onCreateOutgoingConnection(
             PhoneAccountHandle connectionManagerAccount,
             final ConnectionRequest request) {
-        return new TestManagedConnection(
-                createRemoteOutgoingConnection(
-                        request.getAccountHandle(),
-                        request),
-                false);
+        return makeConnection(request, false);
     }
 
     @Override
     public Connection onCreateIncomingConnection(
             PhoneAccountHandle connectionManagerAccount,
             final ConnectionRequest request) {
-        return new TestManagedConnection(
-                createRemoteIncomingConnection(
-                        request.getAccountHandle(),
-                        request),
-                true);
+        return makeConnection(request, true);
+    }
+
+    @Override
+    public void onConference(Connection a, Connection b) {
+        conferenceRemoteConnections(
+                ((TestManagedConnection) a).mRemote,
+                ((TestManagedConnection) b).mRemote);
+    }
+
+    @Override
+    public void onRemoteConferenceAdded(RemoteConference remoteConference) {
+        addConference(new TestManagedConference(remoteConference));
+    }
+
+    private Connection makeConnection(ConnectionRequest request, boolean incoming) {
+        RemoteConnection remote = incoming
+                ? createRemoteIncomingConnection(request.getAccountHandle(), request)
+                : createRemoteOutgoingConnection(request.getAccountHandle(), request);
+        TestManagedConnection local = new TestManagedConnection(remote, false);
+        mManagedConnectionByRemote.put(remote, local);
+        return local;
     }
 }
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index 09a8929..c50e7ab 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
Binary files differ