Allowing enable/disable of phone accounts. (2/3)

- Change broadcast listener to listen to PACKAGE_FULLY_REMOVED instead
of PACKAGE_REMOVED.  This ensures re-installing an app will not
remove all PhoneAccounts, losing the enabled states.
- Changed some method names.
- Added PhoneAccountRegistrar methods to enable/disable PhoneAccounts.
- Changed PhoneAccountRegistrar register method to copy over the
previous enabled state for phone accounts.
- Added some TelecomService methods.


Bug: 17306514
Bug: 17408536

Change-Id: Ie8c5e9f3ddec988b42bee682c91671cec904076b
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 743f67c..30155d4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -188,7 +188,7 @@
 
         <receiver android:name="PhoneAccountBroadcastReceiver">
             <intent-filter>
-                <action android:name="android.intent.action.PACKAGE_REMOVED" />
+                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
                 <data android:scheme="package" />
             </intent-filter>
         </receiver>
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 2b562e3..dd51187 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -296,9 +296,10 @@
 
         // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this call
         // as if a phoneAccount was not specified (does the default behavior instead).
+        // Note: We will not attempt to dial with a requested phoneAccount if it is disabled.
         if (phoneAccountHandle != null) {
             List<PhoneAccountHandle> enabledAccounts =
-                    app.getPhoneAccountRegistrar().getOutgoingPhoneAccounts();
+                    app.getPhoneAccountRegistrar().getEnabledPhoneAccounts(handle.getScheme());
             if (!enabledAccounts.contains(phoneAccountHandle)) {
                 phoneAccountHandle = null;
             }
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index 8f7df33..3d82a4c 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -16,7 +16,6 @@
 
 package com.android.telecomm;
 
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Bundle;
@@ -943,7 +942,7 @@
         // Make a list of ConnectionServices that are listed as being associated with SIM accounts
         final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap(
                 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1));
