Add preference for Connection Service selection

Adds a preference in the Call Features settings to allow the user to choose a
default Connection Service. Adds a default, which should be a built-in component
as noted in the comments in CallFeaturesSetting.java.

Change-Id: I5aaf1afa5972bd687f571c759df7ed5974f981ea
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 9dc2b2e..6c49a3a 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -22,6 +22,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -31,6 +32,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.media.AudioManager;
@@ -53,8 +55,8 @@
 import android.provider.ContactsContract.CommonDataKinds;
 import android.provider.MediaStore;
 import android.provider.Settings;
+import android.telecomm.TelecommConstants;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.MenuItem;
@@ -158,6 +160,7 @@
 
     // String keys for preference lookup
     // TODO: Naming these "BUTTON_*" is confusing since they're not actually buttons(!)
+    private static final String BUTTON_DEFAULT_CONNECTION_SERVICE = "button_connection_service";
     private static final String BUTTON_VOICEMAIL_KEY = "button_voicemail_key";
     private static final String BUTTON_VOICEMAIL_PROVIDER_KEY = "button_voicemail_provider_key";
     private static final String BUTTON_VOICEMAIL_SETTING_KEY = "button_voicemail_setting_key";
@@ -274,11 +277,14 @@
     private ListPreference mButtonSipCallOptions;
     private Preference mWifiCallOptionsPreference;
     private Preference mWifiCallAccountPreference;
+    private ListPreference mConnectionService;
     private ListPreference mVoicemailProviders;
     private PreferenceScreen mVoicemailSettings;
     private Preference mVoicemailNotificationRingtone;
     private CheckBoxPreference mVoicemailNotificationVibrate;
     private SipSharedPreferences mSipSharedPreferences;
+    private final Map<String, CharSequence> mConnectionServiceLabelByComponentName =
+            new HashMap<>();
 
     private class VoiceMailProvider {
         public VoiceMailProvider(String name, Intent intent) {
@@ -592,6 +598,8 @@
             }
         } else if (preference == mButtonSipCallOptions) {
             handleSipCallOptionsChange(objValue);
+        } else if (preference == mConnectionService) {
+            updateConnectionServiceSummary((String) objValue);
         }
         // always let the preference setting proceed.
         return true;
@@ -1532,6 +1540,8 @@
         mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
         mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
         mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY);
+        mConnectionService = (ListPreference)
+                findPreference(BUTTON_DEFAULT_CONNECTION_SERVICE);
         mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
         if (mVoicemailProviders != null) {
             mVoicemailProviders.setOnPreferenceChangeListener(this);
@@ -1669,6 +1679,12 @@
             actionBar.setDisplayHomeAsUpEnabled(true);
             actionBar.setDisplayShowTitleEnabled(true);
         }
+
+        if (mConnectionService != null) {
+            mConnectionService.setOnPreferenceChangeListener(this);
+            setupConnectionServiceOptions();
+            updateConnectionServiceSummary(null);
+        }
     }
 
     /**
@@ -2204,6 +2220,65 @@
         return super.onOptionsItemSelected(item);
     }
 
+    private void setupConnectionServiceOptions() {
+        loadConnectionServiceEntries();
+        String[] entryValues = new String[mConnectionServiceLabelByComponentName.size()];
+        CharSequence[] entries = new CharSequence[mConnectionServiceLabelByComponentName.size()];
+        int i = 0;
+        for (String entryValue : mConnectionServiceLabelByComponentName.keySet()) {
+            entryValues[i] = entryValue;
+            entries[i] = mConnectionServiceLabelByComponentName.get(entryValue);
+            i++;
+        }
+        mConnectionService.setEntryValues(entryValues);
+        mConnectionService.setEntries(entries);
+
+        if (mConnectionService.getValue() == null) {
+            mConnectionService.setValue(getString(R.string.connection_service_default));
+        }
+    }
+
+    private void updateConnectionServiceSummary(String value) {
+        CharSequence label = mConnectionServiceLabelByComponentName.get(
+                value == null ? mConnectionService.getValue() : value);
+        if (label == null) {
+            Log.wtf(LOG_TAG, "Unknown default connection service entry " +
+                    mConnectionService.getValue());
+            mConnectionService.setSummary("");
+        }
+        mConnectionService.setSummary(label);
+    }
+
+    private void loadConnectionServiceEntries() {
+        Intent intent = new Intent(TelecommConstants.ACTION_CALL_SERVICE);
+        for (ResolveInfo entry : getPackageManager().queryIntentServices(intent, 0)) {
+            ServiceInfo serviceInfo = entry.serviceInfo;
+            if (serviceInfo != null) {
+                // The entry resolves to a proper service, add it to the list of service names
+                ComponentName componentName =
+                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                mConnectionServiceLabelByComponentName.put(
+                        componentName.flattenToString(),
+                        serviceInfo.loadLabel(getPackageManager()));
+            }
+        }
+
+        // If the default built-in ConnectionService is not installed, according to the package
+        // manager, then in a newly initialized system, Telecomm is going to read the preference
+        // and find the service to be nonexistent. Telecomm should have error checking for this
+        // case, but it is problematic and it's hard to program around it. Here we simply pretend
+        // like the built-in default is installed anyway (so the default value defined in the XML
+        // for the ListPreference points to something useful and does not throw an NPE) and proceed.
+        String connectionServiceDefault = getString(R.string.connection_service_default);
+        if (!mConnectionServiceLabelByComponentName.containsKey(connectionServiceDefault)) {
+            Log.wtf(LOG_TAG, "Package manager reports built-in ConnectionService not installed: "
+                    + connectionServiceDefault);
+            mConnectionServiceLabelByComponentName.put(
+                    connectionServiceDefault,
+                    getString(R.string.connection_service_default_label));
+        }
+    }
+
     /**
      * Finish current Activity and go up to the top level Settings ({@link CallFeaturesSetting}).
      * This is useful for implementing "HomeAsUp" capability for second-level Settings.