Merge "Fix crash when voice dialing an emergency number" into klp-dev
diff --git a/res/drawable-hdpi/list_pressed_holo_dark.9.png b/res/drawable-hdpi/list_pressed_holo_dark.9.png
index 5654cd6..596accb 100644
--- a/res/drawable-hdpi/list_pressed_holo_dark.9.png
+++ b/res/drawable-hdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_pressed_holo_dark.9.png b/res/drawable-mdpi/list_pressed_holo_dark.9.png
index 6e77525..fd0e8d7 100644
--- a/res/drawable-mdpi/list_pressed_holo_dark.9.png
+++ b/res/drawable-mdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_pressed_holo_dark.9.png b/res/drawable-xhdpi/list_pressed_holo_dark.9.png
index e4b3393..29037a0 100644
--- a/res/drawable-xhdpi/list_pressed_holo_dark.9.png
+++ b/res/drawable-xhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/src/com/android/phone/CallCommandService.java b/src/com/android/phone/CallCommandService.java
index 212ce45..f26fff7 100644
--- a/src/com/android/phone/CallCommandService.java
+++ b/src/com/android/phone/CallCommandService.java
@@ -44,17 +44,14 @@
     private final CallModeler mCallModeler;
     private final DTMFTonePlayer mDtmfTonePlayer;
     private final AudioRouter mAudioRouter;
