Provide enable property on phone accounts.

Bug: 20303449
Change-Id: I4b9cb0e29377233ed4fc01757570351ee6e5856e
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 34647a2..92b1600 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,22 +23,22 @@
     <!-- Prevents the activity manager from delaying any activity-start
          requests by this package, including requests immediately after
          the user presses "home". -->
+    <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
+    <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
+    <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" />
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CALL_LOG" />
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
-    <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
-    <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
-    <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
-    <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" />
 
     <permission
             android:name="android.permission.BROADCAST_CALLLOG_INFO"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 181a7f7..8d2cae1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -18,7 +18,7 @@
     <!-- Official label of the Telecomm/Phone app, as seen in "Manage Applications"
          and other settings UIs. This is the "app name" used in notification, recents,
          and app info screens. -->
-    <string name="telecommAppLabel" product="default">Phone</string>
+    <string name="telecommAppLabel" product="default">Phone - Call Management</string>
 
     <!-- Name for an "unknown" caller. -->
     <string name="unknown">Unknown</string>
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 845fe7f..0946892 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -527,7 +527,7 @@
         Call call = getNewOutgoingCall(handle);
 
         List<PhoneAccountHandle> accounts =
-                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme());
+                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false);
 
         Log.v(this, "startOutgoingCall found accounts = " + accounts);
 
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index c908b92..3531df6 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -194,7 +194,7 @@
             }
         }
 
-        List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme);
+        List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false);
         switch (outgoing.size()) {
             case 0:
                 // There are no accounts, so there can be no default
@@ -348,6 +348,20 @@
         mCurrentUserHandle = userHandle;
     }
 
+    public void enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
+        PhoneAccount account = getPhoneAccount(accountHandle);
+        if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            // We never change the enabled state of SIM-based accounts.
+            return;
+        }
+
+        if (account != null && account.isEnabled() != isEnabled) {
+            account.setIsEnabled(isEnabled);
+            write();
+            fireAccountsChanged();
+        }
+    }
+
     private boolean isVisibleForUser(PhoneAccount account) {
         if (account == null) {
             return false;
@@ -414,15 +428,16 @@
 
     /**
      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
+     * Only returns accounts which are enabled.
      *
      * @return The list of {@link PhoneAccountHandle}s.
      */
     public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
-        return getPhoneAccountHandles(0, null, null);
+        return getPhoneAccountHandles(0, null, null, false);
     }
 
     public List<PhoneAccount> getAllPhoneAccounts() {
-        return getPhoneAccounts(0, null, null);
+        return getPhoneAccounts(0, null, null, false);
     }
 
     /**
@@ -432,8 +447,10 @@
      * @param uriScheme The URI scheme.
      * @return The phone account handles.
      */
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(String uriScheme) {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme, null);
+    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            String uriScheme, boolean includeDisabledAccounts) {
+        return getPhoneAccountHandles(
+                PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme, null, includeDisabledAccounts);
     }
 
     /**
@@ -442,7 +459,7 @@
     public List<PhoneAccountHandle> getSimPhoneAccounts() {
         return getPhoneAccountHandles(
                 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
-                null, null);
+                null, null, false);
     }
 
     /**
@@ -452,7 +469,7 @@
      * @return The phone account handles.
      */
     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
-        return getPhoneAccountHandles(0, null, packageName);
+        return getPhoneAccountHandles(0, null, packageName, false);
     }
 
     /**
@@ -461,7 +478,7 @@
      * @return The phone account handles.
      */
     public List<PhoneAccountHandle> getConnectionManagerPhoneAccounts() {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null);
+        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null, true);
     }
 
     // TODO: Should we implement an artificial limit for # of accounts associated with a single
@@ -489,11 +506,22 @@
         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
                 account.getAccountHandle(), account);
 
