Merge "Remove Phone Account Preferences; moved to Telephony." into lmp-dev
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 28b3a5e..3b13384 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -42,7 +42,7 @@
     <string name="account_ask_every_time" msgid="944077828070287407">"Vra elke keer"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"Moenie Wi-Fi vir oproepe gebruik nie"</string>
     <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"Hierdie gebruiker word nie toegelaat om nienood-foonoproepe te maak nie"</string>
-    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Oproep nie gestuur nie; geen geldige nommer ingevoer nie."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Oproep nie gestuur nie; geen geldige nommer is ingevoer nie."</string>
     <string name="no_vm_number" msgid="4164780423805688336">"Vermiste stemboodskapnommer"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Geen stemboodskapnommer is op die SIM-kaart gestoor nie."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Voeg nommer by"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 2b2fc56..0a44223 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -42,7 +42,7 @@
     <string name="account_ask_every_time" msgid="944077828070287407">"Galdetu beti"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"Ez erabili Wi-Fi bidezko deiak"</string>
     <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"Erabiltzaile honek ez du larrialdietakoak ez diren telefono-deiak egiteko baimenik"</string>
-    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Ez da deia egin, ez delako baliozko zenbakirik idatzi."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Ez da deia egin ez delako baliozko zenbakirik idatzi."</string>
     <string name="no_vm_number" msgid="4164780423805688336">"Erantzungailuaren zenbakia falta da"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Ez da erantzungailuaren zenbakirik gorde SIM txartelean."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Gehitu zenbakia"</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 31b273d..df9fbac 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -44,6 +44,6 @@
     <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"அவசரமற்ற ஃபோன் அழைப்புகளைச் செய்ய இவருக்கு அனுமதியில்லை"</string>
     <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"அழைக்க முடியவில்லை, சரியான எண் உள்ளிடப்படவில்லை."</string>
     <string name="no_vm_number" msgid="4164780423805688336">"குரலஞ்சல் எண் இல்லை"</string>
-    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM கார்டில் குரலஞ்சலுக்கான எண் எதுவும் சேமிக்கப்படவில்லை."</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"சிம் கார்டில் குரலஞ்சலுக்கான எண் எதுவும் சேமிக்கப்படவில்லை."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"எண்ணைச் சேர்"</string>
 </resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index ffee42a..ea5aa9e 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -42,7 +42,7 @@
     <string name="account_ask_every_time" msgid="944077828070287407">"Luôn hỏi"</string>
     <string name="do_not_use_sim_call_manager" msgid="5519252524007323694">"Không sử dụng tính năng gọi qua Wi-Fi"</string>
     <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"Người dùng này không được phép thực hiện cuộc gọi điện thoại không khẩn cấp"</string>
-    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Cuộc gọi không được gửi đi, bạn đã nhập số không hợp lệ."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"Không gọi được, bạn đã nhập số không hợp lệ."</string>
     <string name="no_vm_number" msgid="4164780423805688336">"Thiếu số thư thoại"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Không có số thư thoại nào được lưu trữ trên thẻ SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Thêm số điện thoại"</string>
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index a742d11..b8e2e19 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -331,8 +331,8 @@
             component = mConnectionService.getComponentName().flattenToShortString();
         }
 
