Merge "Don't create conferences with invalid calls" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 706dda7..dfad570 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -178,8 +178,20 @@
             </intent-filter>
         </activity-alias>
 
-        <!-- Note: Broadcast receivers are now set up in TelecomApp as a step in the transition to
-             running under the system process. -->
+        <receiver android:name="TelecomBroadcastReceiver" android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
+                <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
+                <action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="PhoneAccountBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+                <data android:scheme="package" />
+            </intent-filter>
+        </receiver>
 
         <activity android:name=".RespondViaSmsSettings$Settings"
                   android:label="@string/respond_via_sms_setting_title"
@@ -196,5 +208,10 @@
                 android:theme="@style/Theme.Telecomm.Transparent">
         </activity>
 
+        <receiver android:name=".CallReceiver"
+            android:exported="false">
+        </receiver>
+
+
     </application>
 </manifest>
diff --git a/proguard.flags b/proguard.flags
new file mode 100644
index 0000000..e52ac20
--- /dev/null
+++ b/proguard.flags
@@ -0,0 +1,4 @@
+-verbose
+
+# Keep @VisibleForTesting elements
+-keep @com.android.internal.annotations.VisibleForTesting class *
diff --git a/src/com/android/server/telecom/CallActivity.java b/src/com/android/server/telecom/CallActivity.java
index 07b6f7e..680e387 100644
--- a/src/com/android/server/telecom/CallActivity.java
+++ b/src/com/android/server/telecom/CallActivity.java
@@ -35,7 +35,7 @@
 // TODO: Needed for move to system service: import com.android.internal.R;
 
 /**
- * Activity that handles system CALL actions and forwards them to {@link CallsManager}.
+ * Activity that handles system CALL actions and forwards them to {@link CallReceiver}.
  * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY.
  *
  * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the
@@ -53,12 +53,6 @@
  */
 public class CallActivity extends Activity {
 
-    /**
-     * {@inheritDoc}
-     *
-     * This method is the single point of entry for the CALL intent, which is used by built-in apps
-     * like Contacts & Dialer, as well as 3rd party apps to initiate outgoing calls.
-     */
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
@@ -81,7 +75,6 @@
     private void processIntent(Intent intent) {
         // Ensure call intents are not processed on devices that are not capable of calling.
         if (!isVoiceCapable()) {
-            setResult(RESULT_CANCELED);
             return;
         }
 
@@ -96,11 +89,6 @@
         }
     }
 
-    /**
-     * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
-     *
-     * @param intent Call intent containing data about the handle to call.
-     */
     private void processOutgoingCallIntent(Intent intent) {
         Uri handle = intent.getData();
         String scheme = handle.getScheme();
@@ -123,74 +111,12 @@
             return;
         }
 
-        // This must come after the code which checks to see if this user is allowed to place
-        // outgoing calls.
-        if (maybeSwitchToPrimaryUser(intent, true /* isForResult */)) {
-            return;
-        }
-
-        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
-                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
-
-        Bundle clientExtras = null;
-        if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
-            clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
-        }
-        if (clientExtras == null) {
-            clientExtras = Bundle.EMPTY;
-        }
-
-        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
-        Call call = getCallsManager().startOutgoingCall(handle, phoneAccountHandle, clientExtras);
-
-        if (call == null) {
-            setResult(RESULT_CANCELED);
-        } else {
-            NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
-                    this, getCallsManager(), call, intent, isDefaultDialer());
-            final int result = broadcaster.processIntent();
-            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
-
-            if (!success && call != null) {
-                disconnectCallAndShowErrorDialog(call, result);
-            }
-            setResult(success ? RESULT_OK : RESULT_CANCELED);
-        }
+        intent.putExtra(CallReceiver.KEY_IS_DEFAULT_DIALER, isDefaultDialer());
+        sendBroadcastToReceiver(intent, false /* isIncoming */);
     }
 