+        // Start _enabled_ property as false.
+        // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
+        // source app provides or else an third party app could enable itself.
+        boolean isEnabled = false;
+
         PhoneAccount oldAccount = getPhoneAccount(account.getAccountHandle());
         if (oldAccount != null) {
             mState.accounts.remove(oldAccount);
+            isEnabled = oldAccount.isEnabled();
         }
+
         mState.accounts.add(account);
+        // Reset enabled state to whatever the value was if the account was already registered,
+        // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled.
+        account.setIsEnabled(
+                isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION));
 
         write();
         fireAccountsChanged();
@@ -636,9 +664,14 @@
      * and package name.
      */
     private List<PhoneAccountHandle> getPhoneAccountHandles(
-            int capabilities, String uriScheme, String packageName) {
+            int capabilities,
+            String uriScheme,
+            String packageName,
+            boolean includeDisabledAccounts) {
         List<PhoneAccountHandle> handles = new ArrayList<>();
-        for (PhoneAccount account : getPhoneAccounts(capabilities, uriScheme, packageName)) {
+
+        for (PhoneAccount account : getPhoneAccounts(
+                capabilities, uriScheme, packageName, includeDisabledAccounts)) {
             handles.add(account.getAccountHandle());
         }
         return handles;
@@ -654,9 +687,17 @@
      * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
      */
     private List<PhoneAccount> getPhoneAccounts(
-            int capabilities, String uriScheme, String packageName) {
+            int capabilities,
+            String uriScheme,
+            String packageName,
+            boolean includeDisabledAccounts) {
         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
         for (PhoneAccount m : mState.accounts) {
+            if (!(m.isEnabled() || includeDisabledAccounts)) {
+                // Do not include disabled accounts.
+                continue;
+            }
+
             if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
                 // Account doesn't have the right capabilities; skip this one.
                 continue;
@@ -1053,6 +1094,7 @@
         private static final String SHORT_DESCRIPTION = "short_description";
         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
         private static final String ICON = "icon";
+        private static final String ENABLED = "enabled";
 
         @Override
         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
@@ -1075,6 +1117,7 @@
                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
+                writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
 
                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
             }
@@ -1097,6 +1140,7 @@
                 String shortDescription = null;
                 List<String> supportedUriSchemes = null;
                 Icon icon = null;
+                boolean enabled = false;
 
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
@@ -1139,6 +1183,9 @@
                     } else if (parser.getName().equals(ICON)) {
                         parser.next();
                         icon = readIcon(parser);
+                    } else if (parser.getName().equals(ENABLED)) {
+                        parser.next();
+                        enabled = "true".equalsIgnoreCase(parser.getText());
                     }
                 }
 
@@ -1176,7 +1223,8 @@
                         .setCapabilities(capabilities)
                         .setShortDescription(shortDescription)
                         .setSupportedUriSchemes(supportedUriSchemes)
-                        .setHighlightColor(highlightColor);
+                        .setHighlightColor(highlightColor)
+                        .setIsEnabled(enabled);
 
                 if (icon != null) {
                     builder.setIcon(icon);
@@ -1187,7 +1235,7 @@
                     // TODO: Need to set tint.
                 }
 
-                return builder.build();
+                builder.build();
             }
             return null;
         }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index b219358..bed6c6c 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -124,7 +124,8 @@
         }
 
         @Override