-        return String.format(Locale.US, "[%s, %s, %s, %d]", mState, component,
-                Log.piiHandle(mHandle), getVideoState());
+        return String.format(Locale.US, "[%s, %s, %s, %s, %d]", System.identityHashCode(this),
+                mState, component, Log.piiHandle(mHandle), getVideoState());
     }
 
     int getState() {
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index 6d3b98f..f354291 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -119,9 +119,14 @@
      * @param intent Call intent containing data about the handle to call.
      */
     private void processOutgoingCallIntent(Intent intent) {
-        String uriString = intent.getData().getSchemeSpecificPart();
-        Uri handle = Uri.fromParts(
-                PhoneNumberUtils.isUriNumber(uriString) ? "sip" : "tel", uriString, null);
+        Uri handle = intent.getData();
+        String scheme = handle.getScheme();
+        String uriString = handle.getSchemeSpecificPart();
+
+        if (!Constants.SCHEME_VOICEMAIL.equals(scheme)) {
+            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
+                    Constants.SCHEME_SIP : Constants.SCHEME_TEL, uriString, null);
+        }
 
         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
         if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS)
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 784877c..116cf95 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -276,9 +276,6 @@
     /**
      * Kicks off the first steps to creating an outgoing call so that InCallUI can launch.
      *
-     * NOTE: emergency calls will never pass through this because they call
-     * placeOutgoingCall directly.
-     *
      * @param handle Handle to connect the call with.
      * @param phoneAccountHandle The phone account which contains the component name of the
      *        connection service to use for this call.
@@ -815,7 +812,8 @@
             return;
         }
         int oldState = call.getState();
-        Log.i(this, "setCallState %s -> %s, call: %s", oldState, newState, call);
+        Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
+                CallState.toString(newState), call);
         if (newState != oldState) {
             // Unfortunately, in the telephony world the radio is king. So if the call notifies
             // us that the call is in a particular state, we allow it even if it doesn't make
diff --git a/src/com/android/telecomm/Constants.java b/src/com/android/telecomm/Constants.java
new file mode 100644
index 0000000..9967fa2
--- /dev/null
+++ b/src/com/android/telecomm/Constants.java
@@ -0,0 +1,35 @@
+/*
+ * 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.telecomm;
+
+/**
+ * App-wide constants for the phone app.
+ *
+ * Any constants that need to be shared between two or more classes within
+ * the com.android.phone package should be defined here.  (Constants that
+ * are private to only one class can go in that class's .java file.)
+ */
+public class Constants {
+    //
+    // URI schemes
+    //
+
+    public static final String SCHEME_SIP = "sip";
+    public static final String SCHEME_SMSTO = "smsto";
+    public static final String SCHEME_TEL = "tel";
+    public static final String SCHEME_VOICEMAIL = "voicemail";
+}
\ No newline at end of file
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index da41a56..f132934 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -61,11 +61,13 @@
     private class InCallServiceConnection implements ServiceConnection {
         /** {@inheritDoc} */
         @Override public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.d(this, "onServiceConnected: %s", name);
             onConnected(name, service);
         }
 
         /** {@inheritDoc} */
         @Override public void onServiceDisconnected(ComponentName name) {
+            Log.d(this, "onDisconnected: %s", name);
             onDisconnected(name);
         }
     }