-    /**
-     * Processes INCOMING_CALL intents. Grabs the connection service information from the intent
-     * extra and forwards that to the CallsManager to start the incoming call flow.
-     *
-     * @param intent The incoming call intent.
-     */
     private void processIncomingCallIntent(Intent intent) {
-        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
-                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
-        if (phoneAccountHandle == null) {
-            Log.w(this, "Rejecting incoming call due to null phone account");
-            return;
-        }
-        if (phoneAccountHandle.getComponentName() == null) {
-            Log.w(this, "Rejecting incoming call due to null component name");
-            return;
-        }
-
-        if (maybeSwitchToPrimaryUser(intent, false /* isForResult */)) {
-            return;
-        }
-
-        Bundle clientExtras = null;
-        if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
-            clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
-        }
-        if (clientExtras == null) {
-            clientExtras = Bundle.EMPTY;
-        }
-
-        Log.d(this, "Processing incoming call from connection service [%s]",
-                phoneAccountHandle.getComponentName());
-        getCallsManager().processIncomingCallIntent(phoneAccountHandle, clientExtras);
+        sendBroadcastToReceiver(intent, true /* isIncoming */);
     }
 
     private boolean isDefaultDialer() {
@@ -216,46 +142,14 @@
                 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);
-    }
-
     /**
-     * Checks to see if we are running as a secondary user and if so, starts an activity with the
-     * specified intent on the primary user.
-     *
-     * @return True if the intent was resent to the primary user, false otherwise.
+     * Trampolines the intent to the broadcast receiver that runs only as the primary user.
      */
-    private boolean maybeSwitchToPrimaryUser(Intent intent, boolean isForResult) {
-        // Check to see if the we are running as a secondary user and if so, forward the intent to
-        // the primary user. The core of Telecom only runs in the primary user space so this in
-        // necessary for secondary users.
-        if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
-            if (isForResult) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-            }
-            startActivityAsUser(intent, UserHandle.OWNER);
-            return true;
-        }
-        return false;
-    }
-
-    CallsManager getCallsManager() {
-        return CallsManager.getInstance();
+    private boolean sendBroadcastToReceiver(Intent intent, boolean incoming) {
+        intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, incoming);
+        intent.setClass(this, CallReceiver.class);
+        Log.d(this, "Sending broadcast as user to CallReceiver- isIncoming: %s", incoming);
+        sendBroadcastAsUser(intent, UserHandle.OWNER);
+        return true;
     }
 }