-    private final RejectWithTextMessageManager mRejectWithTextMessageManager;
 
     public CallCommandService(Context context, CallManager callManager, CallModeler callModeler,
-            DTMFTonePlayer dtmfTonePlayer, AudioRouter audioRouter,
-            RejectWithTextMessageManager rejectWithTextMessageManager) {
+            DTMFTonePlayer dtmfTonePlayer, AudioRouter audioRouter) {
         mContext = context;
         mCallManager = callManager;
         mCallModeler = callModeler;
         mDtmfTonePlayer = dtmfTonePlayer;
         mAudioRouter = audioRouter;
-        mRejectWithTextMessageManager = rejectWithTextMessageManager;
     }
 
     /**
@@ -82,13 +79,13 @@
             if (result != null) {
                 final String number = result.getConnection().getAddress();
 
-                Log.v(TAG, "Hanging up");
-                PhoneUtils.hangupRingingCall(result.getConnection().getCall());
-
                 if (rejectWithMessage) {
-                    mRejectWithTextMessageManager.rejectCallWithMessage(
+                    RejectWithTextMessageManager.rejectCallWithMessage(
                             result.getConnection().getCall(), message);
                 }
+
+                Log.v(TAG, "Hanging up");
+                PhoneUtils.hangupRingingCall(result.getConnection().getCall());
             }
         } catch (Exception e) {
             Log.e(TAG, "Error during rejectCall().", e);
diff --git a/src/com/android/phone/CallModeler.java b/src/com/android/phone/CallModeler.java
index 23f442a..51d3a37 100644
--- a/src/com/android/phone/CallModeler.java
+++ b/src/com/android/phone/CallModeler.java
@@ -91,16 +91,13 @@
     private final HashMap<Connection, Call> mConfCallMap = Maps.newHashMap();
     private final AtomicInteger mNextCallId = new AtomicInteger(CALL_ID_START_VALUE);
     private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
-    private RejectWithTextMessageManager mRejectWithTextMessageManager;
     private Connection mCdmaIncomingConnection;
     private Connection mCdmaOutgoingConnection;
 
     public CallModeler(CallStateMonitor callStateMonitor, CallManager callManager,
-            RejectWithTextMessageManager rejectWithTextMessageManager,
             CallGatewayManager callGatewayManager) {
         mCallStateMonitor = callStateMonitor;
         mCallManager = callManager;
-        mRejectWithTextMessageManager = rejectWithTextMessageManager;
         mCallGatewayManager = callGatewayManager;
 
         mCallStateMonitor.addListener(this);
diff --git a/src/com/android/phone/HfaActivity.java b/src/com/android/phone/HfaActivity.java
index e3c9345..bcd3652 100644
--- a/src/com/android/phone/HfaActivity.java
+++ b/src/com/android/phone/HfaActivity.java
@@ -19,9 +19,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -39,22 +37,16 @@
 public class HfaActivity extends Activity {
     private static final String TAG = HfaActivity.class.getSimpleName();
 
-    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
-
-    public static final int OTASP_UNKNOWN = 0;
-    public static final int OTASP_USER_SKIPPED = 1;
-    public static final int OTASP_SUCCESS = 2;
-    public static final int OTASP_FAILURE = 3;
-
-    private boolean mCanSkip;
     private AlertDialog mDialog;
     private HfaLogic mHfaLogic;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        Log.i(TAG, "onCreate");
 
-        if (VERBOSE) Log.v(TAG, "onCreate");
+        final PendingIntent otaResponseIntent = getIntent().getParcelableExtra(
+                OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT);
 
         mHfaLogic = new HfaLogic(this.getApplicationContext(), new HfaLogic.HfaLogicCallback() {
             @Override
@@ -66,7 +58,7 @@
             public void onError(String error) {
                 onHfaError(error);
             }
-        });
+        }, otaResponseIntent);
 
         startProvisioning();
     }
@@ -75,7 +67,7 @@
     protected void onDestroy() {
         super.onDestroy();
 
-        if (VERBOSE) Log.v(TAG, "onDestroy");
+        Log.i(TAG, "onDestroy");
 
         if (mDialog != null && mDialog.isShowing()) {
             mDialog.dismiss();
@@ -89,8 +81,6 @@
     }
 
     private void buildAndShowDialog() {
-        mCanSkip = true;
-
         mDialog = new AlertDialog.Builder(this)
                 .setTitle(R.string.ota_hfa_activation_title)
                 .setMessage(R.string.ota_hfa_activation_dialog_message)
@@ -98,9 +88,7 @@
                         new DialogInterface.OnClickListener() {
                             @Override
                             public void onClick(DialogInterface di, int which) {
-                                if (mCanSkip) {
-                                    sendFinalResponse(OTASP_USER_SKIPPED);
-                                }
+                                onUserSkip();
                             }})
                 /*.setOnCancelListener(new DialogInterface.OnCancelListener() {
                     @Override
@@ -113,7 +101,7 @@
         mDialog.setCanceledOnTouchOutside(false);
         mDialog.setCancelable(false);
 
-        if (VERBOSE) Log.v(TAG, "showing dialog");
+        Log.i(TAG, "showing dialog");
         mDialog.show();
     }
 
@@ -127,7 +115,7 @@
                         @Override
                         public void onClick(DialogInterface di, int which) {
                             di.dismiss();
-                            sendFinalResponse(OTASP_USER_SKIPPED);
+                            onUserSkip();
                         }
                     })
             .setNegativeButton(R.string.ota_try_again,
@@ -144,29 +132,11 @@
     }
 
     private void onHfaSuccess() {
-        // User can no longer skip after success.
-        mCanSkip = false;
-
-        sendFinalResponse(OTASP_SUCCESS);
-    }
-
-    private void sendFinalResponse(int responseCode) {
-        final PendingIntent otaResponseIntent = getIntent().getParcelableExtra(
-                OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT);
-
-        if (otaResponseIntent != null) {
-            final Intent extraStuff = new Intent();
-            extraStuff.putExtra(OtaUtils.EXTRA_OTASP_RESULT_CODE, responseCode);
-
-            try {
-                if (VERBOSE) Log.v(TAG, "Sending OTASP confirmation with result code: "
-                        + responseCode);
-                otaResponseIntent.send(this, 0 /* resultCode (not used) */, extraStuff);
-            } catch (CanceledException e) {
-                Log.e(TAG, "Pending Intent canceled");
-            }
-        }
-
         finish();
     }
+
+    private void onUserSkip() {
+        finish();
+    }
+
 }
