(Telecom-system part 2) Move telecom intialization from application to service.

Instead of having TelecomApp initialize the global state of telecom, it
will bind to the telecom service and the service itself will
initialize the global state. This prepares telecom to run in the system
process since at that point TelecomAppw will stop running and the
framework will need to use the telecom service to start the global state.

Bug: 18112269
Change-Id: I76cd520e55ba2f58915ea2a7938cffd3cc101bab
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d0ae09c..4021d07 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -216,5 +216,12 @@
             </intent-filter>
         </service>
 
+        <service android:name=".TelecomService"
+                android:singleUser="true">
+            <intent-filter>
+                <android android:name="android.telecom.ITelecomService" />
+            </intent-filter>
+        </service>
+
     </application>
 </manifest>
diff --git a/src/com/android/server/telecom/TelecomApp.java b/src/com/android/server/telecom/TelecomApp.java
index f9df53c..8f46b49 100644
--- a/src/com/android/server/telecom/TelecomApp.java
+++ b/src/com/android/server/telecom/TelecomApp.java
@@ -17,19 +17,67 @@
 package com.android.server.telecom;
 
 import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 
 /**
  * Top-level Application class for Telecom.
  */
 public final class TelecomApp extends Application {
+
+    /**
+     * Used to bind to the telecom service. Once created, the telecom service will start the telecom
+     * global state.
+     */
+    private class TelecomServiceConnection implements ServiceConnection {
+        /** {@inheritDoc} */
+        @Override public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.i(this, "onServiceConnected: %s", name);
+            ServiceManager.addService(Context.TELECOM_SERVICE, service);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onServiceDisconnected(ComponentName name) {
+            Log.i(this, "onDisconnected: %s", name);
+            bindToService();
+        }
+    }
+
+    private ServiceConnection mServiceConnection;
+
     /** {@inheritDoc} */
     @Override
     public void onCreate() {
         super.onCreate();
 
         if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
-            TelecomGlobals.getInstance().initialize(this);
+            bindToService();
+        }
+    }
+
+    private void bindToService() {
+        if (mServiceConnection != null) {
+            unbindService(mServiceConnection);
+            mServiceConnection = null;
+        }
+
+        ComponentName componentName = new ComponentName(this, TelecomService.class);
+        Intent intent = new Intent(TelecomService.SERVICE_INTERFACE);
+        intent.setComponent(componentName);
+        int bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT;
+
+        Log.i(this, "binding to TelecomService.");
+        ServiceConnection serviceConnection = new TelecomServiceConnection();
+        if (bindServiceAsUser(intent, serviceConnection, bindFlags, UserHandle.OWNER)) {
+            mServiceConnection = serviceConnection;
+            Log.i(this, "TelecomService binding successful");
+        } else {
+            Log.e(this, null, "Failed to bind to TelecomService.");
         }
     }
 }
diff --git a/src/com/android/server/telecom/TelecomGlobals.java b/src/com/android/server/telecom/TelecomGlobals.java
index e30fee1..a11b470 100644
--- a/src/com/android/server/telecom/TelecomGlobals.java
+++ b/src/com/android/server/telecom/TelecomGlobals.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 
 /**
@@ -38,7 +37,7 @@
     /**
      * The Telecom service implementation.
      */