@@ -148,7 +150,7 @@
         if (mInCallServices.isEmpty()) {
             bind();
         } else {
-            Log.i(this, "Adding call: %s", call);
+            Log.i(this, "onCallAdded: %s", call);
             // Track the call if we don't already know about it.
             addCall(call);
 
@@ -168,6 +170,7 @@
 
     @Override
     public void onCallRemoved(Call call) {
+        Log.i(this, "onCallRemoved: %s", call);
         if (CallsManager.getInstance().getCalls().isEmpty()) {
             // TODO: Wait for all messages to be delivered to the service before unbinding.
             unbind();
@@ -309,6 +312,8 @@
     private void onConnected(ComponentName componentName, IBinder service) {
         ThreadUtil.checkOnMainThread();
 
+        Log.i(this, "onConnected to %s", componentName);
+
         IInCallService inCallService = IInCallService.Stub.asInterface(service);
 
         try {
@@ -323,9 +328,12 @@
         // Upon successful connection, send the state of the world to the service.
         ImmutableCollection<Call> calls = CallsManager.getInstance().getCalls();
         if (!calls.isEmpty()) {
+            Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
+                    componentName);
             for (Call call : calls) {
                 try {
                     // Track the call if we don't already know about it.
+                    Log.i(this, "addCall after binding: %s", call);
                     addCall(call);
 
                     inCallService.addCall(toParcelableCall(call,
@@ -345,6 +353,7 @@
      * @param disconnectedComponent The {@link ComponentName} of the service which disconnected.
      */
     private void onDisconnected(ComponentName disconnectedComponent) {
+        Log.i(this, "onDisconnected from %s", disconnectedComponent);
         ThreadUtil.checkOnMainThread();
         if (mInCallServices.containsKey(disconnectedComponent)) {
             mInCallServices.remove(disconnectedComponent);
diff --git a/src/com/android/telecomm/MissedCallNotifier.java b/src/com/android/telecomm/MissedCallNotifier.java
index eede65c..f3c87e2 100644
--- a/src/com/android/telecomm/MissedCallNotifier.java
+++ b/src/com/android/telecomm/MissedCallNotifier.java
@@ -53,7 +53,6 @@
         Calls.TYPE,
     };
     private static final int MISSED_CALL_NOTIFICATION_ID = 1;
-    private static final String SCHEME_SMSTO = "smsto";
 
     private final Context mContext;
     private final NotificationManager mNotificationManager;
@@ -237,7 +236,7 @@
     private PendingIntent createSendSmsFromNotificationPendingIntent(Uri handle) {
         return createTelecommPendingIntent(
                 TelecommBroadcastReceiver.ACTION_SEND_SMS_FROM_NOTIFICATION,
-                Uri.fromParts(SCHEME_SMSTO, handle.getSchemeSpecificPart(), null));
+                Uri.fromParts(Constants.SCHEME_SMSTO, handle.getSchemeSpecificPart(), null));
     }
 
     /**
@@ -270,36 +269,42 @@
         AsyncQueryHandler queryHandler = new AsyncQueryHandler(mContext.getContentResolver()) {
             @Override
             protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+                Log.d(MissedCallNotifier.this, "onQueryComplete()...");
                 if (cursor != null) {
-                    while (cursor.moveToNext()) {
-                        // Get data about the missed call from the cursor
-                        Uri handle = Uri.parse(cursor.getString(
-                                cursor.getColumnIndexOrThrow(Calls.NUMBER)));
-                        int presentation = cursor.getInt(cursor.getColumnIndexOrThrow(
-                                Calls.NUMBER_PRESENTATION));
+                    try {
+                        while (cursor.moveToNext()) {
+                            // Get data about the missed call from the cursor
+                            Uri handle = Uri.parse(cursor.getString(
+                                    cursor.getColumnIndexOrThrow(Calls.NUMBER)));
+                            int presentation = cursor.getInt(cursor.getColumnIndexOrThrow(
+                                    Calls.NUMBER_PRESENTATION));
 
-                        if (presentation != Calls.PRESENTATION_ALLOWED) {
-                            handle = null;
-                        }
-
-                        // Convert the data to a call object
-                        Call call = new Call(null, null, null, null, null, true, false);
-                        call.setDisconnectCause(DisconnectCause.INCOMING_MISSED, "");
-                        call.setState(CallState.DISCONNECTED);
-
-                        // Listen for the update to the caller information before posting the
-                        // notification so that we have the contact info and photo.
-                        call.addListener(new Call.ListenerBase() {
-                            @Override
-                            public void onCallerInfoChanged(Call call) {
-                                call.removeListener(this);  // No longer need to listen to call
-                                                            // changes after the contact info
-                                                            // is retrieved.
-                                showMissedCallNotification(call);
+                            if (presentation != Calls.PRESENTATION_ALLOWED) {
+                                handle = null;
                             }
-                        });
-                        // Set the handle here because that is what triggers the contact info query.
-                        call.setHandle(handle, presentation);
+
+                            // Convert the data to a call object
+                            Call call = new Call(null, null, null, null, null, true, false);
+                            call.setDisconnectCause(DisconnectCause.INCOMING_MISSED, "");
+                            call.setState(CallState.DISCONNECTED);
+
+                            // Listen for the update to the caller information before posting the
+                            // notification so that we have the contact info and photo.
+                            call.addListener(new Call.ListenerBase() {
+                                @Override
+                                public void onCallerInfoChanged(Call call) {
+                                    call.removeListener(this);  // No longer need to listen to call
+                                                                // changes after the contact info
+                                                                // is retrieved.
+                                    showMissedCallNotification(call);
+                                }
+                            });
+                            // Set the handle here because that is what triggers the contact info
+                            // query.
+                            call.setHandle(handle, presentation);
+                        }
+                    } finally {
+                        cursor.close();
                     }
                 }
             }
diff --git a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
index 1c44fb2..1032018 100644
--- a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
@@ -65,10 +65,6 @@
     public static final String EXTRA_GATEWAY_ORIGINAL_URI =
             "com.android.phone.extra.GATEWAY_ORIGINAL_URI";
 
-    private static final String SCHEME_TEL = "tel";
-    private static final String SCHEME_SIP = "sip";
-    private static final String SCHEME_VOICEMAIL = "voicemail";
-
     private final CallsManager mCallsManager;
     private final Call mCall;
     private final Intent mIntent;
@@ -98,15 +94,15 @@
 
             // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData is used as the
             // actual number to call. (If null, no call will be placed.)
-            String resultHandle = getResultData();
-            Log.v(this, "- got number from resultData: %s", Log.pii(resultHandle));
+            String resultNumber = getResultData();
+            Log.v(this, "- got number from resultData: %s", Log.pii(resultNumber));
 
             boolean endEarly = false;
-            if (resultHandle == null) {
+            if (resultNumber == null) {
                 Log.v(this, "Call cancelled (null number), returning...");
                 endEarly = true;
-            } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(context, resultHandle)) {
-                Log.w(this, "Cannot modify outgoing call to emergency number %s.", resultHandle);
+            } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(context, resultNumber)) {
+                Log.w(this, "Cannot modify outgoing call to emergency number %s.", resultNumber);
                 endEarly = true;
             }
 
@@ -117,15 +113,13 @@
                 return;
             }
 
-            Uri resultHandleUri = Uri.fromParts(
-                    PhoneNumberUtils.isUriNumber(resultHandle) ? SCHEME_SIP : SCHEME_TEL,
-                    resultHandle,
-                    null);
+            Uri resultHandleUri = Uri.fromParts(PhoneNumberUtils.isUriNumber(resultNumber) ?
+                    Constants.SCHEME_SIP : Constants.SCHEME_TEL, resultNumber, null);
 
             Uri originalUri = mIntent.getData();
 
-            if (originalUri.getSchemeSpecificPart().equals(resultHandle)) {
-                Log.v(this, "Call handle unmodified after new outgoing call intent broadcast.");
+            if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
+                Log.v(this, "Call number unmodified after new outgoing call intent broadcast.");
             } else {
                 Log.v(this, "Retrieved modified handle after outgoing call intent broadcast: "
                         + "Original: %s, Modified: %s",
@@ -159,29 +153,48 @@
         Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");
 
         final Context context = TelecommApp.getInstance();
+
         Intent intent = mIntent;
+        String action = intent.getAction();
+        final Uri handle = intent.getData();
 
-        String handle = PhoneNumberUtils.getNumberFromIntent(intent, context);
+        if (handle == null) {
+            Log.w(this, "Empty handle obtained from the call intent.");
+            return DisconnectCause.INVALID_NUMBER;
+        }
 
-        if (TextUtils.isEmpty(handle)) {
-            final Uri data = intent.getData();
-            if (data != null && SCHEME_VOICEMAIL.equals(data.getScheme())) {
-                Log.w(this, "Voicemail scheme provided but no voicemail number set.");
-                return DisconnectCause.VOICEMAIL_NUMBER_MISSING;
+        boolean isVoicemailNumber = Constants.SCHEME_VOICEMAIL.equals(handle.getScheme());
+        if (isVoicemailNumber) {
+            if (Intent.ACTION_CALL.equals(action)) {
+                // Voicemail calls will be handled directly by the telephony connection manager
+                Log.i(this, "Placing call immediately instead of waiting for "
+                        + " OutgoingCallBroadcastReceiver: %s", intent);
+
+                boolean speakerphoneOn = mIntent.getBooleanExtra(
+                        TelecommManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
+                mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,
+                        VideoProfile.VideoState.AUDIO_ONLY);
+
+                return DisconnectCause.NOT_DISCONNECTED;
             } else {
-                Log.w(this, "Empty handle obtained from the call intent.");
-                return DisconnectCause.INVALID_NUMBER;
+                Log.i(this, "Unhandled intent %s. Ignoring and not placing call.", intent);
+                return DisconnectCause.OUTGOING_CANCELED;
             }
         }
 
-        boolean isUriNumber = PhoneNumberUtils.isUriNumber(handle);
-
-        if (!isUriNumber) {
-            handle = PhoneNumberUtils.convertKeypadLettersToDigits(handle);
-            handle = PhoneNumberUtils.stripSeparators(handle);
+        String number = PhoneNumberUtils.getNumberFromIntent(intent, context);
+        if (TextUtils.isEmpty(number)) {
+            Log.w(this, "Empty number obtained from the call intent.");
+            return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;
         }
 
-        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(context, handle);
+        boolean isUriNumber = PhoneNumberUtils.isUriNumber(number);
+        if (!isUriNumber) {
+            number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
+            number = PhoneNumberUtils.stripSeparators(number);
+        }
+
+        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(context, number);
         Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
 
         rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
@@ -189,12 +202,11 @@
         // by third parties (e.g. emergency numbers).
         boolean callImmediately = false;
 
-        String action = intent.getAction();
         if (Intent.ACTION_CALL.equals(action)) {
             if (isPotentialEmergencyNumber) {
                 if (!mIsDefaultOrSystemPhoneApp) {
                     Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
-                            + "unless caller is system or default dialer.", handle, intent);
+                            + "unless caller is system or default dialer.", number, intent);
                     launchSystemDialer(context, intent.getData());
                     return DisconnectCause.OUTGOING_CANCELED;
                 } else {
@@ -204,7 +216,7 @@
         } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
             if (!isPotentialEmergencyNumber) {
                 Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
-                        + "Intent %s.", handle, intent);
+                        + "Intent %s.", number, intent);
                 return DisconnectCause.OUTGOING_CANCELED;
             }
             callImmediately = true;
@@ -216,13 +228,13 @@
         if (callImmediately) {
             Log.i(this, "Placing call immediately instead of waiting for "
                     + " OutgoingCallBroadcastReceiver: %s", intent);
-            String scheme = isUriNumber ? SCHEME_SIP : SCHEME_TEL;
+            String scheme = isUriNumber ? Constants.SCHEME_SIP : Constants.SCHEME_TEL;
             boolean speakerphoneOn = mIntent.getBooleanExtra(
                     TelecommManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
             int videoState = mIntent.getIntExtra(
                     TelecommManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                     VideoProfile.VideoState.AUDIO_ONLY);
-            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, handle, null), null,
+            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
                     speakerphoneOn, videoState);
 
             // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
@@ -231,7 +243,7 @@
             // initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
         }
 
-        broadcastIntent(intent, handle, context, !callImmediately);
+        broadcastIntent(intent, number, context, !callImmediately);
         return DisconnectCause.NOT_DISCONNECTED;
     }
 
@@ -240,19 +252,19 @@
      * placement of the call or redirect it to a different number.
      *
      * @param originalCallIntent The original call intent.
-     * @param handle Call handle that was stored in the original call intent.
+     * @param number Call number that was stored in the original call intent.
      * @param context Valid context to send the ordered broadcast using.
      * @param receiverRequired Whether or not the result from the ordered broadcast should be
      *     processed using a {@link NewOutgoingCallIntentBroadcaster}.
      */
     private void broadcastIntent(
             Intent originalCallIntent,
-            String handle,
+            String number,
             Context context,
             boolean receiverRequired) {
         Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
-        if (handle != null) {
-            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, handle);
+        if (number != null) {
+            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
         }
 
         // Force receivers of this broadcast intent to run at foreground priority because we
@@ -269,7 +281,7 @@
                 receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
                 null,  // scheduler
                 Activity.RESULT_OK,  // initialCode
-                handle,  // initialData: initial value for the result data (number to be modified)
+                number,  // initialData: initial value for the result data (number to be modified)
                 null);  // initialExtras
     }
 
@@ -360,13 +372,13 @@
      * isPotentialLocalEmergencyNumber instead of isLocalEmergencyNumber.
      *
      * @param context Valid context
-     * @param handle Handle to inspect in order to determine whether or not an emergency number
+     * @param number number to inspect in order to determine whether or not an emergency number
      * is potentially being dialed
      * @return True if the handle is potentially an emergency number.
      */
-    private boolean isPotentialEmergencyNumber(Context context, String handle) {
-        Log.v(this, "Checking restrictions for number : %s", Log.pii(handle));
-        return (handle != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(context,handle);
+    private boolean isPotentialEmergencyNumber(Context context, String number) {
+        Log.v(this, "Checking restrictions for number : %s", Log.pii(number));
+        return (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(context,number);
     }
 
     /**
@@ -374,7 +386,7 @@
      * the call intent action to an appropriate one.
      *
      * @param intent Intent to rewrite the action for
-     * @param isPotentialEmergencyNumber Whether or not the handle is potentially an emergency
+     * @param isPotentialEmergencyNumber Whether or not the number is potentially an emergency
      * number.
      */
     private void rewriteCallIntentAction(Intent intent, boolean isPotentialEmergencyNumber) {
diff --git a/src/com/android/telecomm/QuickResponseUtils.java b/src/com/android/telecomm/QuickResponseUtils.java
new file mode 100644
index 0000000..ead9105
--- /dev/null
+++ b/src/com/android/telecomm/QuickResponseUtils.java
@@ -0,0 +1,116 @@
+/*
+ * 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.telecomm;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+
+
+/**
+ * Utils class that exposes some helper routines to used to manage the QuickResponses
+ */
+public class QuickResponseUtils {
+    public static final String LOG_TAG = "QuickResponseUtils";
+
+    // SharedPreferences file name for our persistent settings.
+    public static final String SHARED_PREFERENCES_NAME = "respond_via_sms_prefs";
+    private static final String PACKAGE_NAME_TELEPHONY = "com.android.phone";
+
+    // 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.
+    public static final int NUM_CANNED_RESPONSES = 4;
+    public static final String KEY_CANNED_RESPONSE_PREF_1 = "canned_response_pref_1";
+    public static final String KEY_CANNED_RESPONSE_PREF_2 = "canned_response_pref_2";
+    public static final String KEY_CANNED_RESPONSE_PREF_3 = "canned_response_pref_3";
+    public static final String KEY_CANNED_RESPONSE_PREF_4 = "canned_response_pref_4";
+
+    /**
+     * As of L, QuickResponses were moved from Telephony to Telecomm. Because of
+     * this, we need to make sure that we migrate any old QuickResponses to our
+     * current SharedPreferences.  This is a lazy migration as it happens only when
+     * the QuickResponse settings are viewed or if they are queried via RespondViaSmsManager.
+     */
+    public static void maybeMigrateLegacyQuickResponses() {
+        // The algorithm will go as such:
+        // If Telecomm QuickResponses exist, we will skip migration because this implies
+        // that a user has already specified their desired QuickResponses and have abandoned any
+        // older QuickResponses.
+        // Then, if Telephony QuickResponses exist, we will move those to Telecomm.
+        // If neither exist, we'll populate Telecomm with the default QuickResponses.
+        // This guarantees the caller that QuickResponses exist in SharedPreferences after this
+        // function is called.
+
+        Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Starting");
+
+        final Context telecommContext = TelecommApp.getInstance();
+        final SharedPreferences prefs = telecommContext.getSharedPreferences(
+                SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+        final Resources res = telecommContext.getResources();
+
+        final boolean responsesExist = prefs.contains(KEY_CANNED_RESPONSE_PREF_1);
+        if (responsesExist) {
+            // If one QuickResponse exists, they all exist.
+            Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Telecomm QuickResponses exist");
+            return;
+        }
+
+        // Grab the all the default QuickResponses from our resources.
+        String cannedResponse1 = res.getString(R.string.respond_via_sms_canned_response_1);
+        String cannedResponse2 = res.getString(R.string.respond_via_sms_canned_response_2);
+        String cannedResponse3 = res.getString(R.string.respond_via_sms_canned_response_3);
+        String cannedResponse4 = res.getString(R.string.respond_via_sms_canned_response_4);
+
+        Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - No local QuickResponses");
+
+        // We don't have local QuickResponses, let's see if they live in
+        // the Telephony package and we'll fall back on using our default values.
+        Context telephonyContext = null;
+        try {
+            telephonyContext = telecommContext.createPackageContext(PACKAGE_NAME_TELEPHONY, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(LOG_TAG, e, "maybeMigrateLegacyQuickResponses() - Can't find Telephony package.");
+        }
+
+        // Read the old canned responses from the Telephony SharedPreference if possible.
+        if (telephonyContext != null) {
+            // Note that if any one QuickResponse does not exist, we'll use the default
+            // value to populate it.
+            Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Using Telephony QuickResponses.");
+            final SharedPreferences oldPrefs = telephonyContext.getSharedPreferences(
+                    SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+            cannedResponse1 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_1, cannedResponse1);
+            cannedResponse2 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_2, cannedResponse2);
+            cannedResponse3 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_3, cannedResponse3);
+            cannedResponse4 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_4, cannedResponse4);
+        }
+
+        // Either way, write them back into Telecomm SharedPreferences.
+        final SharedPreferences.Editor editor = prefs.edit();
+        editor.putString(KEY_CANNED_RESPONSE_PREF_1, cannedResponse1);
+        editor.putString(KEY_CANNED_RESPONSE_PREF_2, cannedResponse2);
+        editor.putString(KEY_CANNED_RESPONSE_PREF_3, cannedResponse3);
+        editor.putString(KEY_CANNED_RESPONSE_PREF_4, cannedResponse4);
+        editor.commit();
+
+        Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Done.");
+        return;
+    }
+}
diff --git a/src/com/android/telecomm/RespondViaSmsManager.java b/src/com/android/telecomm/RespondViaSmsManager.java
index 8618af0..60f419d 100644
--- a/src/com/android/telecomm/RespondViaSmsManager.java
+++ b/src/com/android/telecomm/RespondViaSmsManager.java
@@ -38,21 +38,6 @@
  * Helper class to manage the "Respond via Message" feature for incoming calls.
  */
 public class RespondViaSmsManager extends CallsManagerListenerBase {
-    private static final String SCHEME_SMSTO = "smsto";
-
-    /** SharedPreferences file name for our persistent settings. */
-    private static final String SHARED_PREFERENCES_NAME = "respond_via_sms_prefs";
-
-    // 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.
-    private static final int NUM_CANNED_RESPONSES = 4;
-    private static final String KEY_CANNED_RESPONSE_PREF_1 = "canned_response_pref_1";
-    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";
-
     private static final int MSG_CANNED_TEXT_MESSAGES_READY = 1;
     private static final int MSG_SHOW_SENT_TOAST = 2;
 
@@ -104,22 +89,28 @@
             @Override
             public void run() {
                 Log.d(RespondViaSmsManager.this, "loadCannedResponses() starting");
+
+                // This function guarantees that QuickResponses will be in our
+                // SharedPreferences with the proper values considering there may be
+                // old QuickResponses in Telephony pre L.
+                QuickResponseUtils.maybeMigrateLegacyQuickResponses();
+
                 final SharedPreferences prefs = TelecommApp.getInstance().getSharedPreferences(
-                        SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+                        QuickResponseUtils.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
                 final Resources res = TelecommApp.getInstance().getInstance().getResources();
 
-                final ArrayList<String> textMessages = new ArrayList<>(NUM_CANNED_RESPONSES);
+                final ArrayList<String> textMessages = new ArrayList<>(
+                        QuickResponseUtils.NUM_CANNED_RESPONSES);
 
                 // Note the default values here must agree with the corresponding
                 // android:defaultValue attributes in respond_via_sms_settings.xml.
-
-                textMessages.add(0, prefs.getString(KEY_CANNED_RESPONSE_PREF_1,
+                textMessages.add(0, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1,
                         res.getString(R.string.respond_via_sms_canned_response_1)));
-                textMessages.add(1, prefs.getString(KEY_CANNED_RESPONSE_PREF_2,
+                textMessages.add(1, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2,
                         res.getString(R.string.respond_via_sms_canned_response_2)));
-                textMessages.add(2, prefs.getString(KEY_CANNED_RESPONSE_PREF_3,
+                textMessages.add(2, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3,
                         res.getString(R.string.respond_via_sms_canned_response_3)));
-                textMessages.add(3, prefs.getString(KEY_CANNED_RESPONSE_PREF_4,
+                textMessages.add(3, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4,
                         res.getString(R.string.respond_via_sms_canned_response_4)));
 
                 Log.d(RespondViaSmsManager.this,
@@ -177,7 +168,7 @@
                             TelecommApp.getInstance(), true /*updateIfNeeded*/);
             if (component != null) {
                 // Build and send the intent
-                final Uri uri = Uri.fromParts(SCHEME_SMSTO, phoneNumber, null);
+                final Uri uri = Uri.fromParts(Constants.SCHEME_SMSTO, phoneNumber, null);
                 final Intent intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, uri);
                 intent.putExtra(Intent.EXTRA_TEXT, textMessage);
                 mHandler.obtainMessage(MSG_SHOW_SENT_TOAST, phoneNumber).sendToTarget();
diff --git a/src/com/android/telecomm/RespondViaSmsSettings.java b/src/com/android/telecomm/RespondViaSmsSettings.java
index 231dbaa..ecca39c 100644
--- a/src/com/android/telecomm/RespondViaSmsSettings.java
+++ b/src/com/android/telecomm/RespondViaSmsSettings.java
@@ -19,9 +19,7 @@
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.preference.EditTextPreference;
 import android.preference.Preference;
@@ -33,18 +31,6 @@
  * Helper class to manage the "Respond via SMS Message" feature for incoming calls.
  */
 public class RespondViaSmsSettings {
-    /** SharedPreferences file name for our persistent settings. */
-    private static final String SHARED_PREFERENCES_NAME = "respond_via_sms_prefs";
-
-    // 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.
-    private static final int NUM_CANNED_RESPONSES = 4;
-    private static final String KEY_CANNED_RESPONSE_PREF_1 = "canned_response_pref_1";
-    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";
     private static final String KEY_PREFERRED_PACKAGE = "preferred_package_pref";
     private static final String KEY_INSTANT_TEXT_DEFAULT_COMPONENT = "instant_text_def_component";
 
@@ -63,7 +49,13 @@
             super.onCreate(icicle);
             Log.d(this, "Settings: onCreate()...");
 
-            getPreferenceManager().setSharedPreferencesName(SHARED_PREFERENCES_NAME);
+            // This function guarantees that QuickResponses will be in our
+            // SharedPreferences with the proper values considering there may be
+            // old QuickResponses in Telephony pre L.
+            QuickResponseUtils.maybeMigrateLegacyQuickResponses();
+
+            getPreferenceManager().setSharedPreferencesName(
+                    QuickResponseUtils.SHARED_PREFERENCES_NAME);
 
             // This preference screen is ultra-simple; it's just 4 plain
             // <EditTextPreference>s, one for each of the 4 "canned responses".
@@ -79,19 +71,23 @@
             addPreferencesFromResource(R.xml.respond_via_sms_settings);
 
             EditTextPreference pref;
-            pref = (EditTextPreference) findPreference(KEY_CANNED_RESPONSE_PREF_1);
+            pref = (EditTextPreference) findPreference(
+                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1);
             pref.setTitle(pref.getText());
             pref.setOnPreferenceChangeListener(this);
 
-            pref = (EditTextPreference) findPreference(KEY_CANNED_RESPONSE_PREF_2);
+            pref = (EditTextPreference) findPreference(
+                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2);
             pref.setTitle(pref.getText());
             pref.setOnPreferenceChangeListener(this);
 
-            pref = (EditTextPreference) findPreference(KEY_CANNED_RESPONSE_PREF_3);
+            pref = (EditTextPreference) findPreference(
+                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3);
             pref.setTitle(pref.getText());
             pref.setOnPreferenceChangeListener(this);
 
-            pref = (EditTextPreference) findPreference(KEY_CANNED_RESPONSE_PREF_4);
+            pref = (EditTextPreference) findPreference(
+                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4);
             pref.setTitle(pref.getText());
             pref.setOnPreferenceChangeListener(this);
 
@@ -130,7 +126,7 @@
                 case R.id.respond_via_message_reset:
                     // Reset the preferences settings
                     SharedPreferences prefs = getSharedPreferences(
-                            SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+                            QuickResponseUtils.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
                     SharedPreferences.Editor editor = prefs.edit();
                     editor.remove(KEY_INSTANT_TEXT_DEFAULT_COMPONENT);
                     editor.apply();
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 8ae47d2..47ce802 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -60,6 +60,11 @@
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.telecomm.testapps.ACTION_START_INCOMING_CALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="tel" />
+            </intent-filter>
         </activity>
 
         <receiver android:name="com.android.telecomm.testapps.CallNotificationReceiver"
diff --git a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
index fb44069..5b49434 100644
--- a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
+++ b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.telecomm.PhoneAccountHandle;
 import android.telecomm.TelecommManager;
@@ -55,19 +56,19 @@
         } else if (ACTION_SHOW_ALL_PHONE_ACCOUNTS.equals(action)) {
             CallServiceNotifier.getInstance().showAllPhoneAccounts(context);
         } else if (ACTION_VIDEO_CALL.equals(action)) {
-            sendIncomingCallIntent(context, true);
+            sendIncomingCallIntent(context, null, true);
         } else if (ACTION_AUDIO_CALL.equals(action)) {
-            sendIncomingCallIntent(context, false);
+            sendIncomingCallIntent(context, null, false);
         }
     }
 
     /**
-     * Creates the intent to add an incoming call through Telecomm.
+     * Creates and sends the intent to add an incoming call through Telecomm.
      *
      * @param context The current context.
      * @param isVideoCall {@code True} if this is a video call.
      */
-    private void sendIncomingCallIntent(Context context, boolean isVideoCall) {
+    public static void sendIncomingCallIntent(Context context, Uri handle, boolean isVideoCall) {
         PhoneAccountHandle phoneAccount = new PhoneAccountHandle(
                 new ComponentName(context, TestConnectionService.class),
                 CallServiceNotifier.SIM_SUBSCRIPTION_ID);
@@ -75,7 +76,10 @@
         // For the purposes of testing, indicate whether the incoming call is a video call by
         // stashing an indicator in the EXTRA_INCOMING_CALL_EXTRAS.
         Bundle extras = new Bundle();
-        extras.putBoolean(TestConnectionService.IS_VIDEO_CALL, isVideoCall);
+        extras.putBoolean(TestConnectionService.EXTRA_IS_VIDEO_CALL, isVideoCall);
+        if (handle != null) {
+            extras.putParcelable(TestConnectionService.EXTRA_HANDLE, handle);
+        }
 
         TelecommManager.from(context).addNewIncomingCall(phoneAccount, extras);
     }
diff --git a/tests/src/com/android/telecomm/testapps/TestCallActivity.java b/tests/src/com/android/telecomm/testapps/TestCallActivity.java
index b85888d..4caf3e8 100644
--- a/tests/src/com/android/telecomm/testapps/TestCallActivity.java
+++ b/tests/src/com/android/telecomm/testapps/TestCallActivity.java
@@ -17,21 +17,41 @@
 package com.android.telecomm.testapps;
 
 import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
+import android.util.Log;
 
 /**
  * This activity exists in order to add an icon to the launcher. This activity has no UI of its own
  * and instead starts the notification for {@link TestConnectionService} via
  * {@link CallServiceNotifier}. After triggering a notification update, this activity immediately
  * finishes.
+ *
+ * To directly trigger a new incoming call, use the following adb command:
+ *
+ * adb shell am start -a android.telecomm.testapps.ACTION_START_INCOMING_CALL -d "tel:123456789"
  */
 public class TestCallActivity extends Activity {
 
+    public static final String ACTION_NEW_INCOMING_CALL =
+            "android.telecomm.testapps.ACTION_START_INCOMING_CALL";
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-
+        final Intent intent = getIntent();
+        if (intent != null && intent.getData() != null) {
+            startIncomingCallBroadcast(intent.getData());
+        }
         CallServiceNotifier.getInstance().updateNotification(this);
         finish();
     }
+
+    /**
+     * Bypass the notification and start the test incoming call directly.
+     */
+    private void startIncomingCallBroadcast(Uri handle) {
+        CallNotificationReceiver.sendIncomingCallIntent(this, handle, false);
+    }
 }
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index c50e7ab..e5d54e9 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
Binary files differ