diff --git a/src/com/android/phone/HfaLogic.java b/src/com/android/phone/HfaLogic.java
index 7fd37cf..5a5e4b4 100644
--- a/src/com/android/phone/HfaLogic.java
+++ b/src/com/android/phone/HfaLogic.java
@@ -16,6 +16,8 @@
 
 package com.android.phone;
 
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -46,7 +48,6 @@
  */
 public class HfaLogic {
     private static final String TAG = HfaLogic.class.getSimpleName();
-    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final String ACTION_START = "com.android.action.START_HFA";
     private static final String ACTION_ERROR = "com.android.action.ERROR_HFA";
@@ -59,9 +60,15 @@
     public static final int WAITING_FOR_RADIO_OFF = 1;
     public static final int WAITING_FOR_RADIO_ON = 2;
 
+    public static final int OTASP_UNKNOWN = 0;
+    public static final int OTASP_USER_SKIPPED = 1;
+    public static final int OTASP_SUCCESS = 2;
+    public static final int OTASP_FAILURE = 3;
+
     private int mPhoneMonitorState = NOT_WAITING;
     private BroadcastReceiver mReceiver;
     private HfaLogicCallback mCallback;
+    private PendingIntent mResponseIntent;
     private Context mContext;
 
     public interface HfaLogicCallback {
@@ -69,9 +76,10 @@
         public void onError(String errorMsg);
     }
 
-    public HfaLogic(Context context, HfaLogicCallback callback) {
+    public HfaLogic(Context context, HfaLogicCallback callback, PendingIntent intent) {
         mCallback = Preconditions.checkNotNull(callback);
         mContext = Preconditions.checkNotNull(context);
+        mResponseIntent = intent;
     }
 
     public void start() {
@@ -85,21 +93,25 @@
     }
 
     private void sendHfaCommand(String action) {
-        if (VERBOSE) Log.v(TAG, "Sending command: " + action);
+        Log.i(TAG, "Sending command: " + action);
         mContext.sendBroadcast(new Intent(action));
     }
 
     private void onHfaError(String errorMsg) {
+        Log.i(TAG, "HfaError");
         stopHfaIntentReceiver();
+        sendFinalResponse(OTASP_FAILURE, errorMsg);
         mCallback.onError(errorMsg);
     }
 
     private void onHfaSuccess() {
+        Log.i(TAG, "HfaSuccess");
         stopHfaIntentReceiver();
         bounceRadio();
     }
 
     private void onTotalSuccess() {
+        sendFinalResponse(OTASP_SUCCESS, null);
         mCallback.onSuccess();
     }
 
@@ -116,7 +128,7 @@
         final boolean radioIsOff = state.getVoiceRegState() == ServiceState.STATE_POWER_OFF;
         final Phone phone = PhoneGlobals.getInstance().getPhone();
 
-        if (VERBOSE) Log.v(TAG, "Radio is on: " + !radioIsOff);
+        Log.i(TAG, "Radio is on: " + !radioIsOff);
 
         if (mPhoneMonitorState == WAITING_FOR_RADIO_OFF) {
             if (radioIsOff) {
@@ -144,7 +156,7 @@
                 if (action.equals(ACTION_ERROR)) {
                     onHfaError(intent.getStringExtra("errorCode"));
                 } else if (action.equals(ACTION_COMPLETE)) {
-                    if (VERBOSE) Log.v(TAG, "Hfa Successful");
+                    Log.i(TAG, "Hfa Successful");
                     onHfaSuccess();
                 }
             }
@@ -160,6 +172,25 @@
         }
     }
 
+    private void sendFinalResponse(int responseCode, String errorCode) {
+        if (mResponseIntent != null) {
+            final Intent extraStuff = new Intent();
+            extraStuff.putExtra(OtaUtils.EXTRA_OTASP_RESULT_CODE, responseCode);
+
+            if (responseCode == OTASP_FAILURE && errorCode != null) {
+                extraStuff.putExtra(OtaUtils.EXTRA_OTASP_ERROR_CODE, errorCode);
+            }
+
+            try {
+                Log.i(TAG, "Sending OTASP confirmation with result code: "
+                        + responseCode);
+                mResponseIntent.send(mContext, 0 /* resultCode (not used) */, extraStuff);
+            } catch (CanceledException e) {
+                Log.e(TAG, "Pending Intent canceled");
+            }
+        }
+    }
+
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
diff --git a/src/com/android/phone/HfaService.java b/src/com/android/phone/HfaService.java
index a4d13f2..3aeed4d 100644
--- a/src/com/android/phone/HfaService.java
+++ b/src/com/android/phone/HfaService.java
@@ -16,6 +16,7 @@
 
 package com.android.phone;
 
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
@@ -29,6 +30,14 @@
 
     @Override
     public void onCreate() {
+        Log.i(TAG, "service started");
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        final PendingIntent otaResponseIntent = intent.getParcelableExtra(
+                OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT);
+
         new HfaLogic(this, new HfaLogic.HfaLogicCallback() {
             @Override
             public void onSuccess() {
@@ -43,9 +52,9 @@
                 // we do the same thing...finish.
                 onComplete();
             }
-        }).start();
+        }, otaResponseIntent).start();
 
