1 /* 2 * Copyright (C) 2018 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.callredirection; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.ServiceConnection; 23 import android.net.Uri; 24 import android.os.Binder; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.Looper; 28 import android.os.RemoteException; 29 import android.os.UserHandle; 30 import android.telecom.CallRedirectionService; 31 import android.telecom.GatewayInfo; 32 import android.telecom.Log; 33 import android.telecom.Logging.Runnable; 34 import android.telecom.PhoneAccountHandle; 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.telecom.ICallRedirectionAdapter; 37 import com.android.internal.telecom.ICallRedirectionService; 38 import com.android.server.telecom.Call; 39 import com.android.server.telecom.CallsManager; 40 import com.android.server.telecom.LogUtils; 41 import com.android.server.telecom.PhoneAccountRegistrar; 42 import com.android.server.telecom.TelecomSystem; 43 import com.android.server.telecom.Timeouts; 44 45 /** 46 * A single instance of call redirection processor that handles the call redirection with 47 * user-defined {@link CallRedirectionService} and carrier {@link CallRedirectionService} for a 48 * single call. 49 * 50 * A user-defined call redirection will be performed firstly and a carrier call redirection will be 51 * performed after that; there will be a total of two call redirection cycles. 52 * 53 * A call redirection cycle is a cycle: 54 * 1) Telecom requests a call redirection of a call with a specific {@link CallRedirectionService}, 55 * 2) Telecom receives the response either from a specific {@link CallRedirectionService} or from 56 * the timeout. 57 * 58 * Telecom should return to {@link CallsManager} at the end of current call redirection 59 * cycle, if 60 * 1) {@link CallRedirectionService} sends {@link CallRedirectionService#cancelCall()} response 61 * before timeout; 62 * or 2) Telecom finishes call redirection with carrier {@link CallRedirectionService}. 63 */ 64 public class CallRedirectionProcessor implements CallRedirectionCallback { 65 66 private class CallRedirectionAttempt { 67 private final ComponentName mComponentName; 68 private final String mServiceType; 69 private ServiceConnection mConnection; 70 private ICallRedirectionService mService; 71 CallRedirectionAttempt(ComponentName componentName, String serviceType)72 private CallRedirectionAttempt(ComponentName componentName, String serviceType) { 73 mComponentName = componentName; 74 mServiceType = serviceType; 75 } 76 process(UserHandle userHandleForCallRedirection)77 private void process(UserHandle userHandleForCallRedirection) { 78 Intent intent = new Intent(CallRedirectionService.SERVICE_INTERFACE) 79 .setComponent(mComponentName); 80 ServiceConnection connection = new CallRedirectionServiceConnection(); 81 if (mContext.bindServiceAsUser( 82 intent, 83 connection, 84 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE 85 | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, 86 userHandleForCallRedirection)) { 87 Log.d(this, "bindService, found " + mServiceType + " call redirection service," 88 + " waiting for it to connect"); 89 mConnection = connection; 90 } 91 } 92 onServiceBound(ICallRedirectionService service)93 private void onServiceBound(ICallRedirectionService service) { 94 mService = service; 95 try { 96 // Telecom does not perform user interactions for carrier call redirection. 97 mService.placeCall(new CallRedirectionAdapter(), mProcessedDestinationUri, 98 mPhoneAccountHandle, mAllowInteractiveResponse 99 && mServiceType.equals(SERVICE_TYPE_USER_DEFINED)); 100 Log.addEvent(mCall, mServiceType.equals(SERVICE_TYPE_USER_DEFINED) 101 ? LogUtils.Events.REDIRECTION_SENT_USER 102 : LogUtils.Events.REDIRECTION_SENT_CARRIER, mComponentName); 103 Log.d(this, "Requested placeCall with [Destination Uri] " 104 + Log.pii(mProcessedDestinationUri) 105 + " [phoneAccountHandle]" + mPhoneAccountHandle); 106 } catch (RemoteException e) { 107 Log.e(this, e, "Failed to request with the found " + mServiceType + " call" 108 + " redirection service"); 109 finishCallRedirection(); 110 } 111 } 112 finishCallRedirection()113 private void finishCallRedirection() { 114 if (((mServiceType.equals(SERVICE_TYPE_CARRIER)) && mIsCarrierRedirectionPending) 115 || ((mServiceType.equals(SERVICE_TYPE_USER_DEFINED)) 116 && mIsUserDefinedRedirectionPending)) { 117 if (mConnection != null) { 118 // We still need to call unbind even if the service disconnected. 119 mContext.unbindService(mConnection); 120 mConnection = null; 121 } 122 mService = null; 123 onCallRedirectionComplete(mCall); 124 } 125 } 126 notifyTimeout()127 public void notifyTimeout() { 128 if (mService != null) { 129 try { 130 mService.notifyTimeout(); 131 } catch (RemoteException e) { 132 Log.e(this, e, "Failed to notify call redirection timed out to " 133 + mServiceType + " call redirection service"); 134 } 135 } 136 } 137 138 private class CallRedirectionServiceConnection implements ServiceConnection { 139 @Override onServiceConnected(ComponentName componentName, IBinder service)140 public void onServiceConnected(ComponentName componentName, IBinder service) { 141 Log.startSession("CRSC.oSC"); 142 try { 143 synchronized (mTelecomLock) { 144 Log.addEvent(mCall, mServiceType.equals(SERVICE_TYPE_USER_DEFINED) 145 ? LogUtils.Events.REDIRECTION_BOUND_USER 146 : LogUtils.Events.REDIRECTION_BOUND_CARRIER, componentName); 147 onServiceBound(ICallRedirectionService.Stub.asInterface(service)); 148 } 149 } finally { 150 Log.endSession(); 151 } 152 } 153 154 @Override onServiceDisconnected(ComponentName componentName)155 public void onServiceDisconnected(ComponentName componentName) { 156 Log.startSession("CRSC.oSD"); 157 try { 158 synchronized (mTelecomLock) { 159 finishCallRedirection(); 160 } 161 } finally { 162 Log.endSession(); 163 } 164 } 165 166 @Override onNullBinding(ComponentName componentName)167 public void onNullBinding(ComponentName componentName) { 168 // Make sure we unbind the service if onBind returns null 169 Log.startSession("CRSC.oNB"); 170 try { 171 synchronized (mTelecomLock) { 172 finishCallRedirection(); 173 } 174 } finally { 175 Log.endSession(); 176 } 177 } 178 179 @Override onBindingDied(ComponentName componentName)180 public void onBindingDied(ComponentName componentName) { 181 // Make sure we unbind the service if binding died to avoid background stating 182 // activity leaks 183 Log.startSession("CRSC.oBD"); 184 try { 185 synchronized (mTelecomLock) { 186 finishCallRedirection(); 187 } 188 } finally { 189 Log.endSession(); 190 } 191 } 192 } 193 194 private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub { 195 @Override cancelCall()196 public void cancelCall() { 197 Log.startSession("CRA.cC"); 198 long token = Binder.clearCallingIdentity(); 199 try { 200 synchronized (mTelecomLock) { 201 Log.d(this, "Received cancelCall from " + mServiceType + " call" 202 + " redirection service"); 203 mShouldCancelCall = true; 204 finishCallRedirection(); 205 } 206 } finally { 207 Binder.restoreCallingIdentity(token); 208 Log.endSession(); 209 } 210 } 211 212 @Override placeCallUnmodified()213 public void placeCallUnmodified() { 214 Log.startSession("CRA.pCU"); 215 long token = Binder.clearCallingIdentity(); 216 try { 217 synchronized (mTelecomLock) { 218 Log.d(this, "Received placeCallUnmodified from " + mServiceType + " call" 219 + " redirection service"); 220 finishCallRedirection(); 221 } 222 } finally { 223 Binder.restoreCallingIdentity(token); 224 Log.endSession(); 225 } 226 } 227 228 @Override redirectCall(Uri gatewayUri, PhoneAccountHandle targetPhoneAccount, boolean confirmFirst)229 public void redirectCall(Uri gatewayUri, PhoneAccountHandle targetPhoneAccount, 230 boolean confirmFirst) { 231 Log.startSession("CRA.rC"); 232 long token = Binder.clearCallingIdentity(); 233 try { 234 synchronized (mTelecomLock) { 235 mRedirectionGatewayInfo = mCallRedirectionProcessorHelper 236 .getGatewayInfoFromGatewayUri(mComponentName.getPackageName(), 237 gatewayUri, mDestinationUri, mPostDialDigits); 238 mPhoneAccountHandle = targetPhoneAccount; 239 // If carrier redirects call, we should skip to notify users about 240 // the user-defined call redirection service. 241 mUiAction = (confirmFirst && mServiceType.equals(SERVICE_TYPE_USER_DEFINED) 242 && mAllowInteractiveResponse) 243 ? UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM : UI_TYPE_NO_ACTION; 244 Log.d(this, "Received redirectCall with [gatewayUri]" 245 + Log.pii(gatewayUri) + " [phoneAccountHandle]" 246 + mPhoneAccountHandle + "[confirmFirst]" + confirmFirst + " from " 247 + mServiceType + " call redirection service"); 248 finishCallRedirection(); 249 } 250 } finally { 251 Binder.restoreCallingIdentity(token); 252 Log.endSession(); 253 } 254 } 255 } 256 } 257 258 private final Context mContext; 259 private final CallsManager mCallsManager; 260 private final Call mCall; 261 private final boolean mAllowInteractiveResponse; 262 private GatewayInfo mRedirectionGatewayInfo; 263 private final boolean mSpeakerphoneOn; 264 private final int mVideoState; 265 private final Timeouts.Adapter mTimeoutsAdapter; 266 private final TelecomSystem.SyncRoot mTelecomLock; 267 private final Handler mHandler = new Handler(Looper.getMainLooper()); 268 269 private CallRedirectionAttempt mAttempt; 270 private CallRedirectionProcessorHelper mCallRedirectionProcessorHelper; 271 272 public static final String SERVICE_TYPE_CARRIER = "carrier"; 273 public static final String SERVICE_TYPE_USER_DEFINED = "user_defined"; 274 public static final String UI_TYPE_NO_ACTION = "no_action"; 275 public static final String UI_TYPE_USER_DEFINED_TIMEOUT = "user_defined_timeout"; 276 public static final String UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM 277 = "user_defined_ask_for_confirm"; 278 279 private PhoneAccountHandle mPhoneAccountHandle; 280 private Uri mDestinationUri; 281 /** 282 * Try to send the implemented service with processed destination uri by formatting it to E.164 283 * and removing post dial digits. 284 */ 285 private Uri mProcessedDestinationUri; 286 287 /** 288 * The post dial digits which were removed from {@link #mDestinationUri} when determining 289 * {@link #mProcessedDestinationUri}. 290 */ 291 private String mPostDialDigits; 292 293 /** 294 * Indicates if Telecom should cancel the call when the whole call redirection finishes. 295 */ 296 private boolean mShouldCancelCall = false; 297 /** 298 * Indicates Telecom should handle different types of UI if need. 299 */ 300 private String mUiAction = UI_TYPE_NO_ACTION; 301 /** 302 * Indicates if Telecom is waiting for a callback from a user-defined 303 * {@link CallRedirectionService}. 304 */ 305 private boolean mIsUserDefinedRedirectionPending = false; 306 /** 307 * Indicates if Telecom is waiting for a callback from a carrier 308 * {@link CallRedirectionService}. 309 */ 310 private boolean mIsCarrierRedirectionPending = false; 311 CallRedirectionProcessor( Context context, CallsManager callsManager, Call call, Uri handle, PhoneAccountRegistrar phoneAccountRegistrar, GatewayInfo gatewayInfo, boolean speakerphoneOn, int videoState)312 public CallRedirectionProcessor( 313 Context context, 314 CallsManager callsManager, 315 Call call, 316 Uri handle, 317 PhoneAccountRegistrar phoneAccountRegistrar, 318 GatewayInfo gatewayInfo, 319 boolean speakerphoneOn, 320 int videoState) { 321 mContext = context; 322 mCallsManager = callsManager; 323 mCall = call; 324 mDestinationUri = handle; 325 mPhoneAccountHandle = call.getTargetPhoneAccount(); 326 mRedirectionGatewayInfo = gatewayInfo; 327 mSpeakerphoneOn = speakerphoneOn; 328 mVideoState = videoState; 329 mTimeoutsAdapter = callsManager.getTimeoutsAdapter(); 330 mTelecomLock = callsManager.getLock(); 331 /** 332 * The current rule to decide whether the implemented {@link CallRedirectionService} should 333 * allow interactive responses with users is only based on whether it is in car mode. 334 */ 335 mAllowInteractiveResponse = !callsManager.getSystemStateHelper().isCarModeOrProjectionActive(); 336 mCallRedirectionProcessorHelper = new CallRedirectionProcessorHelper( 337 context, callsManager, phoneAccountRegistrar); 338 mProcessedDestinationUri = mCallRedirectionProcessorHelper.formatNumberForRedirection( 339 mDestinationUri); 340 mPostDialDigits = mCallRedirectionProcessorHelper.getPostDialDigits(mDestinationUri); 341 } 342 343 @Override onCallRedirectionComplete(Call call)344 public void onCallRedirectionComplete(Call call) { 345 // synchronized on mTelecomLock to enter into Telecom. 346 mHandler.post(new Runnable("CRP.oCRC", mTelecomLock) { 347 @Override 348 public void loggedRun() { 349 if (mIsUserDefinedRedirectionPending) { 350 Log.addEvent(mCall, LogUtils.Events.REDIRECTION_COMPLETED_USER); 351 mIsUserDefinedRedirectionPending = false; 352 if (mShouldCancelCall) { 353 mCallsManager.onCallRedirectionComplete(mCall, mDestinationUri, 354 mPhoneAccountHandle, mRedirectionGatewayInfo, mSpeakerphoneOn, 355 mVideoState, mShouldCancelCall, mUiAction); 356 } else { 357 // Use the current user for carrier call redirection 358 performCarrierCallRedirection(UserHandle.CURRENT); 359 } 360 } else if (mIsCarrierRedirectionPending) { 361 Log.addEvent(mCall, LogUtils.Events.REDIRECTION_COMPLETED_CARRIER); 362 mIsCarrierRedirectionPending = false; 363 mCallsManager.onCallRedirectionComplete(mCall, mDestinationUri, 364 mPhoneAccountHandle, mRedirectionGatewayInfo, mSpeakerphoneOn, 365 mVideoState, mShouldCancelCall, mUiAction); 366 } 367 } 368 }.prepare()); 369 } 370 371 /** 372 * The entry to perform call redirection of the call from (@link CallsManager) 373 */ performCallRedirection(UserHandle userHandleForCallRedirection)374 public void performCallRedirection(UserHandle userHandleForCallRedirection) { 375 // If the Gateway Info is set with intent, only request with carrier call redirection. 376 if (mRedirectionGatewayInfo != null) { 377 // Use the current user for carrier call redirection 378 performCarrierCallRedirection(UserHandle.CURRENT); 379 } else { 380 performUserDefinedCallRedirection(userHandleForCallRedirection); 381 } 382 } 383 performUserDefinedCallRedirection(UserHandle userHandleForCallRedirection)384 private void performUserDefinedCallRedirection(UserHandle userHandleForCallRedirection) { 385 Log.d(this, "performUserDefinedCallRedirection"); 386 ComponentName componentName = 387 mCallRedirectionProcessorHelper. 388 getUserDefinedCallRedirectionService(userHandleForCallRedirection); 389 if (componentName != null) { 390 mAttempt = new CallRedirectionAttempt(componentName, SERVICE_TYPE_USER_DEFINED); 391 mAttempt.process(userHandleForCallRedirection); 392 mIsUserDefinedRedirectionPending = true; 393 processTimeoutForCallRedirection(SERVICE_TYPE_USER_DEFINED); 394 } else { 395 Log.i(this, "There are no user-defined call redirection services installed on this" 396 + " device."); 397 performCarrierCallRedirection(UserHandle.CURRENT); 398 } 399 } 400 performCarrierCallRedirection(UserHandle userHandleForCallRedirection)401 private void performCarrierCallRedirection(UserHandle userHandleForCallRedirection) { 402 Log.d(this, "performCarrierCallRedirection"); 403 ComponentName componentName = 404 mCallRedirectionProcessorHelper.getCarrierCallRedirectionService( 405 mPhoneAccountHandle); 406 if (componentName != null) { 407 mAttempt = new CallRedirectionAttempt(componentName, SERVICE_TYPE_CARRIER); 408 mAttempt.process(userHandleForCallRedirection); 409 mIsCarrierRedirectionPending = true; 410 processTimeoutForCallRedirection(SERVICE_TYPE_CARRIER); 411 } else { 412 Log.i(this, "There are no carrier call redirection services installed on this" 413 + " device."); 414 mCallsManager.onCallRedirectionComplete(mCall, mDestinationUri, 415 mPhoneAccountHandle, mRedirectionGatewayInfo, mSpeakerphoneOn, mVideoState, 416 mShouldCancelCall, mUiAction); 417 } 418 } 419 processTimeoutForCallRedirection(String serviceType)420 private void processTimeoutForCallRedirection(String serviceType) { 421 long timeout = serviceType.equals(SERVICE_TYPE_USER_DEFINED) ? 422 mTimeoutsAdapter.getUserDefinedCallRedirectionTimeoutMillis( 423 mContext.getContentResolver()) : mTimeoutsAdapter 424 .getCarrierCallRedirectionTimeoutMillis(mContext.getContentResolver()); 425 426 mHandler.postDelayed(new Runnable("CRP.pTFCR", null) { 427 @Override 428 public void loggedRun() { 429 boolean isCurrentRedirectionPending = 430 serviceType.equals(SERVICE_TYPE_USER_DEFINED) ? 431 mIsUserDefinedRedirectionPending : mIsCarrierRedirectionPending; 432 if (isCurrentRedirectionPending) { 433 Log.i(this, serviceType + " call redirection has timed out."); 434 Log.addEvent(mCall, serviceType.equals(SERVICE_TYPE_USER_DEFINED) 435 ? LogUtils.Events.REDIRECTION_TIMED_OUT_USER 436 : LogUtils.Events.REDIRECTION_TIMED_OUT_CARRIER); 437 mAttempt.notifyTimeout(); 438 if (serviceType.equals(SERVICE_TYPE_USER_DEFINED)) { 439 mUiAction = UI_TYPE_USER_DEFINED_TIMEOUT; 440 mShouldCancelCall = true; 441 } 442 onCallRedirectionComplete(mCall); 443 } 444 } 445 }.prepare(), timeout); 446 } 447 448 /** 449 * Checks if Telecom can make call redirection with any available call redirection service 450 * as the specified user. 451 * 452 * @return {@code true} if it can; {@code false} otherwise. 453 */ canMakeCallRedirectionWithServiceAsUser( UserHandle userHandleForCallRedirection)454 public boolean canMakeCallRedirectionWithServiceAsUser( 455 UserHandle userHandleForCallRedirection) { 456 boolean canMakeCallRedirectionWithServiceAsUser = 457 mCallRedirectionProcessorHelper 458 .getUserDefinedCallRedirectionService(userHandleForCallRedirection) != null 459 || mCallRedirectionProcessorHelper.getCarrierCallRedirectionService( 460 mPhoneAccountHandle) != null; 461 Log.i(this, "Can make call redirection with any " 462 + "available service as user (" + userHandleForCallRedirection 463 + ") : " + canMakeCallRedirectionWithServiceAsUser); 464 return canMakeCallRedirectionWithServiceAsUser; 465 } 466 467 /** 468 * Returns the handler, for testing purposes. 469 */ 470 @VisibleForTesting getHandler()471 public Handler getHandler() { 472 return mHandler; 473 } 474 475 /** 476 * Set CallRedirectionProcessorHelper for testing purposes. 477 */ 478 @VisibleForTesting setCallRedirectionServiceHelper( CallRedirectionProcessorHelper callRedirectionProcessorHelper)479 public void setCallRedirectionServiceHelper( 480 CallRedirectionProcessorHelper callRedirectionProcessorHelper) { 481 mCallRedirectionProcessorHelper = callRedirectionProcessorHelper; 482 } 483 } 484