Add default Dialer preference to Settings

Add a Default phone app setting under wireless settings, and also
a dialog activity that allows a user to confirm the selection of an
application as a default phone app.

Bug: 6948882
Bug: 15021725
Change-Id: I2c1473feba20da01b14fbd30dbecc01be560479d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c8362f0..d262651 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1624,6 +1624,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".PhoneDefaultDialog"
+                  android:label="@string/phone_application_title"
+                  android:excludeFromRecents="true"
+                  android:theme="@*android:style/Theme.Material.Light.Dialog.Alert">
+            <intent-filter>
+                <action android:name="android.telecomm.ACTION_CHANGE_DEFAULT_PHONE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".ActiveNetworkScorerDialog"
                   android:label="@string/network_scorer_application"
                   android:excludeFromRecents="true"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5e5e912..c801d9a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2378,6 +2378,11 @@
     <string name="sms_change_default_dialog_text" translatable="true">Use <xliff:g id="new_app">%1$s</xliff:g> instead of <xliff:g id="current_app">%2$s</xliff:g> as your SMS app?</string>
     <string name="sms_change_default_no_previous_dialog_text" translatable="true">Use <xliff:g id="new_app">%s</xliff:g> as your SMS app?</string>
 
+    <!-- Default phone application [CHAR LIMIT=35] -->
+    <string name="phone_application_title" translatable="true">Default phone app</string>
+    <!-- Title of dialog used to change the default phone application [CHAR LIMIT=35]-->
+    <string name="phone_change_default_dialog_title" translatable="true">Change default phone app?</string>
+
     <!-- Network Scorer Application -->
     <!-- TODO: Final UX and strings, then mark these as translatable. -->
     <string name="network_scorer_application" translatable="false">Active network scorer</string>
diff --git a/res/xml/wireless_settings.xml b/res/xml/wireless_settings.xml
index bf1523e..bad7da6 100644
--- a/res/xml/wireless_settings.xml
+++ b/res/xml/wireless_settings.xml
@@ -4,9 +4,9 @@
      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.
@@ -29,6 +29,12 @@
         android:summary="%s"
         android:persistent="false" />
 
+    <com.android.settings.AppListPreference
+        android:key="phone_application"
+        android:title="@string/phone_application_title"
+        android:summary="%s"
+        android:persistent="false" />
+
     <CheckBoxPreference
         android:key="toggle_nfc"
         android:title="@string/nfc_quick_toggle_title"
