DO NOT MERGE. Port "respond via SMS message" feature to new Telecomm. (2/4)
Bug: 15275904
Bug: 15196474
Change-Id: I3e2ee62b3e32ad5715457fee1b0e714f88ecea8e
diff --git a/src/com/android/telecomm/RespondViaSmsManager.java b/src/com/android/telecomm/RespondViaSmsManager.java
new file mode 100644
index 0000000..bf1a2a5
--- /dev/null
+++ b/src/com/android/telecomm/RespondViaSmsManager.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.os.SomeArgs;
+import com.android.internal.telephony.SmsApplication;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.telecomm.Response;
+import android.telephony.TelephonyManager;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 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;
+
+ private static final RespondViaSmsManager sInstance = new RespondViaSmsManager();
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CANNED_TEXT_MESSAGES_READY:
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Response<Void, List<String>> response =
+ (Response<Void, List<String>>) args.arg1;
+ List<String> textMessages =
+ (List<String>) args.arg2;
+ if (textMessages != null) {
+ response.onResult(null, textMessages);
+ } else {
+ response.onError(null, 0, null);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ case MSG_SHOW_SENT_TOAST:
+ showMessageSentToast((String) msg.obj);
+ break;
+ }
+ }
+ };
+
+ public static RespondViaSmsManager getInstance() { return sInstance; }
+
+ private RespondViaSmsManager() {}
+
+ /**
+ * Read the (customizable) canned responses from SharedPreferences,
+ * or from defaults if the user has never actually brought up
+ * the Settings UI.
+ *
+ * The interface of this method is asynchronous since it does disk I/O.
+ *
+ * @param response An object to receive an async reply, which will be called from
+ * the main thread.
+ */
+ public void loadCannedTextMessages(final Response<Void, List<String>> response) {
+ new Thread() {
+ @Override
+ public void run() {
+ Log.d(RespondViaSmsManager.this, "loadCannedResponses() starting");
+ final SharedPreferences prefs = TelecommApp.getInstance().getSharedPreferences(
+ SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+ final Resources res = TelecommApp.getInstance().getInstance().getResources();
+
+ final ArrayList<String> textMessages = new ArrayList<String>(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,
+ res.getString(R.string.respond_via_sms_canned_response_1)));
+ textMessages.add(1, prefs.getString(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,
+ res.getString(R.string.respond_via_sms_canned_response_3)));
+ textMessages.add(3, prefs.getString(KEY_CANNED_RESPONSE_PREF_4,
+ res.getString(R.string.respond_via_sms_canned_response_4)));
+
+ Log.d(RespondViaSmsManager.this,
+ "loadCannedResponses() completed, found responses: %s",
+ textMessages.toString());
+
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = response;
+ args.arg2 = textMessages;
+ mHandler.obtainMessage(MSG_CANNED_TEXT_MESSAGES_READY, args).sendToTarget();
+ }
+ }.start();
+ }
+
+ @Override
+ public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
+ if (rejectWithMessage) {
+ rejectCallWithMessage(call.getHandle().getSchemeSpecificPart(), textMessage);
+ }
+ }
+
+ private 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.)
+ final Resources res = TelecommApp.getInstance().getResources();
+ final String formatString = res.getString(
+ R.string.respond_via_sms_confirmation_format);
+ final String confirmationMsg = String.format(formatString, phoneNumber);
+ Toast.makeText(TelecommApp.getInstance(), confirmationMsg,
+ Toast.LENGTH_LONG).show();
+
+ // TODO: If the device is locked, this toast won't actually ever
+ // be visible! (That's because we're about to dismiss the call
+ // screen, which means that the device will return to the
+ // keyguard. But toasts aren't visible on top of the keyguard.)
+ // Possible fixes:
+ // (1) Is it possible to allow a specific Toast to be visible
+ // on top of the keyguard?
+ // (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
+ // progressIndication feature), and have that state be
+ // visible for 3 seconds before calling dismissCallScreen().
+ }
+
+ /**
+ * Reject the call with the specified message. If message is null this call is ignored.
+ */
+ private void rejectCallWithMessage(String phoneNumber, String textMessage) {
+ if (textMessage != null) {
+ final ComponentName component =
+ SmsApplication.getDefaultRespondViaMessageApplication(
+ TelecommApp.getInstance(), true /*updateIfNeeded*/);
+ if (component != null) {
+ // Build and send the intent
+ final Uri uri = Uri.fromParts(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();
+ intent.setComponent(component);
+ TelecommApp.getInstance().startService(intent);
+ }
+ }
+ }
+}