diff --git a/src/com/android/server/telecom/CallReceiver.java b/src/com/android/server/telecom/CallReceiver.java
new file mode 100644
index 0000000..fe82b67
--- /dev/null
+++ b/src/com/android/server/telecom/CallReceiver.java
@@ -0,0 +1,133 @@
+package com.android.server.telecom;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.DisconnectCause;
+import android.telephony.PhoneNumberUtils;
+
+/**
+ * Single point of entry for all outgoing and incoming calls. {@link CallActivity} serves as a
+ * trampoline activity that captures call intents for individual users and forwards it to
+ * the {@link CallReceiver} which interacts with the rest of Telecom, both of which run only as
+ * the primary user.
+ */
+public class CallReceiver extends BroadcastReceiver {
+
+    static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
+    static final String KEY_IS_DEFAULT_DIALER =
+            "is_default_dialer";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final boolean isIncomingCall = intent.getBooleanExtra(KEY_IS_INCOMING_CALL, false);
+        Log.d(this, "onReceive - isIncomingCall: %s", isIncomingCall);
+
+        if (isIncomingCall) {
+            processIncomingCallIntent(intent);
+        } else {
+            processOutgoingCallIntent(context, intent);
+        }
+    }
+
+    /**
+     * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
+     *
+     * @param intent Call intent containing data about the handle to call.
+     */
+    private void processOutgoingCallIntent(Context context, Intent intent) {
+        Uri handle = intent.getData();
+        String scheme = handle.getScheme();
+        String uriString = handle.getSchemeSpecificPart();
+
+        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
+                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+        }
+
+        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
+                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+
+        Bundle clientExtras = null;
+        if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
+            clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
+        }
+        if (clientExtras == null) {
+            clientExtras = Bundle.EMPTY;
+        }
+
+        final boolean isDefaultDialer = intent.getBooleanExtra(KEY_IS_DEFAULT_DIALER, false);
+
+        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
+        Call call = getCallsManager().startOutgoingCall(handle, phoneAccountHandle, clientExtras);
+
+        if (call != null) {
+            // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
+            // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
+            // killed if memory is scarce. However, this is OK here because the entire Telecom
+            // process will be running throughout the duration of the phone call and should never
+            // be killed.
+            NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
+                    context, getCallsManager(), call, intent, isDefaultDialer);
+            final int result = broadcaster.processIntent();
+            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
+
+            if (!success && call != null) {
+                disconnectCallAndShowErrorDialog(context, call, result);
+            }
+        }
+    }
+
+    private void processIncomingCallIntent(Intent intent) {
+        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
+                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+
+        if (phoneAccountHandle == null) {
+            Log.w(this, "Rejecting incoming call due to null phone account");
+            return;
+        }
+        if (phoneAccountHandle.getComponentName() == null) {
+            Log.w(this, "Rejecting incoming call due to null component name");
+            return;
+        }
+
+        Bundle clientExtras = null;
+        if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
+            clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
+        }
+        if (clientExtras == null) {
+            clientExtras = Bundle.EMPTY;
+        }
+
+        Log.d(this, "Processing incoming call from connection service [%s]",
+                phoneAccountHandle.getComponentName());
+        getCallsManager().processIncomingCallIntent(phoneAccountHandle, clientExtras);
+    }
+
+    CallsManager getCallsManager() {
+        return CallsManager.getInstance();
+    }
+
+    private void disconnectCallAndShowErrorDialog(Context context, Call call, int errorCode) {
+        call.disconnect();
+        final Intent errorIntent = new Intent(context, ErrorDialogActivity.class);
+        int errorMessageId = -1;
+        switch (errorCode) {
+            case DisconnectCause.INVALID_NUMBER:
+            case DisconnectCause.NO_PHONE_NUMBER_SUPPLIED:
+                errorMessageId = R.string.outgoing_call_error_no_phone_number_supplied;
+                break;
+        }
+        if (errorMessageId != -1) {
+            errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId);
+        }
+        errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivityAsUser(errorIntent, UserHandle.CURRENT);
+    }
+}
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index cd2195c..4e866a1 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -279,7 +279,7 @@
 
         mContext.sendOrderedBroadcastAsUser(
                 broadcastIntent,
-                UserHandle.OWNER,
+                UserHandle.CURRENT,
                 PERMISSION,
                 receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
                 null,  // scheduler
diff --git a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java b/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
index d2516b1..1104518 100644
--- a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
+++ b/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
@@ -35,16 +35,6 @@
  * the enabled state of the accounts is retained.
  */
 public class PhoneAccountBroadcastReceiver extends BroadcastReceiver {
-
-    /**
-     * The {@link PhoneAccountRegistrar}.
-     */
-    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
-
-    public PhoneAccountBroadcastReceiver(PhoneAccountRegistrar phoneAccountRegistrar) {
-        mPhoneAccountRegistrar = phoneAccountRegistrar;
-    }
-
     /**
      * Receives the intents the class is configured to received.
      *
@@ -71,6 +61,6 @@
      * @param packageName The name of the removed package.
      */
     private void handlePackageRemoved(Context context, String packageName) {
-        mPhoneAccountRegistrar.clearAccounts(packageName);
+        CallsManager.getInstance().getPhoneAccountRegistrar().clearAccounts(packageName);
     }
 }
diff --git a/src/com/android/server/telecom/TelecomApp.java b/src/com/android/server/telecom/TelecomApp.java
index e8288f8..eaa89ac 100644
--- a/src/com/android/server/telecom/TelecomApp.java
+++ b/src/com/android/server/telecom/TelecomApp.java
@@ -27,7 +27,6 @@
  * Top-level Application class for Telecom.
  */
 public final class TelecomApp extends Application {
-
     /**
      * The Telecom service implementation.
      */
@@ -49,16 +48,6 @@
      */
     private CallsManager mCallsManager;
 
-    /**
-     * The Telecom broadcast receiver.
-     */
-    private TelecomBroadcastReceiver mTelecomBroadcastReceiver;
-
-    /**
-     * The {@link android.telecom.PhoneAccount} broadcast receiver.
-     */
-    private PhoneAccountBroadcastReceiver mPhoneAccountBroadcastReceiver;
-
     /** {@inheritDoc} */
     @Override
     public void onCreate() {
@@ -78,21 +67,6 @@
             mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,
                     mCallsManager, this);
             ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);
-            mPhoneAccountBroadcastReceiver = new PhoneAccountBroadcastReceiver(
-                    mPhoneAccountRegistrar);
-            mTelecomBroadcastReceiver = new TelecomBroadcastReceiver(mMissedCallNotifier);
-
-            // Setup broadcast listener for telecom intents.
-            IntentFilter telecomFilter = new IntentFilter();
-            telecomFilter.addAction(TelecomBroadcastReceiver.ACTION_CALL_BACK_FROM_NOTIFICATION);
-            telecomFilter.addAction(TelecomBroadcastReceiver.ACTION_CALL_BACK_FROM_NOTIFICATION);
-            telecomFilter.addAction(TelecomBroadcastReceiver.ACTION_SEND_SMS_FROM_NOTIFICATION);
-            registerReceiver(mTelecomBroadcastReceiver, telecomFilter);
-
-            IntentFilter phoneAccountFilter = new IntentFilter();
-            phoneAccountFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
-            phoneAccountFilter.addDataScheme("package");
-            registerReceiver(mPhoneAccountBroadcastReceiver, phoneAccountFilter);
         }
     }
 
