blob: f1e60335318f2d0e76d8cc107e9d8e04d6e9aeaf [file] [log] [blame]
Ihab Awadff7493a2014-06-10 13:47:44 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.telecomm;
18
19import com.android.internal.os.SomeArgs;
20import com.android.internal.telephony.SmsApplication;
21
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.SharedPreferences;
26import android.content.res.Resources;
27import android.net.Uri;
28import android.os.Handler;
29import android.os.Message;
30import android.telecomm.Response;
31import android.telephony.TelephonyManager;
32import android.widget.Toast;
33
34import java.util.ArrayList;
35import java.util.List;
36
37/**
38 * Helper class to manage the "Respond via Message" feature for incoming calls.
39 */
40public class RespondViaSmsManager extends CallsManagerListenerBase {
41 private static final String SCHEME_SMSTO = "smsto";
42
Ihab Awadff7493a2014-06-10 13:47:44 -070043 private static final int MSG_CANNED_TEXT_MESSAGES_READY = 1;
44 private static final int MSG_SHOW_SENT_TOAST = 2;
45
46 private static final RespondViaSmsManager sInstance = new RespondViaSmsManager();
47
48 private final Handler mHandler = new Handler() {
49 @Override
50 public void handleMessage(Message msg) {
51 switch (msg.what) {
52 case MSG_CANNED_TEXT_MESSAGES_READY:
53 SomeArgs args = (SomeArgs) msg.obj;
54 try {
55 Response<Void, List<String>> response =
56 (Response<Void, List<String>>) args.arg1;
57 List<String> textMessages =
58 (List<String>) args.arg2;
59 if (textMessages != null) {
60 response.onResult(null, textMessages);
61 } else {
62 response.onError(null, 0, null);
63 }
64 } finally {
65 args.recycle();
66 }
67 break;
68 case MSG_SHOW_SENT_TOAST:
69 showMessageSentToast((String) msg.obj);
70 break;
71 }
72 }
73 };
74
75 public static RespondViaSmsManager getInstance() { return sInstance; }
76
77 private RespondViaSmsManager() {}
78
79 /**
80 * Read the (customizable) canned responses from SharedPreferences,
81 * or from defaults if the user has never actually brought up
82 * the Settings UI.
83 *
84 * The interface of this method is asynchronous since it does disk I/O.
85 *
86 * @param response An object to receive an async reply, which will be called from
87 * the main thread.
88 */
89 public void loadCannedTextMessages(final Response<Void, List<String>> response) {
90 new Thread() {
91 @Override
92 public void run() {
93 Log.d(RespondViaSmsManager.this, "loadCannedResponses() starting");
Anthony Leec67cd752014-09-02 23:43:44 -070094
95 // This function guarantees that QuickResponses will be in our
96 // SharedPreferences with the proper values considering there may be
97 // old QuickResponses in Telephony pre L.
98 QuickResponseUtils.maybeMigrateLegacyQuickResponses();
99
Ihab Awadff7493a2014-06-10 13:47:44 -0700100 final SharedPreferences prefs = TelecommApp.getInstance().getSharedPreferences(
Anthony Leec67cd752014-09-02 23:43:44 -0700101 QuickResponseUtils.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
Ihab Awadff7493a2014-06-10 13:47:44 -0700102 final Resources res = TelecommApp.getInstance().getInstance().getResources();
103
Anthony Leec67cd752014-09-02 23:43:44 -0700104 final ArrayList<String> textMessages = new ArrayList<>(
105 QuickResponseUtils.NUM_CANNED_RESPONSES);
Ihab Awadff7493a2014-06-10 13:47:44 -0700106
107 // Note the default values here must agree with the corresponding
108 // android:defaultValue attributes in respond_via_sms_settings.xml.
Anthony Leec67cd752014-09-02 23:43:44 -0700109 textMessages.add(0, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1,
Ihab Awadff7493a2014-06-10 13:47:44 -0700110 res.getString(R.string.respond_via_sms_canned_response_1)));
Anthony Leec67cd752014-09-02 23:43:44 -0700111 textMessages.add(1, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2,
Ihab Awadff7493a2014-06-10 13:47:44 -0700112 res.getString(R.string.respond_via_sms_canned_response_2)));
Anthony Leec67cd752014-09-02 23:43:44 -0700113 textMessages.add(2, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3,
Ihab Awadff7493a2014-06-10 13:47:44 -0700114 res.getString(R.string.respond_via_sms_canned_response_3)));
Anthony Leec67cd752014-09-02 23:43:44 -0700115 textMessages.add(3, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4,
Ihab Awadff7493a2014-06-10 13:47:44 -0700116 res.getString(R.string.respond_via_sms_canned_response_4)));
117
118 Log.d(RespondViaSmsManager.this,
119 "loadCannedResponses() completed, found responses: %s",
120 textMessages.toString());
121
122 SomeArgs args = SomeArgs.obtain();
123 args.arg1 = response;
124 args.arg2 = textMessages;
125 mHandler.obtainMessage(MSG_CANNED_TEXT_MESSAGES_READY, args).sendToTarget();
126 }
127 }.start();
128 }
129
130 @Override
131 public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
132 if (rejectWithMessage) {
133 rejectCallWithMessage(call.getHandle().getSchemeSpecificPart(), textMessage);
134 }
135 }
136
137 private void showMessageSentToast(final String phoneNumber) {
138 // ...and show a brief confirmation to the user (since
139 // otherwise it's hard to be sure that anything actually
140 // happened.)
141 final Resources res = TelecommApp.getInstance().getResources();
142 final String formatString = res.getString(
143 R.string.respond_via_sms_confirmation_format);
144 final String confirmationMsg = String.format(formatString, phoneNumber);
145 Toast.makeText(TelecommApp.getInstance(), confirmationMsg,
146 Toast.LENGTH_LONG).show();
147
148 // TODO: If the device is locked, this toast won't actually ever
149 // be visible! (That's because we're about to dismiss the call
150 // screen, which means that the device will return to the
151 // keyguard. But toasts aren't visible on top of the keyguard.)
152 // Possible fixes:
153 // (1) Is it possible to allow a specific Toast to be visible
154 // on top of the keyguard?
155 // (2) Artificially delay the dismissCallScreen() call by 3
156 // seconds to allow the toast to be seen?
157 // (3) Don't use a toast at all; instead use a transient state
158 // of the InCallScreen (perhaps via the InCallUiState
159 // progressIndication feature), and have that state be
160 // visible for 3 seconds before calling dismissCallScreen().
161 }
162
163 /**
164 * Reject the call with the specified message. If message is null this call is ignored.
165 */
166 private void rejectCallWithMessage(String phoneNumber, String textMessage) {
167 if (textMessage != null) {
168 final ComponentName component =
169 SmsApplication.getDefaultRespondViaMessageApplication(
170 TelecommApp.getInstance(), true /*updateIfNeeded*/);
171 if (component != null) {
172 // Build and send the intent
173 final Uri uri = Uri.fromParts(SCHEME_SMSTO, phoneNumber, null);
174 final Intent intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, uri);
175 intent.putExtra(Intent.EXTRA_TEXT, textMessage);
176 mHandler.obtainMessage(MSG_SHOW_SENT_TOAST, phoneNumber).sendToTarget();
177 intent.setComponent(component);
178 TelecommApp.getInstance().startService(intent);
179 }
180 }
181 }
182}