-        Log.i(TAG, "service started");
+        return START_STICKY;
     }
 
     @Override
diff --git a/src/com/android/phone/OtaUtils.java b/src/com/android/phone/OtaUtils.java
index 8b67148..fe11831 100644
--- a/src/com/android/phone/OtaUtils.java
+++ b/src/com/android/phone/OtaUtils.java
@@ -125,8 +125,11 @@
 
     // Extra attached to the above PendingIntent that indicates
     // success or failure.
-    public static final String EXTRA_OTASP_RESULT_CODE =
-            "otasp_result_code";
+    public static final String EXTRA_OTASP_RESULT_CODE = "otasp_result_code";
+
+    // Extra attached to the above PendingIntent that contains an error code.
+    public static final String EXTRA_OTASP_ERROR_CODE = "otasp_error_code";
+
     public static final int OTASP_UNKNOWN = 0;
     public static final int OTASP_USER_SKIPPED = 1;  // Only meaningful with interactive OTASP
     public static final int OTASP_SUCCESS = 2;
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 5474a62..3f35900 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -175,7 +175,6 @@
     private CallModeler callModeler;
     private CallStateMonitor callStateMonitor;
     private DTMFTonePlayer dtmfTonePlayer;
-    private RejectWithTextMessageManager rejectWithTextMessageManager;
     private IBluetoothHeadsetPhone mBluetoothPhone;
     private Ringer ringer;
     private WiredHeadsetManager wiredHeadsetManager;
@@ -464,12 +463,8 @@
             // Monitors call activity from the telephony layer
             callStateMonitor = new CallStateMonitor(mCM);
 
-            // Rejects calls with TextMessages
-            rejectWithTextMessageManager = new RejectWithTextMessageManager();
-
             // Creates call models for use with CallHandlerService.
-            callModeler = new CallModeler(callStateMonitor, mCM, rejectWithTextMessageManager,
-                    callGatewayManager);
+            callModeler = new CallModeler(callStateMonitor, mCM, callGatewayManager);
 
             // Plays DTMF Tones
             dtmfTonePlayer = new DTMFTonePlayer(mCM, callModeler);