diff --git a/src/com/android/server/telecom/TelecomBroadcastReceiver.java b/src/com/android/server/telecom/TelecomBroadcastReceiver.java
index 9a777d6..cc5116d 100644
--- a/src/com/android/server/telecom/TelecomBroadcastReceiver.java
+++ b/src/com/android/server/telecom/TelecomBroadcastReceiver.java
@@ -38,13 +38,6 @@
     static final String ACTION_CLEAR_MISSED_CALLS =
             "com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS";
 
-    /** The missed call notifier. */
-    private final MissedCallNotifier mMissedCallNotifier;
-
-    public TelecomBroadcastReceiver(MissedCallNotifier missedCallNotifier) {
-        mMissedCallNotifier = missedCallNotifier;
-    }
-
     /** {@inheritDoc} */
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -52,11 +45,13 @@
 
         Log.v(this, "Action received: %s.", action);
 
+        MissedCallNotifier missedCallNotifier = CallsManager.getInstance().getMissedCallNotifier();
+
         // Send an SMS from the missed call notification.
         if (ACTION_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
             // Close the notification shade and the notification itself.
             closeSystemDialogs(context);
-            mMissedCallNotifier.clearMissedCalls();
+            missedCallNotifier.clearMissedCalls();
 
             Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
             callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -66,7 +61,7 @@
         } else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
             // Close the notification shade and the notification itself.
             closeSystemDialogs(context);
-            mMissedCallNotifier.clearMissedCalls();
+            missedCallNotifier.clearMissedCalls();
 
             Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
             callIntent.setFlags(
@@ -75,7 +70,7 @@
 
         // Clear the missed call notification and call log entries.
         } else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
-            mMissedCallNotifier.clearMissedCalls();
+            missedCallNotifier.clearMissedCalls();
         }
     }
 
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index f0ac0a1..299ca24 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -466,7 +466,9 @@
                 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
             }
 
-            mContext.startActivity(intent);
+            long token = Binder.clearCallingIdentity();
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            Binder.restoreCallingIdentity(token);
         }
     }
 
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index a6c25c5..cd9b77f 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -38,6 +38,13 @@
             </intent-filter>
         </service>
 
+        <service android:name="com.android.server.telecom.tests.MockConnectionService"
+                 android:permission="android.permission.BIND_CONNECTION_SERVICE" >
+            <intent-filter>
+                <action android:name="android.telecom.ConnectionService" />
+            </intent-filter>
+        </service>
+
         <service android:name="com.android.server.telecom.testapps.TestConnectionManager"
                  android:permission="android.permission.BIND_CONNECTION_SERVICE" >
             <intent-filter>