-    private TelecomServiceImpl mTelecomService;
+    private TelecomService mTelecomService;
 
     /**
      * Missed call notifier. Exists here so that the instance can be shared with
@@ -76,12 +75,12 @@
 
     void initialize(Context context) {
         if (mContext != null) {
-            Log.e(TAG, null, "Attempting to intialize TelecomGlobals a second time.");
+            Log.e(TAG, new Exception(), "Attempting to intialize TelecomGlobals a second time.");
             return;
         } else {
             Log.i(TAG, "TelecomGlobals initializing");
         }
-        mContext = context;
+        mContext = context.getApplicationContext();
 
         mMissedCallNotifier = new MissedCallNotifier(mContext);
         mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);
@@ -89,10 +88,6 @@
         mCallsManager = new CallsManager(mContext, mMissedCallNotifier, mPhoneAccountRegistrar);
         CallsManager.initialize(mCallsManager);
 
-        mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,
-                mCallsManager, mContext);
-        ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);
-
         // Start the BluetoothPhoneService
         BluetoothPhoneService.start(mContext);
 
@@ -106,4 +101,8 @@
     PhoneAccountRegistrar getPhoneAccountRegistrar() {
         return mPhoneAccountRegistrar;
     }
+
+    CallsManager getCallsManager() {
+        return mCallsManager;
+    }
 }
diff --git a/src/com/android/server/telecom/TelecomService.java b/src/com/android/server/telecom/TelecomService.java
new file mode 100644
index 0000000..eab7947
--- /dev/null
+++ b/src/com/android/server/telecom/TelecomService.java
@@ -0,0 +1,956 @@
+/*
+ * 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;
+
+import android.Manifest;
+import android.annotation.SdkConstant;
+import android.app.AppOpsManager;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.CallState;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+import com.android.internal.telecom.ITelecomService;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of the ITelecom interface.
+ */
+public class TelecomService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.ITelecomService";
+
+    /** The context. */
+    private Context mContext;
+
+    /**
+     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
+     * request after sending. The main thread will notify the request when it is complete.
+     */
+    private static final class MainThreadRequest {
+        /** The result of the request that is run on the main thread */
+        public Object result;
+        /** Object that can be used to store non-integer arguments */
+        public Object arg;
+    }
+
+    /**
+     * A handler that processes messages on the main thread. Since many of the method calls are not
+     * thread safe this is needed to shuttle the requests from the inbound binder threads to the
+     * main thread.
+     */
+    private final class MainThreadHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.obj instanceof MainThreadRequest) {
+                MainThreadRequest request = (MainThreadRequest) msg.obj;
+                Object result = null;
+                switch (msg.what) {
+                    case MSG_SILENCE_RINGER:
+                        mCallsManager.getRinger().silence();
+                        break;
+                    case MSG_SHOW_CALL_SCREEN:
+                        mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
+                        break;
+                    case MSG_END_CALL:
+                        result = endCallInternal();
+                        break;
+                    case MSG_ACCEPT_RINGING_CALL:
+                        acceptRingingCallInternal();
+                        break;
+                    case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
+                        mMissedCallNotifier.clearMissedCalls();
+                        break;
+                    case MSG_IS_TTY_SUPPORTED:
+                        result = mCallsManager.isTtySupported();
+                        break;
+                    case MSG_GET_CURRENT_TTY_MODE:
+                        result = mCallsManager.getCurrentTtyMode();
+                        break;
+                    case MSG_NEW_INCOMING_CALL:
+                        if (request.arg == null || !(request.arg instanceof Intent)) {
+                            Log.w(this, "Invalid new incoming call request");
+                            break;
+                        }
+                        CallReceiver.processIncomingCallIntent((Intent) request.arg);
+                        break;
+                }
+
+                if (result != null) {
+                    request.result = result;
+                    synchronized(request) {
+                        request.notifyAll();
+                    }
+                }
+            }
+        }
+    }
+
+    private static final String TAG = TelecomService.class.getSimpleName();
+
+    private static final String SERVICE_NAME = "telecom";
+
+    private static final int MSG_SILENCE_RINGER = 1;
+    private static final int MSG_SHOW_CALL_SCREEN = 2;
+    private static final int MSG_END_CALL = 3;
+    private static final int MSG_ACCEPT_RINGING_CALL = 4;
+    private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
+    private static final int MSG_IS_TTY_SUPPORTED = 6;
+    private static final int MSG_GET_CURRENT_TTY_MODE = 7;
+    private static final int MSG_NEW_INCOMING_CALL = 8;
+
+    private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
+
+    private CallsManager mCallsManager;
+    private MissedCallNotifier mMissedCallNotifier;
+    private PhoneAccountRegistrar mPhoneAccountRegistrar;
+    private AppOpsManager mAppOpsManager;
+    private UserManager mUserManager;
+    private PackageManager mPackageManager;
+    private TelecomServiceImpl mServiceImpl;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        Log.d(this, "onCreate");
+        mContext = this;
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mServiceImpl = new TelecomServiceImpl();
+
+        TelecomGlobals globals = TelecomGlobals.getInstance();
+        globals.initialize(this);
+
+        mMissedCallNotifier = globals.getMissedCallNotifier();
+        mPhoneAccountRegistrar = globals.getPhoneAccountRegistrar();
+        mCallsManager = globals.getCallsManager();
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d(this, "onBind");
+        return mServiceImpl;
+    }
+
+    /**
+     * Implementation of the ITelecomService interface.
+     * TODO: Reorganize this inner class to top of file.
+     */
+    class TelecomServiceImpl extends ITelecomService.Stub {
+        @Override
+        public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
+            try {
+                PhoneAccountHandle defaultOutgoingPhoneAccount =
+                        mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme);
+                // Make sure that the calling user can see this phone account.
+                if (defaultOutgoingPhoneAccount != null
+                        && !isVisibleToCaller(defaultOutgoingPhoneAccount)) {
+                    Log.w(this, "No account found for the calling user");
+                    return null;
+                }
+                return defaultOutgoingPhoneAccount;
+            } catch (Exception e) {
+                Log.e(this, e, "getDefaultOutgoingPhoneAccount");
+                throw e;
+            }
+        }
+
+        @Override
+        public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
+            try {
+                PhoneAccountHandle userSelectedOutgoingPhoneAccount =
+                        mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount();
+                // Make sure that the calling user can see this phone account.
+                if (!isVisibleToCaller(userSelectedOutgoingPhoneAccount)) {
+                    Log.w(this, "No account found for the calling user");
+                    return null;
+                }
+                return userSelectedOutgoingPhoneAccount;
+            } catch (Exception e) {
+                Log.e(this, e, "getUserSelectedOutgoingPhoneAccount");
+                throw e;
+            }
+        }
+
+        @Override
+        public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
+            enforceModifyPermission();
+
+            try {
+                mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle);
+            } catch (Exception e) {
+                Log.e(this, e, "setUserSelectedOutgoingPhoneAccount");
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
+            try {
+                return filterForAccountsVisibleToCaller(
+                        mPhoneAccountRegistrar.getCallCapablePhoneAccounts());
+            } catch (Exception e) {
+                Log.e(this, e, "getCallCapablePhoneAccounts");
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
+            try {
+                return filterForAccountsVisibleToCaller(
+                        mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme));
+            } catch (Exception e) {
+                Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
+            try {
+                return filterForAccountsVisibleToCaller(
+                        mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName));
+            } catch (Exception e) {
+                Log.e(this, e, "getPhoneAccountsForPackage %s", packageName);
+                throw e;
+            }
+        }
+
+        @Override
+        public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
+            try {
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.w(this, "%s is not visible for the calling user", accountHandle);
+                    return null;
+                }
+                return mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle);
+            } catch (Exception e) {
+                Log.e(this, e, "getPhoneAccount %s", accountHandle);
+                throw e;
+            }
+        }
+
+        @Override
+        public int getAllPhoneAccountsCount() {
+            try {
+                // This list is pre-filtered for the calling user.
+                return getAllPhoneAccounts().size();
+            } catch (Exception e) {
+                Log.e(this, e, "getAllPhoneAccountsCount");
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccount> getAllPhoneAccounts() {
+            try {
+                List<PhoneAccount> allPhoneAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
+                List<PhoneAccount> profilePhoneAccounts = new ArrayList<>(allPhoneAccounts.size());
+                for (PhoneAccount phoneAccount : profilePhoneAccounts) {
+                    if (isVisibleToCaller(phoneAccount)) {
+                        profilePhoneAccounts.add(phoneAccount);
+                    }
+                }
+                return profilePhoneAccounts;
+            } catch (Exception e) {
+                Log.e(this, e, "getAllPhoneAccounts");
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
+            try {
+                return filterForAccountsVisibleToCaller(
+                        mPhoneAccountRegistrar.getAllPhoneAccountHandles());
+            } catch (Exception e) {
+                Log.e(this, e, "getAllPhoneAccounts");
+                throw e;
+            }
+        }
+
+        @Override
+        public PhoneAccountHandle getSimCallManager() {
+            try {
+                PhoneAccountHandle accountHandle = mPhoneAccountRegistrar.getSimCallManager();
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.w(this, "%s is not visible for the calling user", accountHandle);
+                    return null;
+                }
+                return accountHandle;
+            } catch (Exception e) {
+                Log.e(this, e, "getSimCallManager");
+                throw e;
+            }
+        }
+
+        @Override
+        public void setSimCallManager(PhoneAccountHandle accountHandle) {
+            enforceModifyPermission();
+
+            try {
+                mPhoneAccountRegistrar.setSimCallManager(accountHandle);
+            } catch (Exception e) {
+                Log.e(this, e, "setSimCallManager");
+                throw e;
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getSimCallManagers() {
+            try {
+                return filterForAccountsVisibleToCaller(
+                        mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts());
+            } catch (Exception e) {
+                Log.e(this, e, "getSimCallManagers");
+                throw e;
+            }
+        }
+
+        @Override
+        public void registerPhoneAccount(PhoneAccount account) {
+            try {
+                enforcePhoneAccountModificationForPackage(
+                        account.getAccountHandle().getComponentName().getPackageName());
+                if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
+                    enforceRegisterCallProviderPermission();
+                }
+                if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                    enforceRegisterSimSubscriptionPermission();
+                }
+                if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
+                    enforceRegisterConnectionManagerPermission();
+                }
+                if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+                    enforceRegisterMultiUser();
+                }
+                enforceUserHandleMatchesCaller(account.getAccountHandle());
+
+                mPhoneAccountRegistrar.registerPhoneAccount(account);
+            } catch (Exception e) {
+                Log.e(this, e, "registerPhoneAccount %s", account);
+                throw e;
+            }
+        }
+
+        @Override
+        public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
+            try {
+                enforcePhoneAccountModificationForPackage(
+                        accountHandle.getComponentName().getPackageName());
+                enforceUserHandleMatchesCaller(accountHandle);
+                mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
+            } catch (Exception e) {
+                Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
+                throw e;
+            }
+        }
+
+        @Override
+        public void clearAccounts(String packageName) {
+            try {
+                enforcePhoneAccountModificationForPackage(packageName);
+                mPhoneAccountRegistrar.clearAccounts(packageName, Binder.getCallingUserHandle());
+            } catch (Exception e) {
+                Log.e(this, e, "clearAccounts %s", packageName);
+                throw e;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isVoiceMailNumber
+         */
+        @Override
+        public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
+            enforceReadPermissionOrDefaultDialer();
+            try {
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.w(this, "%s is not visible for the calling user", accountHandle);
+                    return false;
+                }
+                return mPhoneAccountRegistrar.isVoiceMailNumber(accountHandle, number);
+            } catch (Exception e) {
+                Log.e(this, e, "getSubscriptionIdForPhoneAccount");
+                throw e;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#hasVoiceMailNumber
+         */
+        @Override
+        public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
+            enforceReadPermissionOrDefaultDialer();
+            try {
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.w(this, "%s is not visible for the calling user", accountHandle);
+                    return false;
+                }
+
+                int subId = SubscriptionManager.getDefaultVoiceSubId();
+                if (accountHandle != null) {
+                    subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
+                }
+                return !TextUtils.isEmpty(getTelephonyManager().getVoiceMailNumber(subId));
+            } catch (Exception e) {
+                Log.e(this, e, "getSubscriptionIdForPhoneAccount");
+                throw e;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#silenceRinger
+         */
+        @Override
+        public void silenceRinger() {
+            Log.d(this, "silenceRinger");
+            enforceModifyPermission();
+            sendRequestAsync(MSG_SILENCE_RINGER, 0);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getDefaultPhoneApp
+         */
+        @Override
+        public ComponentName getDefaultPhoneApp() {
+            Resources resources = mContext.getResources();
+            return new ComponentName(
+                    resources.getString(R.string.ui_default_package),
+                    resources.getString(R.string.dialer_default_class));
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isInCall
+         */
+        @Override
+        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().
+            final int callState = mCallsManager.getCallState();
+            return callState == TelephonyManager.CALL_STATE_OFFHOOK
+                    || callState == TelephonyManager.CALL_STATE_RINGING;
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isRinging
+         */
+        @Override
+        public boolean isRinging() {
+            enforceReadPermission();
+            return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
+        }
+
+        /**
+         * @see TelecomManager#getCallState
+         */
+        @Override
+        public int getCallState() {
+            return mCallsManager.getCallState();
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#endCall
+         */
+        @Override
+        public boolean endCall() {
+            enforceModifyPermission();
+            return (boolean) sendRequest(MSG_END_CALL);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#acceptRingingCall
+         */
+        @Override
+        public void acceptRingingCall() {
+            enforceModifyPermission();
+            sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#showInCallScreen
+         */
+        @Override
+        public void showInCallScreen(boolean showDialpad) {
+            enforceReadPermissionOrDefaultDialer();
+            sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#cancelMissedCallsNotification
+         */
+        @Override
+        public void cancelMissedCallsNotification() {
+            enforceModifyPermissionOrDefaultDialer();
+            sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#handleMmi
+         */
+        @Override
+        public boolean handlePinMmi(String dialString) {
+            enforceModifyPermissionOrDefaultDialer();
+
+            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+            long token = Binder.clearCallingIdentity();
+            boolean retval = false;
+            try {
+                retval = getTelephonyManager().handlePinMmi(dialString);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            return retval;
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#handleMmi
+         */
+        @Override
+        public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
+                String dialString) {
+            enforceModifyPermissionOrDefaultDialer();
+
+            if (!isVisibleToCaller(accountHandle)) {
+                Log.w(this, "%s is not visible for the calling user", accountHandle);
+                return false;
+            }
+
+            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+            long token = Binder.clearCallingIdentity();
+            boolean retval = false;
+            try {
+                int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
+                retval = getTelephonyManager().handlePinMmiForSubscriber(subId, dialString);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            return retval;
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getAdnUriForPhoneAccount
+         */
+        @Override
+        public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
+            enforceModifyPermissionOrDefaultDialer();
+
+            if (!isVisibleToCaller(accountHandle)) {
+                Log.w(this, "%s is not visible for the calling user", accountHandle);
+                return null;
+            }
+
+            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+            long token = Binder.clearCallingIdentity();
+            String retval = "content://icc/adn/";
+            try {
+                long subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
+                retval = retval + "subId/" + subId;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            return Uri.parse(retval);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isTtySupported
+         */
+        @Override
+        public boolean isTtySupported() {
+            enforceReadPermission();
+            return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getCurrentTtyMode
+         */
+        @Override
+        public int getCurrentTtyMode() {
+            enforceReadPermission();
+            return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#addNewIncomingCall
+         */
+        @Override
+        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
+            Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle);
+            if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
+                mAppOpsManager.checkPackage(
+                        Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
+
+                // Make sure it doesn't cross the UserHandle boundary
+                enforceUserHandleMatchesCaller(phoneAccountHandle);
+
+                Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
+                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+                intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, true);
+                if (extras != null) {
+                    intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
+                }
+                sendRequestAsync(MSG_NEW_INCOMING_CALL, 0, intent);
+            } else {
+                Log.w(this, "Null phoneAccountHandle. Ignoring request to add new incoming call");
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#addNewUnknownCall
+         */
+        @Override
+        public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
+            if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null &&
+                    TelephonyUtil.isPstnComponentName(phoneAccountHandle.getComponentName())) {
+                mAppOpsManager.checkPackage(
+                        Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
+
+                // Make sure it doesn't cross the UserHandle boundary
+                enforceUserHandleMatchesCaller(phoneAccountHandle);
+
+                Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
+                intent.setClass(mContext, CallReceiver.class);
+                intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                intent.putExtras(extras);
+                intent.putExtra(CallReceiver.KEY_IS_UNKNOWN_CALL, true);
+                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+                mContext.sendBroadcastAsUser(intent, phoneAccountHandle.getUserHandle());
+            } else {
+                Log.i(this, "Null phoneAccountHandle or not initiated by Telephony. Ignoring request"
+                        + " to add new unknown call.");
+            }
+        }
+    }
+
+    //
+    // Supporting methods for the ITelecomService interface implementation.
+    //
+
+    private boolean isVisibleToCaller(PhoneAccountHandle accountHandle) {
+        if (accountHandle == null) {
+            return false;
+        }
+
+        return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle));
+    }
+
+    private boolean isVisibleToCaller(PhoneAccount account) {
+        if (account == null) {
+            return false;
+        }
+
+        // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
+        // all profiles. Only Telephony and SIP accounts should have this capability.
+        if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+            return true;
+        }
+
+        UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
+        if (phoneAccountUserHandle == null) {
+            return false;
+        }
+
+        List<UserHandle> profileUserHandles;
+        if (isCallerSystemApp()) {
+            // If the caller lives in /system/priv-app, it can see PhoneAccounts for all of the
+            // *profiles* that the calling user owns, but not for any other *users*.
+            profileUserHandles = mUserManager.getUserProfiles();
+        } else {
+            // Otherwise, it has to be owned by the current caller's profile.
+            profileUserHandles = new ArrayList<>(1);
+            profileUserHandles.add(Binder.getCallingUserHandle());
+        }
+
+        return profileUserHandles.contains(phoneAccountUserHandle);
+    }
+
+    /**
+     * Given a list of {@link PhoneAccountHandle}s, filter them to the ones that the calling
+     * user can see.
+     *
+     * @param phoneAccountHandles Unfiltered list of account handles.
+     *
+     * @return {@link PhoneAccountHandle}s visible to the calling user and its profiles.
+     */
+    private List<PhoneAccountHandle> filterForAccountsVisibleToCaller(
+            List<PhoneAccountHandle> phoneAccountHandles) {
+        List<PhoneAccountHandle> profilePhoneAccountHandles =
+                new ArrayList<>(phoneAccountHandles.size());
+        for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
+            if (isVisibleToCaller(phoneAccountHandle)) {
+                profilePhoneAccountHandles.add(phoneAccountHandle);
+            }
+        }
+        return profilePhoneAccountHandles;
+    }
+
+    private boolean isCallerSystemApp() {
+        int uid = Binder.getCallingUid();
+        String[] packages = mPackageManager.getPackagesForUid(uid);
+        for (String packageName : packages) {
+            if (isPackageSystemApp(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isPackageSystemApp(String packageName) {
+        try {
+            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
+                    PackageManager.GET_META_DATA);
+            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                return true;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        return false;
+    }
+
+    private void acceptRingingCallInternal() {
+        Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
+        if (call != null) {
+            call.answer(call.getVideoState());
+        }
+    }
+
+    private boolean endCallInternal() {
+        // Always operate on the foreground call if one exists, otherwise get the first call in
+        // priority order by call-state.
+        Call call = mCallsManager.getForegroundCall();
+        if (call == null) {
+            call = mCallsManager.getFirstCallWithState(
+                    CallState.ACTIVE,
+                    CallState.DIALING,
+                    CallState.RINGING,
+                    CallState.ON_HOLD);
+        }
+
+        if (call != null) {
+            if (call.getState() == CallState.RINGING) {
+                call.reject(false /* rejectWithMessage */, null);
+            } else {
+                call.disconnect();
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    private void enforcePhoneAccountModificationForPackage(String packageName) {
+        // TODO: Use a new telecomm permission for this instead of reusing modify.
+
+        int result = mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+
+        // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
+        // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
+        // may also modify PhoneAccounts on behalf of any 'packageName'.
+
+        if (result != PackageManager.PERMISSION_GRANTED) {
+            // Other callers are only allowed to modify PhoneAccounts if the relevant system
+            // feature is enabled ...
+            enforceConnectionServiceFeature();
+            // ... and the PhoneAccounts they refer to are for their own package.
+            enforceCallingPackage(packageName);
+        }
+    }
+
+    private void enforceReadPermissionOrDefaultDialer() {
+        if (!isDefaultDialerCalling()) {
+            enforceReadPermission();
+        }
+    }
+
+    private void enforceModifyPermissionOrDefaultDialer() {
+        if (!isDefaultDialerCalling()) {
+            enforceModifyPermission();
+        }
+    }
+
+    private void enforceCallingPackage(String packageName) {
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+    }
+
+    private void enforceConnectionServiceFeature() {
+        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
+    }
+
+    private void enforceRegisterCallProviderPermission() {
+        enforcePermission(android.Manifest.permission.REGISTER_CALL_PROVIDER);
+    }
+
+    private void enforceRegisterSimSubscriptionPermission() {
+        enforcePermission(android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION);
+    }
+
+    private void enforceRegisterConnectionManagerPermission() {
+        enforcePermission(android.Manifest.permission.REGISTER_CONNECTION_MANAGER);
+    }
+
+    private void enforceReadPermission() {
+        enforcePermission(Manifest.permission.READ_PHONE_STATE);
+    }
+
+    private void enforceModifyPermission() {
+        enforcePermission(Manifest.permission.MODIFY_PHONE_STATE);
+    }
+
+    private void enforcePermission(String permission) {
+        mContext.enforceCallingOrSelfPermission(permission, null);
+    }
+
+    private void enforceRegisterMultiUser() {
+        if (!isCallerSystemApp()) {
+            throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");
+        }
+    }
+
+    private void enforceUserHandleMatchesCaller(PhoneAccountHandle accountHandle) {
+        if (!Binder.getCallingUserHandle().equals(accountHandle.getUserHandle())) {
+            throw new SecurityException("Calling UserHandle does not match PhoneAccountHandle's");
+        }
+    }
+
+    private void enforceFeature(String feature) {
+        PackageManager pm = mContext.getPackageManager();
+        if (!pm.hasSystemFeature(feature)) {
+            throw new UnsupportedOperationException(
+                    "System does not support feature " + feature);
+        }
+    }
+
+    private boolean isDefaultDialerCalling() {
+        ComponentName defaultDialerComponent = getDefaultPhoneAppInternal();
+        if (defaultDialerComponent != null) {
+            try {
+                mAppOpsManager.checkPackage(
+                        Binder.getCallingUid(), defaultDialerComponent.getPackageName());
+                return true;
+            } catch (SecurityException e) {
+                Log.e(TAG, e, "Could not get default dialer.");
+            }
+        }
+        return false;
+    }
+
+    private ComponentName getDefaultPhoneAppInternal() {
+        Resources resources = mContext.getResources();
+        return new ComponentName(
+                resources.getString(R.string.ui_default_package),
+                resources.getString(R.string.dialer_default_class));
+    }
+
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
+    private MainThreadRequest sendRequestAsync(int command, int arg1) {
+        return sendRequestAsync(command, arg1, null);
+    }
+
+    private MainThreadRequest sendRequestAsync(int command, int arg1, Object arg) {
+        MainThreadRequest request = new MainThreadRequest();
+        request.arg = arg;
+        mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
+        return request;
+    }
+
+    /**
+     * Posts the specified command to be executed on the main thread, waits for the request to
+     * complete, and returns the result.
+     */
+    private Object sendRequest(int command) {
+        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
+            MainThreadRequest request = new MainThreadRequest();
+            mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
+            return request.result;
+        } else {
+            MainThreadRequest request = sendRequestAsync(command, 0);
+
+            // Wait for the request to complete
+            synchronized (request) {
+                while (request.result == null) {
+                    try {
+                        request.wait();
+                    } catch (InterruptedException e) {
+                        // Do nothing, go back and wait until the request is complete
+                    }
+                }
+            }
+            return request.result;
+        }
+    }
+
+    /**
+     * Dumps the current state of the TelecomService.  Used when generating problem reports.
+     *
+     * @param fd The file descriptor.
+     * @param writer The print writer to dump the state to.
+     * @param args Optional dump arguments.
+     */
+    @Override
+    protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        if (mCallsManager != null) {
+            pw.println("mCallsManager: ");
+            pw.increaseIndent();
+            mCallsManager.dump(pw);
+            pw.decreaseIndent();
+
+            pw.println("mPhoneAccountRegistrar: ");
+            pw.increaseIndent();
+            mPhoneAccountRegistrar.dump(pw);
+            pw.decreaseIndent();
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
deleted file mode 100644
index a7fbb6a..0000000
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * 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;
-
-import android.Manifest;
-import android.app.AppOpsManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.telecom.CallState;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-
-// TODO: Needed for move to system service: import com.android.internal.R;
-import com.android.internal.telecom.ITelecomService;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation of the ITelecom interface.
- */
-public class TelecomServiceImpl extends ITelecomService.Stub {
-    /** The context. */
-    private Context mContext;
-
-    /** ${inheritDoc} */
-    @Override
-    public IBinder asBinder() {
-        return super.asBinder();
-    }
-
- /**
-     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
-     * request after sending. The main thread will notify the request when it is complete.
-     */
-    private static final class MainThreadRequest {
-        /** The result of the request that is run on the main thread */
-        public Object result;
-        /** Object that can be used to store non-integer arguments */
-        public Object arg;
-    }
-
-    /**
-     * A handler that processes messages on the main thread in the phone process. Since many
-     * of the Phone calls are not thread safe this is needed to shuttle the requests from the
-     * inbound binder threads to the main thread in the phone process.
-     */
-    private final class MainThreadHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.obj instanceof MainThreadRequest) {
-                MainThreadRequest request = (MainThreadRequest) msg.obj;
-                Object result = null;
-                switch (msg.what) {
-                    case MSG_SILENCE_RINGER:
-                        mCallsManager.getRinger().silence();
-                        break;
-                    case MSG_SHOW_CALL_SCREEN:
-                        mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
-                        break;
-                    case MSG_END_CALL:
-                        result = endCallInternal();
-                        break;
-                    case MSG_ACCEPT_RINGING_CALL:
-                        acceptRingingCallInternal();
-                        break;
-                    case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
-                        mMissedCallNotifier.clearMissedCalls();
-                        break;
-                    case MSG_IS_TTY_SUPPORTED:
-                        result = mCallsManager.isTtySupported();
-                        break;
-                    case MSG_GET_CURRENT_TTY_MODE:
-                        result = mCallsManager.getCurrentTtyMode();
-                        break;
-                    case MSG_NEW_INCOMING_CALL:
-                        if (request.arg == null || !(request.arg instanceof Intent)) {
-                            Log.w(this, "Invalid new incoming call request");
-                            break;
-                        }
-                        CallReceiver.processIncomingCallIntent((Intent) request.arg);
-                        break;
-                }
-
-                if (result != null) {
-                    request.result = result;
-                    synchronized(request) {
-                        request.notifyAll();
-                    }
-                }
-            }
-        }
-    }
-
-    /** Private constructor; @see init() */
-    private static final String TAG = TelecomServiceImpl.class.getSimpleName();
-
-    private static final String SERVICE_NAME = "telecom";
-
-    private static final int MSG_SILENCE_RINGER = 1;
-    private static final int MSG_SHOW_CALL_SCREEN = 2;
-    private static final int MSG_END_CALL = 3;
-    private static final int MSG_ACCEPT_RINGING_CALL = 4;
-    private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
-    private static final int MSG_IS_TTY_SUPPORTED = 6;
-    private static final int MSG_GET_CURRENT_TTY_MODE = 7;
-    private static final int MSG_NEW_INCOMING_CALL = 8;
-
-    /** The singleton instance. */
-    private static TelecomServiceImpl sInstance;
-
-    private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
-    private final CallsManager mCallsManager;
-    private final MissedCallNotifier mMissedCallNotifier;
-    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
-    private final AppOpsManager mAppOpsManager;
-    private final UserManager mUserManager;
-    private final PackageManager mPackageManager;
-
-    public TelecomServiceImpl(
-            MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar,
-            CallsManager callsManager, Context context) {
-        mMissedCallNotifier = missedCallNotifier;
-        mPhoneAccountRegistrar = phoneAccountRegistrar;
-        mCallsManager = callsManager;
-        mContext = context;
-        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mPackageManager = mContext.getPackageManager();
-    }
-
-    //
-    // Implementation of the ITelecomService interface.
-    //
-
-    @Override
-    public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
-        try {
-            PhoneAccountHandle defaultOutgoingPhoneAccount =
-                    mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme);
-            // Make sure that the calling user can see this phone account.
-            if (defaultOutgoingPhoneAccount != null
-                    && !isVisibleToCaller(defaultOutgoingPhoneAccount)) {
-                Log.w(this, "No account found for the calling user");
-                return null;
-            }
-            return defaultOutgoingPhoneAccount;
-        } catch (Exception e) {
-            Log.e(this, e, "getDefaultOutgoingPhoneAccount");
-            throw e;
-        }
-    }
-
-    @Override
-    public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
-        try {
-            PhoneAccountHandle userSelectedOutgoingPhoneAccount =
-                    mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount();
-            // Make sure that the calling user can see this phone account.
-            if (!isVisibleToCaller(userSelectedOutgoingPhoneAccount)) {
-                Log.w(this, "No account found for the calling user");
-                return null;
-            }
-            return userSelectedOutgoingPhoneAccount;
-        } catch (Exception e) {
-            Log.e(this, e, "getUserSelectedOutgoingPhoneAccount");
-            throw e;
-        }
-    }
-
-    @Override
-    public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
-        enforceModifyPermission();
-
-        try {
-            mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle);
-        } catch (Exception e) {
-            Log.e(this, e, "setUserSelectedOutgoingPhoneAccount");
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
-        try {
-            return filterForAccountsVisibleToCaller(
-                    mPhoneAccountRegistrar.getCallCapablePhoneAccounts());
-        } catch (Exception e) {
-            Log.e(this, e, "getCallCapablePhoneAccounts");
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
-        try {
-            return filterForAccountsVisibleToCaller(
-                    mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme));
-        } catch (Exception e) {
-            Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
-        try {
-            return filterForAccountsVisibleToCaller(
-                    mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName));
-        } catch (Exception e) {
-            Log.e(this, e, "getPhoneAccountsForPackage %s", packageName);
-            throw e;
-        }
-    }
-
-    @Override
-    public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
-        try {
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return null;
-            }
-            return mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle);
-        } catch (Exception e) {
-            Log.e(this, e, "getPhoneAccount %s", accountHandle);
-            throw e;
-        }
-    }
-
-    @Override
-    public int getAllPhoneAccountsCount() {
-        try {
-            // This list is pre-filtered for the calling user.
-            return getAllPhoneAccounts().size();
-        } catch (Exception e) {
-            Log.e(this, e, "getAllPhoneAccountsCount");
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccount> getAllPhoneAccounts() {
-        try {
-            List<PhoneAccount> allPhoneAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
-            List<PhoneAccount> profilePhoneAccounts = new ArrayList<>(allPhoneAccounts.size());
-            for (PhoneAccount phoneAccount : profilePhoneAccounts) {
-                if (isVisibleToCaller(phoneAccount)) {
-                    profilePhoneAccounts.add(phoneAccount);
-                }
-            }
-            return profilePhoneAccounts;
-        } catch (Exception e) {
-            Log.e(this, e, "getAllPhoneAccounts");
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
-        try {
-            return filterForAccountsVisibleToCaller(
-                    mPhoneAccountRegistrar.getAllPhoneAccountHandles());
-        } catch (Exception e) {
-            Log.e(this, e, "getAllPhoneAccounts");
-            throw e;
-        }
-    }
-
-    @Override
-    public PhoneAccountHandle getSimCallManager() {
-        try {
-            PhoneAccountHandle accountHandle = mPhoneAccountRegistrar.getSimCallManager();
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return null;
-            }
-            return accountHandle;
-        } catch (Exception e) {
-            Log.e(this, e, "getSimCallManager");
-            throw e;
-        }
-    }
-
-    @Override
-    public void setSimCallManager(PhoneAccountHandle accountHandle) {
-        enforceModifyPermission();
-
-        try {
-            mPhoneAccountRegistrar.setSimCallManager(accountHandle);
-        } catch (Exception e) {
-            Log.e(this, e, "setSimCallManager");
-            throw e;
-        }
-    }
-
-    @Override
-    public List<PhoneAccountHandle> getSimCallManagers() {
-        try {
-            return filterForAccountsVisibleToCaller(
-                    mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts());
-        } catch (Exception e) {
-            Log.e(this, e, "getSimCallManagers");
-            throw e;
-        }
-    }
-
-    @Override
-    public void registerPhoneAccount(PhoneAccount account) {
-        try {
-            enforcePhoneAccountModificationForPackage(
-                    account.getAccountHandle().getComponentName().getPackageName());
-            if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
-                enforceRegisterCallProviderPermission();
-            }
-            if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
-                enforceRegisterSimSubscriptionPermission();
-            }
-            if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
-                enforceRegisterConnectionManagerPermission();
-            }
-            if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
-                enforceRegisterMultiUser();
-            }
-            enforceUserHandleMatchesCaller(account.getAccountHandle());
-
-            mPhoneAccountRegistrar.registerPhoneAccount(account);
-        } catch (Exception e) {
-            Log.e(this, e, "registerPhoneAccount %s", account);
-            throw e;
-        }
-    }
-
-    @Override
-    public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
-        try {
-            enforcePhoneAccountModificationForPackage(
-                    accountHandle.getComponentName().getPackageName());
-            enforceUserHandleMatchesCaller(accountHandle);
-            mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
-        } catch (Exception e) {
-            Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
-            throw e;
-        }
-    }
-
-    @Override
-    public void clearAccounts(String packageName) {
-        try {
-            enforcePhoneAccountModificationForPackage(packageName);
-            mPhoneAccountRegistrar.clearAccounts(packageName, Binder.getCallingUserHandle());
-        } catch (Exception e) {
-            Log.e(this, e, "clearAccounts %s", packageName);
-            throw e;
-        }
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#isVoiceMailNumber
-     */
-    @Override
-    public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
-        enforceReadPermissionOrDefaultDialer();
-        try {
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return false;
-            }
-            return mPhoneAccountRegistrar.isVoiceMailNumber(accountHandle, number);
-        } catch (Exception e) {
-            Log.e(this, e, "getSubscriptionIdForPhoneAccount");
-            throw e;
-        }
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#hasVoiceMailNumber
-     */
-    @Override
-    public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
-        enforceReadPermissionOrDefaultDialer();
-        try {
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return false;
-            }
-
-            int subId = SubscriptionManager.getDefaultVoiceSubId();
-            if (accountHandle != null) {
-                subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-            }
-            return !TextUtils.isEmpty(getTelephonyManager().getVoiceMailNumber(subId));
-        } catch (Exception e) {
-            Log.e(this, e, "getSubscriptionIdForPhoneAccount");
-            throw e;
-        }
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#silenceRinger
-     */
-    @Override
-    public void silenceRinger() {
-        Log.d(this, "silenceRinger");
-        enforceModifyPermission();
-        sendRequestAsync(MSG_SILENCE_RINGER, 0);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#getDefaultPhoneApp
-     */
-    @Override
-    public ComponentName getDefaultPhoneApp() {
-        Resources resources = mContext.getResources();
-        return new ComponentName(
-                resources.getString(R.string.ui_default_package),
-                resources.getString(R.string.dialer_default_class));
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#isInCall
-     */
-    @Override
-    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().
-        final int callState = mCallsManager.getCallState();
-        return callState == TelephonyManager.CALL_STATE_OFFHOOK
-                || callState == TelephonyManager.CALL_STATE_RINGING;
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#isRinging
-     */
-    @Override
-    public boolean isRinging() {
-        enforceReadPermission();
-        return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
-    }
-
-    /**
-     * @see TelecomManager#getCallState
-     */
-    @Override
-    public int getCallState() {
-        return mCallsManager.getCallState();
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#endCall
-     */
-    @Override
-    public boolean endCall() {
-        enforceModifyPermission();
-        return (boolean) sendRequest(MSG_END_CALL);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#acceptRingingCall
-     */
-    @Override
-    public void acceptRingingCall() {
-        enforceModifyPermission();
-        sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#showInCallScreen
-     */
-    @Override
-    public void showInCallScreen(boolean showDialpad) {
-        enforceReadPermissionOrDefaultDialer();
-        sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#cancelMissedCallsNotification
-     */
-    @Override
-    public void cancelMissedCallsNotification() {
-        enforceModifyPermissionOrDefaultDialer();
-        sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#handleMmi
-     */
-    @Override
-    public boolean handlePinMmi(String dialString) {
-        enforceModifyPermissionOrDefaultDialer();
-
-        // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-        long token = Binder.clearCallingIdentity();
-        boolean retval = false;
-        try {
-            retval = getTelephonyManager().handlePinMmi(dialString);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        return retval;
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#handleMmi
-     */
-    @Override
-    public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
-            String dialString) {
-        enforceModifyPermissionOrDefaultDialer();
-
-        if (!isVisibleToCaller(accountHandle)) {
-            Log.w(this, "%s is not visible for the calling user", accountHandle);
-            return false;
-        }
-
-        // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-        long token = Binder.clearCallingIdentity();
-        boolean retval = false;
-        try {
-            int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-            retval = getTelephonyManager().handlePinMmiForSubscriber(subId, dialString);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        return retval;
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#getAdnUriForPhoneAccount
-     */
-    @Override
-    public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
-        enforceModifyPermissionOrDefaultDialer();
-
-        if (!isVisibleToCaller(accountHandle)) {
-            Log.w(this, "%s is not visible for the calling user", accountHandle);
-            return null;
-        }
-
-        // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-        long token = Binder.clearCallingIdentity();
-        String retval = "content://icc/adn/";
-        try {
-            long subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-            retval = retval + "subId/" + subId;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        return Uri.parse(retval);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#isTtySupported
-     */
-    @Override
-    public boolean isTtySupported() {
-        enforceReadPermission();
-        return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#getCurrentTtyMode
-     */
-    @Override
-    public int getCurrentTtyMode() {
-        enforceReadPermission();
-        return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#addNewIncomingCall
-     */
-    @Override
-    public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
-        Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle);
-        if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
-            mAppOpsManager.checkPackage(
-                    Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
-
-            // Make sure it doesn't cross the UserHandle boundary
-            enforceUserHandleMatchesCaller(phoneAccountHandle);
-
-            Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
-            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
-            intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, true);
-            if (extras != null) {
-                intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
-            }
-            sendRequestAsync(MSG_NEW_INCOMING_CALL, 0, intent);
-        } else {
-            Log.w(this, "Null phoneAccountHandle. Ignoring request to add new incoming call");
-        }
-    }
-
-    /**
-     * @see android.telecom.TelecomManager#addNewUnknownCall
-     */
-    @Override
-    public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
-        if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null &&
-                TelephonyUtil.isPstnComponentName(phoneAccountHandle.getComponentName())) {
-            mAppOpsManager.checkPackage(
-                    Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
-
-            // Make sure it doesn't cross the UserHandle boundary
-            enforceUserHandleMatchesCaller(phoneAccountHandle);
-
-            Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
-            intent.setClass(mContext, CallReceiver.class);
-            intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-            intent.putExtras(extras);
-            intent.putExtra(CallReceiver.KEY_IS_UNKNOWN_CALL, true);
-            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
-            mContext.sendBroadcastAsUser(intent, phoneAccountHandle.getUserHandle());
-        } else {
-            Log.i(this, "Null phoneAccountHandle or not initiated by Telephony. Ignoring request"
-                    + " to add new unknown call.");
-        }
-    }
-
-    //
-    // Supporting methods for the ITelecomService interface implementation.
-    //
-
-    private boolean isVisibleToCaller(PhoneAccountHandle accountHandle) {
-        if (accountHandle == null) {
-            return false;
-        }
-
-        return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle));
-    }
-
-    private boolean isVisibleToCaller(PhoneAccount account) {
-        if (account == null) {
-            return false;
-        }
-
-        // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
-        // all profiles. Only Telephony and SIP accounts should have this capability.
-        if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
-            return true;
-        }
-
-        UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
-        if (phoneAccountUserHandle == null) {
-            return false;
-        }
-
-        List<UserHandle> profileUserHandles;
-        if (isCallerSystemApp()) {
-            // If the caller lives in /system/priv-app, it can see PhoneAccounts for all of the
-            // *profiles* that the calling user owns, but not for any other *users*.
-            profileUserHandles = mUserManager.getUserProfiles();
-        } else {
-            // Otherwise, it has to be owned by the current caller's profile.
-            profileUserHandles = new ArrayList<>(1);
-            profileUserHandles.add(Binder.getCallingUserHandle());
-        }
-
-        return profileUserHandles.contains(phoneAccountUserHandle);
-    }
-
-    /**
-     * Given a list of {@link PhoneAccountHandle}s, filter them to the ones that the calling
-     * user can see.
-     *
-     * @param phoneAccountHandles Unfiltered list of account handles.
-     *
-     * @return {@link PhoneAccountHandle}s visible to the calling user and its profiles.
-     */
-    private List<PhoneAccountHandle> filterForAccountsVisibleToCaller(
-            List<PhoneAccountHandle> phoneAccountHandles) {
-        List<PhoneAccountHandle> profilePhoneAccountHandles =
-                new ArrayList<>(phoneAccountHandles.size());
-        for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
-            if (isVisibleToCaller(phoneAccountHandle)) {
-                profilePhoneAccountHandles.add(phoneAccountHandle);
-            }
-        }
-        return profilePhoneAccountHandles;
-    }
-
-    private boolean isCallerSystemApp() {
-        int uid = Binder.getCallingUid();
-        String[] packages = mPackageManager.getPackagesForUid(uid);
-        for (String packageName : packages) {
-            if (isPackageSystemApp(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isPackageSystemApp(String packageName) {
-        try {
-            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA);
-            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                return true;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-        }
-        return false;
-    }
-
-    private void acceptRingingCallInternal() {
-        Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
-        if (call != null) {
-            call.answer(call.getVideoState());
-        }
-    }
-
-    private boolean endCallInternal() {
-        // Always operate on the foreground call if one exists, otherwise get the first call in
-        // priority order by call-state.
-        Call call = mCallsManager.getForegroundCall();
-        if (call == null) {
-            call = mCallsManager.getFirstCallWithState(
-                    CallState.ACTIVE,
-                    CallState.DIALING,
-                    CallState.RINGING,
-                    CallState.ON_HOLD);
-        }
-
-        if (call != null) {
-            if (call.getState() == CallState.RINGING) {
-                call.reject(false /* rejectWithMessage */, null);
-            } else {
-                call.disconnect();
-            }
-            return true;
-        }
-
-        return false;
-    }
-
-    private void enforcePhoneAccountModificationForPackage(String packageName) {
-        // TODO: Use a new telecomm permission for this instead of reusing modify.
-
-        int result = mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
-
-        // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
-        // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
-        // may also modify PhoneAccounts on behalf of any 'packageName'.
-
-        if (result != PackageManager.PERMISSION_GRANTED) {
-            // Other callers are only allowed to modify PhoneAccounts if the relevant system
-            // feature is enabled ...
-            enforceConnectionServiceFeature();
-            // ... and the PhoneAccounts they refer to are for their own package.
-            enforceCallingPackage(packageName);
-        }
-    }
-
-    private void enforceReadPermissionOrDefaultDialer() {
-        if (!isDefaultDialerCalling()) {
-            enforceReadPermission();
-        }
-    }
-
-    private void enforceModifyPermissionOrDefaultDialer() {
-        if (!isDefaultDialerCalling()) {
-            enforceModifyPermission();
-        }
-    }
-
-    private void enforceCallingPackage(String packageName) {
-        mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
-    }
-
-    private void enforceConnectionServiceFeature() {
-        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
-    }
-
-    private void enforceRegisterCallProviderPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_CALL_PROVIDER);
-    }
-
-    private void enforceRegisterSimSubscriptionPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION);
-    }
-
-    private void enforceRegisterConnectionManagerPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_CONNECTION_MANAGER);
-    }
-
-    private void enforceReadPermission() {
-        enforcePermission(Manifest.permission.READ_PHONE_STATE);
-    }
-
-    private void enforceModifyPermission() {
-        enforcePermission(Manifest.permission.MODIFY_PHONE_STATE);
-    }
-
-    private void enforcePermission(String permission) {
-        mContext.enforceCallingOrSelfPermission(permission, null);
-    }
-
-    private void enforceRegisterMultiUser() {
-        if (!isCallerSystemApp()) {
-            throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");
-        }
-    }
-
-    private void enforceUserHandleMatchesCaller(PhoneAccountHandle accountHandle) {
-        if (!Binder.getCallingUserHandle().equals(accountHandle.getUserHandle())) {
-            throw new SecurityException("Calling UserHandle does not match PhoneAccountHandle's");
-        }
-    }
-
-    private void enforceFeature(String feature) {
-        PackageManager pm = mContext.getPackageManager();
-        if (!pm.hasSystemFeature(feature)) {
-            throw new UnsupportedOperationException(
-                    "System does not support feature " + feature);
-        }
-    }
-
-    private boolean isDefaultDialerCalling() {
-        ComponentName defaultDialerComponent = getDefaultPhoneApp();
-        if (defaultDialerComponent != null) {
-            try {
-                mAppOpsManager.checkPackage(
-                        Binder.getCallingUid(), defaultDialerComponent.getPackageName());
-                return true;
-            } catch (SecurityException e) {
-                Log.e(TAG, e, "Could not get default dialer.");
-            }
-        }
-        return false;
-    }
-
-    private TelephonyManager getTelephonyManager() {
-        return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
-    }
-
-    private MainThreadRequest sendRequestAsync(int command, int arg1) {
-        return sendRequestAsync(command, arg1, null);
-    }
-
-    private MainThreadRequest sendRequestAsync(int command, int arg1, Object arg) {
-        MainThreadRequest request = new MainThreadRequest();
-        request.arg = arg;
-        mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
-        return request;
-    }
-
-    /**
-     * Posts the specified command to be executed on the main thread, waits for the request to
-     * complete, and returns the result.
-     */
-    private Object sendRequest(int command) {
-        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
-            MainThreadRequest request = new MainThreadRequest();
-            mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
-            return request.result;
-        } else {
-            MainThreadRequest request = sendRequestAsync(command, 0);
-
-            // Wait for the request to complete
-            synchronized (request) {
-                while (request.result == null) {
-                    try {
-                        request.wait();
-                    } catch (InterruptedException e) {
-                        // Do nothing, go back and wait until the request is complete
-                    }
-                }
-            }
-            return request.result;
-        }
-    }
-
-    /**
-     * Dumps the current state of the TelecomService.  Used when generating problem reports.
-     *
-     * @param fd The file descriptor.
-     * @param writer The print writer to dump the state to.
-     * @param args Optional dump arguments.
-     */
-    @Override
-    protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        if (mCallsManager != null) {
-            pw.println("mCallsManager: ");
-            pw.increaseIndent();
-            mCallsManager.dump(pw);
-            pw.decreaseIndent();
-
-            pw.println("mPhoneAccountRegistrar: ");
-            pw.increaseIndent();
-            mPhoneAccountRegistrar.dump(pw);
-            pw.decreaseIndent();
-        }
-    }
-}