@@ -488,7 +483,7 @@
 
             // Service used by in-call UI to control calls
             callCommandService = new CallCommandService(this, mCM, callModeler, dtmfTonePlayer,
-                    audioRouter, rejectWithTextMessageManager);
+                    audioRouter);
 
             // Sends call state to the UI
             callHandlerServiceProxy = new CallHandlerServiceProxy(this, callModeler,
diff --git a/src/com/android/phone/RejectWithTextMessageManager.java b/src/com/android/phone/RejectWithTextMessageManager.java
index b816eb0..8ad1257 100644
--- a/src/com/android/phone/RejectWithTextMessageManager.java
+++ b/src/com/android/phone/RejectWithTextMessageManager.java
@@ -16,20 +16,11 @@
 
 package com.android.phone;
 
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
@@ -38,24 +29,14 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.PhoneConstants;
-
-import com.google.android.collect.Lists;
+import com.android.internal.telephony.SmsApplication;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Helper class to manage the "Respond via Message" feature for incoming calls.
@@ -63,24 +44,13 @@
  * @see com.android.phone.InCallScreen.internalRespondViaSms()
  */
 public class RejectWithTextMessageManager {
-
     private static final String TAG = RejectWithTextMessageManager.class.getSimpleName();
     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
-    private static final String PERMISSION_SEND_RESPOND_VIA_MESSAGE =
-            "android.permission.SEND_RESPOND_VIA_MESSAGE";
-
-    /** The array of "canned responses"; see loadCannedResponses(). */
-    private String[] mCannedResponses;
-
     /** SharedPreferences file name for our persistent settings. */
     private static final String SHARED_PREFERENCES_NAME = "respond_via_sms_prefs";
 
-    private Intent mIntent;
-
-    private ArrayList<ComponentName> mComponentsWithPermission = new ArrayList<ComponentName>();
-
-            // Preference keys for the 4 "canned responses"; see RespondViaSmsManager$Settings.
+    // Preference keys for the 4 "canned responses"; see RespondViaSmsManager$Settings.
     // Since (for now at least) the number of messages is fixed at 4, and since
     // SharedPreferences can't deal with arrays anyway, just store the messages
     // as 4 separate strings.
@@ -89,12 +59,6 @@
     private static final String KEY_CANNED_RESPONSE_PREF_2 = "canned_response_pref_2";
     private static final String KEY_CANNED_RESPONSE_PREF_3 = "canned_response_pref_3";
     private static final String KEY_CANNED_RESPONSE_PREF_4 = "canned_response_pref_4";
-    /* package */ static final String KEY_INSTANT_TEXT_DEFAULT_COMPONENT =
-            "instant_text_def_component";
-
-    /* package */ static final String TAG_ALL_SMS_SERVICES = "com.android.phone.AvailablePackages";
-    /* package */ static final String TAG_SEND_SMS = "com.android.phone.MessageIntent";
-    /* package */ static final String TAG_SMS_DESTINATION = "com.android.phone.SmsDestination";
 
     /**
      * Read the (customizable) canned responses from SharedPreferences,
@@ -129,42 +93,37 @@
         return responses;
     }
 
-    private void sendTextAndExit(final String phoneNumber) {
-        // Send the selected message immediately with no user interaction.
-        if (mIntent.getComponent() != null) {
-            PhoneGlobals.getInstance().startService(mIntent);
+    private static void showMessageSentToast(final String phoneNumber) {
+        // ...and show a brief confirmation to the user (since
+        // otherwise it's hard to be sure that anything actually
+        // happened.)
+        // Ugly hack to show a toaster from a service.
+        (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                Handler innerHandler = new Handler() {
+                    @Override
+                    public void handleMessage(Message message) {
+                        final Resources res = PhoneGlobals.getInstance().getResources();
+                        final String formatString = res.getString(
+                                R.string.respond_via_sms_confirmation_format);
+                        final String confirmationMsg = String.format(formatString, phoneNumber);
+                        Toast.makeText(PhoneGlobals.getInstance(), confirmationMsg,
+                                Toast.LENGTH_LONG).show();
+                    }
 
-            // ...and show a brief confirmation to the user (since
-            // otherwise it's hard to be sure that anything actually
-            // happened.)
-            // Ugly hack to show a toaster from a service.
-            (new Thread(new Runnable() {
-                @Override
-                public void run() {
-                    Looper.prepare();
-                    Handler innerHandler = new Handler() {
-                        @Override
-                        public void handleMessage(Message message) {
-                            final Resources res = PhoneGlobals.getInstance().getResources();
-                            final String formatString = res.getString(
-                                    R.string.respond_via_sms_confirmation_format);
-                            final String confirmationMsg = String.format(formatString, phoneNumber);
-                            Toast.makeText(PhoneGlobals.getInstance(), confirmationMsg,
-                                    Toast.LENGTH_LONG).show();
-                        }
+                    @Override
+                    public void dispatchMessage(Message message) {
+                        handleMessage(message);
+                    }
+                };
 
-                        @Override
-                        public void dispatchMessage(Message message) {
-                            handleMessage(message);
-                        }
-                    };
-
-                    Message message = innerHandler.obtainMessage();
-                    innerHandler.dispatchMessage(message);
-                    Looper.loop();
-                }
-            })).start();
-        }
+                Message message = innerHandler.obtainMessage();
+                innerHandler.dispatchMessage(message);
+                Looper.loop();
+            }
+        })).start();
 
         // TODO: If the device is locked, this toast won't actually ever
         // be visible!  (That's because we're about to dismiss the call
@@ -173,7 +132,7 @@
         // Possible fixes:
         // (1) Is it possible to allow a specific Toast to be visible
         //     on top of the keyguard?
-        // (2) Artifically delay the dismissCallScreen() call by 3
+        // (2) Artificially delay the dismissCallScreen() call by 3
         //     seconds to allow the toast to be seen?
         // (3) Don't use a toast at all; instead use a transient state
         //     of the InCallScreen (perhaps via the InCallUiState
@@ -182,125 +141,29 @@
     }
 
     /**
-     * Queries the System to determine what packages contain services that can handle the instant
-     * text response Action AND have permissions to do so.
+     * Reject the call with the specified message (or launch messaging UX if null message)
      */
-    private static ArrayList<ComponentName> getPackagesWithInstantTextPermission() {
-        final PackageManager packageManager = PhoneGlobals.getInstance().getPackageManager();
-
-        final ArrayList<ComponentName> componentsWithPermission = new ArrayList<ComponentName>();
-
-        // Get list of all services set up to handle the Instant Text intent.
-        final List<ResolveInfo> infos = packageManager.queryIntentServices(
-                getInstantTextIntent("", null, null), 0);
-
-        // Collect all the valid services
-        for (ResolveInfo resolveInfo : infos) {
-            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            if (serviceInfo == null) {
-                Log.w(TAG, "Ignore package without proper service.");
-                continue;
+    public static void rejectCallWithMessage(Call call, String message) {
+        Connection conn = call.getLatestConnection();
+        if (conn != null) {
+            final String phoneNumber = conn.getAddress();
+            final ComponentName component =
+                    SmsApplication.getDefaultRespondViaMessageApplication(
+                            PhoneGlobals.getInstance(), true /*updateIfNeeded*/);
+            if (component != null) {
+                // Build and send the intent
+                final Uri uri = Uri.fromParts(Constants.SCHEME_SMSTO, phoneNumber, null);
+                final Intent intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, uri);
+                if (message != null) {
+                    intent.putExtra(Intent.EXTRA_TEXT, message);
+                    showMessageSentToast(phoneNumber);
+                } else {
+                    intent.putExtra("exit_on_sent", true);
+                    intent.putExtra("showUI", true);
+                }
+                intent.setComponent(component);
+                PhoneGlobals.getInstance().startService(intent);
             }
-
-            // A Service is valid only if it requires the permission
-            // PERMISSION_SEND_RESPOND_VIA_MESSAGE
-            if (PERMISSION_SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) {
-                componentsWithPermission.add(new ComponentName(serviceInfo.packageName,
-                    serviceInfo.name));
-            }
-        }
-
-        return componentsWithPermission;
-    }
-
-    /**
-     * @param phoneNumber Must not be null.
-     * @param message Can be null. If message is null, the returned Intent will be configured to
-     * launch the SMS compose UI. If non-null, the returned Intent will cause the specified message
-     * to be sent with no interaction from the user.
-     * @param component The component that should handle this intent.
-     * @return Service Intent for the instant response.
-     */
-    private static Intent getInstantTextIntent(String phoneNumber, String message,
-            ComponentName component) {
-        final Uri uri = Uri.fromParts(Constants.SCHEME_SMSTO, phoneNumber, null);
-        final Intent intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, uri);
-        if (message != null) {
-            intent.putExtra(Intent.EXTRA_TEXT, message);
-        } else {
-            intent.putExtra("exit_on_sent", true);
-            intent.putExtra("showUI", true);
-        }
-        if (component != null) {
-            intent.setComponent(component);
-        }
-        return intent;
-    }
-
-    private boolean getSmsService(String phoneNumber) {
-        if (DBG) log("sendTextToDefaultActivity()...");
-        final PackageManager packageManager = PhoneGlobals.getInstance().getPackageManager();
-
-        // Check to see if the default component to receive this intent is already saved
-        // and check to see if it still has the corrent permissions.
-        final SharedPreferences prefs = PhoneGlobals.getInstance().
-                getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
-        final String flattenedName = prefs.getString(KEY_INSTANT_TEXT_DEFAULT_COMPONENT, null);
-        if (flattenedName != null) {
-            if (DBG) log("Default package was found." + flattenedName);
-
-            final ComponentName componentName = ComponentName.unflattenFromString(flattenedName);
-            ServiceInfo serviceInfo = null;
-            try {
-                serviceInfo = packageManager.getServiceInfo(componentName, 0);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Default service does not have permission.");
-            }
-
-            if (serviceInfo != null &&
-                    PERMISSION_SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) {
-                mIntent.setComponent(componentName);
-                return true;
-            } else {
-                SharedPreferences.Editor editor = prefs.edit();
-                editor.remove(KEY_INSTANT_TEXT_DEFAULT_COMPONENT);
-                editor.apply();
-            }
-        }
-
-        mComponentsWithPermission = getPackagesWithInstantTextPermission();
-
-        final int size = mComponentsWithPermission.size();
-        if (size == 0) {
-            Log.e(TAG, "No appropriate package receiving the Intent. Don't send anything");
-            return false;
-        } else if (size == 1) {
-            mIntent.setComponent(mComponentsWithPermission.get(0));
-            return true;
-        } else {
-            Log.v(TAG, "Choosing from one of the apps");
-            final Intent intent = new Intent(Intent.ACTION_VIEW, null);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                    Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
-                    Intent.FLAG_ACTIVITY_NO_ANIMATION  |
-                    Intent.FLAG_ACTIVITY_NO_HISTORY |
-                    Intent.FLAG_FROM_BACKGROUND);
-            intent.setClass(PhoneGlobals.getInstance(), TextMessagePackageChooser.class);
-            intent.putExtra(TAG_ALL_SMS_SERVICES, mComponentsWithPermission);
-            intent.putExtra(TAG_SEND_SMS, mIntent);
-            intent.putExtra(TAG_SMS_DESTINATION, phoneNumber);
-            PhoneGlobals.getInstance().startActivity(intent);
-            return false;
-            // return componentsWithPermission.get(0);
-        }
-    }
-
-    public void rejectCallWithMessage(Call call, String message) {
-        mComponentsWithPermission.clear();
-        final String phoneNumber = call.getLatestConnection().getAddress();
-        mIntent = getInstantTextIntent(phoneNumber, message, null);
-        if (getSmsService(phoneNumber))  {
-            sendTextAndExit(phoneNumber);
         }
     }
 
@@ -379,8 +242,9 @@
             return false;
         }
 
-        // Allow the feature only when there's a destination for it.
-        if (getPackagesWithInstantTextPermission().size() < 1) {
+        // Is there a valid SMS application on the phone?
+        if (SmsApplication.getDefaultRespondViaMessageApplication(PhoneGlobals.getInstance(),
+                true /*updateIfNeeded*/) == null) {
             return false;
         }
 
diff --git a/src/com/android/phone/TextMessagePackageChooser.java b/src/com/android/phone/TextMessagePackageChooser.java
deleted file mode 100644
index 6760a3a..0000000
--- a/src/com/android/phone/TextMessagePackageChooser.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
-
- * Copyright (C) 2013 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.phone;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class TextMessagePackageChooser extends Activity {
-    private static final String TAG = TextMessagePackageChooser.class.getSimpleName();
-
-    /** SharedPreferences file name for our persistent settings. */
-    private static final String SHARED_PREFERENCES_NAME = "respond_via_sms_prefs";
-
-    private int mIconSize = -1;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final ArrayList<ComponentName> components = getIntent().getParcelableArrayListExtra(
-                RejectWithTextMessageManager.TAG_ALL_SMS_SERVICES);
-        BaseAdapter adapter = new PackageSelectionAdapter(this, components);
-
-        PackageClickListener clickListener = new PackageClickListener(components);
-
-        final CharSequence title = getResources().getText(
-                com.android.internal.R.string.whichApplication);
-        LayoutInflater inflater =
-                (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-        final View view = inflater.inflate(com.android.internal.R.layout.always_use_checkbox,
-                null);
-        final CheckBox alwaysUse = (CheckBox) view.findViewById(
-                com.android.internal.R.id.alwaysUse);
-        alwaysUse.setText(com.android.internal.R.string.alwaysUse);
-        alwaysUse.setOnCheckedChangeListener(clickListener);
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(this)
-                .setTitle(title)
-                .setCancelable(true)
-                .setOnCancelListener(new RespondViaSmsCancelListener())
-                .setAdapter(adapter, clickListener)
-                .setView(view);
-                       
-        builder.create().show();
-    }
-    
-    private class PackageSelectionAdapter extends BaseAdapter {
-        private final LayoutInflater mInflater;
-        private final List<ComponentName> mComponents;
-
-        public PackageSelectionAdapter(Context context, List<ComponentName> components) {
-            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            mComponents = components;
-        }
-
-        @Override
-        public int getCount() {
-            return mComponents.size();
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return mComponents.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = mInflater.inflate(
-                        com.android.internal.R.layout.activity_chooser_view_list_item, parent,
-                        false);
-            }
-
-            final ComponentName component = mComponents.get(position);
-            final String packageName = component.getPackageName();
-            final PackageManager packageManager = getPackageManager();
-
-            // Set the application label
-            final TextView text = (TextView) convertView.findViewById(
-                    com.android.internal.R.id.title);
-
-            text.setText("");
-            try {
-                final ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0);
-                final CharSequence label = packageManager.getApplicationLabel(appInfo);
-                if (label != null) {
-                    text.setText(label);
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Failed to load app label because package was not found.");
-            }
-
-            // Set the application icon
-            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
-            Drawable drawable = null;
-            try {
-                drawable = getPackageManager().getApplicationIcon(packageName);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Failed to load icon because it wasn't found.");
-            }
-            if (drawable == null) {
-                drawable = getPackageManager().getDefaultActivityIcon();
-            }
-            icon.setImageDrawable(drawable);
-            ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) icon.getLayoutParams();
-            lp.width = lp.height = getIconSize();
-
-            return convertView;
-        }
-
-    }
-
-    private class PackageClickListener implements DialogInterface.OnClickListener,
-            CompoundButton.OnCheckedChangeListener {
-        final private List<ComponentName> mComponents;
-        private boolean mMakeDefault = false;
-
-        public PackageClickListener(List<ComponentName> components) {
-            mComponents = components;
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            final ComponentName component = mComponents.get(which);
-
-            if (mMakeDefault) {
-                final SharedPreferences prefs = PhoneGlobals.getInstance().getSharedPreferences(
-                        SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
-                prefs.edit().putString(
-                        RejectWithTextMessageManager.KEY_INSTANT_TEXT_DEFAULT_COMPONENT,
-                        component.flattenToString()).apply();
-            }
-
-            final Intent messageIntent = (Intent) getIntent().getParcelableExtra(
-                    RejectWithTextMessageManager.TAG_SEND_SMS);
-            if (messageIntent != null) {
-                messageIntent.setComponent(component);
-                PhoneGlobals.getInstance().startService(messageIntent);
-
-                // ...and show a brief confirmation to the user (since
-                // otherwise it's hard to be sure that anything actually
-                // happened.)
-                final Resources res = getResources();
-                final String formatString = res.getString(
-                        R.string.respond_via_sms_confirmation_format);
-                final String phoneNumber = (String) getIntent().getStringExtra(
-                        RejectWithTextMessageManager.TAG_SMS_DESTINATION);
-                final String confirmationMsg = String.format(formatString, phoneNumber);
-                Toast.makeText(PhoneGlobals.getInstance(), confirmationMsg, Toast.LENGTH_LONG).show();
-            }
-            finish();
-        }
-
-        @Override
-        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            Log.i(TAG, "mMakeDefault : " + isChecked);
-            mMakeDefault = isChecked;
-        }
-    }
-
-    /**
-     * OnCancelListener for the "Respond via SMS" popup.
-     */
-    public class RespondViaSmsCancelListener implements DialogInterface.OnCancelListener {
-        public RespondViaSmsCancelListener() {
-        }
-
-        /**
-         * Handles the user canceling the popup, either by touching
-         * outside the popup or by pressing Back.
-         */
-        @Override
-        public void onCancel(DialogInterface dialog) {
-            finish();
-        }
-    }
-
-    private int getIconSize() {
-      if (mIconSize < 0) {
-          final ActivityManager am =
-              (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-          mIconSize = am.getLauncherLargeIconSize();
-      }
-
-      return mIconSize;
-    }
-}