-        public List<PhoneAccountHandle> getCallCapablePhoneAccounts(String callingPackage) {
+        public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+                boolean includeDisabledAccounts, String callingPackage) {
             if (!canReadPhoneState(callingPackage, "getDefaultOutgoingPhoneAccount")) {
                 return Collections.emptyList();
             }
@@ -135,7 +136,8 @@
                     // TODO: Does this isVisible check actually work considering we are clearing
                     // the calling identity?
                     return filterForAccountsVisibleToCaller(
-                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null));
+                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
+                                    null, includeDisabledAccounts));
                 } catch (Exception e) {
                     Log.e(this, e, "getCallCapablePhoneAccounts");
                     throw e;
@@ -158,7 +160,7 @@
                     // TODO: Does this isVisible check actually work considering we are clearing
                     // the calling identity?
                     return filterForAccountsVisibleToCaller(
-                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme));
+                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme, false));
                 } catch (Exception e) {
                     Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
                     throw e;
@@ -825,6 +827,23 @@
         }
 
         /**
+         * @see android.telecom.TelecomManager#enablePhoneAccount
+         */
+        @Override
+        public void enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
+            enforceModifyPermission();
+            synchronized (mLock) {
+                long token  = Binder.clearCallingIdentity();
+                try {
+                    // enable/disable phone account
+                    mPhoneAccountRegistrar.enablePhoneAccount(accountHandle, isEnabled);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
          * Dumps the current state of the TelecomService.  Used when generating problem reports.
          *
          * @param fd The file descriptor.
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index 04f08f9..5827e73 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -51,7 +51,9 @@
         return PhoneAccount.builder(DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE, "E")
                 .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
                         PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS).build();
+                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
+                .setIsEnabled(true)
+                .build();
     }
 
     static boolean isPstnComponentName(ComponentName componentName) {
diff --git a/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java b/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java
index b68c8ff..383b416 100644
--- a/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java
+++ b/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java
@@ -16,8 +16,10 @@
 
 package com.android.server.telecom.settings;
 
+import android.app.ActionBar;
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.MenuItem;
 
 public class EnableAccountPreferenceActivity extends Activity {
     @Override
@@ -27,5 +29,22 @@
         getFragmentManager().beginTransaction()
                 .replace(android.R.id.content, new EnableAccountPreferenceFragment())
                 .commit();
+
+        ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
     }
+
+    /** ${inheritDoc} */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                onBackPressed();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
 }
diff --git a/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java b/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java
index 48e22b6f..83eb113 100644
--- a/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java
+++ b/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java
@@ -38,7 +38,7 @@
  */
 public class EnableAccountPreferenceFragment extends PreferenceFragment {
 
-    private static final class AccountSwitchPreference extends SwitchPreference {
+    private final class AccountSwitchPreference extends SwitchPreference {
         private final PhoneAccount mAccount;
 
         public AccountSwitchPreference(Context context, PhoneAccount account) {
@@ -51,6 +51,7 @@
             if (icon != null) {
                 setIcon(icon.loadDrawable(context));
             }
+            setChecked(account.isEnabled());
         }
 
         /** ${inheritDoc} */
@@ -58,7 +59,7 @@
         protected void onClick() {
             super.onClick();
 
-            // TODO: Handle enabling/disabling phone accounts
+            mTelecomManager.enablePhoneAccount(mAccount.getAccountHandle(), isChecked());
         }
     }
 
@@ -75,11 +76,17 @@
     public void onResume() {
         super.onResume();
 
-        addPreferencesFromResource(R.xml.enable_account_preference);
-
-        List<PhoneAccountHandle> accountHandles = mTelecomManager.getCallCapablePhoneAccounts();
-
         PreferenceScreen screen = getPreferenceScreen();
+        if (screen != null) {
+            screen.removeAll();
+        }
+
+        addPreferencesFromResource(R.xml.enable_account_preference);
+        screen = getPreferenceScreen();
+
+        List<PhoneAccountHandle> accountHandles =
+                mTelecomManager.getCallCapablePhoneAccounts(true /* includeDisabledAccounts */);
+
         Context context = getActivity();
         for (PhoneAccountHandle handle : accountHandles) {
             PhoneAccount account = mTelecomManager.getPhoneAccount(handle);
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 8674b09..c55e89c 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -131,7 +131,7 @@
                 .build());
 
         assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
-        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts(null).size());
+        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts(null, false).size());
         assertEquals(null, mRegistrar.getSimCallManager());
         assertEquals(null, mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL));
     }