-        for (PhoneAccountHandle handle : registrar.getOutgoingPhoneAccounts()) {
+        for (PhoneAccountHandle handle : registrar.getEnabledPhoneAccounts()) {
             PhoneAccount account = registrar.getPhoneAccount(handle);
             if ((account.getCapabilities() & PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0) {
                 ConnectionServiceWrapper service =
diff --git a/src/com/android/telecomm/CreateConnectionProcessor.java b/src/com/android/telecomm/CreateConnectionProcessor.java
index fcf94cc..023f43e 100644
--- a/src/com/android/telecomm/CreateConnectionProcessor.java
+++ b/src/com/android/telecomm/CreateConnectionProcessor.java
@@ -235,31 +235,39 @@
         if (TelephonyUtil.shouldProcessAsEmergency(TelecommApp.getInstance(), mCall.getHandle())) {
             Log.i(this, "Emergency number detected");
             mAttemptRecords.clear();
-            List<PhoneAccountHandle> allAccountHandles = TelecommApp.getInstance()
-                    .getPhoneAccountRegistrar().getOutgoingPhoneAccounts();
-            // First, add the PSTN phone account
-            for (int i = 0; i < allAccountHandles.size(); i++) {
-                if (TelephonyUtil.isPstnComponentName(
-                        allAccountHandles.get(i).getComponentName())) {
-                    Log.i(this, "Will try PSTN account %s for emergency", allAccountHandles.get(i));
+            List<PhoneAccount> allAccounts = TelecommApp.getInstance()
+                    .getPhoneAccountRegistrar().getAllPhoneAccounts();
+            // First, add SIM phone accounts which can place emergency calls.
+            for (PhoneAccount phoneAccount : allAccounts) {
+                if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
+                        phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                    Log.i(this, "Will try PSTN account %s for emergency",
+                            phoneAccount.getAccountHandle());
                     mAttemptRecords.add(
                             new CallAttemptRecord(
-                                    allAccountHandles.get(i),
-                                    allAccountHandles.get(i)));
+                                    phoneAccount.getAccountHandle(),
+                                    phoneAccount.getAccountHandle()));
                 }
             }
 
-            // Next, add the connection manager account as a backup.
-            PhoneAccountHandle callManager = TelecommApp.getInstance()
+            // Next, add the connection manager account as a backup if it can place emergency calls.
+            PhoneAccountHandle callManagerHandle = TelecommApp.getInstance()
                     .getPhoneAccountRegistrar().getSimCallManager();
-            CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManager,
-                    TelecommApp.getInstance().getPhoneAccountRegistrar().
-                            getDefaultOutgoingPhoneAccount(mCall.getHandle().getScheme()));
+            if (callManagerHandle != null) {
+                PhoneAccount callManager = TelecommApp.getInstance()
+                        .getPhoneAccountRegistrar().getPhoneAccount(callManagerHandle);
+                if (callManager.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
+                    CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle,
+                            TelecommApp.getInstance().getPhoneAccountRegistrar().
+                                    getDefaultOutgoingPhoneAccount(mCall.getHandle().getScheme())
+                    );
 
-            if (callManager != null && !mAttemptRecords.contains(callAttemptRecord)) {
-                Log.i(this, "Will try Connection Manager account %s for emergency",
-                        callManager);
-                mAttemptRecords.add(callAttemptRecord);
+                    if (!mAttemptRecords.contains(callAttemptRecord)) {
+                        Log.i(this, "Will try Connection Manager account %s for emergency",
+                                callManager);
+                        mAttemptRecords.add(callAttemptRecord);
+                    }
+                }
             }
         }
     }
diff --git a/src/com/android/telecomm/PhoneAccountBroadcastReceiver.java b/src/com/android/telecomm/PhoneAccountBroadcastReceiver.java
index 8f70211..69639b6 100644
--- a/src/com/android/telecomm/PhoneAccountBroadcastReceiver.java
+++ b/src/com/android/telecomm/PhoneAccountBroadcastReceiver.java
@@ -24,9 +24,15 @@
 import java.lang.String;
 
 /**
- * Captures {@code android.intent.action.PACKAGE_REMOVED} intents and triggers the removal of
- * associated {@link android.telecomm.PhoneAccount}s via the
+ * Captures {@code android.intent.action.ACTION_PACKAGE_FULLY_REMOVED} intents and triggers the
+ * removal of associated {@link android.telecomm.PhoneAccount}s via the
  * {@link com.android.telecomm.PhoneAccountRegistrar}.
+ * Note: This class listens for the {@code PACKAGE_FULLY_REMOVED} intent rather than
+ * {@code PACKAGE_REMOVED} as {@code PACKAGE_REMOVED} is triggered on re-installation of the same
+ * package, where {@code PACKAGE_FULLY_REMOVED} is triggered only when an application is completely
+ * uninstalled.  This is desirable as we do not wish to un-register all
+ * {@link android.telecomm.PhoneAccount}s associated with a package being re-installed to ensure
+ * the enabled state of the accounts is retained.
  */
 public class PhoneAccountBroadcastReceiver extends BroadcastReceiver {
     /**
@@ -37,7 +43,7 @@
      */
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+        if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(intent.getAction())) {
             Uri uri = intent.getData();
             if (uri == null) {
                 return;
diff --git a/src/com/android/telecomm/PhoneAccountRegistrar.java b/src/com/android/telecomm/PhoneAccountRegistrar.java
index 4223b63..7aa9261 100644
--- a/src/com/android/telecomm/PhoneAccountRegistrar.java
+++ b/src/com/android/telecomm/PhoneAccountRegistrar.java
@@ -78,7 +78,7 @@
 
     private static final String FILE_NAME = "phone-account-registrar-state.xml";
     @VisibleForTesting
-    public static final int EXPECTED_STATE_VERSION = 2;
+    public static final int EXPECTED_STATE_VERSION = 3;
 
     /** Keep in sync with the same in SipSettings.java */
     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
@@ -118,7 +118,7 @@
             }
         }
 
-        List<PhoneAccountHandle> outgoing = getOutgoingPhoneAccounts(uriScheme);
+        List<PhoneAccountHandle> outgoing = getEnabledPhoneAccounts(uriScheme);
         switch (outgoing.size()) {
             case 0:
                 // There are no accounts, so there can be no default
@@ -166,7 +166,8 @@
                 return;
             }
 
-            if (!has(getPhoneAccount(accountHandle), PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
+            if (!getPhoneAccount(accountHandle).hasCapabilities(
+                    PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
                         accountHandle);
                 return;
@@ -189,7 +190,8 @@
             if (callManagerAccount == null) {
                 Log.d(this, "setSimCallManager: Nonexistent call manager: %s", callManager);
                 return;
-            } else if (!has(callManagerAccount, PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
+            } else if (!callManagerAccount.hasCapabilities(
+                    PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
                 Log.d(this, "setSimCallManager: Not a call manager: %s", callManagerAccount);
                 return;
             }
@@ -251,6 +253,11 @@
         return null;
     }
 
+    /**
+     * Retrieves a list of all {@link PhoneAccountHandle}s registered.
+     *
+     * @return The list of {@link PhoneAccountHandle}s.
+     */
     public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
         List<PhoneAccountHandle> accountHandles = new ArrayList<>();
         for (PhoneAccount m : mState.accounts) {
@@ -263,17 +270,45 @@
         return new ArrayList<>(mState.accounts);
     }
 
-    public List<PhoneAccountHandle> getOutgoingPhoneAccounts() {
+    /**
+     * Determines the number of enabled and disabled {@link PhoneAccount}s.
+     *
+     * @return The number of enabled and disabled {@link PhoneAccount}s
+     */
+    public int getAllPhoneAccountsCount() {
+        return mState.accounts.size();
+    }
+
+    /**
+     * Retrieves a list of all enabled call provider phone accounts.
+     *
+     * @return The phone account handles.
+     */
+    public List<PhoneAccountHandle> getEnabledPhoneAccounts() {
         return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER);
     }
 
-    public List<PhoneAccountHandle> getOutgoingPhoneAccounts(String uriScheme) {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme);
+    /**
+     * Retrieves a list of all enabled phone account call provider phone accounts supporting the
+     * specified URI scheme.
+     *
+     * @param uriScheme The URI scheme.
+     * @return The phone account handles.
+     */
+    public List<PhoneAccountHandle> getEnabledPhoneAccounts(String uriScheme) {
+        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme,
+                false /* includeDisabled */);
     }
 
-    public List<PhoneAccountHandle> getAllConnectionManagerPhoneAccounts() {
+    /**
+     * Retrieves a list of all enabled phone account handles with the connection manager capability.
+     *
+     * @return The phone account handles.
+     */
+    public List<PhoneAccountHandle> getConnectionManagerPhoneAccounts() {
         if (isEnabledConnectionManager()) {
-            return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER);
+            return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
+                    null /* supportedUriScheme */, false /* includeDisabled */);
         }
         return Collections.emptyList();
     }
@@ -287,6 +322,43 @@
         return null;
     }
 
+    /**
+     * Changes the enabled state of the {@link PhoneAccount} identified by a
+     * {@link PhoneAccountHandle}.
+     *
+     * @param handle The {@link PhoneAccountHandle}.
+     * @param isEnabled The new enabled state of the {@link PhoneAccount}.
+     */
+    public void setPhoneAccountEnabled(PhoneAccountHandle handle, boolean isEnabled) {
+        PhoneAccount existing = getPhoneAccount(handle);
+        if (existing.isEnabled() == isEnabled) {
+            return;
+        }
+
+        // Do not permit PhoneAccounts which are marked as always enabled to be disabled.
+        if (existing.hasCapabilities(PhoneAccount.CAPABILITY_ALWAYS_ENABLED)) {
+            return;
+        }
+
+        // If we are disabling the current default outgoing phone account or Sim call manager we
+        // need to null out those preferences.
+        if (!isEnabled) {
+            if (mState.defaultOutgoing != null && mState.defaultOutgoing.equals(handle)) {
+                setUserSelectedOutgoingPhoneAccount(null);
+            }
+
+            if (mState.simCallManager != null && mState.simCallManager.equals(handle)) {
+                setSimCallManager(null);
+            }
+        }
+
+
+        PhoneAccount.Builder builder = existing.toBuilder().setEnabled(isEnabled);
+        PhoneAccount replacement = builder.build();
+
+        addOrReplacePhoneAccount(replacement);
+    }
+
     // TODO: Should we implement an artificial limit for # of accounts associated with a single
     // ComponentName?
     public void registerPhoneAccount(PhoneAccount account) {
@@ -299,6 +371,22 @@
                     "PhoneAccount connection service requires BIND_CONNECTION_SERVICE permission.");
         }
 
+        // If there is an existing PhoneAccount already registered with this handle, copy its
+        // enabled state to the new phone account.
+        PhoneAccount existing = getPhoneAccount(account.getAccountHandle());
+        if (existing != null) {
+            account = account.toBuilder().setEnabled(existing.isEnabled()).build();
+        }
+
+        addOrReplacePhoneAccount(account);
+    }
+
+    /**
+     * Adds a {@code PhoneAccount}, replacing an existing one if found.
+     *
+     * @param account The {@code PhoneAccount} to add or replace.
+     */
+    private void addOrReplacePhoneAccount(PhoneAccount account) {
         mState.accounts.add(account);
         // Search for duplicates and remove any that are found.
         for (int i = 0; i < mState.accounts.size() - 1; i++) {
@@ -406,33 +494,32 @@
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
 
-    // TODO: Add a corresponding has(...) method to class PhoneAccount itself and remove this one
-    // Return true iff the given account has all the specified capability flags
-    static boolean has(PhoneAccount account, int capability) {
-        return (account.getCapabilities() & capability) == capability;
-    }
-
     /**
      * Returns a list of phone account handles with the specified flag.
      *
      * @param flags Flags which the {@code PhoneAccount} must have.
      */
     private List<PhoneAccountHandle> getPhoneAccountHandles(int flags) {
-        return getPhoneAccountHandles(flags, null);
+        return getPhoneAccountHandles(flags, null, false /* includeDisabled */);
     }
 
     /**
      * Returns a list of phone account handles with the specified flag, supporting the specified
-     * URI scheme.
+     * URI scheme.  By default, only enabled phone accounts are included, unless the
+     * {@code includeDisabled} parameter is set {@code true}.
      *
      * @param flags Flags which the {@code PhoneAccount} must have.
      * @param uriScheme URI schemes the PhoneAccount must handle.  {@code Null} bypasses the
      *                  URI scheme check.
+     * @param includeDisabled When {@code true}, the list of phone accounts handles includes those
+     *                        which are marked as disabled.
      */
-    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags, String uriScheme) {
+    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags, String uriScheme,
+            boolean includeDisabled) {
         List<PhoneAccountHandle> accountHandles = new ArrayList<>();
         for (PhoneAccount m : mState.accounts) {
-            if (has(m, flags) && (uriScheme == null || m.supportsUriScheme(uriScheme))) {
+            if ((includeDisabled || m.isEnabled()) && m.hasCapabilities(flags) &&
+                    (uriScheme == null || m.supportsUriScheme(uriScheme))) {
                 accountHandles.add(m.getAccountHandle());
             }
         }
@@ -596,7 +683,6 @@
                     if (toSerialize != null ){
                         serializer.text(toSerialize);
                     }
-
                     serializer.endTag(null, VALUE_TAG);
                 }
             } else {
@@ -628,6 +714,7 @@
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 if (parser.getName().equals(VALUE_TAG)) {
+                    parser.next();
                     value = parser.getText();
                     arrayEntries.add(value);
                 }
@@ -725,6 +812,9 @@
         private static final String LABEL = "label";
         private static final String SHORT_DESCRIPTION = "short_description";
         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
+        private static final String ENABLED = "enabled";
+        private static final String TRUE = "true";
+        private static final String FALSE = "false";
 
         @Override
         public void writeToXml(PhoneAccount o, XmlSerializer serializer)
@@ -745,6 +835,7 @@
                 writeTextSafely(LABEL, o.getLabel(), serializer);
                 writeTextSafely(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
+                writeTextSafely(ENABLED, o.isEnabled() ? TRUE : FALSE, serializer);
 
                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
             }
@@ -762,6 +853,7 @@
                 String label = null;
                 String shortDescription = null;
                 List<String> supportedUriSchemes = null;
+                boolean enabled = false;
 
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
@@ -789,6 +881,9 @@
                         shortDescription = parser.getText();
                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
                         supportedUriSchemes = readStringList(parser);
+                    } else if (parser.getName().equals(ENABLED)) {
+                        parser.next();
+                        enabled = parser.getText().equals(TRUE);
                     }
                 }
 
