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 } 189 } finally { 190 Log.endSession(); 191 } 192 } else if (ACTION_REJECT_FROM_NOTIFICATION.equals(action)) { 193 Log.startSession("TBIP.aRFM"); 194 try { 195 196 // Reject the current ringing call. 197 Call incomingCall = mCallsManager.getIncomingCallNotifier().getIncomingCall(); 198 if (incomingCall != null) { 199 mCallsManager.rejectCall(incomingCall, false /* isRejectWithMessage */, null); 200 } 201 } finally { 202 Log.endSession(); 203 } 204 } else if (ACTION_PROCEED_WITH_CALL.equals(action)) { 205 Log.startSession("TBIP.aPWC"); 206 try { 207 String callId = intent.getStringExtra( 208 ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID); 209 mCallsManager.confirmPendingCall(callId); 210 } finally { 211 Log.endSession(); 212 } 213 } else if (ACTION_CANCEL_CALL.equals(action)) { 214 Log.startSession("TBIP.aCC"); 215 try { 216 String callId = intent.getStringExtra( 217 ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID); 218 mCallsManager.cancelPendingCall(callId); 219 } finally { 220 Log.endSession(); 221 } 222 } else if (ACTION_PLACE_REDIRECTED_CALL.equals(action)) { 223 Log.startSession("TBIP.aPRC"); 224 try { 225 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction( 226 intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID), 227 ACTION_PLACE_REDIRECTED_CALL); 228 } finally { 229 Log.endSession(); 230 } 231 } else if (ACTION_PLACE_UNREDIRECTED_CALL.equals(action)) { 232 Log.startSession("TBIP.aPUC"); 233 try { 234 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction( 235 intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID), 236 ACTION_PLACE_UNREDIRECTED_CALL); 237 } finally { 238 Log.endSession(); 239 } 240 } else if (ACTION_CANCEL_REDIRECTED_CALL.equals(action)) { 241 Log.startSession("TBIP.aCRC"); 242 try { 243 mCallsManager.processRedirectedOutgoingCallAfterUserInteraction( 244 intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID), 245 ACTION_CANCEL_REDIRECTED_CALL); 246 } finally { 247 Log.endSession(); 248 } 249 } else if (ACTION_HANGUP_CALL.equals(action)) { 250 Log.startSession("TBIP.aHC", "streamingDialog"); 251 try { 252 Call call = mCallsManager.getCall(intent.getData().getSchemeSpecificPart()); 253 if (call != null) { 254 mCallsManager.disconnectCall(call); 255 } 256 } finally { 257 Log.endSession(); 258 } 259 } else if (ACTION_STOP_STREAMING.equals(action)) { 260 Log.startSession("TBIP.aSS", "streamingDialog"); 261 try { 262 Call call = mCallsManager.getCall(intent.getData().getSchemeSpecificPart()); 263 if (call != null) { 264 mCallsManager.stopCallStreaming(call); 265 } 266 } finally { 267 Log.endSession(); 268 } 269 } 270 } 271 272 /** 273 * Closes open system dialogs and the notification shade. 274 */ closeSystemDialogs(Context context)275 private void closeSystemDialogs(Context context) { 276 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) 277 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 278 Bundle options = BroadcastOptions.makeBasic() 279 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 280 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 281 .toBundle(); 282 context.sendBroadcastAsUser(intent, UserHandle.ALL, null /* receiverPermission */, 283 options); 284 } 285 sendSmsIntent(Intent intent, UserHandle userHandle)286 private void sendSmsIntent(Intent intent, UserHandle userHandle) { 287 Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData()); 288 callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 289 PackageManager packageManager = mContext.getPackageManager(); 290 List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser( 291 callIntent, PackageManager.MATCH_DEFAULT_ONLY, userHandle.getIdentifier()); 292 if (activities.size() > 0) { 293 mContext.startActivityAsUser(callIntent, userHandle); 294 } else { 295 Toast.makeText(mContext, com.android.internal.R.string.noApplications, 296 Toast.LENGTH_SHORT).show(); 297 } 298 } 299 sendCallBackIntent(Intent intent, UserHandle userHandle)300 private void sendCallBackIntent(Intent intent, UserHandle userHandle) { 301 Intent callIntent = new Intent(Intent.ACTION_CALL, intent.getData()); 302 callIntent.setFlags( 303 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 304 mContext.startActivityAsUser(callIntent, userHandle); 305 } 306 } 307