• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 
17 package com.android.server.telecom;
18 
19 import android.app.BroadcastOptions;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.PackageManager;
23 import android.content.pm.ResolveInfo;
24 import android.os.Bundle;
25 import android.os.UserHandle;
26 import android.telecom.Log;
27 import android.widget.Toast;
28 
29 import com.android.server.telecom.ui.ConfirmCallDialogActivity;
30 import com.android.server.telecom.ui.DisconnectedCallNotifier;
31 
32 import java.util.List;
33 
34 public final class TelecomBroadcastIntentProcessor {
35     /** The action used to send SMS response for the missed call notification. */
36     public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
37             "com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION";
38 
39     /** The action used to call a handle back for the missed call notification. */
40     public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
41             "com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION";
42 
43     /** The action used to send SMS response for the disconnected call notification. */
44     public static final String ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION =
45             "com.android.server.telecom.ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION";
46 
47     /** The action used to call a handle back for the disconnected call notification. */
48     public static final String ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION =
49             "com.android.server.telecom.ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION";
50 
51     /** The action used to clear missed calls. */
52     public static final String ACTION_CLEAR_MISSED_CALLS =
53             "com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS";
54 
55     /**
56      * The action used to answer the current incoming call displayed by
57      * {@link com.android.server.telecom.ui.IncomingCallNotifier}.
58      */
59     public static final String ACTION_ANSWER_FROM_NOTIFICATION =
60             "com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION";
61 
62     /**
63      * The action used to reject the current incoming call displayed by
64      * {@link com.android.server.telecom.ui.IncomingCallNotifier}.
65      */
66     public static final String ACTION_REJECT_FROM_NOTIFICATION =
67             "com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION";
68 
69     /**
70      * The action used to proceed with a call being confirmed via
71      * {@link com.android.server.telecom.ui.ConfirmCallDialogActivity}.
72      */
73     public static final String ACTION_PROCEED_WITH_CALL =
74             "com.android.server.telecom.PROCEED_WITH_CALL";
75 
76     /**
77      * The action used to cancel a call being confirmed via
78      * {@link com.android.server.telecom.ui.ConfirmCallDialogActivity}.
79      */
80     public static final String ACTION_CANCEL_CALL =
81             "com.android.server.telecom.CANCEL_CALL";
82 
83     /**
84      * The action used to proceed with a redirected call being confirmed via the call redirection
85      * confirmation dialog.
86      */
87     public static final String ACTION_PLACE_REDIRECTED_CALL =
88             "com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL";
89 
90     /**
91      * The action used to confirm to proceed the call without redirection via the call redirection
92      * confirmation dialog.
93      */
94     public static final String ACTION_PLACE_UNREDIRECTED_CALL =
95             "com.android.server.telecom.PROCEED_WITH_UNREDIRECTED_CALL";
96 
97     /**
98      * The action used to cancel a redirected call being confirmed via the call redirection
99      * confirmation dialog.
100      */
101     public static final String ACTION_CANCEL_REDIRECTED_CALL =
102             "com.android.server.telecom.CANCEL_REDIRECTED_CALL";
103 
104     public static final String ACTION_HANGUP_CALL = "com.android.server.telecom.HANGUP_CALL";
105     public static final String ACTION_STOP_STREAMING =
106             "com.android.server.telecom.ACTION_STOP_STREAMING";
107 
108     public static final String EXTRA_USERHANDLE = "userhandle";
109     public static final String EXTRA_REDIRECTION_OUTGOING_CALL_ID =
110             "android.telecom.extra.REDIRECTION_OUTGOING_CALL_ID";
111     public static final String EXTRA_REDIRECTION_APP_NAME =
112             "android.telecom.extra.REDIRECTION_APP_NAME";
113 
114     private final Context mContext;
115     private final CallsManager mCallsManager;
116 
TelecomBroadcastIntentProcessor(Context context, CallsManager callsManager)117     public TelecomBroadcastIntentProcessor(Context context, CallsManager callsManager) {
118         mContext = context;
119         mCallsManager = callsManager;
120     }
121 
processIntent(Intent intent)122     public void processIntent(Intent intent) {
123         String action = intent.getAction();
124 
125         if (ACTION_SEND_SMS_FROM_NOTIFICATION.equals(action) ||
126                 ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action) ||
127                 ACTION_CLEAR_MISSED_CALLS.equals(action)) {
128             Log.v(this, "Action received: %s.", action);
129             UserHandle userHandle = intent.getParcelableExtra(EXTRA_USERHANDLE);
130             if (userHandle == null) {
131                 Log.d(this, "user handle can't be null, not processing the broadcast");
132                 return;
133             }
134 
135             MissedCallNotifier missedCallNotifier = mCallsManager.getMissedCallNotifier();
136 
137             // Send an SMS from the missed call notification.
138             if (ACTION_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
139                 // Close the notification shade and the notification itself.
140                 closeSystemDialogs(mContext);
141                 missedCallNotifier.clearMissedCalls(userHandle);
142                 sendSmsIntent(intent, userHandle);
143 
144                 // Call back recent caller from the missed call notification.
145             } else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
146                 // Close the notification shade and the notification itself.
147                 closeSystemDialogs(mContext);
148                 missedCallNotifier.clearMissedCalls(userHandle);
149                 sendCallBackIntent(intent, userHandle);
150 
151                 // Clear the missed call notification and call log entries.
152             } else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
153                 missedCallNotifier.clearMissedCalls(userHandle);
154             }
155         } else if(ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION.equals(action) ||
156                 ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
157             Log.v(this, "Action received: %s.", action);
158             UserHandle userHandle = intent.getParcelableExtra(EXTRA_USERHANDLE);
159             if (userHandle == null) {
160                 Log.d(this, "disconnect user handle can't be null, not processing the broadcast");
161                 return;
162             }
163 
164             DisconnectedCallNotifier disconnectedCallNotifier =
165                     mCallsManager.getDisconnectedCallNotifier();
166 
167             // Send an SMS from the disconnected call notification.
168             if (ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
169                 // Close the notification shade and the notification itself.
170                 closeSystemDialogs(mContext);
171                 disconnectedCallNotifier.clearNotification(userHandle);
172                 sendSmsIntent(intent, userHandle);
173 
174             // Call back recent caller from the disconnected call notification.
175             } else if (ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
176                 // Close the notification shade and the notification itself.
177                 closeSystemDialogs(mContext);
178                 disconnectedCallNotifier.clearNotification(userHandle);
179                 sendCallBackIntent(intent, userHandle);
180             }
181         } else if (ACTION_ANSWER_FROM_NOTIFICATION.equals(action)) {
182             Log.startSession("TBIP.aAFM");
183             try {
184                 // Answer the current ringing call.
185                 Call incomingCall = mCallsManager.getIncomingCallNotifier().getIncomingCall();
186                 if (incomingCall != null) {
187                     mCallsManager.answerCall(incomingCall, incomingCall.getVideoState(),
188                             CallsManager.REQUEST_ORIGIN_TELECOM_DISAMBIGUATION);
189                 }
190             } finally {
191                 Log.endSession();
192             }
193         } else if (ACTION_REJECT_FROM_NOTIFICATION.equals(action)) {
194             Log.startSession("TBIP.aRFM");
195             try {
196 
197                 // Reject the current ringing call.
198                 Call incomingCall = mCallsManager.getIncomingCallNotifier().getIncomingCall();
199                 if (incomingCall != null) {
200                     mCallsManager.rejectCall(incomingCall, false /* isRejectWithMessage */, null);
201                 }
202             } finally {
203                 Log.endSession();
204             }
205         } else if (ACTION_PROCEED_WITH_CALL.equals(action)) {
206             Log.startSession("TBIP.aPWC");
207             try {
208                 String callId = intent.getStringExtra(
209                         ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID);
210                 mCallsManager.confirmPendingCall(callId);
211             } finally {
212                 Log.endSession();
213             }
214         } else if (ACTION_CANCEL_CALL.equals(action)) {
215             Log.startSession("TBIP.aCC");
216             try {
217                 String callId = intent.getStringExtra(
218                         ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID);
219                 mCallsManager.cancelPendingCall(callId);
220             } finally {
221                 Log.endSession();
222             }
223         } else if (ACTION_PLACE_REDIRECTED_CALL.equals(action)) {
224             Log.startSession("TBIP.aPRC");
225             try {
226                 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
227                         intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
228                         ACTION_PLACE_REDIRECTED_CALL);
229             } finally {
230                 Log.endSession();
231             }
232         } else if (ACTION_PLACE_UNREDIRECTED_CALL.equals(action)) {
233             Log.startSession("TBIP.aPUC");
234             try {
235                 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
236                         intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
237                         ACTION_PLACE_UNREDIRECTED_CALL);
238             } finally {
239                 Log.endSession();
240             }
241         } else if (ACTION_CANCEL_REDIRECTED_CALL.equals(action)) {
242             Log.startSession("TBIP.aCRC");
243             try {
244                 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
245                         intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
246                         ACTION_CANCEL_REDIRECTED_CALL);
247             } finally {
248                 Log.endSession();
249             }
250         } else if (ACTION_HANGUP_CALL.equals(action)) {
251             Log.startSession("TBIP.aHC", "streamingDialog");
252             try {
253                 Call call = mCallsManager.getCall(intent.getData().getSchemeSpecificPart());
254                 if (call != null) {
255                     mCallsManager.disconnectCall(call);
256                 }
257             } finally {
258                 Log.endSession();
259             }
260         } else if (ACTION_STOP_STREAMING.equals(action)) {
261             Log.startSession("TBIP.aSS", "streamingDialog");
262             try {
263                 Call call = mCallsManager.getCall(intent.getData().getSchemeSpecificPart());
264                 if (call != null) {
265                     mCallsManager.stopCallStreaming(call);
266                 }
267             } finally {
268                 Log.endSession();
269             }
270         }
271     }
272 
273     /**
274      * Closes open system dialogs and the notification shade.
275      */
closeSystemDialogs(Context context)276     private void closeSystemDialogs(Context context) {
277         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
278                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
279         Bundle options = BroadcastOptions.makeBasic()
280                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
281                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
282                 .toBundle();
283         context.sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */,
284                 options);
285     }
286 
sendSmsIntent(Intent intent, UserHandle userHandle)287     private void sendSmsIntent(Intent intent, UserHandle userHandle) {
288         Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
289         callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
290         PackageManager packageManager = mContext.getPackageManager();
291         List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
292                 callIntent, PackageManager.MATCH_DEFAULT_ONLY, userHandle.getIdentifier());
293         if (activities.size() > 0) {
294             mContext.startActivityAsUser(callIntent, userHandle);
295         } else {
296             Toast.makeText(mContext, com.android.internal.R.string.noApplications,
297                     Toast.LENGTH_SHORT).show();
298         }
299     }
300 
sendCallBackIntent(Intent intent, UserHandle userHandle)301     private void sendCallBackIntent(Intent intent, UserHandle userHandle) {
302         Intent callIntent = new Intent(Intent.ACTION_CALL, intent.getData());
303         callIntent.setFlags(
304                 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
305         mContext.startActivityAsUser(callIntent, userHandle);
306     }
307 }
308