diff --git a/tests/src/com/android/server/telecom/tests/MockConnectionService.java b/tests/src/com/android/server/telecom/tests/MockConnectionService.java
new file mode 100644
index 0000000..62448cd
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/MockConnectionService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package com.android.server.telecom.tests;
+
+import android.telecom.ConnectionService;
+
+/**
+ * A non-functional {@link android.telecom.ConnectionService} to use for unit tests.
+ */
+public class MockConnectionService extends ConnectionService {
+
+}
diff --git a/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java
index b1f6e9e..014c2d2 100644
--- a/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java
@@ -36,7 +36,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.util.Arrays;
 
 public class PhoneAccountRegistrarTest extends AndroidTestCase {
 
@@ -46,56 +45,6 @@
     @Override
     public void setUp() {
         mRegistrar = new PhoneAccountRegistrar(getContext(), FILE_NAME);
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"),
-                "label0")
-                .setAddress(Uri.parse("tel:555-1212"))
-                .setSubscriptionAddress(Uri.parse("tel:555-1212"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
-                .setIconResId(0)
-                .setShortDescription("desc0")
-                .build());
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1"),
-                "label1")
-                .setAddress(Uri.parse("tel:555-1212"))
-                .setSubscriptionAddress(Uri.parse("tel:555-1212"))
-                .setCapabilities(
-                        PhoneAccount.CAPABILITY_CALL_PROVIDER
-                                | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
-                )
-                .setIconResId(0)
-                .setShortDescription("desc1")
-                .build());
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id2"),
-                "label2")
-                .setAddress(Uri.parse("tel:555-1212"))
-                .setSubscriptionAddress(Uri.parse("tel:555-1212"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setIconResId(0)
-                .setShortDescription("desc2")
-                .build());
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
-                "label2")
-                .setAddress(Uri.parse("sip:test@sip.com"))
-                .setSubscriptionAddress(Uri.parse("test"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setIconResId(0)
-                .setShortDescription("desc2")
-                .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
-                .build());
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
-                "label2")
-                .setAddress(Uri.parse("sip:test@sip.com"))
-                .setSubscriptionAddress(Uri.parse("test"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setIconResId(0)
-                .setShortDescription("desc2")
-                .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
-                .build());
     }
 
     @Override
@@ -104,6 +53,161 @@
         new File(getContext().getFilesDir(), FILE_NAME).delete();
     }
 
+    public void testPhoneAccountHandle() throws Exception {
+        PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
+        PhoneAccountHandle result = roundTrip(this, input,
+                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
+        assertPhoneAccountHandleEquals(input, result);
+
+        PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
+        PhoneAccountHandle resultN = roundTrip(this, inputN,
+                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
+        Log.i(this, "inputN = %s, resultN = %s", inputN, resultN);
+        assertPhoneAccountHandleEquals(inputN, resultN);
+    }
+
+    public void testPhoneAccount() throws Exception {
+        PhoneAccount input = makeQuickAccountBuilder("id0", 0)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .build();
+        PhoneAccount result = roundTrip(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
+                mContext);
+        assertPhoneAccountEquals(input, result);
+    }
+
+    public void testState() throws Exception {
+        PhoneAccountRegistrar.State input = makeQuickState();
+        PhoneAccountRegistrar.State result = roundTrip(this, input, PhoneAccountRegistrar.sStateXml,
+                mContext);
+        assertStateEquals(input, result);
+    }
+
+    public void testAccounts() throws Exception {
+        int i = 0;
+        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
+                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build());
+        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
+                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build());
+        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
+                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build());
+        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+                .build());
+
+        assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
+        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts().size());
+        assertEquals(null, mRegistrar.getSimCallManager());
+        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+    }
+
+    public void testSimCallManager() throws Exception {
+        PhoneAccountHandle simManager = makeQuickAccountHandle("sim_mgr");
+        PhoneAccount simManagerAccount = new PhoneAccount.Builder(simManager, "sim_mgr")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
+                        | PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+                .build();
+        mRegistrar.registerPhoneAccount(simManagerAccount);
+        assertNull(mRegistrar.getSimCallManager());
+
+        // Test the basic case
+        mRegistrar.setSimCallManager(simManager);
+        assertEquals(simManager, mRegistrar.getSimCallManager());
+
+        // Make sure clearing it works, too
+        mRegistrar.unregisterPhoneAccount(simManager);
+        assertNull(mRegistrar.getSimCallManager());
+
+        // Re-registering it makes the setting come back
+        mRegistrar.registerPhoneAccount(simManagerAccount);
+        assertEquals(simManager, mRegistrar.getSimCallManager());
+
+        // Make sure that the manager has CAPABILITY_CONNECTION_MANAGER
+        PhoneAccountHandle simManagerImposter = makeQuickAccountHandle("imposter");
+        PhoneAccount simManagerImposterAccount =
+                new PhoneAccount.Builder(simManagerImposter, "imposter")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .build();
+        mRegistrar.registerPhoneAccount(simManagerImposterAccount);
+
+        mRegistrar.setSimCallManager(null);
+        assertNull(mRegistrar.getSimCallManager());
+        mRegistrar.setSimCallManager(simManagerImposter);
+        assertNull(mRegistrar.getSimCallManager());
+    }
+
+    public void testDefaultOutgoing() {
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount = makeQuickAccountHandle("tel_acct");
+        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(telAccount, "tel_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount, defaultAccount);
+
+        // Add a SIP account, make sure tel: doesn't change
+        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
+        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+                .build());
+        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_SIP);
+        assertEquals(sipAccount, defaultAccount);
+        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount, defaultAccount);
+
+        // Add a connection manager, make sure tel: doesn't change
+        PhoneAccountHandle connectionManager = makeQuickAccountHandle("mgr_acct");
+        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount, defaultAccount);
+
+        // Unregister the tel: account, make sure there is no tel: default now.
+        mRegistrar.unregisterPhoneAccount(telAccount);
+        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+    }
+
+    private static PhoneAccountHandle makeQuickAccountHandle(String id) {
+        return new PhoneAccountHandle(
+                new ComponentName(
+                        "com.android.server.telecom.tests",
+                        "com.android.server.telecom.tests.MockConnectionService"
+                ),
+                id
+        );
+    }
+
+    private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
+        return new PhoneAccount.Builder(
+                makeQuickAccountHandle(id),
+                "label" + idx
+        );
+    }
+
+    private PhoneAccount makeQuickAccount(String id, int idx) {
+        return makeQuickAccountBuilder(id, idx)
+                .setAddress(Uri.parse("http://foo.com/" + idx))
+                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
+                .setCapabilities(idx)
+                .setIconResId(idx)
+                .setShortDescription("desc" + idx)
+                .build();
+    }
+
     private static <T> T roundTrip(
             Object self,
             T input,
@@ -137,7 +241,7 @@
         return result;
     }
 
