Use sendMultipartTextMessage for respond with sms
Long messages won't send properly if used in the respond-with-sms API.
Use sendMultipartTextMessage to get around this. Also display an error
toast if the message didn't send properly.
Bug: 65087120
Test: manual
Change-Id: I31ba24a0600e42010752b1216b1aca7d1098b319
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9202e74..b17c6f3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -21,6 +21,8 @@
android:sharedUserId="android.uid.system">
<protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT" />
+
<!-- Prevents the activity manager from delaying any activity-start
requests by this package, including requests immediately after
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8c29a21..9065173 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -79,6 +79,10 @@
a text response. [CHAR LIMIT=40] -->
<string name="respond_via_sms_confirmation_format">Message sent to <xliff:g id="phone_number">%s</xliff:g>.</string>
+ <!-- "Respond via SMS": Error toast shown after failing to send
+ a text response. [CHAR LIMIT=40] -->
+ <string name="respond_via_sms_failure_format">Message failed to send to <xliff:g id="phone_number">%s</xliff:g>.</string>
+
<!-- Title of settings screen that allows user to enable and disable phone-accounts.
Each method for placing a call (SIM1, SIM2, SIP account, etc) has a phone-account.
Phone-accounts that are created by third party apps can be disabled and enabled by user.
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index fadc6b5..4c13222 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -18,10 +18,14 @@
// TODO: Needed for move to system service: import com.android.internal.R;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telephony.SmsApplication;
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Handler;
@@ -45,30 +49,37 @@
* Helper class to manage the "Respond via Message" feature for incoming calls.
*/
public class RespondViaSmsManager extends CallsManagerListenerBase {
- private static final int MSG_SHOW_SENT_TOAST = 2;
+ private static final String ACTION_MESSAGE_SENT = "com.android.server.telecom.MESSAGE_SENT";
+
+ private static final class MessageSentReceiver extends BroadcastReceiver {
+ private final String mContactName;
+ private final int mNumMessageParts;
+ private int mNumMessagesSent = 0;
+ MessageSentReceiver(String contactName, int numMessageParts) {
+ mContactName = contactName;
+ mNumMessageParts = numMessageParts;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() == Activity.RESULT_OK) {
+ mNumMessagesSent++;
+ if (mNumMessagesSent == mNumMessageParts) {
+ showMessageResultToast(mContactName, context, true);
+ context.unregisterReceiver(this);
+ }
+ } else {
+ context.unregisterReceiver(this);
+ showMessageResultToast(mContactName, context, false);
+ Log.w(RespondViaSmsManager.class.getSimpleName(),
+ "Message failed with error %s", getResultCode());
+ }
+ }
+ }
private final CallsManager mCallsManager;
private final TelecomSystem.SyncRoot mLock;
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SHOW_SENT_TOAST: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- String toastMessage = (String) args.arg1;
- Context context = (Context) args.arg2;
- showMessageSentToast(toastMessage, context);
- } finally {
- args.recycle();
- }
- break;
- }
- }
- }
- };
-
public RespondViaSmsManager(CallsManager callsManager, TelecomSystem.SyncRoot lock) {
mCallsManager = callsManager;
mLock = lock;
@@ -144,13 +155,15 @@
}
}
- private void showMessageSentToast(final String phoneNumber, final Context context) {
+ private static void showMessageResultToast(final String phoneNumber,
+ final Context context, boolean success) {
// ...and show a brief confirmation to the user (since
// otherwise it's hard to be sure that anything actually
// happened.)
final Resources res = context.getResources();
- final String formatString = res.getString(
- R.string.respond_via_sms_confirmation_format);
+ final String formatString = res.getString(success
+ ? R.string.respond_via_sms_confirmation_format
+ : R.string.respond_via_sms_failure_format);
final String confirmationMsg = String.format(formatString, phoneNumber);
int startingPosition = confirmationMsg.indexOf(phoneNumber);
int endingPosition = startingPosition + phoneNumber.length();
@@ -192,13 +205,20 @@
SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
try {
- smsManager.sendTextMessage(phoneNumber, null, textMessage, null /*sentIntent*/,
- null /*deliveryIntent*/);
-
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = !TextUtils.isEmpty(contactName) ? contactName : phoneNumber;
- args.arg2 = context;
- mHandler.obtainMessage(MSG_SHOW_SENT_TOAST, args).sendToTarget();
+ ArrayList<String> messageParts = smsManager.divideMessage(textMessage);
+ ArrayList<PendingIntent> sentIntents = new ArrayList<>(messageParts.size());
+ for (int i = 0; i < messageParts.size(); i++) {
+ Intent intent = new Intent(ACTION_MESSAGE_SENT);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, i, intent,
+ PendingIntent.FLAG_ONE_SHOT);
+ sentIntents.add(pendingIntent);
+ }
+ MessageSentReceiver receiver = new MessageSentReceiver(
+ !TextUtils.isEmpty(contactName) ? contactName : phoneNumber,
+ messageParts.size());
+ context.registerReceiver(receiver, new IntentFilter(ACTION_MESSAGE_SENT));
+ smsManager.sendMultipartTextMessage(phoneNumber, null, messageParts,
+ sentIntents/*sentIntent*/, null /*deliveryIntent*/);
} catch (IllegalArgumentException e) {
Log.w(RespondViaSmsManager.this, "Couldn't send SMS message: " +
e.getMessage());