diff --git a/src/com/android/settings/PhoneDefaultDialog.java b/src/com/android/settings/PhoneDefaultDialog.java
new file mode 100644
index 0000000..09f1804
--- /dev/null
+++ b/src/com/android/settings/PhoneDefaultDialog.java
@@ -0,0 +1,137 @@
+/*
+ * 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.settings;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.provider.Telephony.Sms.Intents;
+import android.telecomm.PhoneApplication;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.settings.R;
+
+/**
+ * Displays the dialog that provides a list of installed phone applications to allow the user to
+ * select a default phone application.
+ */
+public final class PhoneDefaultDialog extends AlertActivity implements
+        DialogInterface.OnClickListener {
+    private static final String TAG = "PhoneDefaultDialog";
+    private ComponentName mNewComponent;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final String packageName = getIntent().getStringExtra(Intents.EXTRA_PACKAGE_NAME);
+
+        setResult(RESULT_CANCELED);
+        if (!buildDialog(packageName)) {
+            finish();
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case BUTTON_POSITIVE:
+                PhoneApplication.setDefaultPhoneApplication(mNewComponent.getPackageName(),
+                        this);
+                setResult(RESULT_OK);
+                break;
+            case BUTTON_NEGATIVE:
+                break;
+        }
+    }
+
+    private boolean buildDialog(String packageName) {
+        final TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
+        if (!tm.isVoiceCapable()) {
+            Log.w(TAG, "Dialog launched but device is not voice capable.");
+            return false;
+        }
+
+        mNewComponent = PhoneApplication.getPhoneApplicationForPackageName(this,
+                packageName);
+        if (mNewComponent == null) {
+            Log.w(TAG,
+                    "Provided package name does not correspond to an installed Phone application.");
+            return false;
+        }
+
+        final ComponentName oldComponent = PhoneApplication.getDefaultPhoneApplication(this);
+        if (oldComponent != null &&
+                TextUtils.equals(oldComponent.getPackageName(), mNewComponent.getPackageName())) {
+            return false;
+        }
+
+        final PackageManager pm = getPackageManager();
+        final String newComponentLabel =
+                getApplicationLabelForPackageName(pm, mNewComponent.getPackageName());
+        final AlertController.AlertParams p = mAlertParams;
+        p.mTitle = getString(R.string.phone_change_default_dialog_title);
+        if (oldComponent != null) {
+            String oldComponentLabel =
+                    getApplicationLabelForPackageName(pm, oldComponent.getPackageName());
+            p.mMessage = getString(R.string.sms_change_default_dialog_text,
+                    newComponentLabel,
+                    oldComponentLabel);
+        } else {
+            p.mMessage = getString(R.string.sms_change_default_no_previous_dialog_text,
+                    newComponentLabel);
+        }
+        p.mPositiveButtonText = getString(R.string.yes);
+        p.mNegativeButtonText = getString(R.string.no);
+        p.mPositiveButtonListener = this;
+        p.mNegativeButtonListener = this;
+        setupAlert();
+
+        return true;
+    }
+
+    /**
+     * Returns the application label that corresponds to the given package name
+     *
+     * @param pm An instance of a {@link PackageManager}.
+     * @param packageName A valid package name.
+     *
+     * @return Application label for the given package name, or null if not found.
+     */
+    private String getApplicationLabelForPackageName(PackageManager pm, String packageName) {
+        ApplicationInfo info = null;
+        try {
+            info = pm.getApplicationInfo(packageName, 0);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Application info not found for packageName " + packageName);
+        }
+        if (info == null) {
+            return packageName;
+        } else {
+            return info.loadLabel(pm).toString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 507445f..17234e9 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -41,6 +41,7 @@
 import android.preference.PreferenceScreen;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
+import android.telecomm.PhoneApplication;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -74,6 +75,7 @@
     private static final String KEY_SMS_APPLICATION = "sms_application";
     private static final String KEY_TOGGLE_NSD = "toggle_nsd"; //network service discovery
     private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
+    private static final String KEY_PHONE_APPLICATION = "phone_application";
 
     public static final String EXIT_ECM_RESULT = "exit_ecm_result";
     public static final int REQUEST_CODE_EXIT_ECM = 1;
@@ -93,6 +95,7 @@
     private static final String SAVED_MANAGE_MOBILE_PLAN_MSG = "mManageMobilePlanMessage";
 
     private AppListPreference mSmsApplicationPreference;
+    private AppListPreference mDialerApplicationPreference;
 
     public WirelessSettings() {
         super(null);
@@ -202,6 +205,24 @@
         mSmsApplicationPreference.setPackageNames(packageNames, defaultPackageName);
     }
 
+    private void initDialerApplicationSetting() {
+        log("initDialerApplicationSetting:");
+        final List<ComponentName> dialers =
+                PhoneApplication.getInstalledPhoneApplications(getActivity());
+
+        final int count = dialers.size();
+        final String[] packageNames = new String[count];
+        for (int i = 0; i < count; i++) {
+            packageNames[i] = dialers.get(i).getPackageName();
+        }
+        String defaultPackageName = null;
+        final ComponentName appName = PhoneApplication.getDefaultPhoneApplication(getActivity());
+        if (appName != null) {
+            defaultPackageName = appName.getPackageName();
+        }
+        mDialerApplicationPreference.setPackageNames(packageNames, defaultPackageName);
+    }
+
     @Override
     public Dialog onCreateDialog(int dialogId) {
         log("onCreateDialog: dialogId=" + dialogId);
@@ -242,6 +263,10 @@
         return mTm.isSmsCapable();
     }
 
+    private boolean isVoiceCapable() {
+        return mTm.isVoiceCapable();
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -272,6 +297,10 @@
         mSmsApplicationPreference.setOnPreferenceChangeListener(this);
         initSmsApplicationSetting();
 
+        mDialerApplicationPreference = (AppListPreference) findPreference(KEY_PHONE_APPLICATION);
+        mDialerApplicationPreference.setOnPreferenceChangeListener(this);
+        initDialerApplicationSetting();
+
         // Remove NSD checkbox by default
         getPreferenceScreen().removePreference(nsd);
         //mNsdEnabler = new NsdEnabler(activity, nsd);
@@ -346,6 +375,11 @@
             removePreference(KEY_SMS_APPLICATION);
         }
 
+        // Remove Dialer setting if the device does not support voice
+        if (!isVoiceCapable()) {
+            removePreference(KEY_PHONE_APPLICATION);
+        }
+
         // Remove Airplane Mode settings if it's a stationary device such as a TV.
         if (mPm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             removePreference(KEY_TOGGLE_AIRPLANE);
@@ -454,6 +488,9 @@
         if (preference == mSmsApplicationPreference && newValue != null) {
             SmsApplication.setDefaultApplication(newValue.toString(), getActivity());
             return true;
+        } else if (preference == mDialerApplicationPreference && newValue != null) {
+            PhoneApplication.setDefaultPhoneApplication(newValue.toString(), getActivity());
+            return true;
         }
         return false;
     }
@@ -513,12 +550,17 @@
                 }
 
                 // Remove SMS Application if the device does not support SMS
-                TelephonyManager tm =
+                final TelephonyManager tm =
                         (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                 if (!tm.isSmsCapable()) {
                     result.add(KEY_SMS_APPLICATION);
                 }
 
+                // Remove Phone Application if the device is not voice capable
+                if (!tm.isVoiceCapable()) {
+                    result.add(KEY_PHONE_APPLICATION);
+                }
+
                 final PackageManager pm = context.getPackageManager();
 
                 // Remove Airplane Mode settings if it's a stationary device such as a TV.
@@ -530,8 +572,8 @@
                 result.add(KEY_PROXY_SETTINGS);
 
                 // Disable Tethering if it's not allowed or if it's a wifi-only device
-                ConnectivityManager cm =
-                        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+                final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
                 if (isSecondaryUser || !cm.isTetheringSupported()) {
                     result.add(KEY_TETHER_SETTINGS);
                 }