CallsManager.java revision fb8d5abd22ed0cb328365e4c64885471b1c7c53a
1/* 2 * Copyright (C) 2013 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.server.telecom; 18 19import android.app.ActivityManager; 20import android.content.Context; 21import android.content.pm.UserInfo; 22import android.content.Intent; 23import android.media.AudioManager; 24import android.net.Uri; 25import android.os.Bundle; 26import android.os.Handler; 27import android.os.Looper; 28import android.os.Process; 29import android.os.SystemClock; 30import android.os.SystemProperties; 31import android.os.SystemVibrator; 32import android.os.Trace; 33import android.os.UserHandle; 34import android.os.UserManager; 35import android.provider.CallLog.Calls; 36import android.provider.Settings; 37import android.telecom.CallAudioState; 38import android.telecom.Conference; 39import android.telecom.Connection; 40import android.telecom.DisconnectCause; 41import android.telecom.GatewayInfo; 42import android.telecom.Log; 43import android.telecom.ParcelableConference; 44import android.telecom.ParcelableConnection; 45import android.telecom.PhoneAccount; 46import android.telecom.PhoneAccountHandle; 47import android.telecom.Logging.Runnable; 48import android.telecom.TelecomManager; 49import android.telecom.VideoProfile; 50import android.telephony.PhoneNumberUtils; 51import android.telephony.TelephonyManager; 52import android.text.TextUtils; 53 54import com.android.internal.annotations.VisibleForTesting; 55import com.android.internal.telephony.AsyncEmergencyContactNotifier; 56import com.android.internal.telephony.PhoneConstants; 57import com.android.internal.telephony.TelephonyProperties; 58import com.android.internal.util.IndentingPrintWriter; 59import com.android.server.telecom.bluetooth.BluetoothRouteManager; 60import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter; 61import com.android.server.telecom.callfiltering.BlockCheckerAdapter; 62import com.android.server.telecom.callfiltering.CallFilterResultCallback; 63import com.android.server.telecom.callfiltering.CallFilteringResult; 64import com.android.server.telecom.callfiltering.CallScreeningServiceFilter; 65import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter; 66import com.android.server.telecom.callfiltering.IncomingCallFilter; 67import com.android.server.telecom.components.ErrorDialogActivity; 68import com.android.server.telecom.ui.ConfirmCallDialogActivity; 69import com.android.server.telecom.ui.IncomingCallNotifier; 70 71import java.util.ArrayList; 72import java.util.Arrays; 73import java.util.Collection; 74import java.util.Collections; 75import java.util.HashMap; 76import java.util.HashSet; 77import java.util.Iterator; 78import java.util.List; 79import java.util.Map; 80import java.util.Objects; 81import java.util.Optional; 82import java.util.Set; 83import java.util.concurrent.ConcurrentHashMap; 84import java.util.concurrent.CountDownLatch; 85import java.util.concurrent.TimeUnit; 86import java.util.stream.Collectors; 87import java.util.stream.IntStream; 88import java.util.stream.Stream; 89 90/** 91 * Singleton. 92 * 93 * NOTE: by design most APIs are package private, use the relevant adapter/s to allow 94 * access from other packages specifically refraining from passing the CallsManager instance 95 * beyond the com.android.server.telecom package boundary. 96 */ 97@VisibleForTesting 98public class CallsManager extends Call.ListenerBase 99 implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy { 100 101 // TODO: Consider renaming this CallsManagerPlugin. 102 @VisibleForTesting 103 public interface CallsManagerListener { 104 void onCallAdded(Call call); 105 void onCallRemoved(Call call); 106 void onCallStateChanged(Call call, int oldState, int newState); 107 void onConnectionServiceChanged( 108 Call call, 109 ConnectionServiceWrapper oldService, 110 ConnectionServiceWrapper newService); 111 void onIncomingCallAnswered(Call call); 112 void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage); 113 void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState); 114 void onRingbackRequested(Call call, boolean ringback); 115 void onIsConferencedChanged(Call call); 116 void onIsVoipAudioModeChanged(Call call); 117 void onVideoStateChanged(Call call, int previousVideoState, int newVideoState); 118 void onCanAddCallChanged(boolean canAddCall); 119 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); 120 void onHoldToneRequested(Call call); 121 void onExternalCallChanged(Call call, boolean isExternalCall); 122 void onDisconnectedTonePlaying(boolean isTonePlaying); 123 } 124 125 /** Interface used to define the action which is executed delay under some condition. */ 126 interface PendingAction { 127 void performAction(); 128 } 129 130 private static final String TAG = "CallsManager"; 131 132 /** 133 * Call filter specifier used with 134 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 135 * self-managed calls should be included. 136 */ 137 private static final int CALL_FILTER_SELF_MANAGED = 1; 138 139 /** 140 * Call filter specifier used with 141 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 142 * managed calls should be included. 143 */ 144 private static final int CALL_FILTER_MANAGED = 2; 145 146 /** 147 * Call filter specifier used with 148 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed 149 * and self-managed calls should be included. 150 */ 151 private static final int CALL_FILTER_ALL = 3; 152 153 private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION = 154 "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"; 155 156 private static final int HANDLER_WAIT_TIMEOUT = 10000; 157 private static final int MAXIMUM_LIVE_CALLS = 1; 158 private static final int MAXIMUM_HOLD_CALLS = 1; 159 private static final int MAXIMUM_RINGING_CALLS = 1; 160 private static final int MAXIMUM_DIALING_CALLS = 1; 161 private static final int MAXIMUM_OUTGOING_CALLS = 1; 162 private static final int MAXIMUM_TOP_LEVEL_CALLS = 2; 163 private static final int MAXIMUM_SELF_MANAGED_CALLS = 10; 164 165 private static final int[] OUTGOING_CALL_STATES = 166 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 167 CallState.PULLING}; 168 169 /** 170 * These states are used by {@link #makeRoomForOutgoingCall(Call, boolean)} to determine which 171 * call should be ended first to make room for a new outgoing call. 172 */ 173 private static final int[] LIVE_CALL_STATES = 174 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 175 CallState.PULLING, CallState.ACTIVE}; 176 177 /** 178 * These states determine which calls will cause {@link TelecomManager#isInCall()} or 179 * {@link TelecomManager#isInManagedCall()} to return true. 180 * 181 * See also {@link PhoneStateBroadcaster}, which considers a similar set of states as being 182 * off-hook. 183 */ 184 public static final int[] ONGOING_CALL_STATES = 185 {CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.PULLING, CallState.ACTIVE, 186 CallState.ON_HOLD, CallState.RINGING}; 187 188 private static final int[] ANY_CALL_STATE = 189 {CallState.NEW, CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 190 CallState.RINGING, CallState.ACTIVE, CallState.ON_HOLD, CallState.DISCONNECTED, 191 CallState.ABORTED, CallState.DISCONNECTING, CallState.PULLING}; 192 193 public static final String TELECOM_CALL_ID_PREFIX = "TC@"; 194 195 // Maps call technologies in PhoneConstants to those in Analytics. 196 private static final Map<Integer, Integer> sAnalyticsTechnologyMap; 197 static { 198 sAnalyticsTechnologyMap = new HashMap<>(5); 199 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE); 200 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE); 201 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE); 202 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE); 203 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY, 204 Analytics.THIRD_PARTY_PHONE); 205 } 206 207 /** 208 * The main call repository. Keeps an instance of all live calls. New incoming and outgoing 209 * calls are added to the map and removed when the calls move to the disconnected state. 210 * 211 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 212 * load factor before resizing, 1 means we only expect a single thread to 213 * access the map so make only a single shard 214 */ 215 private final Set<Call> mCalls = Collections.newSetFromMap( 216 new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1)); 217 218 /** 219 * A pending call is one which requires user-intervention in order to be placed. 220 * Used by {@link #startCallConfirmation(Call)}. 221 */ 222 private Call mPendingCall; 223 224 /** 225 * The current telecom call ID. Used when creating new instances of {@link Call}. Should 226 * only be accessed using the {@link #getNextCallId()} method which synchronizes on the 227 * {@link #mLock} sync root. 228 */ 229 private int mCallId = 0; 230 231 private int mRttRequestId = 0; 232 /** 233 * Stores the current foreground user. 234 */ 235 private UserHandle mCurrentUserHandle = UserHandle.of(ActivityManager.getCurrentUser()); 236 237 private final ConnectionServiceRepository mConnectionServiceRepository; 238 private final DtmfLocalTonePlayer mDtmfLocalTonePlayer; 239 private final InCallController mInCallController; 240 private final CallAudioManager mCallAudioManager; 241 private final CallRecordingTonePlayer mCallRecordingTonePlayer; 242 private RespondViaSmsManager mRespondViaSmsManager; 243 private final Ringer mRinger; 244 private final InCallWakeLockController mInCallWakeLockController; 245 // For this set initial table size to 16 because we add 13 listeners in 246 // the CallsManager constructor. 247 private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap( 248 new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1)); 249 private final HeadsetMediaButton mHeadsetMediaButton; 250 private final WiredHeadsetManager mWiredHeadsetManager; 251 private final BluetoothRouteManager mBluetoothRouteManager; 252 private final DockManager mDockManager; 253 private final TtyManager mTtyManager; 254 private final ProximitySensorManager mProximitySensorManager; 255 private final PhoneStateBroadcaster mPhoneStateBroadcaster; 256 private final CallLogManager mCallLogManager; 257 private final Context mContext; 258 private final TelecomSystem.SyncRoot mLock; 259 private final ContactsAsyncHelper mContactsAsyncHelper; 260 private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory; 261 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 262 private final MissedCallNotifier mMissedCallNotifier; 263 private IncomingCallNotifier mIncomingCallNotifier; 264 private final CallerInfoLookupHelper mCallerInfoLookupHelper; 265 private final DefaultDialerCache mDefaultDialerCache; 266 private final Timeouts.Adapter mTimeoutsAdapter; 267 private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; 268 private final ClockProxy mClockProxy; 269 private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>(); 270 private final Set<Call> mPendingCallsToDisconnect = new HashSet<>(); 271 private final ConnectionServiceFocusManager mConnectionSvrFocusMgr; 272 /* Handler tied to thread in which CallManager was initialized. */ 273 private final Handler mHandler = new Handler(Looper.getMainLooper()); 274 private final EmergencyCallHelper mEmergencyCallHelper; 275 276 private final ConnectionServiceFocusManager.CallsManagerRequester mRequester = 277 new ConnectionServiceFocusManager.CallsManagerRequester() { 278 @Override 279 public void releaseConnectionService( 280 ConnectionServiceFocusManager.ConnectionServiceFocus connectionService) { 281 mCalls.stream() 282 .filter(c -> c.getConnectionServiceWrapper().equals(connectionService)) 283 .forEach(c -> c.disconnect()); 284 } 285 286 @Override 287 public void setCallsManagerListener(CallsManagerListener listener) { 288 mListeners.add(listener); 289 } 290 }; 291 292 private boolean mCanAddCall = true; 293 294 private TelephonyManager.MultiSimVariants mRadioSimVariants = null; 295 296 private Runnable mStopTone; 297 298 /** 299 * Listener to PhoneAccountRegistrar events. 300 */ 301 private PhoneAccountRegistrar.Listener mPhoneAccountListener = 302 new PhoneAccountRegistrar.Listener() { 303 public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar, 304 PhoneAccountHandle handle) { 305 broadcastRegisterIntent(handle); 306 } 307 public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, 308 PhoneAccountHandle handle) { 309 broadcastUnregisterIntent(handle); 310 } 311 }; 312 313 /** 314 * Initializes the required Telecom components. 315 */ 316 @VisibleForTesting 317 public CallsManager( 318 Context context, 319 TelecomSystem.SyncRoot lock, 320 ContactsAsyncHelper contactsAsyncHelper, 321 CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory, 322 MissedCallNotifier missedCallNotifier, 323 PhoneAccountRegistrar phoneAccountRegistrar, 324 HeadsetMediaButtonFactory headsetMediaButtonFactory, 325 ProximitySensorManagerFactory proximitySensorManagerFactory, 326 InCallWakeLockControllerFactory inCallWakeLockControllerFactory, 327 ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory 328 connectionServiceFocusManagerFactory, 329 CallAudioManager.AudioServiceFactory audioServiceFactory, 330 BluetoothRouteManager bluetoothManager, 331 WiredHeadsetManager wiredHeadsetManager, 332 SystemStateProvider systemStateProvider, 333 DefaultDialerCache defaultDialerCache, 334 Timeouts.Adapter timeoutsAdapter, 335 AsyncRingtonePlayer asyncRingtonePlayer, 336 PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, 337 EmergencyCallHelper emergencyCallHelper, 338 InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory, 339 ClockProxy clockProxy, 340 InCallControllerFactory inCallControllerFactory) { 341 mContext = context; 342 mLock = lock; 343 mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; 344 mContactsAsyncHelper = contactsAsyncHelper; 345 mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory; 346 mPhoneAccountRegistrar = phoneAccountRegistrar; 347 mPhoneAccountRegistrar.addListener(mPhoneAccountListener); 348 mMissedCallNotifier = missedCallNotifier; 349 StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this); 350 mWiredHeadsetManager = wiredHeadsetManager; 351 mDefaultDialerCache = defaultDialerCache; 352 mBluetoothRouteManager = bluetoothManager; 353 mDockManager = new DockManager(context); 354 mTimeoutsAdapter = timeoutsAdapter; 355 mEmergencyCallHelper = emergencyCallHelper; 356 mCallerInfoLookupHelper = new CallerInfoLookupHelper(context, mCallerInfoAsyncQueryFactory, 357 mContactsAsyncHelper, mLock); 358 359 mDtmfLocalTonePlayer = 360 new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy()); 361 CallAudioRouteStateMachine callAudioRouteStateMachine = new CallAudioRouteStateMachine( 362 context, 363 this, 364 bluetoothManager, 365 wiredHeadsetManager, 366 statusBarNotifier, 367 audioServiceFactory, 368 CallAudioRouteStateMachine.EARPIECE_AUTO_DETECT 369 ); 370 callAudioRouteStateMachine.initialize(); 371 372 CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter = 373 new CallAudioRoutePeripheralAdapter( 374 callAudioRouteStateMachine, 375 bluetoothManager, 376 wiredHeadsetManager, 377 mDockManager); 378 379 InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory( 380 callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory); 381 382 SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil(); 383 RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context); 384 SystemVibrator systemVibrator = new SystemVibrator(context); 385 mInCallController = inCallControllerFactory.create(context, mLock, this, 386 systemStateProvider, defaultDialerCache, mTimeoutsAdapter, 387 emergencyCallHelper); 388 mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer, 389 ringtoneFactory, systemVibrator, mInCallController); 390 mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, 391 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE), mLock); 392 mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine, 393 this,new CallAudioModeStateMachine((AudioManager) 394 mContext.getSystemService(Context.AUDIO_SERVICE)), 395 playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer); 396 397 mConnectionSvrFocusMgr = connectionServiceFocusManagerFactory.create( 398 mRequester, Looper.getMainLooper()); 399 mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock); 400 mTtyManager = new TtyManager(context, mWiredHeadsetManager); 401 mProximitySensorManager = proximitySensorManagerFactory.create(context, this); 402 mPhoneStateBroadcaster = new PhoneStateBroadcaster(this); 403 mCallLogManager = new CallLogManager(context, phoneAccountRegistrar, mMissedCallNotifier); 404 mConnectionServiceRepository = 405 new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this); 406 mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this); 407 mClockProxy = clockProxy; 408 409 mListeners.add(mInCallWakeLockController); 410 mListeners.add(statusBarNotifier); 411 mListeners.add(mCallLogManager); 412 mListeners.add(mPhoneStateBroadcaster); 413 mListeners.add(mInCallController); 414 mListeners.add(mCallAudioManager); 415 mListeners.add(mCallRecordingTonePlayer); 416 mListeners.add(missedCallNotifier); 417 mListeners.add(mHeadsetMediaButton); 418 mListeners.add(mProximitySensorManager); 419 420 // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly. 421 final UserManager userManager = UserManager.get(mContext); 422 // Don't load missed call if it is run in split user model. 423 if (userManager.isPrimaryUser()) { 424 onUserSwitch(Process.myUserHandle()); 425 } 426 } 427 428 public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) { 429 if (mIncomingCallNotifier != null) { 430 mListeners.remove(mIncomingCallNotifier); 431 } 432 mIncomingCallNotifier = incomingCallNotifier; 433 mListeners.add(mIncomingCallNotifier); 434 } 435 436 public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) { 437 if (mRespondViaSmsManager != null) { 438 mListeners.remove(mRespondViaSmsManager); 439 } 440 mRespondViaSmsManager = respondViaSmsManager; 441 mListeners.add(respondViaSmsManager); 442 } 443 444 public RespondViaSmsManager getRespondViaSmsManager() { 445 return mRespondViaSmsManager; 446 } 447 448 public CallerInfoLookupHelper getCallerInfoLookupHelper() { 449 return mCallerInfoLookupHelper; 450 } 451 452 @Override 453 public void onSuccessfulOutgoingCall(Call call, int callState) { 454 Log.v(this, "onSuccessfulOutgoingCall, %s", call); 455 456 setCallState(call, callState, "successful outgoing call"); 457 if (!mCalls.contains(call)) { 458 // Call was not added previously in startOutgoingCall due to it being a potential MMI 459 // code, so add it now. 460 addCall(call); 461 } 462 463 // The call's ConnectionService has been updated. 464 for (CallsManagerListener listener : mListeners) { 465 listener.onConnectionServiceChanged(call, null, call.getConnectionService()); 466 } 467 468 markCallAsDialing(call); 469 } 470 471 @Override 472 public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) { 473 Log.v(this, "onFailedOutgoingCall, call: %s", call); 474 475 markCallAsRemoved(call); 476 } 477 478 @Override 479 public void onSuccessfulIncomingCall(Call incomingCall) { 480 Log.d(this, "onSuccessfulIncomingCall"); 481 if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) { 482 Log.i(this, "Skipping call filtering due to ECBM"); 483 onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true)); 484 return; 485 } 486 487 List<IncomingCallFilter.CallFilter> filters = new ArrayList<>(); 488 filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper)); 489 filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter())); 490 filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar, 491 mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock)); 492 new IncomingCallFilter(mContext, this, incomingCall, mLock, 493 mTimeoutsAdapter, filters).performFiltering(); 494 } 495 496 @Override 497 public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) { 498 // Only set the incoming call as ringing if it isn't already disconnected. It is possible 499 // that the connection service disconnected the call before it was even added to Telecom, in 500 // which case it makes no sense to set it back to a ringing state. 501 if (incomingCall.getState() != CallState.DISCONNECTED && 502 incomingCall.getState() != CallState.DISCONNECTING) { 503 setCallState(incomingCall, CallState.RINGING, 504 result.shouldAllowCall ? "successful incoming call" : "blocking call"); 505 } else { 506 Log.i(this, "onCallFilteringCompleted: call already disconnected."); 507 return; 508 } 509 510 if (result.shouldAllowCall) { 511 if (hasMaximumManagedRingingCalls(incomingCall)) { 512 if (shouldSilenceInsteadOfReject(incomingCall)) { 513 incomingCall.silence(); 514 } else { 515 Log.i(this, "onCallFilteringCompleted: Call rejected! " + 516 "Exceeds maximum number of ringing calls."); 517 rejectCallAndLog(incomingCall); 518 } 519 } else if (hasMaximumManagedDialingCalls(incomingCall)) { 520 Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + 521 "dialing calls."); 522 rejectCallAndLog(incomingCall); 523 } else { 524 addCall(incomingCall); 525 } 526 } else { 527 if (result.shouldReject) { 528 Log.i(this, "onCallFilteringCompleted: blocked call, rejecting."); 529 incomingCall.reject(false, null); 530 } 531 if (result.shouldAddToCallLog) { 532 Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log."); 533 if (result.shouldShowNotification) { 534 Log.w(this, "onCallScreeningCompleted: blocked call, showing notification."); 535 } 536 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, 537 result.shouldShowNotification); 538 } else if (result.shouldShowNotification) { 539 Log.i(this, "onCallScreeningCompleted: blocked call, showing notification."); 540 mMissedCallNotifier.showMissedCallNotification( 541 new MissedCallNotifier.CallInfo(incomingCall)); 542 } 543 } 544 } 545 546 /** 547 * Whether allow (silence rather than reject) the incoming call if it has a different source 548 * (connection service) from the existing ringing call when reaching maximum ringing calls. 549 */ 550 private boolean shouldSilenceInsteadOfReject(Call incomingCall) { 551 if (!mContext.getResources().getBoolean( 552 R.bool.silence_incoming_when_different_service_and_maximum_ringing)) { 553 return false; 554 } 555 556 Call ringingCall = null; 557 558 for (Call call : mCalls) { 559 // Only operate on top-level calls 560 if (call.getParentCall() != null) { 561 continue; 562 } 563 564 if (call.isExternalCall()) { 565 continue; 566 } 567 568 if (CallState.RINGING == call.getState() && 569 call.getConnectionService() == incomingCall.getConnectionService()) { 570 return false; 571 } 572 } 573 574 return true; 575 } 576 577 @Override 578 public void onFailedIncomingCall(Call call) { 579 setCallState(call, CallState.DISCONNECTED, "failed incoming call"); 580 call.removeListener(this); 581 } 582 583 @Override 584 public void onSuccessfulUnknownCall(Call call, int callState) { 585 setCallState(call, callState, "successful unknown call"); 586 Log.i(this, "onSuccessfulUnknownCall for call %s", call); 587 addCall(call); 588 } 589 590 @Override 591 public void onFailedUnknownCall(Call call) { 592 Log.i(this, "onFailedUnknownCall for call %s", call); 593 setCallState(call, CallState.DISCONNECTED, "failed unknown call"); 594 call.removeListener(this); 595 } 596 597 @Override 598 public void onRingbackRequested(Call call, boolean ringback) { 599 for (CallsManagerListener listener : mListeners) { 600 listener.onRingbackRequested(call, ringback); 601 } 602 } 603 604 @Override 605 public void onPostDialWait(Call call, String remaining) { 606 mInCallController.onPostDialWait(call, remaining); 607 } 608 609 @Override 610 public void onPostDialChar(final Call call, char nextChar) { 611 if (PhoneNumberUtils.is12Key(nextChar)) { 612 // Play tone if it is one of the dialpad digits, canceling out the previously queued 613 // up stopTone runnable since playing a new tone automatically stops the previous tone. 614 if (mStopTone != null) { 615 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 616 mStopTone.cancel(); 617 } 618 619 mDtmfLocalTonePlayer.playTone(call, nextChar); 620 621 mStopTone = new Runnable("CM.oPDC", mLock) { 622 @Override 623 public void loggedRun() { 624 // Set a timeout to stop the tone in case there isn't another tone to 625 // follow. 626 mDtmfLocalTonePlayer.stopTone(call); 627 } 628 }; 629 mHandler.postDelayed(mStopTone.prepare(), 630 Timeouts.getDelayBetweenDtmfTonesMillis(mContext.getContentResolver())); 631 } else if (nextChar == 0 || nextChar == TelecomManager.DTMF_CHARACTER_WAIT || 632 nextChar == TelecomManager.DTMF_CHARACTER_PAUSE) { 633 // Stop the tone if a tone is playing, removing any other stopTone callbacks since 634 // the previous tone is being stopped anyway. 635 if (mStopTone != null) { 636 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 637 mStopTone.cancel(); 638 } 639 mDtmfLocalTonePlayer.stopTone(call); 640 } else { 641 Log.w(this, "onPostDialChar: invalid value %d", nextChar); 642 } 643 } 644 645 @Override 646 public void onParentChanged(Call call) { 647 // parent-child relationship affects which call should be foreground, so do an update. 648 updateCanAddCall(); 649 for (CallsManagerListener listener : mListeners) { 650 listener.onIsConferencedChanged(call); 651 } 652 } 653 654 @Override 655 public void onChildrenChanged(Call call) { 656 // parent-child relationship affects which call should be foreground, so do an update. 657 updateCanAddCall(); 658 for (CallsManagerListener listener : mListeners) { 659 listener.onIsConferencedChanged(call); 660 } 661 } 662 663 @Override 664 public void onIsVoipAudioModeChanged(Call call) { 665 for (CallsManagerListener listener : mListeners) { 666 listener.onIsVoipAudioModeChanged(call); 667 } 668 } 669 670 @Override 671 public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) { 672 for (CallsManagerListener listener : mListeners) { 673 listener.onVideoStateChanged(call, previousVideoState, newVideoState); 674 } 675 } 676 677 @Override 678 public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call, 679 long disconnectionTimeout) { 680 mPendingCallsToDisconnect.add(call); 681 mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) { 682 @Override 683 public void loggedRun() { 684 if (mPendingCallsToDisconnect.remove(call)) { 685 Log.i(this, "Delayed disconnection of call: %s", call); 686 call.disconnect(); 687 } 688 } 689 }.prepare(), disconnectionTimeout); 690 691 return true; 692 } 693 694 /** 695 * Handles changes to the {@link Connection.VideoProvider} for a call. Adds the 696 * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created 697 * in {@link Call#setVideoProvider(IVideoProvider)}. This allows the {@link CallsManager} to 698 * respond to callbacks from the {@link VideoProviderProxy}. 699 * 700 * @param call The call. 701 */ 702 @Override 703 public void onVideoCallProviderChanged(Call call) { 704 VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy(); 705 706 if (videoProviderProxy == null) { 707 return; 708 } 709 710 videoProviderProxy.addListener(this); 711 } 712 713 /** 714 * Handles session modification requests received via the {@link TelecomVideoCallCallback} for 715 * a call. Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session 716 * modification request. 717 * 718 * @param call The call. 719 * @param videoProfile The {@link VideoProfile}. 720 */ 721 @Override 722 public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) { 723 int videoState = videoProfile != null ? videoProfile.getVideoState() : 724 VideoProfile.STATE_AUDIO_ONLY; 725 Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile 726 .videoStateToString(videoState)); 727 728 for (CallsManagerListener listener : mListeners) { 729 listener.onSessionModifyRequestReceived(call, videoProfile); 730 } 731 } 732 733 public Collection<Call> getCalls() { 734 return Collections.unmodifiableCollection(mCalls); 735 } 736 737 /** 738 * Play or stop a call hold tone for a call. Triggered via 739 * {@link Connection#sendConnectionEvent(String)} when the 740 * {@link Connection#EVENT_ON_HOLD_TONE_START} event or 741 * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the 742 * 743 * @param call The call which requested the hold tone. 744 */ 745 @Override 746 public void onHoldToneRequested(Call call) { 747 for (CallsManagerListener listener : mListeners) { 748 listener.onHoldToneRequested(call); 749 } 750 } 751 752 /** 753 * A {@link Call} managed by the {@link CallsManager} has requested a handover to another 754 * {@link PhoneAccount}. 755 * @param call The call. 756 * @param handoverTo The {@link PhoneAccountHandle} to handover the call to. 757 * @param videoState The desired video state of the call after handover. 758 * @param extras 759 */ 760 @Override 761 public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState, 762 Bundle extras, boolean isLegacy) { 763 if (isLegacy) { 764 requestHandoverViaEvents(call, handoverTo, videoState, extras); 765 } else { 766 requestHandover(call, handoverTo, videoState, extras); 767 } 768 } 769 770 @VisibleForTesting 771 public Call getForegroundCall() { 772 if (mCallAudioManager == null) { 773 // Happens when getForegroundCall is called before full initialization. 774 return null; 775 } 776 return mCallAudioManager.getForegroundCall(); 777 } 778 779 @Override 780 public UserHandle getCurrentUserHandle() { 781 return mCurrentUserHandle; 782 } 783 784 public CallAudioManager getCallAudioManager() { 785 return mCallAudioManager; 786 } 787 788 InCallController getInCallController() { 789 return mInCallController; 790 } 791 792 EmergencyCallHelper getEmergencyCallHelper() { 793 return mEmergencyCallHelper; 794 } 795 796 @VisibleForTesting 797 public boolean hasEmergencyCall() { 798 for (Call call : mCalls) { 799 if (call.isEmergencyCall()) { 800 return true; 801 } 802 } 803 return false; 804 } 805 806 @VisibleForTesting 807 public boolean hasOnlyDisconnectedCalls() { 808 if (mCalls.size() == 0) { 809 return false; 810 } 811 for (Call call : mCalls) { 812 if (!call.isDisconnected()) { 813 return false; 814 } 815 } 816 return true; 817 } 818 819 public boolean hasVideoCall() { 820 for (Call call : mCalls) { 821 if (VideoProfile.isVideo(call.getVideoState())) { 822 return true; 823 } 824 } 825 return false; 826 } 827 828 @VisibleForTesting 829 public CallAudioState getAudioState() { 830 return mCallAudioManager.getCallAudioState(); 831 } 832 833 boolean isTtySupported() { 834 return mTtyManager.isTtySupported(); 835 } 836 837 int getCurrentTtyMode() { 838 return mTtyManager.getCurrentTtyMode(); 839 } 840 841 @VisibleForTesting 842 public void addListener(CallsManagerListener listener) { 843 mListeners.add(listener); 844 } 845 846 void removeListener(CallsManagerListener listener) { 847 mListeners.remove(listener); 848 } 849 850 /** 851 * Starts the process to attach the call to a connection service. 852 * 853 * @param phoneAccountHandle The phone account which contains the component name of the 854 * connection service to use for this call. 855 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 856 */ 857 void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 858 Log.d(this, "processIncomingCallIntent"); 859 boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER); 860 Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); 861 if (handle == null) { 862 // Required for backwards compatibility 863 handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER); 864 } 865 Call call = new Call( 866 getNextCallId(), 867 mContext, 868 this, 869 mLock, 870 mConnectionServiceRepository, 871 mContactsAsyncHelper, 872 mCallerInfoAsyncQueryFactory, 873 mPhoneNumberUtilsAdapter, 874 handle, 875 null /* gatewayInfo */, 876 null /* connectionManagerPhoneAccount */, 877 phoneAccountHandle, 878 Call.CALL_DIRECTION_INCOMING /* callDirection */, 879 false /* forceAttachToExistingConnection */, 880 false, /* isConference */ 881 mClockProxy); 882 883 // Ensure new calls related to self-managed calls/connections are set as such. This will 884 // be overridden when the actual connection is returned in startCreateConnection, however 885 // doing this now ensures the logs and any other logic will treat this call as self-managed 886 // from the moment it is created. 887 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 888 phoneAccountHandle); 889 if (phoneAccount != null) { 890 call.setIsSelfManaged(phoneAccount.isSelfManaged()); 891 if (call.isSelfManaged()) { 892 // Self managed calls will always be voip audio mode. 893 call.setIsVoipAudioMode(true); 894 } else { 895 // Incoming call is managed, the active call is self-managed and can't be held. 896 // We need to set extras on it to indicate whether answering will cause a 897 // active self-managed call to drop. 898 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 899 if (activeCall != null && !canHold(activeCall) && activeCall.isSelfManaged()) { 900 Bundle dropCallExtras = new Bundle(); 901 dropCallExtras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true); 902 903 // Include the name of the app which will drop the call. 904 CharSequence droppedApp = activeCall.getTargetPhoneAccountLabel(); 905 dropCallExtras.putCharSequence( 906 Connection.EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME, droppedApp); 907 Log.i(this, "Incoming managed call will drop %s call.", droppedApp); 908 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, dropCallExtras); 909 } 910 } 911 912 if (extras.getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 913 Log.d(this, "processIncomingCallIntent: defaulting to voip mode for call %s", 914 call.getId()); 915 call.setIsVoipAudioMode(true); 916 } 917 } 918 if (isRttSettingOn() || 919 extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) { 920 Log.d(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn()); 921 if (phoneAccount != null && 922 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) { 923 call.setRttStreams(true); 924 } 925 // Even if the phone account doesn't support RTT yet, the connection manager might 926 // change that. Set this to check it later. 927 call.setRequestedToStartWithRtt(); 928 } 929 // If the extras specifies a video state, set it on the call if the PhoneAccount supports 930 // video. 931 int videoState = VideoProfile.STATE_AUDIO_ONLY; 932 if (extras.containsKey(TelecomManager.EXTRA_INCOMING_VIDEO_STATE) && 933 phoneAccount != null && phoneAccount.hasCapabilities( 934 PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 935 videoState = extras.getInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE); 936 call.setVideoState(videoState); 937 } 938 939 call.initAnalytics(); 940 if (getForegroundCall() != null) { 941 getForegroundCall().getAnalytics().setCallIsInterrupted(true); 942 call.getAnalytics().setCallIsAdditional(true); 943 } 944 setIntentExtrasAndStartTime(call, extras); 945 // TODO: Move this to be a part of addCall() 946 call.addListener(this); 947 948 boolean isHandoverAllowed = true; 949 if (isHandover) { 950 if (!isHandoverInProgress() && 951 isHandoverToPhoneAccountSupported(phoneAccountHandle)) { 952 final String handleScheme = handle.getSchemeSpecificPart(); 953 Call fromCall = mCalls.stream() 954 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 955 c.getHandle().getSchemeSpecificPart(), handleScheme)) 956 .findFirst() 957 .orElse(null); 958 if (fromCall != null) { 959 if (!isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount())) { 960 Log.w(this, "processIncomingCallIntent: From account doesn't support " + 961 "handover."); 962 isHandoverAllowed = false; 963 } 964 } else { 965 Log.w(this, "processIncomingCallIntent: handover fail; can't find from call."); 966 isHandoverAllowed = false; 967 } 968 969 if (isHandoverAllowed) { 970 // Link the calls so we know we're handing over. 971 fromCall.setHandoverDestinationCall(call); 972 call.setHandoverSourceCall(fromCall); 973 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 974 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 975 Log.addEvent(fromCall, LogUtils.Events.START_HANDOVER, 976 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 977 Log.addEvent(call, LogUtils.Events.START_HANDOVER, 978 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 979 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 980 // Ensure when the call goes active that it will go to speakerphone if the 981 // handover to call is a video call. 982 call.setStartWithSpeakerphoneOn(true); 983 } 984 } 985 } else { 986 Log.w(this, "processIncomingCallIntent: To account doesn't support handover."); 987 } 988 } 989 990 if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call, 991 call.getTargetPhoneAccount()))) { 992 notifyCreateConnectionFailed(phoneAccountHandle, call); 993 } else { 994 call.startCreateConnection(mPhoneAccountRegistrar); 995 } 996 } 997 998 void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 999 Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE); 1000 Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle)); 1001 Call call = new Call( 1002 getNextCallId(), 1003 mContext, 1004 this, 1005 mLock, 1006 mConnectionServiceRepository, 1007 mContactsAsyncHelper, 1008 mCallerInfoAsyncQueryFactory, 1009 mPhoneNumberUtilsAdapter, 1010 handle, 1011 null /* gatewayInfo */, 1012 null /* connectionManagerPhoneAccount */, 1013 phoneAccountHandle, 1014 Call.CALL_DIRECTION_UNKNOWN /* callDirection */, 1015 // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach 1016 // to the existing connection instead of trying to create a new one. 1017 true /* forceAttachToExistingConnection */, 1018 false, /* isConference */ 1019 mClockProxy); 1020 call.initAnalytics(); 1021 1022 setIntentExtrasAndStartTime(call, extras); 1023 call.addListener(this); 1024 call.startCreateConnection(mPhoneAccountRegistrar); 1025 } 1026 1027 private boolean areHandlesEqual(Uri handle1, Uri handle2) { 1028 if (handle1 == null || handle2 == null) { 1029 return handle1 == handle2; 1030 } 1031 1032 if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) { 1033 return false; 1034 } 1035 1036 final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart()); 1037 final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart()); 1038 return TextUtils.equals(number1, number2); 1039 } 1040 1041 private Call reuseOutgoingCall(Uri handle) { 1042 // Check to see if we can reuse any of the calls that are waiting to disconnect. 1043 // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information. 1044 Call reusedCall = null; 1045 for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) { 1046 Call pendingCall = callIter.next(); 1047 if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) { 1048 callIter.remove(); 1049 Log.i(this, "Reusing disconnected call %s", pendingCall); 1050 reusedCall = pendingCall; 1051 } else { 1052 Log.i(this, "Not reusing disconnected call %s", pendingCall); 1053 callIter.remove(); 1054 pendingCall.disconnect(); 1055 } 1056 } 1057 1058 return reusedCall; 1059 } 1060 1061 /** 1062 * Kicks off the first steps to creating an outgoing call. 1063 * 1064 * For managed connections, this is the first step to launching the Incall UI. 1065 * For self-managed connections, we don't expect the Incall UI to launch, but this is still a 1066 * first step in getting the self-managed ConnectionService to create the connection. 1067 * @param handle Handle to connect the call with. 1068 * @param phoneAccountHandle The phone account which contains the component name of the 1069 * connection service to use for this call. 1070 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 1071 * @param initiatingUser {@link UserHandle} of user that place the outgoing call. 1072 * @param originalIntent 1073 */ 1074 @VisibleForTesting 1075 public Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras, 1076 UserHandle initiatingUser, Intent originalIntent) { 1077 boolean isReusedCall = true; 1078 Call call = reuseOutgoingCall(handle); 1079 1080 PhoneAccount account = 1081 mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser); 1082 boolean isSelfManaged = account != null && account.isSelfManaged(); 1083 1084 // Create a call with original handle. The handle may be changed when the call is attached 1085 // to a connection service, but in most cases will remain the same. 1086 if (call == null) { 1087 call = new Call(getNextCallId(), mContext, 1088 this, 1089 mLock, 1090 mConnectionServiceRepository, 1091 mContactsAsyncHelper, 1092 mCallerInfoAsyncQueryFactory, 1093 mPhoneNumberUtilsAdapter, 1094 handle, 1095 null /* gatewayInfo */, 1096 null /* connectionManagerPhoneAccount */, 1097 null /* phoneAccountHandle */, 1098 Call.CALL_DIRECTION_OUTGOING /* callDirection */, 1099 false /* forceAttachToExistingConnection */, 1100 false, /* isConference */ 1101 mClockProxy); 1102 call.initAnalytics(); 1103 1104 // Ensure new calls related to self-managed calls/connections are set as such. This 1105 // will be overridden when the actual connection is returned in startCreateConnection, 1106 // however doing this now ensures the logs and any other logic will treat this call as 1107 // self-managed from the moment it is created. 1108 call.setIsSelfManaged(isSelfManaged); 1109 if (isSelfManaged) { 1110 // Self-managed calls will ALWAYS use voip audio mode. 1111 call.setIsVoipAudioMode(true); 1112 } 1113 call.setInitiatingUser(initiatingUser); 1114 isReusedCall = false; 1115 } 1116 1117 int videoState = VideoProfile.STATE_AUDIO_ONLY; 1118 if (extras != null) { 1119 // Set the video state on the call early so that when it is added to the InCall UI the 1120 // UI knows to configure itself as a video call immediately. 1121 videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 1122 VideoProfile.STATE_AUDIO_ONLY); 1123 1124 // If this is an emergency video call, we need to check if the phone account supports 1125 // emergency video calling. 1126 // Also, ensure we don't try to place an outgoing call with video if video is not 1127 // supported. 1128 if (VideoProfile.isVideo(videoState)) { 1129 if (call.isEmergencyCall() && account != null && 1130 !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) { 1131 // Phone account doesn't support emergency video calling, so fallback to 1132 // audio-only now to prevent the InCall UI from setting up video surfaces 1133 // needlessly. 1134 Log.i(this, "startOutgoingCall - emergency video calls not supported; " + 1135 "falling back to audio-only"); 1136 videoState = VideoProfile.STATE_AUDIO_ONLY; 1137 } else if (account != null && 1138 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 1139 // Phone account doesn't support video calling, so fallback to audio-only. 1140 Log.i(this, "startOutgoingCall - video calls not supported; fallback to " + 1141 "audio-only."); 1142 videoState = VideoProfile.STATE_AUDIO_ONLY; 1143 } 1144 } 1145 1146 call.setVideoState(videoState); 1147 } 1148 1149 List<PhoneAccountHandle> potentialPhoneAccounts = findOutgoingCallPhoneAccount( 1150 phoneAccountHandle, handle, VideoProfile.isVideo(videoState), initiatingUser); 1151 if (potentialPhoneAccounts.size() == 1) { 1152 phoneAccountHandle = potentialPhoneAccounts.get(0); 1153 } else { 1154 phoneAccountHandle = null; 1155 } 1156 call.setTargetPhoneAccount(phoneAccountHandle); 1157 1158 boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle) && !isSelfManaged; 1159 1160 // Do not support any more live calls. Our options are to move a call to hold, disconnect 1161 // a call, or cancel this call altogether. If a call is being reused, then it has already 1162 // passed the makeRoomForOutgoingCall check once and will fail the second time due to the 1163 // call transitioning into the CONNECTING state. 1164 if (!isPotentialInCallMMICode && (!isReusedCall 1165 && !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) { 1166 Call foregroundCall = getForegroundCall(); 1167 Log.d(this, "No more room for outgoing call %s ", call); 1168 if (foregroundCall.isSelfManaged()) { 1169 // If the ongoing call is a self-managed call, then prompt the user to ask if they'd 1170 // like to disconnect their ongoing call and place the outgoing call. 1171 call.setOriginalCallIntent(originalIntent); 1172 startCallConfirmation(call); 1173 } else { 1174 // If the ongoing call is a managed call, we will prevent the outgoing call from 1175 // dialing. 1176 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 1177 } 1178 return null; 1179 } 1180 1181 // The outgoing call can be placed, go forward. 1182 1183 boolean needsAccountSelection = 1184 phoneAccountHandle == null && potentialPhoneAccounts.size() > 1 1185 && !call.isEmergencyCall() && !isSelfManaged; 1186 if (needsAccountSelection) { 1187 // This is the state where the user is expected to select an account 1188 call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection"); 1189 // Create our own instance to modify (since extras may be Bundle.EMPTY) 1190 extras = new Bundle(extras); 1191 extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, 1192 potentialPhoneAccounts); 1193 } else { 1194 PhoneAccount accountToUse = 1195 mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser); 1196 if (accountToUse != null && accountToUse.getExtras() != null) { 1197 if (accountToUse.getExtras() 1198 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 1199 Log.d(this, "startOutgoingCall: defaulting to voip mode for call %s", 1200 call.getId()); 1201 call.setIsVoipAudioMode(true); 1202 } 1203 } 1204 1205 call.setState( 1206 CallState.CONNECTING, 1207 phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString()); 1208 1209 if (isRttSettingOn() || (extras != null 1210 && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false))) { 1211 Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", isRttSettingOn()); 1212 if (accountToUse != null 1213 && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) { 1214 call.setRttStreams(true); 1215 } 1216 // Even if the phone account doesn't support RTT yet, the connection manager might 1217 // change that. Set this to check it later. 1218 call.setRequestedToStartWithRtt(); 1219 } 1220 } 1221 setIntentExtrasAndStartTime(call, extras); 1222 1223 if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) { 1224 // Do not add the call if it is a potential MMI code. 1225 call.addListener(this); 1226 } else if (!mCalls.contains(call)) { 1227 // We check if mCalls already contains the call because we could potentially be reusing 1228 // a call which was previously added (See {@link #reuseOutgoingCall}). 1229 addCall(call); 1230 } 1231 1232 return call; 1233 } 1234 1235 /** 1236 * Finds the {@link PhoneAccountHandle}(s) which could potentially be used to place an outgoing 1237 * call. Takes into account the following: 1238 * 1. Any pre-chosen {@link PhoneAccountHandle} which was specified on the 1239 * {@link Intent#ACTION_CALL} intent. If one was chosen it will be used if possible. 1240 * 2. Whether the call is a video call. If the call being placed is a video call, an attempt is 1241 * first made to consider video capable phone accounts. If no video capable phone accounts are 1242 * found, the usual non-video capable phone accounts will be considered. 1243 * 3. Whether there is a user-chosen default phone account; that one will be used if possible. 1244 * 1245 * @param targetPhoneAccountHandle The pre-chosen {@link PhoneAccountHandle} passed in when the 1246 * call was placed. Will be {@code null} if the 1247 * {@link Intent#ACTION_CALL} intent did not specify a target 1248 * phone account. 1249 * @param handle The handle of the outgoing call; used to determine the SIP scheme when matching 1250 * phone accounts. 1251 * @param isVideo {@code true} if the call is a video call, {@code false} otherwise. 1252 * @param initiatingUser The {@link UserHandle} the call is placed on. 1253 * @return 1254 */ 1255 @VisibleForTesting 1256 public List<PhoneAccountHandle> findOutgoingCallPhoneAccount( 1257 PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, 1258 UserHandle initiatingUser) { 1259 boolean isSelfManaged = isSelfManaged(targetPhoneAccountHandle, initiatingUser); 1260 1261 List<PhoneAccountHandle> accounts; 1262 if (!isSelfManaged) { 1263 // Try to find a potential phone account, taking into account whether this is a video 1264 // call. 1265 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo); 1266 if (isVideo && accounts.size() == 0) { 1267 // Placing a video call but no video capable accounts were found, so consider any 1268 // call capable accounts (we can fallback to audio). 1269 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, 1270 false /* isVideo */); 1271 } 1272 Log.v(this, "findOutgoingCallPhoneAccount: accounts = " + accounts); 1273 1274 // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this 1275 // call as if a phoneAccount was not specified (does the default behavior instead). 1276 // Note: We will not attempt to dial with a requested phoneAccount if it is disabled. 1277 if (targetPhoneAccountHandle != null) { 1278 if (!accounts.contains(targetPhoneAccountHandle)) { 1279 targetPhoneAccountHandle = null; 1280 } else { 1281 // The target phone account is valid and was found. 1282 return Arrays.asList(targetPhoneAccountHandle); 1283 } 1284 } 1285 1286 if (targetPhoneAccountHandle == null && accounts.size() > 0) { 1287 // No preset account, check if default exists that supports the URI scheme for the 1288 // handle and verify it can be used. 1289 if (accounts.size() > 1) { 1290 PhoneAccountHandle defaultPhoneAccountHandle = 1291 mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme( 1292 handle.getScheme(), initiatingUser); 1293 if (defaultPhoneAccountHandle != null && 1294 accounts.contains(defaultPhoneAccountHandle)) { 1295 accounts.clear(); 1296 accounts.add(defaultPhoneAccountHandle); 1297 } 1298 } 1299 } 1300 } else { 1301 // Self-managed ConnectionServices can only have a single potential account. 1302 accounts = Arrays.asList(targetPhoneAccountHandle); 1303 } 1304 return accounts; 1305 } 1306 1307 /** 1308 * Determines if a {@link PhoneAccountHandle} is for a self-managed ConnectionService. 1309 * @param targetPhoneAccountHandle The phone account to check. 1310 * @param initiatingUser The user associated with the account. 1311 * @return {@code true} if the phone account is self-managed, {@code false} otherwise. 1312 */ 1313 public boolean isSelfManaged(PhoneAccountHandle targetPhoneAccountHandle, 1314 UserHandle initiatingUser) { 1315 PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount( 1316 targetPhoneAccountHandle, initiatingUser); 1317 return targetPhoneAccount != null && targetPhoneAccount.isSelfManaged(); 1318 } 1319 1320 /** 1321 * Attempts to issue/connect the specified call. 1322 * 1323 * @param handle Handle to connect the call with. 1324 * @param gatewayInfo Optional gateway information that can be used to route the call to the 1325 * actual dialed handle via a gateway provider. May be null. 1326 * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects. 1327 * @param videoState The desired video state for the outgoing call. 1328 */ 1329 @VisibleForTesting 1330 public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, 1331 boolean speakerphoneOn, int videoState) { 1332 if (call == null) { 1333 // don't do anything if the call no longer exists 1334 Log.i(this, "Canceling unknown call."); 1335 return; 1336 } 1337 1338 final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress(); 1339 1340 if (gatewayInfo == null) { 1341 Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle)); 1342 } else { 1343 Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s", 1344 Log.pii(uriHandle), Log.pii(handle)); 1345 } 1346 1347 call.setHandle(uriHandle); 1348 call.setGatewayInfo(gatewayInfo); 1349 1350 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 1351 R.bool.use_speaker_when_docked); 1352 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 1353 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 1354 1355 // Auto-enable speakerphone if the originating intent specified to do so, if the call 1356 // is a video call, of if using speaker when docked 1357 call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall 1358 || (useSpeakerWhenDocked && useSpeakerForDock)); 1359 call.setVideoState(videoState); 1360 1361 if (speakerphoneOn) { 1362 Log.i(this, "%s Starting with speakerphone as requested", call); 1363 } else if (useSpeakerWhenDocked && useSpeakerForDock) { 1364 Log.i(this, "%s Starting with speakerphone because car is docked.", call); 1365 } else if (useSpeakerForVideoCall) { 1366 Log.i(this, "%s Starting with speakerphone because its a video call.", call); 1367 } 1368 1369 if (call.isEmergencyCall()) { 1370 new AsyncEmergencyContactNotifier(mContext).execute(); 1371 } 1372 1373 final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean( 1374 com.android.internal.R.bool.config_requireCallCapableAccountForHandle); 1375 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 1376 call.getTargetPhoneAccount()); 1377 if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { 1378 // If the account has been set, proceed to place the outgoing call. 1379 // Otherwise the connection will be initiated when the account is set by the user. 1380 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 1381 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 1382 } else { 1383 if (call.isEmergencyCall()) { 1384 // Disconnect calls from other ConnectionServices other than the one the 1385 // emergency call targets. 1386 // Except, do not disconnect calls from the Connection Manager's 1387 // ConnectionService. 1388 disconnectCallsHaveDifferentConnectionService(call); 1389 } 1390 1391 call.startCreateConnection(mPhoneAccountRegistrar); 1392 } 1393 } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts( 1394 requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false, 1395 call.getInitiatingUser()).isEmpty()) { 1396 // If there are no call capable accounts, disconnect the call. 1397 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED, 1398 "No registered PhoneAccounts")); 1399 markCallAsRemoved(call); 1400 } 1401 } 1402 1403 /** 1404 * Attempts to start a conference call for the specified call. 1405 * 1406 * @param call The call to conference. 1407 * @param otherCall The other call to conference with. 1408 */ 1409 @VisibleForTesting 1410 public void conference(Call call, Call otherCall) { 1411 call.conferenceWith(otherCall); 1412 } 1413 1414 /** 1415 * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call 1416 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 1417 * the user opting to answer said call. 1418 * 1419 * @param call The call to answer. 1420 * @param videoState The video state in which to answer the call. 1421 */ 1422 @VisibleForTesting 1423 public void answerCall(Call call, int videoState) { 1424 if (!mCalls.contains(call)) { 1425 Log.i(this, "Request to answer a non-existent call %s", call); 1426 } else { 1427 // Hold or disconnect the active call and request call focus for the incoming call. 1428 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 1429 Log.d(this, "Incoming call = %s Ongoing call %s", call, activeCall); 1430 if (activeCall != null && activeCall != call) { 1431 // Hold the telephony call even if it doesn't have the hold capability. 1432 if (canHold(activeCall)) { 1433 Log.d(this, "Answer %s, hold %s", call, activeCall); 1434 activeCall.hold(); 1435 } else { 1436 // This call does not support hold. If it is from a different connection 1437 // service, then disconnect it, otherwise allow the connection service to 1438 // figure out the right states. 1439 if (activeCall.getConnectionService() != call.getConnectionService()) { 1440 activeCall.disconnect(); 1441 } 1442 } 1443 } 1444 1445 mConnectionSvrFocusMgr.requestFocus( 1446 call, 1447 new RequestCallback(new ActionAnswerCall(call, videoState))); 1448 } 1449 } 1450 1451 /** 1452 * Instructs Telecom to deflect the specified call. Intended to be invoked by the in-call 1453 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 1454 * the user opting to deflect said call. 1455 */ 1456 @VisibleForTesting 1457 public void deflectCall(Call call, Uri address) { 1458 if (!mCalls.contains(call)) { 1459 Log.i(this, "Request to deflect a non-existent call %s", call); 1460 } else { 1461 call.deflect(address); 1462 } 1463 } 1464 1465 /** 1466 * Determines if the speakerphone should be automatically enabled for the call. Speakerphone 1467 * should be enabled if the call is a video call and bluetooth or the wired headset are not in 1468 * use. 1469 * 1470 * @param videoState The video state of the call. 1471 * @return {@code true} if the speakerphone should be enabled. 1472 */ 1473 public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) { 1474 return VideoProfile.isVideo(videoState) && 1475 !mWiredHeadsetManager.isPluggedIn() && 1476 !mBluetoothRouteManager.isBluetoothAvailable() && 1477 isSpeakerEnabledForVideoCalls(); 1478 } 1479 1480 /** 1481 * Determines if the speakerphone should be enabled for when docked. Speakerphone 1482 * should be enabled if the device is docked and bluetooth or the wired headset are 1483 * not in use. 1484 * 1485 * @return {@code true} if the speakerphone should be enabled for the dock. 1486 */ 1487 private boolean isSpeakerphoneEnabledForDock() { 1488 return mDockManager.isDocked() && 1489 !mWiredHeadsetManager.isPluggedIn() && 1490 !mBluetoothRouteManager.isBluetoothAvailable(); 1491 } 1492 1493 /** 1494 * Determines if the speakerphone should be automatically enabled for video calls. 1495 * 1496 * @return {@code true} if the speakerphone should automatically be enabled. 1497 */ 1498 private static boolean isSpeakerEnabledForVideoCalls() { 1499 return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT, 1500 PhoneConstants.AUDIO_OUTPUT_DEFAULT) == 1501 PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER); 1502 } 1503 1504 /** 1505 * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call 1506 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 1507 * the user opting to reject said call. 1508 */ 1509 @VisibleForTesting 1510 public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) { 1511 if (!mCalls.contains(call)) { 1512 Log.i(this, "Request to reject a non-existent call %s", call); 1513 } else { 1514 for (CallsManagerListener listener : mListeners) { 1515 listener.onIncomingCallRejected(call, rejectWithMessage, textMessage); 1516 } 1517 call.reject(rejectWithMessage, textMessage); 1518 } 1519 } 1520 1521 /** 1522 * Instructs Telecom to play the specified DTMF tone within the specified call. 1523 * 1524 * @param digit The DTMF digit to play. 1525 */ 1526 @VisibleForTesting 1527 public void playDtmfTone(Call call, char digit) { 1528 if (!mCalls.contains(call)) { 1529 Log.i(this, "Request to play DTMF in a non-existent call %s", call); 1530 } else { 1531 if (call.getState() != CallState.ON_HOLD) { 1532 call.playDtmfTone(digit); 1533 mDtmfLocalTonePlayer.playTone(call, digit); 1534 } else { 1535 Log.i(this, "Request to play DTMF tone for held call %s", call.getId()); 1536 } 1537 } 1538 } 1539 1540 /** 1541 * Instructs Telecom to stop the currently playing DTMF tone, if any. 1542 */ 1543 @VisibleForTesting 1544 public void stopDtmfTone(Call call) { 1545 if (!mCalls.contains(call)) { 1546 Log.i(this, "Request to stop DTMF in a non-existent call %s", call); 1547 } else { 1548 call.stopDtmfTone(); 1549 mDtmfLocalTonePlayer.stopTone(call); 1550 } 1551 } 1552 1553 /** 1554 * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any. 1555 */ 1556 void postDialContinue(Call call, boolean proceed) { 1557 if (!mCalls.contains(call)) { 1558 Log.i(this, "Request to continue post-dial string in a non-existent call %s", call); 1559 } else { 1560 call.postDialContinue(proceed); 1561 } 1562 } 1563 1564 /** 1565 * Instructs Telecom to disconnect the specified call. Intended to be invoked by the 1566 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 1567 * the user hitting the end-call button. 1568 */ 1569 @VisibleForTesting 1570 public void disconnectCall(Call call) { 1571 Log.v(this, "disconnectCall %s", call); 1572 1573 if (!mCalls.contains(call)) { 1574 Log.w(this, "Unknown call (%s) asked to disconnect", call); 1575 } else { 1576 mLocallyDisconnectingCalls.add(call); 1577 call.disconnect(); 1578 } 1579 } 1580 1581 /** 1582 * Instructs Telecom to disconnect all calls. 1583 */ 1584 void disconnectAllCalls() { 1585 Log.v(this, "disconnectAllCalls"); 1586 1587 for (Call call : mCalls) { 1588 disconnectCall(call); 1589 } 1590 } 1591 1592 /** 1593 * Disconnects calls for any other {@link PhoneAccountHandle} but the one specified. 1594 * Note: As a protective measure, will NEVER disconnect an emergency call. Although that 1595 * situation should never arise, its a good safeguard. 1596 * @param phoneAccountHandle Calls owned by {@link PhoneAccountHandle}s other than this one will 1597 * be disconnected. 1598 */ 1599 private void disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle) { 1600 mCalls.stream() 1601 .filter(c -> !c.isEmergencyCall() && 1602 !c.getTargetPhoneAccount().equals(phoneAccountHandle)) 1603 .forEach(c -> disconnectCall(c)); 1604 } 1605 1606 /** 1607 * Instructs Telecom to put the specified call on hold. Intended to be invoked by the 1608 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 1609 * the user hitting the hold button during an active call. 1610 */ 1611 @VisibleForTesting 1612 public void holdCall(Call call) { 1613 if (!mCalls.contains(call)) { 1614 Log.w(this, "Unknown call (%s) asked to be put on hold", call); 1615 } else { 1616 Log.d(this, "Putting call on hold: (%s)", call); 1617 call.hold(); 1618 } 1619 } 1620 1621 /** 1622 * Instructs Telecom to release the specified call from hold. Intended to be invoked by 1623 * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered 1624 * by the user hitting the hold button during a held call. 1625 */ 1626 @VisibleForTesting 1627 public void unholdCall(Call call) { 1628 if (!mCalls.contains(call)) { 1629 Log.w(this, "Unknown call (%s) asked to be removed from hold", call); 1630 } else { 1631 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 1632 if (activeCall != null) { 1633 if (canHold(activeCall)) { 1634 activeCall.hold(); 1635 Log.addEvent(activeCall, LogUtils.Events.SWAP); 1636 Log.addEvent(call, LogUtils.Events.SWAP); 1637 } else { 1638 // This call does not support hold. If it is from a different connection 1639 // service, then disconnect it, otherwise invoke call.hold() and allow the 1640 // connection service to handle the situation. 1641 if (activeCall.getConnectionService() != call.getConnectionService()) { 1642 activeCall.disconnect(); 1643 } else { 1644 activeCall.hold(); 1645 } 1646 } 1647 } 1648 mConnectionSvrFocusMgr.requestFocus( 1649 call, 1650 new RequestCallback(new ActionUnHoldCall(call))); 1651 } 1652 } 1653 1654 @Override 1655 public void onExtrasRemoved(Call c, int source, List<String> keys) { 1656 if (source != Call.SOURCE_CONNECTION_SERVICE) { 1657 return; 1658 } 1659 updateCanAddCall(); 1660 } 1661 1662 @Override 1663 public void onExtrasChanged(Call c, int source, Bundle extras) { 1664 if (source != Call.SOURCE_CONNECTION_SERVICE) { 1665 return; 1666 } 1667 handleCallTechnologyChange(c); 1668 handleChildAddressChange(c); 1669 updateCanAddCall(); 1670 } 1671 1672 // Construct the list of possible PhoneAccounts that the outgoing call can use based on the 1673 // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount, 1674 // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP. 1675 @VisibleForTesting 1676 public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, 1677 boolean isVideo) { 1678 if (handle == null) { 1679 return Collections.emptyList(); 1680 } 1681 // If we're specifically looking for video capable accounts, then include that capability, 1682 // otherwise specify no additional capability constraints. 1683 List<PhoneAccountHandle> allAccounts = 1684 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user, 1685 isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0 /* any */); 1686 // First check the Radio SIM Technology 1687 if(mRadioSimVariants == null) { 1688 TelephonyManager tm = (TelephonyManager) mContext.getSystemService( 1689 Context.TELEPHONY_SERVICE); 1690 // Cache Sim Variants 1691 mRadioSimVariants = tm.getMultiSimConfiguration(); 1692 } 1693 // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount 1694 // Should be available if a call is already active on the SIM account. 1695 if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) { 1696 List<PhoneAccountHandle> simAccounts = 1697 mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser(); 1698 PhoneAccountHandle ongoingCallAccount = null; 1699 for (Call c : mCalls) { 1700 if (!c.isDisconnected() && !c.isNew() && simAccounts.contains( 1701 c.getTargetPhoneAccount())) { 1702 ongoingCallAccount = c.getTargetPhoneAccount(); 1703 break; 1704 } 1705 } 1706 if (ongoingCallAccount != null) { 1707 // Remove all SIM accounts that are not the active SIM from the list. 1708 simAccounts.remove(ongoingCallAccount); 1709 allAccounts.removeAll(simAccounts); 1710 } 1711 } 1712 return allAccounts; 1713 } 1714 1715 /** 1716 * Informs listeners (notably {@link CallAudioManager} of a change to the call's external 1717 * property. 1718 * . 1719 * @param call The call whose external property changed. 1720 * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise. 1721 */ 1722 @Override 1723 public void onExternalCallChanged(Call call, boolean isExternalCall) { 1724 Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall); 1725 for (CallsManagerListener listener : mListeners) { 1726 listener.onExternalCallChanged(call, isExternalCall); 1727 } 1728 } 1729 1730 private void handleCallTechnologyChange(Call call) { 1731 if (call.getExtras() != null 1732 && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) { 1733 1734 Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get( 1735 call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)); 1736 if (analyticsCallTechnology == null) { 1737 analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE; 1738 } 1739 call.getAnalytics().addCallTechnology(analyticsCallTechnology); 1740 } 1741 } 1742 1743 public void handleChildAddressChange(Call call) { 1744 if (call.getExtras() != null 1745 && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) { 1746 1747 String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS); 1748 call.setViaNumber(viaNumber); 1749 } 1750 } 1751 1752 /** Called by the in-call UI to change the mute state. */ 1753 void mute(boolean shouldMute) { 1754 mCallAudioManager.mute(shouldMute); 1755 } 1756 1757 /** 1758 * Called by the in-call UI to change the audio route, for example to change from earpiece to 1759 * speaker phone. 1760 */ 1761 void setAudioRoute(int route, String bluetoothAddress) { 1762 mCallAudioManager.setAudioRoute(route, bluetoothAddress); 1763 } 1764 1765 /** Called by the in-call UI to turn the proximity sensor on. */ 1766 void turnOnProximitySensor() { 1767 mProximitySensorManager.turnOn(); 1768 } 1769 1770 /** 1771 * Called by the in-call UI to turn the proximity sensor off. 1772 * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise, 1773 * the screen will be kept off until the proximity sensor goes negative. 1774 */ 1775 void turnOffProximitySensor(boolean screenOnImmediately) { 1776 mProximitySensorManager.turnOff(screenOnImmediately); 1777 } 1778 1779 private boolean isRttSettingOn() { 1780 return Settings.System.getInt(mContext.getContentResolver(), 1781 Settings.System.RTT_CALLING_MODE, TelecomManager.TTY_MODE_OFF) 1782 != TelecomManager.TTY_MODE_OFF; 1783 } 1784 1785 void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) { 1786 if (!mCalls.contains(call)) { 1787 Log.i(this, "Attempted to add account to unknown call %s", call); 1788 } else { 1789 call.setTargetPhoneAccount(account); 1790 PhoneAccount realPhoneAccount = 1791 mPhoneAccountRegistrar.getPhoneAccountUnchecked(account); 1792 if (realPhoneAccount != null && realPhoneAccount.getExtras() != null 1793 && realPhoneAccount.getExtras() 1794 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 1795 Log.d("phoneAccountSelected: default to voip mode for call %s", call.getId()); 1796 call.setIsVoipAudioMode(true); 1797 } 1798 if (isRttSettingOn() || call.getIntentExtras() 1799 .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) { 1800 Log.d(this, "Outgoing call after account selection requesting RTT," + 1801 " rtt setting is %b", isRttSettingOn()); 1802 if (realPhoneAccount != null 1803 && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) { 1804 call.setRttStreams(true); 1805 } 1806 // Even if the phone account doesn't support RTT yet, the connection manager might 1807 // change that. Set this to check it later. 1808 call.setRequestedToStartWithRtt(); 1809 } 1810 1811 if (!call.isNewOutgoingCallIntentBroadcastDone()) { 1812 return; 1813 } 1814 1815 // Note: emergency calls never go through account selection dialog so they never 1816 // arrive here. 1817 if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) { 1818 call.startCreateConnection(mPhoneAccountRegistrar); 1819 } else { 1820 call.disconnect(); 1821 } 1822 1823 if (setDefault) { 1824 mPhoneAccountRegistrar 1825 .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser()); 1826 } 1827 } 1828 } 1829 1830 /** Called when the audio state changes. */ 1831 @VisibleForTesting 1832 public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState 1833 newAudioState) { 1834 Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState); 1835 for (CallsManagerListener listener : mListeners) { 1836 listener.onCallAudioStateChanged(oldAudioState, newAudioState); 1837 } 1838 } 1839 1840 /** 1841 * Called when disconnect tone is started or stopped, including any InCallTone 1842 * after disconnected call. 1843 * 1844 * @param isTonePlaying true if the disconnected tone is started, otherwise the disconnected 1845 * tone is stopped. 1846 */ 1847 @VisibleForTesting 1848 public void onDisconnectedTonePlaying(boolean isTonePlaying) { 1849 Log.v(this, "onDisconnectedTonePlaying, %s", isTonePlaying ? "started" : "stopped"); 1850 for (CallsManagerListener listener : mListeners) { 1851 listener.onDisconnectedTonePlaying(isTonePlaying); 1852 } 1853 } 1854 1855 void markCallAsRinging(Call call) { 1856 setCallState(call, CallState.RINGING, "ringing set explicitly"); 1857 } 1858 1859 void markCallAsDialing(Call call) { 1860 setCallState(call, CallState.DIALING, "dialing set explicitly"); 1861 maybeMoveToSpeakerPhone(call); 1862 } 1863 1864 void markCallAsPulling(Call call) { 1865 setCallState(call, CallState.PULLING, "pulling set explicitly"); 1866 maybeMoveToSpeakerPhone(call); 1867 } 1868 1869 void markCallAsActive(Call call) { 1870 if (call.isSelfManaged()) { 1871 // backward compatibility, the self-managed connection service will set the call state 1872 // to active directly. We should request the call focus for self-managed call before 1873 // the state change 1874 mConnectionSvrFocusMgr.requestFocus( 1875 call, 1876 new RequestCallback(new ActionSetCallState( 1877 call, 1878 CallState.ACTIVE, 1879 "active set explicitly for self-managed"))); 1880 } else { 1881 setCallState(call, CallState.ACTIVE, "active set explicitly"); 1882 maybeMoveToSpeakerPhone(call); 1883 } 1884 } 1885 1886 @VisibleForTesting 1887 public void markCallAsOnHold(Call call) { 1888 setCallState(call, CallState.ON_HOLD, "on-hold set explicitly"); 1889 } 1890 1891 /** 1892 * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the 1893 * last live call, then also disconnect from the in-call controller. 1894 * 1895 * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}. 1896 */ 1897 void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) { 1898 call.setDisconnectCause(disconnectCause); 1899 setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly"); 1900 } 1901 1902 /** 1903 * Removes an existing disconnected call, and notifies the in-call app. 1904 */ 1905 void markCallAsRemoved(Call call) { 1906 call.maybeCleanupHandover(); 1907 removeCall(call); 1908 Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall(); 1909 if (mLocallyDisconnectingCalls.contains(call)) { 1910 boolean isDisconnectingChildCall = call.isDisconnectingChildCall(); 1911 Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = " 1912 + isDisconnectingChildCall + "call -> %s", call); 1913 mLocallyDisconnectingCalls.remove(call); 1914 // Auto-unhold the foreground call due to a locally disconnected call, except if the 1915 // call which was disconnected is a member of a conference (don't want to auto un-hold 1916 // the conference if we remove a member of the conference). 1917 if (!isDisconnectingChildCall && foregroundCall != null 1918 && foregroundCall.getState() == CallState.ON_HOLD) { 1919 foregroundCall.unhold(); 1920 } 1921 } else if (foregroundCall != null && 1922 !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD) && 1923 foregroundCall.getState() == CallState.ON_HOLD) { 1924 1925 // The new foreground call is on hold, however the carrier does not display the hold 1926 // button in the UI. Therefore, we need to auto unhold the held call since the user has 1927 // no means of unholding it themselves. 1928 Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)"); 1929 foregroundCall.unhold(); 1930 } 1931 } 1932 1933 /** 1934 * Given a call, marks the call as disconnected and removes it. Set the error message to 1935 * indicate to the user that the call cannot me placed due to an ongoing call in another app. 1936 * 1937 * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed 1938 * call. Called by {@link #startCallConfirmation(Call)} when the user is already confirming an 1939 * outgoing call. Realistically this should almost never be called since in practice the user 1940 * won't make multiple outgoing calls at the same time. 1941 * 1942 * @param call The call to mark as disconnected. 1943 */ 1944 void markCallDisconnectedDueToSelfManagedCall(Call call) { 1945 Call activeCall = getActiveCall(); 1946 CharSequence errorMessage; 1947 if (activeCall == null) { 1948 // Realistically this shouldn't happen, but best to handle gracefully 1949 errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call); 1950 } else { 1951 errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call, 1952 activeCall.getTargetPhoneAccountLabel()); 1953 } 1954 // Call is managed and there are ongoing self-managed calls. 1955 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 1956 errorMessage, errorMessage, "Ongoing call in another app.")); 1957 markCallAsRemoved(call); 1958 } 1959 1960 /** 1961 * Cleans up any calls currently associated with the specified connection service when the 1962 * service binder disconnects unexpectedly. 1963 * 1964 * @param service The connection service that disconnected. 1965 */ 1966 void handleConnectionServiceDeath(ConnectionServiceWrapper service) { 1967 if (service != null) { 1968 Log.i(this, "handleConnectionServiceDeath: service %s died", service); 1969 for (Call call : mCalls) { 1970 if (call.getConnectionService() == service) { 1971 if (call.getState() != CallState.DISCONNECTED) { 1972 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 1973 "CS_DEATH")); 1974 } 1975 markCallAsRemoved(call); 1976 } 1977 } 1978 } 1979 } 1980 1981 /** 1982 * Determines if the {@link CallsManager} has any non-external calls. 1983 * 1984 * @return {@code True} if there are any non-external calls, {@code false} otherwise. 1985 */ 1986 boolean hasAnyCalls() { 1987 if (mCalls.isEmpty()) { 1988 return false; 1989 } 1990 1991 for (Call call : mCalls) { 1992 if (!call.isExternalCall()) { 1993 return true; 1994 } 1995 } 1996 return false; 1997 } 1998 1999 boolean hasActiveOrHoldingCall() { 2000 return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null; 2001 } 2002 2003 boolean hasRingingCall() { 2004 return getFirstCallWithState(CallState.RINGING) != null; 2005 } 2006 2007 boolean onMediaButton(int type) { 2008 if (hasAnyCalls()) { 2009 Call ringingCall = getFirstCallWithState(CallState.RINGING); 2010 if (HeadsetMediaButton.SHORT_PRESS == type) { 2011 if (ringingCall == null) { 2012 Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING, 2013 CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD); 2014 Log.addEvent(callToHangup, LogUtils.Events.INFO, 2015 "media btn short press - end call."); 2016 if (callToHangup != null) { 2017 disconnectCall(callToHangup); 2018 return true; 2019 } 2020 } else { 2021 ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY); 2022 return true; 2023 } 2024 } else if (HeadsetMediaButton.LONG_PRESS == type) { 2025 if (ringingCall != null) { 2026 Log.addEvent(getForegroundCall(), 2027 LogUtils.Events.INFO, "media btn long press - reject"); 2028 ringingCall.reject(false, null); 2029 } else { 2030 Log.addEvent(getForegroundCall(), LogUtils.Events.INFO, 2031 "media btn long press - mute"); 2032 mCallAudioManager.toggleMute(); 2033 } 2034 return true; 2035 } 2036 } 2037 return false; 2038 } 2039 2040 /** 2041 * Returns true if telecom supports adding another top-level call. 2042 */ 2043 @VisibleForTesting 2044 public boolean canAddCall() { 2045 boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 2046 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 2047 if (!isDeviceProvisioned) { 2048 Log.d(TAG, "Device not provisioned, canAddCall is false."); 2049 return false; 2050 } 2051 2052 if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) { 2053 return false; 2054 } 2055 2056 int count = 0; 2057 for (Call call : mCalls) { 2058 if (call.isEmergencyCall()) { 2059 // We never support add call if one of the calls is an emergency call. 2060 return false; 2061 } else if (call.isExternalCall()) { 2062 // External calls don't count. 2063 continue; 2064 } else if (call.getParentCall() == null) { 2065 count++; 2066 } 2067 Bundle extras = call.getExtras(); 2068 if (extras != null) { 2069 if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) { 2070 return false; 2071 } 2072 } 2073 2074 // We do not check states for canAddCall. We treat disconnected calls the same 2075 // and wait until they are removed instead. If we didn't count disconnected calls, 2076 // we could put InCallServices into a state where they are showing two calls but 2077 // also support add-call. Technically it's right, but overall looks better (UI-wise) 2078 // and acts better if we wait until the call is removed. 2079 if (count >= MAXIMUM_TOP_LEVEL_CALLS) { 2080 return false; 2081 } 2082 } 2083 2084 return true; 2085 } 2086 2087 @VisibleForTesting 2088 public Call getRingingCall() { 2089 return getFirstCallWithState(CallState.RINGING); 2090 } 2091 2092 public Call getActiveCall() { 2093 return getFirstCallWithState(CallState.ACTIVE); 2094 } 2095 2096 Call getDialingCall() { 2097 return getFirstCallWithState(CallState.DIALING); 2098 } 2099 2100 @VisibleForTesting 2101 public Call getHeldCall() { 2102 return getFirstCallWithState(CallState.ON_HOLD); 2103 } 2104 2105 @VisibleForTesting 2106 public int getNumHeldCalls() { 2107 int count = 0; 2108 for (Call call : mCalls) { 2109 if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) { 2110 count++; 2111 } 2112 } 2113 return count; 2114 } 2115 2116 @VisibleForTesting 2117 public Call getOutgoingCall() { 2118 return getFirstCallWithState(OUTGOING_CALL_STATES); 2119 } 2120 2121 @VisibleForTesting 2122 public Call getFirstCallWithState(int... states) { 2123 return getFirstCallWithState(null, states); 2124 } 2125 2126 @VisibleForTesting 2127 public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() { 2128 return mPhoneNumberUtilsAdapter; 2129 } 2130 2131 /** 2132 * Returns the first call that it finds with the given states. The states are treated as having 2133 * priority order so that any call with the first state will be returned before any call with 2134 * states listed later in the parameter list. 2135 * 2136 * @param callToSkip Call that this method should skip while searching 2137 */ 2138 Call getFirstCallWithState(Call callToSkip, int... states) { 2139 for (int currentState : states) { 2140 // check the foreground first 2141 Call foregroundCall = getForegroundCall(); 2142 if (foregroundCall != null && foregroundCall.getState() == currentState) { 2143 return foregroundCall; 2144 } 2145 2146 for (Call call : mCalls) { 2147 if (Objects.equals(callToSkip, call)) { 2148 continue; 2149 } 2150 2151 // Only operate on top-level calls 2152 if (call.getParentCall() != null) { 2153 continue; 2154 } 2155 2156 if (call.isExternalCall()) { 2157 continue; 2158 } 2159 2160 if (currentState == call.getState()) { 2161 return call; 2162 } 2163 } 2164 } 2165 return null; 2166 } 2167 2168 Call createConferenceCall( 2169 String callId, 2170 PhoneAccountHandle phoneAccount, 2171 ParcelableConference parcelableConference) { 2172 2173 // If the parceled conference specifies a connect time, use it; otherwise default to 0, 2174 // which is the default value for new Calls. 2175 long connectTime = 2176 parcelableConference.getConnectTimeMillis() == 2177 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2178 parcelableConference.getConnectTimeMillis(); 2179 long connectElapsedTime = 2180 parcelableConference.getConnectElapsedTimeMillis() == 2181 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2182 parcelableConference.getConnectElapsedTimeMillis(); 2183 2184 Call call = new Call( 2185 callId, 2186 mContext, 2187 this, 2188 mLock, 2189 mConnectionServiceRepository, 2190 mContactsAsyncHelper, 2191 mCallerInfoAsyncQueryFactory, 2192 mPhoneNumberUtilsAdapter, 2193 null /* handle */, 2194 null /* gatewayInfo */, 2195 null /* connectionManagerPhoneAccount */, 2196 phoneAccount, 2197 Call.CALL_DIRECTION_UNDEFINED /* callDirection */, 2198 false /* forceAttachToExistingConnection */, 2199 true /* isConference */, 2200 connectTime, 2201 connectElapsedTime, 2202 mClockProxy); 2203 2204 setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()), 2205 "new conference call"); 2206 call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities()); 2207 call.setConnectionProperties(parcelableConference.getConnectionProperties()); 2208 call.setVideoState(parcelableConference.getVideoState()); 2209 call.setVideoProvider(parcelableConference.getVideoProvider()); 2210 call.setStatusHints(parcelableConference.getStatusHints()); 2211 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras()); 2212 // In case this Conference was added via a ConnectionManager, keep track of the original 2213 // Connection ID as created by the originating ConnectionService. 2214 Bundle extras = parcelableConference.getExtras(); 2215 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2216 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 2217 } 2218 2219 // TODO: Move this to be a part of addCall() 2220 call.addListener(this); 2221 addCall(call); 2222 return call; 2223 } 2224 2225 /** 2226 * @return the call state currently tracked by {@link PhoneStateBroadcaster} 2227 */ 2228 int getCallState() { 2229 return mPhoneStateBroadcaster.getCallState(); 2230 } 2231 2232 /** 2233 * Retrieves the {@link PhoneAccountRegistrar}. 2234 * 2235 * @return The {@link PhoneAccountRegistrar}. 2236 */ 2237 PhoneAccountRegistrar getPhoneAccountRegistrar() { 2238 return mPhoneAccountRegistrar; 2239 } 2240 2241 /** 2242 * Retrieves the {@link MissedCallNotifier} 2243 * @return The {@link MissedCallNotifier}. 2244 */ 2245 MissedCallNotifier getMissedCallNotifier() { 2246 return mMissedCallNotifier; 2247 } 2248 2249 /** 2250 * Retrieves the {@link IncomingCallNotifier}. 2251 * @return The {@link IncomingCallNotifier}. 2252 */ 2253 IncomingCallNotifier getIncomingCallNotifier() { 2254 return mIncomingCallNotifier; 2255 } 2256 2257 /** 2258 * Reject an incoming call and manually add it to the Call Log. 2259 * @param incomingCall Incoming call that has been rejected 2260 */ 2261 private void rejectCallAndLog(Call incomingCall) { 2262 if (incomingCall.getConnectionService() != null) { 2263 // Only reject the call if it has not already been destroyed. If a call ends while 2264 // incoming call filtering is taking place, it is possible that the call has already 2265 // been destroyed, and as such it will be impossible to send the reject to the 2266 // associated ConnectionService. 2267 incomingCall.reject(false, null); 2268 } else { 2269 Log.i(this, "rejectCallAndLog - call already destroyed."); 2270 } 2271 2272 // Since the call was not added to the list of calls, we have to call the missed 2273 // call notifier and the call logger manually. 2274 // Do we need missed call notification for direct to Voicemail calls? 2275 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, 2276 true /*showNotificationForMissedCall*/); 2277 } 2278 2279 /** 2280 * Adds the specified call to the main list of live calls. 2281 * 2282 * @param call The call to add. 2283 */ 2284 @VisibleForTesting 2285 public void addCall(Call call) { 2286 Trace.beginSection("addCall"); 2287 Log.v(this, "addCall(%s)", call); 2288 call.addListener(this); 2289 mCalls.add(call); 2290 2291 // Specifies the time telecom finished routing the call. This is used by the dialer for 2292 // analytics. 2293 Bundle extras = call.getIntentExtras(); 2294 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS, 2295 SystemClock.elapsedRealtime()); 2296 2297 updateCanAddCall(); 2298 // onCallAdded for calls which immediately take the foreground (like the first call). 2299 for (CallsManagerListener listener : mListeners) { 2300 if (LogUtils.SYSTRACE_DEBUG) { 2301 Trace.beginSection(listener.getClass().toString() + " addCall"); 2302 } 2303 listener.onCallAdded(call); 2304 if (LogUtils.SYSTRACE_DEBUG) { 2305 Trace.endSection(); 2306 } 2307 } 2308 Trace.endSection(); 2309 } 2310 2311 private void removeCall(Call call) { 2312 Trace.beginSection("removeCall"); 2313 Log.v(this, "removeCall(%s)", call); 2314 2315 call.setParentAndChildCall(null); // clean up parent relationship before destroying. 2316 call.removeListener(this); 2317 call.clearConnectionService(); 2318 // TODO: clean up RTT pipes 2319 2320 boolean shouldNotify = false; 2321 if (mCalls.contains(call)) { 2322 mCalls.remove(call); 2323 shouldNotify = true; 2324 } 2325 2326 call.destroy(); 2327 2328 // Only broadcast changes for calls that are being tracked. 2329 if (shouldNotify) { 2330 updateCanAddCall(); 2331 for (CallsManagerListener listener : mListeners) { 2332 if (LogUtils.SYSTRACE_DEBUG) { 2333 Trace.beginSection(listener.getClass().toString() + " onCallRemoved"); 2334 } 2335 listener.onCallRemoved(call); 2336 if (LogUtils.SYSTRACE_DEBUG) { 2337 Trace.endSection(); 2338 } 2339 } 2340 } 2341 Trace.endSection(); 2342 } 2343 2344 /** 2345 * Sets the specified state on the specified call. 2346 * 2347 * @param call The call. 2348 * @param newState The new state of the call. 2349 */ 2350 private void setCallState(Call call, int newState, String tag) { 2351 if (call == null) { 2352 return; 2353 } 2354 int oldState = call.getState(); 2355 Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState), 2356 CallState.toString(newState), call); 2357 if (newState != oldState) { 2358 // If the call switches to held state while a DTMF tone is playing, stop the tone to 2359 // ensure that the tone generator stops playing the tone. 2360 if (newState == CallState.ON_HOLD && call.isDtmfTonePlaying()) { 2361 stopDtmfTone(call); 2362 } 2363 2364 // Unfortunately, in the telephony world the radio is king. So if the call notifies 2365 // us that the call is in a particular state, we allow it even if it doesn't make 2366 // sense (e.g., STATE_ACTIVE -> STATE_RINGING). 2367 // TODO: Consider putting a stop to the above and turning CallState 2368 // into a well-defined state machine. 2369 // TODO: Define expected state transitions here, and log when an 2370 // unexpected transition occurs. 2371 call.setState(newState, tag); 2372 maybeShowErrorDialogOnDisconnect(call); 2373 2374 Trace.beginSection("onCallStateChanged"); 2375 2376 maybeHandleHandover(call, newState); 2377 2378 // Only broadcast state change for calls that are being tracked. 2379 if (mCalls.contains(call)) { 2380 updateCanAddCall(); 2381 for (CallsManagerListener listener : mListeners) { 2382 if (LogUtils.SYSTRACE_DEBUG) { 2383 Trace.beginSection(listener.getClass().toString() + " onCallStateChanged"); 2384 } 2385 listener.onCallStateChanged(call, oldState, newState); 2386 if (LogUtils.SYSTRACE_DEBUG) { 2387 Trace.endSection(); 2388 } 2389 } 2390 } 2391 Trace.endSection(); 2392 } 2393 } 2394 2395 /** 2396 * Identifies call state transitions for a call which trigger handover events. 2397 * - If this call has a handover to it which just started and this call goes active, treat 2398 * this as if the user accepted the handover. 2399 * - If this call has a handover to it which just started and this call is disconnected, treat 2400 * this as if the user rejected the handover. 2401 * - If this call has a handover from it which just started and this call is disconnected, do 2402 * nothing as the call prematurely disconnected before the user accepted the handover. 2403 * - If this call has a handover from it which was already accepted by the user and this call is 2404 * disconnected, mark the handover as complete. 2405 * 2406 * @param call A call whose state is changing. 2407 * @param newState The new state of the call. 2408 */ 2409 private void maybeHandleHandover(Call call, int newState) { 2410 if (call.getHandoverSourceCall() != null) { 2411 // We are handing over another call to this one. 2412 if (call.getHandoverState() == HandoverState.HANDOVER_TO_STARTED) { 2413 // A handover to this call has just been initiated. 2414 if (newState == CallState.ACTIVE) { 2415 // This call went active, so the user has accepted the handover. 2416 Log.i(this, "setCallState: handover to accepted"); 2417 acceptHandoverTo(call); 2418 } else if (newState == CallState.DISCONNECTED) { 2419 // The call was disconnected, so the user has rejected the handover. 2420 Log.i(this, "setCallState: handover to rejected"); 2421 rejectHandoverTo(call); 2422 } 2423 } 2424 // If this call was disconnected because it was handed over TO another call, report the 2425 // handover as complete. 2426 } else if (call.getHandoverDestinationCall() != null 2427 && newState == CallState.DISCONNECTED) { 2428 int handoverState = call.getHandoverState(); 2429 if (handoverState == HandoverState.HANDOVER_FROM_STARTED) { 2430 // Disconnect before handover was accepted. 2431 Log.i(this, "setCallState: disconnect before handover accepted"); 2432 // Let the handover destination know that the source has disconnected prior to 2433 // completion of the handover. 2434 call.getHandoverDestinationCall().sendCallEvent( 2435 android.telecom.Call.EVENT_HANDOVER_SOURCE_DISCONNECTED, null); 2436 } else if (handoverState == HandoverState.HANDOVER_ACCEPTED) { 2437 Log.i(this, "setCallState: handover from complete"); 2438 completeHandoverFrom(call); 2439 } 2440 } 2441 } 2442 2443 private void completeHandoverFrom(Call call) { 2444 Call handoverTo = call.getHandoverDestinationCall(); 2445 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 2446 call.getId(), handoverTo.getId()); 2447 Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 2448 call.getId(), handoverTo.getId()); 2449 2450 // Inform the "from" Call (ie the source call) that the handover from it has 2451 // completed; this allows the InCallService to be notified that a handover it 2452 // initiated completed. 2453 call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null); 2454 call.onHandoverComplete(); 2455 2456 // Inform the "to" ConnectionService that handover to it has completed. 2457 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null); 2458 handoverTo.onHandoverComplete(); 2459 answerCall(handoverTo, handoverTo.getVideoState()); 2460 call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE); 2461 2462 // If the call we handed over to is self-managed, we need to disconnect the calls for other 2463 // ConnectionServices. 2464 if (handoverTo.isSelfManaged()) { 2465 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 2466 } 2467 } 2468 2469 private void rejectHandoverTo(Call handoverTo) { 2470 Call handoverFrom = handoverTo.getHandoverSourceCall(); 2471 Log.i(this, "rejectHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 2472 Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s", 2473 handoverTo.getId(), handoverFrom.getId()); 2474 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s", 2475 handoverTo.getId(), handoverFrom.getId()); 2476 2477 // Inform the "from" Call (ie the source call) that the handover from it has 2478 // failed; this allows the InCallService to be notified that a handover it 2479 // initiated failed. 2480 handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null); 2481 // Inform the "to" ConnectionService that handover to it has failed. This 2482 // allows the ConnectionService the call was being handed over 2483 if (handoverTo.getConnectionService() != null) { 2484 // Only attempt if the call has a bound ConnectionService if handover failed 2485 // early on in the handover process, the CS will be unbound and we won't be 2486 // able to send the call event. 2487 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 2488 } 2489 handoverTo.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_FAILED); 2490 } 2491 2492 private void acceptHandoverTo(Call handoverTo) { 2493 Call handoverFrom = handoverTo.getHandoverSourceCall(); 2494 Log.i(this, "acceptHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 2495 handoverTo.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 2496 handoverFrom.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 2497 2498 Log.addEvent(handoverTo, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 2499 handoverFrom.getId(), handoverTo.getId()); 2500 Log.addEvent(handoverFrom, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 2501 handoverFrom.getId(), handoverTo.getId()); 2502 2503 // Disconnect the call we handed over from. 2504 disconnectCall(handoverFrom); 2505 // If we handed over to a self-managed ConnectionService, we need to disconnect calls for 2506 // other ConnectionServices. 2507 if (handoverTo.isSelfManaged()) { 2508 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 2509 } 2510 } 2511 2512 private void updateCanAddCall() { 2513 boolean newCanAddCall = canAddCall(); 2514 if (newCanAddCall != mCanAddCall) { 2515 mCanAddCall = newCanAddCall; 2516 for (CallsManagerListener listener : mListeners) { 2517 if (LogUtils.SYSTRACE_DEBUG) { 2518 Trace.beginSection(listener.getClass().toString() + " updateCanAddCall"); 2519 } 2520 listener.onCanAddCallChanged(mCanAddCall); 2521 if (LogUtils.SYSTRACE_DEBUG) { 2522 Trace.endSection(); 2523 } 2524 } 2525 } 2526 } 2527 2528 private boolean isPotentialMMICode(Uri handle) { 2529 return (handle != null && handle.getSchemeSpecificPart() != null 2530 && handle.getSchemeSpecificPart().contains("#")); 2531 } 2532 2533 /** 2534 * Determines if a dialed number is potentially an In-Call MMI code. In-Call MMI codes are 2535 * MMI codes which can be dialed when one or more calls are in progress. 2536 * <P> 2537 * Checks for numbers formatted similar to the MMI codes defined in: 2538 * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)} 2539 * 2540 * @param handle The URI to call. 2541 * @return {@code True} if the URI represents a number which could be an in-call MMI code. 2542 */ 2543 private boolean isPotentialInCallMMICode(Uri handle) { 2544 if (handle != null && handle.getSchemeSpecificPart() != null && 2545 handle.getScheme() != null && 2546 handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) { 2547 2548 String dialedNumber = handle.getSchemeSpecificPart(); 2549 return (dialedNumber.equals("0") || 2550 (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) || 2551 (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) || 2552 dialedNumber.equals("3") || 2553 dialedNumber.equals("4") || 2554 dialedNumber.equals("5")); 2555 } 2556 return false; 2557 } 2558 2559 @VisibleForTesting 2560 public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall, 2561 PhoneAccountHandle phoneAccountHandle, int... states) { 2562 return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED, 2563 excludeCall, phoneAccountHandle, states); 2564 } 2565 2566 /** 2567 * Determines the number of calls matching the specified criteria. 2568 * @param callFilter indicates whether to include just managed calls 2569 * ({@link #CALL_FILTER_MANAGED}), self-managed calls 2570 * ({@link #CALL_FILTER_SELF_MANAGED}), or all calls 2571 * ({@link #CALL_FILTER_ALL}). 2572 * @param excludeCall Where {@code non-null}, this call is excluded from the count. 2573 * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle} 2574 * are excluded from the count. 2575 * @param states The list of {@link CallState}s to include in the count. 2576 * @return Count of calls matching criteria. 2577 */ 2578 @VisibleForTesting 2579 public int getNumCallsWithState(final int callFilter, Call excludeCall, 2580 PhoneAccountHandle phoneAccountHandle, int... states) { 2581 2582 Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet()); 2583 2584 Stream<Call> callsStream = mCalls.stream() 2585 .filter(call -> desiredStates.contains(call.getState()) && 2586 call.getParentCall() == null && !call.isExternalCall()); 2587 2588 if (callFilter == CALL_FILTER_MANAGED) { 2589 callsStream = callsStream.filter(call -> !call.isSelfManaged()); 2590 } else if (callFilter == CALL_FILTER_SELF_MANAGED) { 2591 callsStream = callsStream.filter(call -> call.isSelfManaged()); 2592 } 2593 2594 // If a call to exclude was specified, filter it out. 2595 if (excludeCall != null) { 2596 callsStream = callsStream.filter(call -> call != excludeCall); 2597 } 2598 2599 // If a phone account handle was specified, only consider calls for that phone account. 2600 if (phoneAccountHandle != null) { 2601 callsStream = callsStream.filter( 2602 call -> phoneAccountHandle.equals(call.getTargetPhoneAccount())); 2603 } 2604 2605 return (int) callsStream.count(); 2606 } 2607 2608 private boolean hasMaximumLiveCalls(Call exceptCall) { 2609 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 2610 exceptCall, null /* phoneAccountHandle*/, LIVE_CALL_STATES); 2611 } 2612 2613 private boolean hasMaximumManagedLiveCalls(Call exceptCall) { 2614 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */, 2615 exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES); 2616 } 2617 2618 private boolean hasMaximumSelfManagedCalls(Call exceptCall, 2619 PhoneAccountHandle phoneAccountHandle) { 2620 return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */, 2621 exceptCall, phoneAccountHandle, ANY_CALL_STATE); 2622 } 2623 2624 private boolean hasMaximumManagedHoldingCalls(Call exceptCall) { 2625 return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2626 null /* phoneAccountHandle */, CallState.ON_HOLD); 2627 } 2628 2629 private boolean hasMaximumManagedRingingCalls(Call exceptCall) { 2630 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2631 null /* phoneAccountHandle */, CallState.RINGING); 2632 } 2633 2634 private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall, 2635 PhoneAccountHandle phoneAccountHandle) { 2636 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall, 2637 phoneAccountHandle, CallState.RINGING); 2638 } 2639 2640 private boolean hasMaximumOutgoingCalls(Call exceptCall) { 2641 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 2642 exceptCall, null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 2643 } 2644 2645 private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) { 2646 return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2647 null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 2648 } 2649 2650 private boolean hasMaximumManagedDialingCalls(Call exceptCall) { 2651 return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2652 null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING); 2653 } 2654 2655 /** 2656 * Given a {@link PhoneAccountHandle} determines if there are calls owned by any other 2657 * {@link PhoneAccountHandle}. 2658 * @param phoneAccountHandle The {@link PhoneAccountHandle} to check. 2659 * @return {@code true} if there are other calls, {@code false} otherwise. 2660 */ 2661 public boolean hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 2662 return getNumCallsForOtherPhoneAccount(phoneAccountHandle) > 0; 2663 } 2664 2665 /** 2666 * Determines the number of calls present for PhoneAccounts other than the one specified. 2667 * @param phoneAccountHandle The handle of the PhoneAccount. 2668 * @return Number of calls owned by other PhoneAccounts. 2669 */ 2670 public int getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 2671 return (int) mCalls.stream().filter(call -> 2672 !phoneAccountHandle.equals(call.getTargetPhoneAccount()) && 2673 call.getParentCall() == null && 2674 !call.isExternalCall()).count(); 2675 } 2676 2677 /** 2678 * Determines if there are any managed calls. 2679 * @return {@code true} if there are managed calls, {@code false} otherwise. 2680 */ 2681 public boolean hasManagedCalls() { 2682 return mCalls.stream().filter(call -> !call.isSelfManaged() && 2683 !call.isExternalCall()).count() > 0; 2684 } 2685 2686 /** 2687 * Determines if there are any self-managed calls. 2688 * @return {@code true} if there are self-managed calls, {@code false} otherwise. 2689 */ 2690 public boolean hasSelfManagedCalls() { 2691 return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0; 2692 } 2693 2694 /** 2695 * Determines if there are any ongoing managed or self-managed calls. 2696 * Note: The {@link #ONGOING_CALL_STATES} are 2697 * @return {@code true} if there are ongoing managed or self-managed calls, {@code false} 2698 * otherwise. 2699 */ 2700 public boolean hasOngoingCalls() { 2701 return getNumCallsWithState( 2702 CALL_FILTER_ALL, null /* excludeCall */, 2703 null /* phoneAccountHandle */, 2704 ONGOING_CALL_STATES) > 0; 2705 } 2706 2707 /** 2708 * Determines if there are any ongoing managed calls. 2709 * @return {@code true} if there are ongoing managed calls, {@code false} otherwise. 2710 */ 2711 public boolean hasOngoingManagedCalls() { 2712 return getNumCallsWithState( 2713 CALL_FILTER_MANAGED, null /* excludeCall */, 2714 null /* phoneAccountHandle */, 2715 ONGOING_CALL_STATES) > 0; 2716 } 2717 2718 /** 2719 * Determines if the system incoming call UI should be shown. 2720 * The system incoming call UI will be shown if the new incoming call is self-managed, and there 2721 * are ongoing calls for another PhoneAccount. 2722 * @param incomingCall The incoming call. 2723 * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise. 2724 */ 2725 public boolean shouldShowSystemIncomingCallUi(Call incomingCall) { 2726 return incomingCall.isIncoming() && incomingCall.isSelfManaged() && 2727 hasCallsForOtherPhoneAccount(incomingCall.getTargetPhoneAccount()) && 2728 incomingCall.getHandoverSourceCall() == null; 2729 } 2730 2731 private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) { 2732 if (hasMaximumLiveCalls(call)) { 2733 // NOTE: If the amount of live calls changes beyond 1, this logic will probably 2734 // have to change. 2735 Call liveCall = getFirstCallWithState(LIVE_CALL_STATES); 2736 Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " + 2737 liveCall); 2738 2739 if (call == liveCall) { 2740 // If the call is already the foreground call, then we are golden. 2741 // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT 2742 // state since the call was already populated into the list. 2743 return true; 2744 } 2745 2746 if (hasMaximumOutgoingCalls(call)) { 2747 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES); 2748 if (isEmergency && !outgoingCall.isEmergencyCall()) { 2749 // Disconnect the current outgoing call if it's not an emergency call. If the 2750 // user tries to make two outgoing calls to different emergency call numbers, 2751 // we will try to connect the first outgoing call. 2752 call.getAnalytics().setCallIsAdditional(true); 2753 outgoingCall.getAnalytics().setCallIsInterrupted(true); 2754 outgoingCall.disconnect(); 2755 return true; 2756 } 2757 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) { 2758 // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT} 2759 // state, just disconnect it since the user has explicitly started a new call. 2760 call.getAnalytics().setCallIsAdditional(true); 2761 outgoingCall.getAnalytics().setCallIsInterrupted(true); 2762 outgoingCall.disconnect(); 2763 return true; 2764 } 2765 return false; 2766 } 2767 2768 // Disconnected the live call if the outgoing call is an emergency call. 2769 if (isEmergency && !canHold(liveCall)) { 2770 call.getAnalytics().setCallIsAdditional(true); 2771 liveCall.getAnalytics().setCallIsInterrupted(true); 2772 liveCall.disconnect(); 2773 return true; 2774 } 2775 2776 // TODO: Remove once b/23035408 has been corrected. 2777 // If the live call is a conference, it will not have a target phone account set. This 2778 // means the check to see if the live call has the same target phone account as the new 2779 // call will not cause us to bail early. As a result, we'll end up holding the 2780 // ongoing conference call. However, the ConnectionService is already doing that. This 2781 // has caused problems with some carriers. As a workaround until b/23035408 is 2782 // corrected, we will try and get the target phone account for one of the conference's 2783 // children and use that instead. 2784 PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount(); 2785 if (liveCallPhoneAccount == null && liveCall.isConference() && 2786 !liveCall.getChildCalls().isEmpty()) { 2787 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall); 2788 Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " + 2789 liveCallPhoneAccount); 2790 } 2791 2792 // First thing, if we are trying to make a call with the same phone account as the live 2793 // call, then allow it so that the connection service can make its own decision about 2794 // how to handle the new call relative to the current one. 2795 if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) { 2796 Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches."); 2797 call.getAnalytics().setCallIsAdditional(true); 2798 liveCall.getAnalytics().setCallIsInterrupted(true); 2799 return true; 2800 } else if (call.getTargetPhoneAccount() == null) { 2801 // Without a phone account, we can't say reliably that the call will fail. 2802 // If the user chooses the same phone account as the live call, then it's 2803 // still possible that the call can be made (like with CDMA calls not supporting 2804 // hold but they still support adding a call by going immediately into conference 2805 // mode). Return true here and we'll run this code again after user chooses an 2806 // account. 2807 return true; 2808 } 2809 2810 // Try to hold the live call before attempting the new outgoing call. 2811 if (canHold(liveCall)) { 2812 Log.i(this, "makeRoomForOutgoingCall: holding live call."); 2813 call.getAnalytics().setCallIsAdditional(true); 2814 liveCall.getAnalytics().setCallIsInterrupted(true); 2815 liveCall.hold(); 2816 return true; 2817 } 2818 2819 // The live call cannot be held so we're out of luck here. There's no room. 2820 return false; 2821 } 2822 return true; 2823 } 2824 2825 /** 2826 * Given a call, find the first non-null phone account handle of its children. 2827 * 2828 * @param parentCall The parent call. 2829 * @return The first non-null phone account handle of the children, or {@code null} if none. 2830 */ 2831 private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) { 2832 for (Call childCall : parentCall.getChildCalls()) { 2833 PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount(); 2834 if (childPhoneAccount != null) { 2835 return childPhoneAccount; 2836 } 2837 } 2838 return null; 2839 } 2840 2841 /** 2842 * Checks to see if the call should be on speakerphone and if so, set it. 2843 */ 2844 private void maybeMoveToSpeakerPhone(Call call) { 2845 if (call.isHandoverInProgress() && call.getState() == CallState.DIALING) { 2846 // When a new outgoing call is initiated for the purpose of handing over, do not engage 2847 // speaker automatically until the call goes active. 2848 return; 2849 } 2850 if (call.getStartWithSpeakerphoneOn()) { 2851 setAudioRoute(CallAudioState.ROUTE_SPEAKER, null); 2852 call.setStartWithSpeakerphoneOn(false); 2853 } 2854 } 2855 2856 /** 2857 * Creates a new call for an existing connection. 2858 * 2859 * @param callId The id of the new call. 2860 * @param connection The connection information. 2861 * @return The new call. 2862 */ 2863 Call createCallForExistingConnection(String callId, ParcelableConnection connection) { 2864 boolean isDowngradedConference = (connection.getConnectionProperties() 2865 & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0; 2866 Call call = new Call( 2867 callId, 2868 mContext, 2869 this, 2870 mLock, 2871 mConnectionServiceRepository, 2872 mContactsAsyncHelper, 2873 mCallerInfoAsyncQueryFactory, 2874 mPhoneNumberUtilsAdapter, 2875 connection.getHandle() /* handle */, 2876 null /* gatewayInfo */, 2877 null /* connectionManagerPhoneAccount */, 2878 connection.getPhoneAccount(), /* targetPhoneAccountHandle */ 2879 Call.CALL_DIRECTION_UNDEFINED /* callDirection */, 2880 false /* forceAttachToExistingConnection */, 2881 isDowngradedConference /* isConference */, 2882 connection.getConnectTimeMillis() /* connectTimeMillis */, 2883 connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */ 2884 mClockProxy); 2885 2886 call.initAnalytics(); 2887 call.getAnalytics().setCreatedFromExistingConnection(true); 2888 2889 setCallState(call, Call.getStateFromConnectionState(connection.getState()), 2890 "existing connection"); 2891 call.setConnectionCapabilities(connection.getConnectionCapabilities()); 2892 call.setConnectionProperties(connection.getConnectionProperties()); 2893 call.setHandle(connection.getHandle(), connection.getHandlePresentation()); 2894 call.setCallerDisplayName(connection.getCallerDisplayName(), 2895 connection.getCallerDisplayNamePresentation()); 2896 call.addListener(this); 2897 2898 // In case this connection was added via a ConnectionManager, keep track of the original 2899 // Connection ID as created by the originating ConnectionService. 2900 Bundle extras = connection.getExtras(); 2901 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2902 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 2903 } 2904 Log.i(this, "createCallForExistingConnection: %s", connection); 2905 Call parentCall = null; 2906 if (!TextUtils.isEmpty(connection.getParentCallId())) { 2907 String parentId = connection.getParentCallId(); 2908 parentCall = mCalls 2909 .stream() 2910 .filter(c -> c.getId().equals(parentId)) 2911 .findFirst() 2912 .orElse(null); 2913 if (parentCall != null) { 2914 Log.i(this, "createCallForExistingConnection: %s added as child of %s.", 2915 call.getId(), 2916 parentCall.getId()); 2917 // Set JUST the parent property, which won't send an update to the Incall UI. 2918 call.setParentCall(parentCall); 2919 } 2920 } 2921 addCall(call); 2922 if (parentCall != null) { 2923 // Now, set the call as a child of the parent since it has been added to Telecom. This 2924 // is where we will inform InCall. 2925 call.setChildOf(parentCall); 2926 call.notifyParentChanged(parentCall); 2927 } 2928 2929 return call; 2930 } 2931 2932 /** 2933 * Determines whether Telecom already knows about a Connection added via the 2934 * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle, 2935 * Connection)} API via a ConnectionManager. 2936 * 2937 * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}. 2938 * @param originalConnectionId The new connection ID to check. 2939 * @return {@code true} if this connection is already known by Telecom. 2940 */ 2941 Call getAlreadyAddedConnection(String originalConnectionId) { 2942 Optional<Call> existingCall = mCalls.stream() 2943 .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) || 2944 originalConnectionId.equals(call.getId())) 2945 .findFirst(); 2946 2947 if (existingCall.isPresent()) { 2948 Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s", 2949 originalConnectionId, existingCall.get().getId()); 2950 return existingCall.get(); 2951 } 2952 2953 return null; 2954 } 2955 2956 /** 2957 * @return A new unique telecom call Id. 2958 */ 2959 private String getNextCallId() { 2960 synchronized(mLock) { 2961 return TELECOM_CALL_ID_PREFIX + (++mCallId); 2962 } 2963 } 2964 2965 public int getNextRttRequestId() { 2966 synchronized (mLock) { 2967 return (++mRttRequestId); 2968 } 2969 } 2970 2971 /** 2972 * Callback when foreground user is switched. We will reload missed call in all profiles 2973 * including the user itself. There may be chances that profiles are not started yet. 2974 */ 2975 @VisibleForTesting 2976 public void onUserSwitch(UserHandle userHandle) { 2977 mCurrentUserHandle = userHandle; 2978 mMissedCallNotifier.setCurrentUserHandle(userHandle); 2979 final UserManager userManager = UserManager.get(mContext); 2980 List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier()); 2981 for (UserInfo profile : profiles) { 2982 reloadMissedCallsOfUser(profile.getUserHandle()); 2983 } 2984 } 2985 2986 /** 2987 * Because there may be chances that profiles are not started yet though its parent user is 2988 * switched, we reload missed calls of profile that are just started here. 2989 */ 2990 void onUserStarting(UserHandle userHandle) { 2991 if (UserUtil.isProfile(mContext, userHandle)) { 2992 reloadMissedCallsOfUser(userHandle); 2993 } 2994 } 2995 2996 public TelecomSystem.SyncRoot getLock() { 2997 return mLock; 2998 } 2999 3000 private void reloadMissedCallsOfUser(UserHandle userHandle) { 3001 mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper, 3002 new MissedCallNotifier.CallInfoFactory(), userHandle); 3003 } 3004 3005 public void onBootCompleted() { 3006 mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper, 3007 new MissedCallNotifier.CallInfoFactory()); 3008 } 3009 3010 public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 3011 return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle); 3012 } 3013 3014 public boolean isIncomingCallPermitted(Call excludeCall, 3015 PhoneAccountHandle phoneAccountHandle) { 3016 if (phoneAccountHandle == null) { 3017 return false; 3018 } 3019 PhoneAccount phoneAccount = 3020 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 3021 if (phoneAccount == null) { 3022 return false; 3023 } 3024 3025 if (!phoneAccount.isSelfManaged()) { 3026 return !hasMaximumManagedRingingCalls(excludeCall) && 3027 !hasMaximumManagedHoldingCalls(excludeCall); 3028 } else { 3029 return !hasEmergencyCall() && 3030 !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) && 3031 !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle); 3032 } 3033 } 3034 3035 public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 3036 return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle); 3037 } 3038 3039 public boolean isOutgoingCallPermitted(Call excludeCall, 3040 PhoneAccountHandle phoneAccountHandle) { 3041 if (phoneAccountHandle == null) { 3042 return false; 3043 } 3044 PhoneAccount phoneAccount = 3045 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 3046 if (phoneAccount == null) { 3047 return false; 3048 } 3049 3050 if (!phoneAccount.isSelfManaged()) { 3051 return !hasMaximumManagedOutgoingCalls(excludeCall) && 3052 !hasMaximumManagedDialingCalls(excludeCall) && 3053 !hasMaximumManagedLiveCalls(excludeCall) && 3054 !hasMaximumManagedHoldingCalls(excludeCall); 3055 } else { 3056 // Only permit self-managed outgoing calls if 3057 // 1. there is no emergency ongoing call 3058 // 2. The outgoing call is an handover call or it not hit the self-managed call limit 3059 // and the current active call can be held. 3060 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3061 return !hasEmergencyCall() && 3062 ((excludeCall != null && excludeCall.getHandoverSourceCall() != null) || 3063 (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) && 3064 (activeCall == null || canHold(activeCall)))); 3065 } 3066 } 3067 3068 /** 3069 * Blocks execution until all Telecom handlers have completed their current work. 3070 */ 3071 public void waitOnHandlers() { 3072 CountDownLatch mainHandlerLatch = new CountDownLatch(3); 3073 mHandler.post(() -> { 3074 mainHandlerLatch.countDown(); 3075 }); 3076 mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> { 3077 mainHandlerLatch.countDown(); 3078 }); 3079 mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> { 3080 mainHandlerLatch.countDown(); 3081 }); 3082 3083 try { 3084 mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS); 3085 } catch (InterruptedException e) { 3086 Log.w(this, "waitOnHandlers: interrupted %s", e); 3087 } 3088 } 3089 3090 /** 3091 * Used to confirm creation of an outgoing call which was marked as pending confirmation in 3092 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}. 3093 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 3094 * {@link ConfirmCallDialogActivity}. 3095 * @param callId The call ID of the call to confirm. 3096 */ 3097 public void confirmPendingCall(String callId) { 3098 Log.i(this, "confirmPendingCall: callId=%s", callId); 3099 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 3100 Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED); 3101 addCall(mPendingCall); 3102 3103 // We are going to place the new outgoing call, so disconnect any ongoing self-managed 3104 // calls which are ongoing at this time. 3105 disconnectSelfManagedCalls(); 3106 3107 // Kick of the new outgoing call intent from where it left off prior to confirming the 3108 // call. 3109 CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this, 3110 mPendingCall.getOriginalCallIntent()); 3111 mPendingCall = null; 3112 } 3113 } 3114 3115 /** 3116 * Used to cancel an outgoing call which was marked as pending confirmation in 3117 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}. 3118 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 3119 * {@link ConfirmCallDialogActivity}. 3120 * @param callId The call ID of the call to cancel. 3121 */ 3122 public void cancelPendingCall(String callId) { 3123 Log.i(this, "cancelPendingCall: callId=%s", callId); 3124 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 3125 Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED); 3126 markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED)); 3127 markCallAsRemoved(mPendingCall); 3128 mPendingCall = null; 3129 } 3130 } 3131 3132 /** 3133 * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when 3134 * a managed call is added while there are ongoing self-managed calls. Starts 3135 * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the 3136 * outgoing call or not. 3137 * @param call The call to confirm. 3138 */ 3139 private void startCallConfirmation(Call call) { 3140 if (mPendingCall != null) { 3141 Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s", 3142 mPendingCall.getId(), call.getId()); 3143 markCallDisconnectedDueToSelfManagedCall(call); 3144 return; 3145 } 3146 Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION); 3147 mPendingCall = call; 3148 3149 // Figure out the name of the app in charge of the self-managed call(s). 3150 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3151 if (activeCall != null) { 3152 CharSequence ongoingAppName = activeCall.getTargetPhoneAccountLabel(); 3153 Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(), 3154 ongoingAppName); 3155 3156 Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class); 3157 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId()); 3158 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName); 3159 confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3160 mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT); 3161 } 3162 } 3163 3164 /** 3165 * Disconnects all self-managed calls. 3166 */ 3167 private void disconnectSelfManagedCalls() { 3168 // Disconnect all self-managed calls to make priority for emergency call. 3169 // Use Call.disconnect() to command the ConnectionService to disconnect the calls. 3170 // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to 3171 // disconnect. 3172 mCalls.stream() 3173 .filter(c -> c.isSelfManaged()) 3174 .forEach(c -> c.disconnect()); 3175 3176 // When disconnecting all self-managed calls, switch audio routing back to the baseline 3177 // route. This ensures if, for example, the self-managed ConnectionService was routed to 3178 // speakerphone that we'll switch back to earpiece for the managed call which necessitated 3179 // disconnecting the self-managed calls. 3180 mCallAudioManager.switchBaseline(); 3181 } 3182 3183 private void disconnectCallsHaveDifferentConnectionService(Call exceptCall) { 3184 mCalls.stream().filter(c -> 3185 c.getConnectionService() != exceptCall.getConnectionService() 3186 && c.getConnectionManagerPhoneAccount() 3187 != exceptCall.getConnectionManagerPhoneAccount()) 3188 .forEach(c -> c.disconnect()); 3189 } 3190 3191 /** 3192 * Dumps the state of the {@link CallsManager}. 3193 * 3194 * @param pw The {@code IndentingPrintWriter} to write the state to. 3195 */ 3196 public void dump(IndentingPrintWriter pw) { 3197 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 3198 if (mCalls != null) { 3199 pw.println("mCalls: "); 3200 pw.increaseIndent(); 3201 for (Call call : mCalls) { 3202 pw.println(call); 3203 } 3204 pw.decreaseIndent(); 3205 } 3206 3207 if (mPendingCall != null) { 3208 pw.print("mPendingCall:"); 3209 pw.println(mPendingCall.getId()); 3210 } 3211 3212 if (mCallAudioManager != null) { 3213 pw.println("mCallAudioManager:"); 3214 pw.increaseIndent(); 3215 mCallAudioManager.dump(pw); 3216 pw.decreaseIndent(); 3217 } 3218 3219 if (mTtyManager != null) { 3220 pw.println("mTtyManager:"); 3221 pw.increaseIndent(); 3222 mTtyManager.dump(pw); 3223 pw.decreaseIndent(); 3224 } 3225 3226 if (mInCallController != null) { 3227 pw.println("mInCallController:"); 3228 pw.increaseIndent(); 3229 mInCallController.dump(pw); 3230 pw.decreaseIndent(); 3231 } 3232 3233 if (mDefaultDialerCache != null) { 3234 pw.println("mDefaultDialerCache:"); 3235 pw.increaseIndent(); 3236 mDefaultDialerCache.dumpCache(pw); 3237 pw.decreaseIndent(); 3238 } 3239 3240 if (mConnectionServiceRepository != null) { 3241 pw.println("mConnectionServiceRepository:"); 3242 pw.increaseIndent(); 3243 mConnectionServiceRepository.dump(pw); 3244 pw.decreaseIndent(); 3245 } 3246 } 3247 3248 /** 3249 * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code. 3250 * 3251 * @param call The call. 3252 */ 3253 private void maybeShowErrorDialogOnDisconnect(Call call) { 3254 if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle()) 3255 || isPotentialInCallMMICode(call.getHandle())) && !mCalls.contains(call)) { 3256 DisconnectCause disconnectCause = call.getDisconnectCause(); 3257 if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode() 3258 == DisconnectCause.ERROR)) { 3259 Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 3260 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA, 3261 disconnectCause.getDescription()); 3262 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3263 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 3264 } 3265 } 3266 } 3267 3268 private void setIntentExtrasAndStartTime(Call call, Bundle extras) { 3269 if (extras != null) { 3270 // Create our own instance to modify (since extras may be Bundle.EMPTY) 3271 extras = new Bundle(extras); 3272 } else { 3273 extras = new Bundle(); 3274 } 3275 3276 // Specifies the time telecom began routing the call. This is used by the dialer for 3277 // analytics. 3278 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, 3279 SystemClock.elapsedRealtime()); 3280 3281 call.setIntentExtras(extras); 3282 } 3283 3284 /** 3285 * Notifies the {@link android.telecom.ConnectionService} associated with a 3286 * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. 3287 * 3288 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 3289 * @param call The {@link Call} which could not be added. 3290 */ 3291 private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) { 3292 if (phoneAccountHandle == null) { 3293 return; 3294 } 3295 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 3296 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); 3297 if (service == null) { 3298 Log.i(this, "Found no connection service."); 3299 return; 3300 } else { 3301 call.setConnectionService(service); 3302 service.createConnectionFailed(call); 3303 } 3304 } 3305 3306 /** 3307 * Notifies the {@link android.telecom.ConnectionService} associated with a 3308 * {@link PhoneAccountHandle} that the attempt to handover a call has failed. 3309 * 3310 * @param call The handover call 3311 * @param reason The error reason code for handover failure 3312 */ 3313 private void notifyHandoverFailed(Call call, int reason) { 3314 ConnectionServiceWrapper service = call.getConnectionService(); 3315 service.handoverFailed(call, reason); 3316 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 3317 call.disconnect(); 3318 } 3319 3320 /** 3321 * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)} 3322 * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the 3323 * {@link android.telecom.InCallService} has requested a handover to another 3324 * {@link android.telecom.ConnectionService}. 3325 * 3326 * We will explicitly disallow a handover when there is an emergency call present. 3327 * 3328 * @param handoverFromCall The {@link Call} to be handed over. 3329 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 3330 * @param videoState The desired video state of {@link Call} after handover. 3331 * @param initiatingExtras Extras associated with the handover, to be passed to the handover 3332 * {@link android.telecom.ConnectionService}. 3333 */ 3334 private void requestHandoverViaEvents(Call handoverFromCall, 3335 PhoneAccountHandle handoverToHandle, 3336 int videoState, Bundle initiatingExtras) { 3337 3338 boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported( 3339 handoverFromCall.getTargetPhoneAccount()); 3340 boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle); 3341 3342 if (!isHandoverFromSupported || !isHandoverToSupported || hasEmergencyCall()) { 3343 handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 3344 return; 3345 } 3346 3347 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle); 3348 3349 Bundle extras = new Bundle(); 3350 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 3351 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 3352 handoverFromCall.getTargetPhoneAccount()); 3353 extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 3354 if (initiatingExtras != null) { 3355 extras.putAll(initiatingExtras); 3356 } 3357 extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE, 3358 mCallAudioManager.getCallAudioState()); 3359 Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle, 3360 extras, getCurrentUserHandle(), null /* originalIntent */); 3361 Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER, 3362 "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), handoverToCall.getId()); 3363 handoverFromCall.setHandoverDestinationCall(handoverToCall); 3364 handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 3365 handoverToCall.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 3366 handoverToCall.setHandoverSourceCall(handoverFromCall); 3367 handoverToCall.setNewOutgoingCallIntentBroadcastIsDone(); 3368 placeOutgoingCall(handoverToCall, handoverToCall.getHandle(), null /* gatewayInfo */, 3369 false /* startwithSpeaker */, 3370 videoState); 3371 } 3372 3373 /** 3374 * Called in response to a {@link Call} receiving a {@link Call#handoverTo(PhoneAccountHandle, 3375 * int, Bundle)} indicating the {@link android.telecom.InCallService} has requested a 3376 * handover to another {@link android.telecom.ConnectionService}. 3377 * 3378 * We will explicitly disallow a handover when there is an emergency call present. 3379 * 3380 * @param handoverFromCall The {@link Call} to be handed over. 3381 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 3382 * @param videoState The desired video state of {@link Call} after handover. 3383 * @param extras Extras associated with the handover, to be passed to the handover 3384 * {@link android.telecom.ConnectionService}. 3385 */ 3386 private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle, 3387 int videoState, Bundle extras) { 3388 3389 // Send an error back if there are any ongoing emergency calls. 3390 if (hasEmergencyCall()) { 3391 handoverFromCall.onHandoverFailed( 3392 android.telecom.Call.Callback.HANDOVER_FAILURE_ONGOING_EMERG_CALL); 3393 return; 3394 } 3395 3396 // If source and destination phone accounts don't support handover, send an error back. 3397 boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported( 3398 handoverFromCall.getTargetPhoneAccount()); 3399 boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle); 3400 if (!isHandoverFromSupported || !isHandoverToSupported) { 3401 handoverFromCall.onHandoverFailed( 3402 android.telecom.Call.Callback.HANDOVER_FAILURE_DEST_NOT_SUPPORTED); 3403 return; 3404 } 3405 3406 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle); 3407 3408 // Create a new instance of Call 3409 PhoneAccount account = 3410 mPhoneAccountRegistrar.getPhoneAccount(handoverToHandle, getCurrentUserHandle()); 3411 boolean isSelfManaged = account != null && account.isSelfManaged(); 3412 3413 Call call = new Call(getNextCallId(), mContext, 3414 this, mLock, mConnectionServiceRepository, 3415 mContactsAsyncHelper, mCallerInfoAsyncQueryFactory, mPhoneNumberUtilsAdapter, 3416 handoverFromCall.getHandle(), null, 3417 null, null, 3418 Call.CALL_DIRECTION_OUTGOING, false, 3419 false, mClockProxy); 3420 call.initAnalytics(); 3421 3422 // Set self-managed and voipAudioMode if destination is self-managed CS 3423 call.setIsSelfManaged(isSelfManaged); 3424 if (isSelfManaged) { 3425 call.setIsVoipAudioMode(true); 3426 } 3427 call.setInitiatingUser(getCurrentUserHandle()); 3428 3429 // Ensure we don't try to place an outgoing call with video if video is not 3430 // supported. 3431 if (VideoProfile.isVideo(videoState) && account != null && 3432 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 3433 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 3434 } else { 3435 call.setVideoState(videoState); 3436 } 3437 3438 // Set target phone account to destAcct. 3439 call.setTargetPhoneAccount(handoverToHandle); 3440 3441 if (account != null && account.getExtras() != null && account.getExtras() 3442 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 3443 Log.d(this, "requestHandover: defaulting to voip mode for call %s", 3444 call.getId()); 3445 call.setIsVoipAudioMode(true); 3446 } 3447 3448 // Set call state to connecting 3449 call.setState( 3450 CallState.CONNECTING, 3451 handoverToHandle == null ? "no-handle" : handoverToHandle.toString()); 3452 3453 // Mark as handover so that the ConnectionService knows this is a handover request. 3454 if (extras == null) { 3455 extras = new Bundle(); 3456 } 3457 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 3458 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 3459 handoverFromCall.getTargetPhoneAccount()); 3460 setIntentExtrasAndStartTime(call, extras); 3461 3462 // Add call to call tracker 3463 if (!mCalls.contains(call)) { 3464 addCall(call); 3465 } 3466 3467 Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER, 3468 "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), call.getId()); 3469 3470 handoverFromCall.setHandoverDestinationCall(call); 3471 handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 3472 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 3473 call.setHandoverSourceCall(handoverFromCall); 3474 call.setNewOutgoingCallIntentBroadcastIsDone(); 3475 3476 // Auto-enable speakerphone if the originating intent specified to do so, if the call 3477 // is a video call, of if using speaker when docked 3478 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 3479 R.bool.use_speaker_when_docked); 3480 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 3481 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 3482 call.setStartWithSpeakerphoneOn(false || useSpeakerForVideoCall 3483 || (useSpeakerWhenDocked && useSpeakerForDock)); 3484 call.setVideoState(videoState); 3485 3486 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 3487 call.getTargetPhoneAccount()); 3488 3489 // If the account has been set, proceed to place the outgoing call. 3490 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 3491 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 3492 } else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) { 3493 markCallDisconnectedDueToSelfManagedCall(call); 3494 } else { 3495 if (call.isEmergencyCall()) { 3496 // Disconnect all self-managed calls to make priority for emergency call. 3497 disconnectSelfManagedCalls(); 3498 } 3499 3500 call.startCreateConnection(mPhoneAccountRegistrar); 3501 } 3502 3503 } 3504 3505 /** 3506 * Determines if handover from the specified {@link PhoneAccountHandle} is supported. 3507 * 3508 * @param from The {@link PhoneAccountHandle} the handover originates from. 3509 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 3510 */ 3511 private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) { 3512 return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM); 3513 } 3514 3515 /** 3516 * Determines if handover to the specified {@link PhoneAccountHandle} is supported. 3517 * 3518 * @param to The {@link PhoneAccountHandle} the handover it to. 3519 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 3520 */ 3521 private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) { 3522 return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO); 3523 } 3524 3525 /** 3526 * Retrieves a boolean phone account extra. 3527 * @param handle the {@link PhoneAccountHandle} to retrieve the extra for. 3528 * @param key The extras key. 3529 * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false} 3530 * otherwise. 3531 */ 3532 private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) { 3533 PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle); 3534 if (phoneAccount == null) { 3535 return false; 3536 } 3537 3538 Bundle fromExtras = phoneAccount.getExtras(); 3539 if (fromExtras == null) { 3540 return false; 3541 } 3542 return fromExtras.getBoolean(key); 3543 } 3544 3545 /** 3546 * Determines if there is an existing handover in process. 3547 * @return {@code true} if a call in the process of handover exists, {@code false} otherwise. 3548 */ 3549 private boolean isHandoverInProgress() { 3550 return mCalls.stream().filter(c -> c.getHandoverSourceCall() != null || 3551 c.getHandoverDestinationCall() != null).count() > 0; 3552 } 3553 3554 private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) { 3555 Intent intent = 3556 new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED); 3557 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 3558 intent.putExtra( 3559 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3560 Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle); 3561 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 3562 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 3563 3564 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 3565 getCurrentUserHandle().getIdentifier()); 3566 if (!TextUtils.isEmpty(dialerPackage)) { 3567 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED) 3568 .setPackage(dialerPackage); 3569 directedIntent.putExtra( 3570 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3571 Log.i(this, "Sending phone-account unregistered intent to default dialer"); 3572 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 3573 } 3574 return ; 3575 } 3576 3577 private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) { 3578 Intent intent = new Intent( 3579 TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED); 3580 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 3581 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 3582 accountHandle); 3583 Log.i(this, "Sending phone-account %s registered intent as user", accountHandle); 3584 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 3585 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 3586 3587 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 3588 getCurrentUserHandle().getIdentifier()); 3589 if (!TextUtils.isEmpty(dialerPackage)) { 3590 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED) 3591 .setPackage(dialerPackage); 3592 directedIntent.putExtra( 3593 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3594 Log.i(this, "Sending phone-account registered intent to default dialer"); 3595 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 3596 } 3597 return ; 3598 } 3599 3600 public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) { 3601 3602 final String handleScheme = srcAddr.getSchemeSpecificPart(); 3603 Call fromCall = mCalls.stream() 3604 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 3605 c.getHandle().getSchemeSpecificPart(), handleScheme)) 3606 .findFirst() 3607 .orElse(null); 3608 3609 Call call = new Call( 3610 getNextCallId(), 3611 mContext, 3612 this, 3613 mLock, 3614 mConnectionServiceRepository, 3615 mContactsAsyncHelper, 3616 mCallerInfoAsyncQueryFactory, 3617 mPhoneNumberUtilsAdapter, 3618 srcAddr, 3619 null /* gatewayInfo */, 3620 null /* connectionManagerPhoneAccount */, 3621 destAcct, 3622 Call.CALL_DIRECTION_INCOMING /* callDirection */, 3623 false /* forceAttachToExistingConnection */, 3624 false, /* isConference */ 3625 mClockProxy); 3626 3627 if (fromCall == null || isHandoverInProgress() || 3628 !isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount()) || 3629 !isHandoverToPhoneAccountSupported(destAcct) || 3630 hasEmergencyCall()) { 3631 Log.w(this, "acceptHandover: Handover not supported"); 3632 notifyHandoverFailed(call, 3633 android.telecom.Call.Callback.HANDOVER_FAILURE_DEST_NOT_SUPPORTED); 3634 return; 3635 } 3636 3637 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(destAcct); 3638 if (phoneAccount == null) { 3639 Log.w(this, "acceptHandover: Handover not supported. phoneAccount = null"); 3640 notifyHandoverFailed(call, 3641 android.telecom.Call.Callback.HANDOVER_FAILURE_DEST_NOT_SUPPORTED); 3642 return; 3643 } 3644 call.setIsSelfManaged(phoneAccount.isSelfManaged()); 3645 if (call.isSelfManaged() || (phoneAccount.getExtras() != null && 3646 phoneAccount.getExtras().getBoolean( 3647 PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE))) { 3648 call.setIsVoipAudioMode(true); 3649 } 3650 if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 3651 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 3652 } else { 3653 call.setVideoState(videoState); 3654 } 3655 3656 call.initAnalytics(); 3657 call.addListener(this); 3658 3659 fromCall.setHandoverDestinationCall(call); 3660 call.setHandoverSourceCall(fromCall); 3661 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 3662 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 3663 3664 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 3665 // Ensure when the call goes active that it will go to speakerphone if the 3666 // handover to call is a video call. 3667 call.setStartWithSpeakerphoneOn(true); 3668 } 3669 3670 Bundle extras = call.getIntentExtras(); 3671 if (extras == null) { 3672 extras = new Bundle(); 3673 } 3674 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 3675 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 3676 fromCall.getTargetPhoneAccount()); 3677 3678 call.startCreateConnection(mPhoneAccountRegistrar); 3679 } 3680 3681 ConnectionServiceFocusManager getConnectionServiceFocusManager() { 3682 return mConnectionSvrFocusMgr; 3683 } 3684 3685 private boolean canHold(Call call) { 3686 return call.can(Connection.CAPABILITY_HOLD); 3687 } 3688 3689 private final class ActionSetCallState implements PendingAction { 3690 3691 private final Call mCall; 3692 private final int mState; 3693 private final String mTag; 3694 3695 ActionSetCallState(Call call, int state, String tag) { 3696 mCall = call; 3697 mState = state; 3698 mTag = tag; 3699 } 3700 3701 @Override 3702 public void performAction() { 3703 Log.d(this, "perform set call state for %s, state = %s", mCall, mState); 3704 setCallState(mCall, mState, mTag); 3705 } 3706 } 3707 3708 private final class ActionUnHoldCall implements PendingAction { 3709 private final Call mCall; 3710 3711 ActionUnHoldCall(Call call) { 3712 mCall = call; 3713 } 3714 3715 @Override 3716 public void performAction() { 3717 Log.d(this, "perform unhold call for %s", mCall); 3718 mCall.unhold(); 3719 } 3720 } 3721 3722 private final class ActionAnswerCall implements PendingAction { 3723 private final Call mCall; 3724 private final int mVideoState; 3725 3726 ActionAnswerCall(Call call, int videoState) { 3727 mCall = call; 3728 mVideoState = videoState; 3729 } 3730 3731 @Override 3732 public void performAction() { 3733 Log.d(this, "perform answer call for %s, videoState = %d", mCall, mVideoState); 3734 for (CallsManagerListener listener : mListeners) { 3735 listener.onIncomingCallAnswered(mCall); 3736 } 3737 3738 // We do not update the UI until we get confirmation of the answer() through 3739 // {@link #markCallAsActive}. 3740 mCall.answer(mVideoState); 3741 if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) { 3742 mCall.setStartWithSpeakerphoneOn(true); 3743 } 3744 } 3745 } 3746 3747 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 3748 public static final class RequestCallback implements 3749 ConnectionServiceFocusManager.RequestFocusCallback { 3750 private PendingAction mPendingAction; 3751 3752 RequestCallback(PendingAction pendingAction) { 3753 mPendingAction = pendingAction; 3754 } 3755 3756 @Override 3757 public void onRequestFocusDone(ConnectionServiceFocusManager.CallFocus call) { 3758 if (mPendingAction != null) { 3759 mPendingAction.performAction(); 3760 } 3761 } 3762 } 3763} 3764