@@ -813,6 +908,17 @@
                     }
                 }
 
+                // Prior to version 3, PhoneAccounts didn't include the enabled option.  Enable
+                // all TelephonyConnectionService phone accounts by default.
+                if (version < 3) {
+                    ComponentName telephonyComponentName = new ComponentName("com.android.phone",
+                            "com.android.services.telephony.TelephonyConnectionService");
+
+                    if (accountHandle.getComponentName().equals(telephonyComponentName)) {
+                        enabled = true;
+                    }
+                }
+
                 return PhoneAccount.builder(accountHandle, label)
                         .setAddress(address)
                         .setSubscriptionAddress(subscriptionAddress)
@@ -820,6 +926,7 @@
                         .setIconResId(iconResId)
                         .setShortDescription(shortDescription)
                         .setSupportedUriSchemes(supportedUriSchemes)
+                        .setEnabled(enabled)
                         .build();
             }
             return null;
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index 93337a5..cce34d0 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -192,11 +192,11 @@
     }
 
     @Override
-    public List<PhoneAccountHandle> getOutgoingPhoneAccounts() {
+    public List<PhoneAccountHandle> getEnabledPhoneAccounts() {
         try {
-            return mPhoneAccountRegistrar.getOutgoingPhoneAccounts();
+            return mPhoneAccountRegistrar.getEnabledPhoneAccounts();
         } catch (Exception e) {
-            Log.e(this, e, "getOutgoingPhoneAccounts");
+            Log.e(this, e, "getEnabledPhoneAccounts");
             throw e;
         }
     }
@@ -204,7 +204,7 @@
     @Override
     public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
         try {
-            return mPhoneAccountRegistrar.getOutgoingPhoneAccounts(uriScheme);
+            return mPhoneAccountRegistrar.getEnabledPhoneAccounts(uriScheme);
         } catch (Exception e) {
             Log.e(this, e, "getPhoneAccountsSupportingScheme");
             throw e;
@@ -222,6 +222,36 @@
     }
 
     @Override
+    public int getAllPhoneAccountsCount() {
+        try {
+            return mPhoneAccountRegistrar.getAllPhoneAccountsCount();
+        } catch (Exception e) {
+            Log.e(this, e, "getAllPhoneAccountsCount");
+            throw e;
+        }
+    }
+
+    @Override
+    public List<PhoneAccount> getAllPhoneAccounts() {
+        try {
+            return mPhoneAccountRegistrar.getAllPhoneAccounts();
+        } catch (Exception e) {
+            Log.e(this, e, "getAllPhoneAccounts");
+            throw e;
+        }
+    }
+
+    @Override
+    public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
+        try {
+            return mPhoneAccountRegistrar.getAllPhoneAccountHandles();
+        } catch (Exception e) {
+            Log.e(this, e, "getAllPhoneAccounts");
+            throw e;
+        }
+    }
+
+    @Override
     public PhoneAccountHandle getSimCallManager() {
         try {
             return mPhoneAccountRegistrar.getSimCallManager();
@@ -246,7 +276,7 @@
     @Override
     public List<PhoneAccountHandle> getSimCallManagers() {
         try {
-            return mPhoneAccountRegistrar.getAllConnectionManagerPhoneAccounts();
+            return mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts();
         } catch (Exception e) {
             Log.e(this, e, "getSimCallManagers");
             throw e;
@@ -258,10 +288,30 @@
         try {
             enforceModifyPermissionOrCallingPackage(
                     account.getAccountHandle().getComponentName().getPackageName());
-            if (PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
-                PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
+                account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
                 enforceRegisterProviderOrSubscriptionPermission();
             }
+
+            // If the account is marked as enabled or has CAPABILITY_ALWAYS_ENABLED set, check to
+            // ensure the caller has modify permission.  If they do not, set the account to be
+            // disabled and remove CAPABILITY_ALWAYS_ENABLED.
+            if (account.isEnabled() ||
+                    account.hasCapabilities(PhoneAccount.CAPABILITY_ALWAYS_ENABLED)) {
+                try {
+                    enforceModifyPermission();
+                } catch (SecurityException e) {
+                    // Caller does not have modify permission, so change account to disabled by
+                    // default and remove the CAPABILITY_ALWAYS_ENABLED capability.
+                    int capabilities = account.getCapabilities() &
+                            ~PhoneAccount.CAPABILITY_ALWAYS_ENABLED;
+                    account = account.toBuilder()
+                            .setEnabled(false)
+                            .setCapabilities(capabilities)
+                            .build();
+                }
+            }
+
             mPhoneAccountRegistrar.registerPhoneAccount(account);
         } catch (Exception e) {
             Log.e(this, e, "registerPhoneAccount %s", account);
@@ -270,6 +320,17 @@
     }
 
     @Override
+    public void setPhoneAccountEnabled(PhoneAccountHandle account, boolean isEnabled) {
+        try {
+            enforceModifyPermission();
+            mPhoneAccountRegistrar.setPhoneAccountEnabled(account, isEnabled);
+        } catch (Exception e) {
+            Log.e(this, e, "setPhoneAccountEnabled %s %d", account, isEnabled ? 1 : 0);
+            throw e;
+        }
+    }
+
+    @Override
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
             enforceModifyPermissionOrCallingPackage(
diff --git a/tests/src/com/android/telecomm/tests/unit/PhoneAccountRegistrarTest.java b/tests/src/com/android/telecomm/tests/unit/PhoneAccountRegistrarTest.java
index 939cdf6..08fa351 100644
--- a/tests/src/com/android/telecomm/tests/unit/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/telecomm/tests/unit/PhoneAccountRegistrarTest.java
@@ -47,8 +47,8 @@
     public void setUp() {
         mRegistrar = new PhoneAccountRegistrar(getContext(), FILE_NAME);
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"),
-                        "label0")
+                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)
@@ -56,8 +56,8 @@
                 .setShortDescription("desc0")
                 .build());
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1"),
-                        "label1")
+                new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1"),
+                "label1")
                 .setAddress(Uri.parse("tel:555-1212"))
                 .setSubscriptionAddress(Uri.parse("tel:555-1212"))
                 .setCapabilities(
@@ -68,8 +68,8 @@
                 .setShortDescription("desc1")
                 .build());
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id2"),
-                        "label2")
+                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)
@@ -77,8 +77,8 @@
                 .setShortDescription("desc2")
                 .build());
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
-                        "label2")
+                new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
+                "label2")
                 .setAddress(Uri.parse("sip:test@sip.com"))
                 .setSubscriptionAddress(Uri.parse("test"))
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
@@ -87,8 +87,8 @@
                 .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
                 .build());
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
-                        "label2")
+                new PhoneAccountHandle(new ComponentName("sippkg", "sipcls"), "id4"),
+                "label2")
                 .setAddress(Uri.parse("sip:test@sip.com"))
                 .setSubscriptionAddress(Uri.parse("test"))
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
@@ -207,7 +207,7 @@
 
     public void testAccounts() throws Exception {
         assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
-        assertEquals(3, mRegistrar.getOutgoingPhoneAccounts().size());
+        assertEquals(3, mRegistrar.getEnabledPhoneAccounts().size());
         assertEquals(null, mRegistrar.getSimCallManager());
         assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
     }
@@ -268,8 +268,8 @@
         mRegistrar.unregisterPhoneAccount(
                 new PhoneAccountHandle(new ComponentName("pkg1", "cls1"), "id3"));
         mRegistrar.registerPhoneAccount(PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"),
-                        "label0")
+                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)
@@ -281,8 +281,8 @@
 
     private static PhoneAccount makeQuickAccount(String pkg, String cls, String id, int idx) {
         return PhoneAccount.builder(
-                        new PhoneAccountHandle(new ComponentName(pkg, cls), id),
-                        "label" + idx)
+                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)