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