-    private void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) {
+    private static void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) {
         if (a != b) {
             assertEquals(
                     a.getComponentName().getPackageName(),
@@ -149,20 +253,7 @@
         }
     }
 
-    public void testPhoneAccountHandle() throws Exception {
-        PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
-        PhoneAccountHandle result = roundTrip(this, input,
-                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
-        assertPhoneAccountHandleEquals(input, result);
-
-        PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
-        PhoneAccountHandle resultN = roundTrip(this, inputN,
-                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
-        Log.i(this, "inputN = %s, resultN = %s", inputN, resultN);
-        assertPhoneAccountHandleEquals(inputN, resultN);
-    }
-
-    private void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
+    private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
         if (a != b) {
             assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle());
             assertEquals(a.getAddress(), b.getAddress());
@@ -175,21 +266,8 @@
         }
     }
 
-    public void testPhoneAccount() throws Exception {
-        PhoneAccount input = makeQuickAccount("pkg0", "cls0", "id0", 0);
-        PhoneAccount result = roundTrip(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
-                mContext);
-        assertPhoneAccountEquals(input, result);
-
-        PhoneAccountHandle handleN =
-            new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
-        PhoneAccount inputN = PhoneAccount.builder(handleN, "label").build();
-        PhoneAccount resultN = roundTrip(this, inputN, PhoneAccountRegistrar.sPhoneAccountXml,
-                mContext);
-        assertPhoneAccountEquals(inputN, resultN);
-    }
-
-    private void assertStateEquals(PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) {
+    private static void assertStateEquals(
+            PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) {
         assertPhoneAccountHandleEquals(a.defaultOutgoing, b.defaultOutgoing);
         assertPhoneAccountHandleEquals(a.simCallManager, b.simCallManager);
         assertEquals(a.accounts.size(), b.accounts.size());
@@ -198,106 +276,13 @@
         }
     }
 
-    public void testState() throws Exception {
-        PhoneAccountRegistrar.State input = makeQuickState();
-        PhoneAccountRegistrar.State result = roundTrip(this, input, PhoneAccountRegistrar.sStateXml,
-                mContext);
-        assertStateEquals(input, result);
-    }
-
-    public void testAccounts() throws Exception {
-        assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
-        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts().size());
-        assertEquals(null, mRegistrar.getSimCallManager());
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-    }
-
-    public void testSimCallManager() throws Exception {
-        // Establish initial conditions
-        assertEquals(null, mRegistrar.getSimCallManager());
-        PhoneAccountHandle h = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
-        mRegistrar.setSimCallManager(h);
-        assertPhoneAccountHandleEquals(h, mRegistrar.getSimCallManager());
-        mRegistrar.unregisterPhoneAccount(h);
-        // If account is un-registered, querying returns null
-        assertEquals(null, mRegistrar.getSimCallManager());
-        // But if account is re-registered, setting comes back
-        mRegistrar.registerPhoneAccount(makeQuickAccount("pkg0", "cls0", "id0", 99));
-        assertPhoneAccountHandleEquals(h, mRegistrar.getSimCallManager());
-        // De-register by setting to null
-        mRegistrar.setSimCallManager(null);
-        assertEquals(null, mRegistrar.getSimCallManager());
-        // If argument not have SIM_CALL_MANAGER capability, this is a no-op
-        mRegistrar.setSimCallManager(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1"));
-        assertEquals(null, mRegistrar.getSimCallManager());
-    }
-
-    public void testDefaultOutgoing() {
-        // Establish initial conditions
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-        PhoneAccountHandle h = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1");
-        mRegistrar.setUserSelectedOutgoingPhoneAccount(h);
-        assertPhoneAccountHandleEquals(h, mRegistrar.getDefaultOutgoingPhoneAccount(
-                        PhoneAccount.SCHEME_TEL));
-        // If account is un-registered, querying returns null
-        mRegistrar.unregisterPhoneAccount(h);
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-        // But if account is re-registered, setting comes back
-        mRegistrar.registerPhoneAccount(makeQuickAccount("pkg0", "cls0", "id1", 99));
-        assertPhoneAccountHandleEquals(h, mRegistrar.getDefaultOutgoingPhoneAccount(
-                        PhoneAccount.SCHEME_TEL));
-        // De-register by setting to null
-        mRegistrar.setUserSelectedOutgoingPhoneAccount(null);
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-        // If argument not have CALL_PROVIDER capability, this is a no-op
-        mRegistrar.setUserSelectedOutgoingPhoneAccount(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"));
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-        // If only have one account, it is the default
-        mRegistrar.unregisterPhoneAccount(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"));
-        mRegistrar.unregisterPhoneAccount(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1"));
-        mRegistrar.unregisterPhoneAccount(
-                new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id2"));
-        assertPhoneAccountHandleEquals(
-                new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id3"),
-                mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-        // If have one account but not suitable, default returns null
-        mRegistrar.unregisterPhoneAccount(
-                new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id3"));
-        mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"),
-                "label0")
-                .setAddress(Uri.parse("tel:555-1212"))
-                .setSubscriptionAddress(Uri.parse("tel:555-1212"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
-                .setIconResId(0)
-                .setShortDescription("desc0")
-                .build());
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
-    }
-
-    private static PhoneAccount makeQuickAccount(String pkg, String cls, String id, int idx) {
-        return PhoneAccount.builder(
-                new PhoneAccountHandle(new ComponentName(pkg, cls), id),
-                "label" + idx)
-                .setAddress(Uri.parse("http://foo.com/" + idx))
-                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
-                .setCapabilities(idx)
-                .setIconResId(idx)
-                .setShortDescription("desc" + idx)
-                .build();
-    }
-
-    private static PhoneAccountRegistrar.State makeQuickState() {
+    private PhoneAccountRegistrar.State makeQuickState() {
         PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
-        s.accounts.add(makeQuickAccount("pkg0", "cls0", "id0", 0));
-        s.accounts.add(makeQuickAccount("pkg0", "cls0", "id1", 1));
-        s.accounts.add(makeQuickAccount("pkg1", "cls1", "id2", 2));
+        s.accounts.add(makeQuickAccount("id0", 0));
+        s.accounts.add(makeQuickAccount("id1", 1));
+        s.accounts.add(makeQuickAccount("id2", 2));
         s.defaultOutgoing = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
         s.simCallManager = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1");
         return s;
     }
-}
+}
\ No newline at end of file