blob: 964f6ad4b4b0a4a1745b3f525b21566d58526792 [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
Tyler Gunn7cc70b42014-09-12 22:17:27 -070017package com.android.server.telecom;
Ihab Awadff7493a2014-06-10 13:47:44 -070018
Tyler Gunn91d43cf2014-09-17 12:19:39 -070019// TODO: Needed for move to system service: import com.android.internal.R;
Ihab Awadff7493a2014-06-10 13:47:44 -070020import com.android.internal.os.SomeArgs;
21import com.android.internal.telephony.SmsApplication;
22
23import android.content.ComponentName;
24import android.content.Context;
Ihab Awadff7493a2014-06-10 13:47:44 -070025import android.content.SharedPreferences;
26import android.content.res.Resources;
Ihab Awadff7493a2014-06-10 13:47:44 -070027import android.os.Handler;
Ihab Awade6dbc9d2015-03-26 10:33:44 -070028import android.os.Looper;
Ihab Awadff7493a2014-06-10 13:47:44 -070029import android.os.Message;
Bryce Lee45e8eb42016-07-27 16:57:21 -070030import android.telecom.Connection;
Brad Ebinger953e1af2016-10-05 15:45:22 -070031import android.telecom.Log;
Tyler Gunn7cc70b42014-09-12 22:17:27 -070032import android.telecom.Response;
Hall Liuab914a92016-03-21 15:06:51 -070033import android.telephony.PhoneNumberUtils;
Brad Ebinger21241162017-05-25 15:35:20 -070034import android.telephony.SmsManager;
Nancy Chen6ae4c992014-11-06 12:54:39 -080035import android.telephony.SubscriptionManager;
Hall Liuab914a92016-03-21 15:06:51 -070036import android.text.Spannable;
37import android.text.SpannableString;
Srikanth Chintala3802dab2017-03-03 18:29:04 +053038import android.text.TextUtils;
Ihab Awadff7493a2014-06-10 13:47:44 -070039import android.widget.Toast;
40
41import java.util.ArrayList;
42import java.util.List;
43
44/**
45 * Helper class to manage the "Respond via Message" feature for incoming calls.
46 */
47public class RespondViaSmsManager extends CallsManagerListenerBase {
Ihab Awadff7493a2014-06-10 13:47:44 -070048 private static final int MSG_SHOW_SENT_TOAST = 2;
49
Ihab Awad8de76912015-02-17 12:25:52 -080050 private final CallsManager mCallsManager;
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070051 private final TelecomSystem.SyncRoot mLock;
Ihab Awad8de76912015-02-17 12:25:52 -080052
Ihab Awade6dbc9d2015-03-26 10:33:44 -070053 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
Ihab Awadff7493a2014-06-10 13:47:44 -070054 @Override
55 public void handleMessage(Message msg) {
56 switch (msg.what) {
Tyler Gunn91d43cf2014-09-17 12:19:39 -070057 case MSG_SHOW_SENT_TOAST: {
58 SomeArgs args = (SomeArgs) msg.obj;
59 try {
60 String toastMessage = (String) args.arg1;
61 Context context = (Context) args.arg2;
62 showMessageSentToast(toastMessage, context);
63 } finally {
64 args.recycle();
65 }
Ihab Awadff7493a2014-06-10 13:47:44 -070066 break;
Tyler Gunn91d43cf2014-09-17 12:19:39 -070067 }
Ihab Awadff7493a2014-06-10 13:47:44 -070068 }
69 }
70 };
71
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070072 public RespondViaSmsManager(CallsManager callsManager, TelecomSystem.SyncRoot lock) {
Ihab Awad8de76912015-02-17 12:25:52 -080073 mCallsManager = callsManager;
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070074 mLock = lock;
Ihab Awad8de76912015-02-17 12:25:52 -080075 }
Ihab Awadff7493a2014-06-10 13:47:44 -070076
77 /**
78 * Read the (customizable) canned responses from SharedPreferences,
79 * or from defaults if the user has never actually brought up
80 * the Settings UI.
81 *
82 * The interface of this method is asynchronous since it does disk I/O.
83 *
84 * @param response An object to receive an async reply, which will be called from
85 * the main thread.
Tyler Gunn91d43cf2014-09-17 12:19:39 -070086 * @param context The context.
Ihab Awadff7493a2014-06-10 13:47:44 -070087 */
Tyler Gunn91d43cf2014-09-17 12:19:39 -070088 public void loadCannedTextMessages(final Response<Void, List<String>> response,
89 final Context context) {
Ihab Awadff7493a2014-06-10 13:47:44 -070090 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.
Tyler Gunn91d43cf2014-09-17 12:19:39 -070098 QuickResponseUtils.maybeMigrateLegacyQuickResponses(context);
Anthony Leec67cd752014-09-02 23:43:44 -070099
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700100 final SharedPreferences prefs = context.getSharedPreferences(
Santos Cordon4ba27e92014-12-22 15:40:38 -0800101 QuickResponseUtils.SHARED_PREFERENCES_NAME,
102 Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700103 final Resources res = context.getResources();
Ihab Awadff7493a2014-06-10 13:47:44 -0700104
Anthony Leec67cd752014-09-02 23:43:44 -0700105 final ArrayList<String> textMessages = new ArrayList<>(
106 QuickResponseUtils.NUM_CANNED_RESPONSES);
Ihab Awadff7493a2014-06-10 13:47:44 -0700107
108 // Note the default values here must agree with the corresponding
109 // android:defaultValue attributes in respond_via_sms_settings.xml.
Anthony Leec67cd752014-09-02 23:43:44 -0700110 textMessages.add(0, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1,
Ihab Awadff7493a2014-06-10 13:47:44 -0700111 res.getString(R.string.respond_via_sms_canned_response_1)));
Anthony Leec67cd752014-09-02 23:43:44 -0700112 textMessages.add(1, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2,
Ihab Awadff7493a2014-06-10 13:47:44 -0700113 res.getString(R.string.respond_via_sms_canned_response_2)));
Anthony Leec67cd752014-09-02 23:43:44 -0700114 textMessages.add(2, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3,
Ihab Awadff7493a2014-06-10 13:47:44 -0700115 res.getString(R.string.respond_via_sms_canned_response_3)));
Anthony Leec67cd752014-09-02 23:43:44 -0700116 textMessages.add(3, prefs.getString(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4,
Ihab Awadff7493a2014-06-10 13:47:44 -0700117 res.getString(R.string.respond_via_sms_canned_response_4)));
118
119 Log.d(RespondViaSmsManager.this,
120 "loadCannedResponses() completed, found responses: %s",
121 textMessages.toString());
122
Ihab Awad8d5d9dd2015-03-12 11:11:06 -0700123 synchronized (mLock) {
124 response.onResult(null, textMessages);
125 }
Ihab Awadff7493a2014-06-10 13:47:44 -0700126 }
127 }.start();
128 }
129
130 @Override
131 public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
Bryce Leeddd966e2015-08-28 16:33:50 -0700132 if (rejectWithMessage
133 && call.getHandle() != null
Bryce Lee45e8eb42016-07-27 16:57:21 -0700134 && !call.can(Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
Ihab Awad8de76912015-02-17 12:25:52 -0800135 int subId = mCallsManager.getPhoneAccountRegistrar().getSubscriptionIdForPhoneAccount(
Nancy Chen6ae4c992014-11-06 12:54:39 -0800136 call.getTargetPhoneAccount());
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700137 rejectCallWithMessage(call.getContext(), call.getHandle().getSchemeSpecificPart(),
Srikanth Chintala3802dab2017-03-03 18:29:04 +0530138 textMessage, subId, call.getName());
Ihab Awadff7493a2014-06-10 13:47:44 -0700139 }
140 }
141
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700142 private void showMessageSentToast(final String phoneNumber, final Context context) {
Ihab Awadff7493a2014-06-10 13:47:44 -0700143 // ...and show a brief confirmation to the user (since
144 // otherwise it's hard to be sure that anything actually
145 // happened.)
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700146 final Resources res = context.getResources();
Ihab Awadff7493a2014-06-10 13:47:44 -0700147 final String formatString = res.getString(
148 R.string.respond_via_sms_confirmation_format);
149 final String confirmationMsg = String.format(formatString, phoneNumber);
Hall Liuab914a92016-03-21 15:06:51 -0700150 int startingPosition = confirmationMsg.indexOf(phoneNumber);
151 int endingPosition = startingPosition + phoneNumber.length();
152
153 Spannable styledConfirmationMsg = new SpannableString(confirmationMsg);
154 PhoneNumberUtils.addTtsSpan(styledConfirmationMsg, startingPosition, endingPosition);
155 Toast.makeText(context, styledConfirmationMsg,
Ihab Awadff7493a2014-06-10 13:47:44 -0700156 Toast.LENGTH_LONG).show();
157
158 // TODO: If the device is locked, this toast won't actually ever
159 // be visible! (That's because we're about to dismiss the call
160 // screen, which means that the device will return to the
161 // keyguard. But toasts aren't visible on top of the keyguard.)
162 // Possible fixes:
163 // (1) Is it possible to allow a specific Toast to be visible
164 // on top of the keyguard?
165 // (2) Artificially delay the dismissCallScreen() call by 3
166 // seconds to allow the toast to be seen?
167 // (3) Don't use a toast at all; instead use a transient state
168 // of the InCallScreen (perhaps via the InCallUiState
169 // progressIndication feature), and have that state be
170 // visible for 3 seconds before calling dismissCallScreen().
171 }
172
173 /**
174 * Reject the call with the specified message. If message is null this call is ignored.
175 */
Nancy Chen6ae4c992014-11-06 12:54:39 -0800176 private void rejectCallWithMessage(Context context, String phoneNumber, String textMessage,
Srikanth Chintala3802dab2017-03-03 18:29:04 +0530177 int subId, String contactName) {
Brad Ebinger21241162017-05-25 15:35:20 -0700178 if (TextUtils.isEmpty(textMessage)) {
179 Log.w(RespondViaSmsManager.this, "Couldn't send SMS message: empty text message. ");
180 return;
181 }
182 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
183 Log.w(RespondViaSmsManager.this, "Couldn't send SMS message: Invalid SubId: " +
184 subId);
185 return;
186 }
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700187
Brad Ebinger21241162017-05-25 15:35:20 -0700188 SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
189 try {
190 smsManager.sendTextMessage(phoneNumber, null, textMessage, null /*sentIntent*/,
191 null /*deliveryIntent*/);
192
193 SomeArgs args = SomeArgs.obtain();
194 args.arg1 = !TextUtils.isEmpty(contactName) ? contactName : phoneNumber;
195 args.arg2 = context;
196 mHandler.obtainMessage(MSG_SHOW_SENT_TOAST, args).sendToTarget();
197 } catch (IllegalArgumentException e) {
198 Log.w(RespondViaSmsManager.this, "Couldn't send SMS message: " +
199 e.getMessage());
Ihab Awadff7493a2014-06-10 13:47:44 -0700200 }
201 }
202}