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