CallsManager.java revision 6c3a2dd68c9ac5584f48cf5f62fa01896fccdc7d
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 Log.i(this, "handleConnectionServiceDeath: service %s died", service); 1819 for (Call call : mCalls) { 1820 if (call.getConnectionService() == service) { 1821 if (call.getState() != CallState.DISCONNECTED) { 1822 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 1823 "CS_DEATH")); 1824 } 1825 markCallAsRemoved(call); 1826 } 1827 } 1828 } 1829 } 1830 1831 /** 1832 * Determines if the {@link CallsManager} has any non-external calls. 1833 * 1834 * @return {@code True} if there are any non-external calls, {@code false} otherwise. 1835 */ 1836 boolean hasAnyCalls() { 1837 if (mCalls.isEmpty()) { 1838 return false; 1839 } 1840 1841 for (Call call : mCalls) { 1842 if (!call.isExternalCall()) { 1843 return true; 1844 } 1845 } 1846 return false; 1847 } 1848 1849 boolean hasActiveOrHoldingCall() { 1850 return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null; 1851 } 1852 1853 boolean hasRingingCall() { 1854 return getFirstCallWithState(CallState.RINGING) != null; 1855 } 1856 1857 boolean onMediaButton(int type) { 1858 if (hasAnyCalls()) { 1859 Call ringingCall = getFirstCallWithState(CallState.RINGING); 1860 if (HeadsetMediaButton.SHORT_PRESS == type) { 1861 if (ringingCall == null) { 1862 Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING, 1863 CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD); 1864 Log.addEvent(callToHangup, LogUtils.Events.INFO, 1865 "media btn short press - end call."); 1866 if (callToHangup != null) { 1867 callToHangup.disconnect(); 1868 return true; 1869 } 1870 } else { 1871 ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY); 1872 return true; 1873 } 1874 } else if (HeadsetMediaButton.LONG_PRESS == type) { 1875 if (ringingCall != null) { 1876 Log.addEvent(getForegroundCall(), 1877 LogUtils.Events.INFO, "media btn long press - reject"); 1878 ringingCall.reject(false, null); 1879 } else { 1880 Log.addEvent(getForegroundCall(), LogUtils.Events.INFO, 1881 "media btn long press - mute"); 1882 mCallAudioManager.toggleMute(); 1883 } 1884 return true; 1885 } 1886 } 1887 return false; 1888 } 1889 1890 /** 1891 * Returns true if telecom supports adding another top-level call. 1892 */ 1893 @VisibleForTesting 1894 public boolean canAddCall() { 1895 boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 1896 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 1897 if (!isDeviceProvisioned) { 1898 Log.d(TAG, "Device not provisioned, canAddCall is false."); 1899 return false; 1900 } 1901 1902 if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) { 1903 return false; 1904 } 1905 1906 int count = 0; 1907 for (Call call : mCalls) { 1908 if (call.isEmergencyCall()) { 1909 // We never support add call if one of the calls is an emergency call. 1910 return false; 1911 } else if (call.isExternalCall()) { 1912 // External calls don't count. 1913 continue; 1914 } else if (call.getParentCall() == null) { 1915 count++; 1916 } 1917 Bundle extras = call.getExtras(); 1918 if (extras != null) { 1919 if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) { 1920 return false; 1921 } 1922 } 1923 1924 // We do not check states for canAddCall. We treat disconnected calls the same 1925 // and wait until they are removed instead. If we didn't count disconnected calls, 1926 // we could put InCallServices into a state where they are showing two calls but 1927 // also support add-call. Technically it's right, but overall looks better (UI-wise) 1928 // and acts better if we wait until the call is removed. 1929 if (count >= MAXIMUM_TOP_LEVEL_CALLS) { 1930 return false; 1931 } 1932 } 1933 1934 return true; 1935 } 1936 1937 @VisibleForTesting 1938 public Call getRingingCall() { 1939 return getFirstCallWithState(CallState.RINGING); 1940 } 1941 1942 public Call getActiveCall() { 1943 return getFirstCallWithState(CallState.ACTIVE); 1944 } 1945 1946 Call getDialingCall() { 1947 return getFirstCallWithState(CallState.DIALING); 1948 } 1949 1950 @VisibleForTesting 1951 public Call getHeldCall() { 1952 return getFirstCallWithState(CallState.ON_HOLD); 1953 } 1954 1955 @VisibleForTesting 1956 public int getNumHeldCalls() { 1957 int count = 0; 1958 for (Call call : mCalls) { 1959 if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) { 1960 count++; 1961 } 1962 } 1963 return count; 1964 } 1965 1966 @VisibleForTesting 1967 public Call getOutgoingCall() { 1968 return getFirstCallWithState(OUTGOING_CALL_STATES); 1969 } 1970 1971 @VisibleForTesting 1972 public Call getFirstCallWithState(int... states) { 1973 return getFirstCallWithState(null, states); 1974 } 1975 1976 @VisibleForTesting 1977 public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() { 1978 return mPhoneNumberUtilsAdapter; 1979 } 1980 1981 /** 1982 * Returns the first call that it finds with the given states. The states are treated as having 1983 * priority order so that any call with the first state will be returned before any call with 1984 * states listed later in the parameter list. 1985 * 1986 * @param callToSkip Call that this method should skip while searching 1987 */ 1988 Call getFirstCallWithState(Call callToSkip, int... states) { 1989 for (int currentState : states) { 1990 // check the foreground first 1991 Call foregroundCall = getForegroundCall(); 1992 if (foregroundCall != null && foregroundCall.getState() == currentState) { 1993 return foregroundCall; 1994 } 1995 1996 for (Call call : mCalls) { 1997 if (Objects.equals(callToSkip, call)) { 1998 continue; 1999 } 2000 2001 // Only operate on top-level calls 2002 if (call.getParentCall() != null) { 2003 continue; 2004 } 2005 2006 if (call.isExternalCall()) { 2007 continue; 2008 } 2009 2010 if (currentState == call.getState()) { 2011 return call; 2012 } 2013 } 2014 } 2015 return null; 2016 } 2017 2018 Call createConferenceCall( 2019 String callId, 2020 PhoneAccountHandle phoneAccount, 2021 ParcelableConference parcelableConference) { 2022 2023 // If the parceled conference specifies a connect time, use it; otherwise default to 0, 2024 // which is the default value for new Calls. 2025 long connectTime = 2026 parcelableConference.getConnectTimeMillis() == 2027 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2028 parcelableConference.getConnectTimeMillis(); 2029 long connectElapsedTime = 2030 parcelableConference.getConnectElapsedTimeMillis() == 2031 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2032 parcelableConference.getConnectElapsedTimeMillis(); 2033 2034 Call call = new Call( 2035 callId, 2036 mContext, 2037 this, 2038 mLock, 2039 mConnectionServiceRepository, 2040 mContactsAsyncHelper, 2041 mCallerInfoAsyncQueryFactory, 2042 mPhoneNumberUtilsAdapter, 2043 null /* handle */, 2044 null /* gatewayInfo */, 2045 null /* connectionManagerPhoneAccount */, 2046 phoneAccount, 2047 Call.CALL_DIRECTION_UNDEFINED /* callDirection */, 2048 false /* forceAttachToExistingConnection */, 2049 true /* isConference */, 2050 connectTime, 2051 connectElapsedTime, 2052 mClockProxy); 2053 2054 setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()), 2055 "new conference call"); 2056 call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities()); 2057 call.setConnectionProperties(parcelableConference.getConnectionProperties()); 2058 call.setVideoState(parcelableConference.getVideoState()); 2059 call.setVideoProvider(parcelableConference.getVideoProvider()); 2060 call.setStatusHints(parcelableConference.getStatusHints()); 2061 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras()); 2062 // In case this Conference was added via a ConnectionManager, keep track of the original 2063 // Connection ID as created by the originating ConnectionService. 2064 Bundle extras = parcelableConference.getExtras(); 2065 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2066 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 2067 } 2068 2069 // TODO: Move this to be a part of addCall() 2070 call.addListener(this); 2071 addCall(call); 2072 return call; 2073 } 2074 2075 /** 2076 * @return the call state currently tracked by {@link PhoneStateBroadcaster} 2077 */ 2078 int getCallState() { 2079 return mPhoneStateBroadcaster.getCallState(); 2080 } 2081 2082 /** 2083 * Retrieves the {@link PhoneAccountRegistrar}. 2084 * 2085 * @return The {@link PhoneAccountRegistrar}. 2086 */ 2087 PhoneAccountRegistrar getPhoneAccountRegistrar() { 2088 return mPhoneAccountRegistrar; 2089 } 2090 2091 /** 2092 * Retrieves the {@link MissedCallNotifier} 2093 * @return The {@link MissedCallNotifier}. 2094 */ 2095 MissedCallNotifier getMissedCallNotifier() { 2096 return mMissedCallNotifier; 2097 } 2098 2099 /** 2100 * Retrieves the {@link IncomingCallNotifier}. 2101 * @return The {@link IncomingCallNotifier}. 2102 */ 2103 IncomingCallNotifier getIncomingCallNotifier() { 2104 return mIncomingCallNotifier; 2105 } 2106 2107 /** 2108 * Reject an incoming call and manually add it to the Call Log. 2109 * @param incomingCall Incoming call that has been rejected 2110 */ 2111 private void rejectCallAndLog(Call incomingCall) { 2112 if (incomingCall.getConnectionService() != null) { 2113 // Only reject the call if it has not already been destroyed. If a call ends while 2114 // incoming call filtering is taking place, it is possible that the call has already 2115 // been destroyed, and as such it will be impossible to send the reject to the 2116 // associated ConnectionService. 2117 incomingCall.reject(false, null); 2118 } else { 2119 Log.i(this, "rejectCallAndLog - call already destroyed."); 2120 } 2121 2122 // Since the call was not added to the list of calls, we have to call the missed 2123 // call notifier and the call logger manually. 2124 // Do we need missed call notification for direct to Voicemail calls? 2125 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, 2126 true /*showNotificationForMissedCall*/); 2127 } 2128 2129 /** 2130 * Adds the specified call to the main list of live calls. 2131 * 2132 * @param call The call to add. 2133 */ 2134 private void addCall(Call call) { 2135 Trace.beginSection("addCall"); 2136 Log.v(this, "addCall(%s)", call); 2137 call.addListener(this); 2138 mCalls.add(call); 2139 2140 // Specifies the time telecom finished routing the call. This is used by the dialer for 2141 // analytics. 2142 Bundle extras = call.getIntentExtras(); 2143 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS, 2144 SystemClock.elapsedRealtime()); 2145 2146 updateCanAddCall(); 2147 // onCallAdded for calls which immediately take the foreground (like the first call). 2148 for (CallsManagerListener listener : mListeners) { 2149 if (LogUtils.SYSTRACE_DEBUG) { 2150 Trace.beginSection(listener.getClass().toString() + " addCall"); 2151 } 2152 listener.onCallAdded(call); 2153 if (LogUtils.SYSTRACE_DEBUG) { 2154 Trace.endSection(); 2155 } 2156 } 2157 Trace.endSection(); 2158 } 2159 2160 private void removeCall(Call call) { 2161 Trace.beginSection("removeCall"); 2162 Log.v(this, "removeCall(%s)", call); 2163 2164 call.setParentAndChildCall(null); // clean up parent relationship before destroying. 2165 call.removeListener(this); 2166 call.clearConnectionService(); 2167 // TODO: clean up RTT pipes 2168 2169 boolean shouldNotify = false; 2170 if (mCalls.contains(call)) { 2171 mCalls.remove(call); 2172 shouldNotify = true; 2173 } 2174 2175 call.destroy(); 2176 2177 // Only broadcast changes for calls that are being tracked. 2178 if (shouldNotify) { 2179 updateCanAddCall(); 2180 for (CallsManagerListener listener : mListeners) { 2181 if (LogUtils.SYSTRACE_DEBUG) { 2182 Trace.beginSection(listener.getClass().toString() + " onCallRemoved"); 2183 } 2184 listener.onCallRemoved(call); 2185 if (LogUtils.SYSTRACE_DEBUG) { 2186 Trace.endSection(); 2187 } 2188 } 2189 } 2190 Trace.endSection(); 2191 } 2192 2193 /** 2194 * Sets the specified state on the specified call. 2195 * 2196 * @param call The call. 2197 * @param newState The new state of the call. 2198 */ 2199 private void setCallState(Call call, int newState, String tag) { 2200 if (call == null) { 2201 return; 2202 } 2203 int oldState = call.getState(); 2204 Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState), 2205 CallState.toString(newState), call); 2206 if (newState != oldState) { 2207 // Unfortunately, in the telephony world the radio is king. So if the call notifies 2208 // us that the call is in a particular state, we allow it even if it doesn't make 2209 // sense (e.g., STATE_ACTIVE -> STATE_RINGING). 2210 // TODO: Consider putting a stop to the above and turning CallState 2211 // into a well-defined state machine. 2212 // TODO: Define expected state transitions here, and log when an 2213 // unexpected transition occurs. 2214 call.setState(newState, tag); 2215 maybeShowErrorDialogOnDisconnect(call); 2216 2217 Trace.beginSection("onCallStateChanged"); 2218 2219 maybeHandleHandover(call, newState); 2220 2221 // Only broadcast state change for calls that are being tracked. 2222 if (mCalls.contains(call)) { 2223 updateCanAddCall(); 2224 for (CallsManagerListener listener : mListeners) { 2225 if (LogUtils.SYSTRACE_DEBUG) { 2226 Trace.beginSection(listener.getClass().toString() + " onCallStateChanged"); 2227 } 2228 listener.onCallStateChanged(call, oldState, newState); 2229 if (LogUtils.SYSTRACE_DEBUG) { 2230 Trace.endSection(); 2231 } 2232 } 2233 } 2234 Trace.endSection(); 2235 } 2236 } 2237 2238 /** 2239 * Identifies call state transitions for a call which trigger handover events. 2240 * - If this call has a handover to it which just started and this call goes active, treat 2241 * this as if the user accepted the handover. 2242 * - If this call has a handover to it which just started and this call is disconnected, treat 2243 * this as if the user rejected the handover. 2244 * - If this call has a handover from it which just started and this call is disconnected, do 2245 * nothing as the call prematurely disconnected before the user accepted the handover. 2246 * - If this call has a handover from it which was already accepted by the user and this call is 2247 * disconnected, mark the handover as complete. 2248 * 2249 * @param call A call whose state is changing. 2250 * @param newState The new state of the call. 2251 */ 2252 private void maybeHandleHandover(Call call, int newState) { 2253 if (call.getHandoverSourceCall() != null) { 2254 // We are handing over another call to this one. 2255 if (call.getHandoverState() == HandoverState.HANDOVER_TO_STARTED) { 2256 // A handover to this call has just been initiated. 2257 if (newState == CallState.ACTIVE) { 2258 // This call went active, so the user has accepted the handover. 2259 Log.i(this, "setCallState: handover to accepted"); 2260 acceptHandoverTo(call); 2261 } else if (newState == CallState.DISCONNECTED) { 2262 // The call was disconnected, so the user has rejected the handover. 2263 Log.i(this, "setCallState: handover to rejected"); 2264 rejectHandoverTo(call); 2265 } 2266 } 2267 // If this call was disconnected because it was handed over TO another call, report the 2268 // handover as complete. 2269 } else if (call.getHandoverDestinationCall() != null 2270 && newState == CallState.DISCONNECTED) { 2271 int handoverState = call.getHandoverState(); 2272 if (handoverState == HandoverState.HANDOVER_FROM_STARTED) { 2273 // Disconnect before handover was accepted. 2274 Log.i(this, "setCallState: disconnect before handover accepted"); 2275 // Let the handover destination know that the source has disconnected prior to 2276 // completion of the handover. 2277 call.getHandoverDestinationCall().sendCallEvent( 2278 android.telecom.Call.EVENT_HANDOVER_SOURCE_DISCONNECTED, null); 2279 } else if (handoverState == HandoverState.HANDOVER_ACCEPTED) { 2280 Log.i(this, "setCallState: handover from complete"); 2281 completeHandoverFrom(call); 2282 } 2283 } 2284 } 2285 2286 private void completeHandoverFrom(Call call) { 2287 Call handoverTo = call.getHandoverDestinationCall(); 2288 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 2289 call.getId(), handoverTo.getId()); 2290 Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 2291 call.getId(), handoverTo.getId()); 2292 2293 // Inform the "from" Call (ie the source call) that the handover from it has 2294 // completed; this allows the InCallService to be notified that a handover it 2295 // initiated completed. 2296 call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null); 2297 // Inform the "to" ConnectionService that handover to it has completed. 2298 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null); 2299 answerCall(handoverTo, handoverTo.getVideoState()); 2300 call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE); 2301 } 2302 2303 private void rejectHandoverTo(Call handoverTo) { 2304 Call handoverFrom = handoverTo.getHandoverSourceCall(); 2305 Log.i(this, "rejectHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 2306 Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s", 2307 handoverTo.getId(), handoverFrom.getId()); 2308 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s", 2309 handoverTo.getId(), handoverFrom.getId()); 2310 2311 // Inform the "from" Call (ie the source call) that the handover from it has 2312 // failed; this allows the InCallService to be notified that a handover it 2313 // initiated failed. 2314 handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null); 2315 // Inform the "to" ConnectionService that handover to it has failed. This 2316 // allows the ConnectionService the call was being handed over 2317 if (handoverTo.getConnectionService() != null) { 2318 // Only attempt if the call has a bound ConnectionService if handover failed 2319 // early on in the handover process, the CS will be unbound and we won't be 2320 // able to send the call event. 2321 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 2322 } 2323 handoverTo.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_FAILED); 2324 } 2325 2326 private void acceptHandoverTo(Call handoverTo) { 2327 Call handoverFrom = handoverTo.getHandoverSourceCall(); 2328 Log.i(this, "acceptHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 2329 handoverTo.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 2330 handoverFrom.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 2331 2332 Log.addEvent(handoverTo, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 2333 handoverFrom.getId(), handoverTo.getId()); 2334 Log.addEvent(handoverFrom, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 2335 handoverFrom.getId(), handoverTo.getId()); 2336 2337 // Disconnect the call we handed over from. 2338 disconnectCall(handoverFrom); 2339 } 2340 2341 private void updateCanAddCall() { 2342 boolean newCanAddCall = canAddCall(); 2343 if (newCanAddCall != mCanAddCall) { 2344 mCanAddCall = newCanAddCall; 2345 for (CallsManagerListener listener : mListeners) { 2346 if (LogUtils.SYSTRACE_DEBUG) { 2347 Trace.beginSection(listener.getClass().toString() + " updateCanAddCall"); 2348 } 2349 listener.onCanAddCallChanged(mCanAddCall); 2350 if (LogUtils.SYSTRACE_DEBUG) { 2351 Trace.endSection(); 2352 } 2353 } 2354 } 2355 } 2356 2357 private boolean isPotentialMMICode(Uri handle) { 2358 return (handle != null && handle.getSchemeSpecificPart() != null 2359 && handle.getSchemeSpecificPart().contains("#")); 2360 } 2361 2362 /** 2363 * Determines if a dialed number is potentially an In-Call MMI code. In-Call MMI codes are 2364 * MMI codes which can be dialed when one or more calls are in progress. 2365 * <P> 2366 * Checks for numbers formatted similar to the MMI codes defined in: 2367 * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)} 2368 * 2369 * @param handle The URI to call. 2370 * @return {@code True} if the URI represents a number which could be an in-call MMI code. 2371 */ 2372 private boolean isPotentialInCallMMICode(Uri handle) { 2373 if (handle != null && handle.getSchemeSpecificPart() != null && 2374 handle.getScheme() != null && 2375 handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) { 2376 2377 String dialedNumber = handle.getSchemeSpecificPart(); 2378 return (dialedNumber.equals("0") || 2379 (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) || 2380 (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) || 2381 dialedNumber.equals("3") || 2382 dialedNumber.equals("4") || 2383 dialedNumber.equals("5")); 2384 } 2385 return false; 2386 } 2387 2388 @VisibleForTesting 2389 public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall, 2390 PhoneAccountHandle phoneAccountHandle, int... states) { 2391 return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED, 2392 excludeCall, phoneAccountHandle, states); 2393 } 2394 2395 /** 2396 * Determines the number of calls matching the specified criteria. 2397 * @param callFilter indicates whether to include just managed calls 2398 * ({@link #CALL_FILTER_MANAGED}), self-managed calls 2399 * ({@link #CALL_FILTER_SELF_MANAGED}), or all calls 2400 * ({@link #CALL_FILTER_ALL}). 2401 * @param excludeCall Where {@code non-null}, this call is excluded from the count. 2402 * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle} 2403 * are excluded from the count. 2404 * @param states The list of {@link CallState}s to include in the count. 2405 * @return Count of calls matching criteria. 2406 */ 2407 @VisibleForTesting 2408 public int getNumCallsWithState(final int callFilter, Call excludeCall, 2409 PhoneAccountHandle phoneAccountHandle, int... states) { 2410 2411 Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet()); 2412 2413 Stream<Call> callsStream = mCalls.stream() 2414 .filter(call -> desiredStates.contains(call.getState()) && 2415 call.getParentCall() == null && !call.isExternalCall()); 2416 2417 if (callFilter == CALL_FILTER_MANAGED) { 2418 callsStream = callsStream.filter(call -> !call.isSelfManaged()); 2419 } else if (callFilter == CALL_FILTER_SELF_MANAGED) { 2420 callsStream = callsStream.filter(call -> call.isSelfManaged()); 2421 } 2422 2423 // If a call to exclude was specified, filter it out. 2424 if (excludeCall != null) { 2425 callsStream = callsStream.filter(call -> call != excludeCall); 2426 } 2427 2428 // If a phone account handle was specified, only consider calls for that phone account. 2429 if (phoneAccountHandle != null) { 2430 callsStream = callsStream.filter( 2431 call -> phoneAccountHandle.equals(call.getTargetPhoneAccount())); 2432 } 2433 2434 return (int) callsStream.count(); 2435 } 2436 2437 private boolean hasMaximumManagedLiveCalls(Call exceptCall) { 2438 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */, 2439 exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES); 2440 } 2441 2442 private boolean hasMaximumSelfManagedCalls(Call exceptCall, 2443 PhoneAccountHandle phoneAccountHandle) { 2444 return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */, 2445 exceptCall, phoneAccountHandle, ANY_CALL_STATE); 2446 } 2447 2448 private boolean hasMaximumManagedHoldingCalls(Call exceptCall) { 2449 return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2450 null /* phoneAccountHandle */, CallState.ON_HOLD); 2451 } 2452 2453 private boolean hasMaximumManagedRingingCalls(Call exceptCall) { 2454 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2455 null /* phoneAccountHandle */, CallState.RINGING); 2456 } 2457 2458 private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall, 2459 PhoneAccountHandle phoneAccountHandle) { 2460 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall, 2461 phoneAccountHandle, CallState.RINGING); 2462 } 2463 2464 private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) { 2465 return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2466 null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 2467 } 2468 2469 private boolean hasMaximumManagedDialingCalls(Call exceptCall) { 2470 return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 2471 null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING); 2472 } 2473 2474 /** 2475 * Given a {@link PhoneAccountHandle} determines if there are calls owned by any other 2476 * {@link PhoneAccountHandle}. 2477 * @param phoneAccountHandle The {@link PhoneAccountHandle} to check. 2478 * @return {@code true} if there are other calls, {@code false} otherwise. 2479 */ 2480 public boolean hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 2481 return getNumCallsForOtherPhoneAccount(phoneAccountHandle) > 0; 2482 } 2483 2484 /** 2485 * Determines the number of calls present for PhoneAccounts other than the one specified. 2486 * @param phoneAccountHandle The handle of the PhoneAccount. 2487 * @return Number of calls owned by other PhoneAccounts. 2488 */ 2489 public int getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) { 2490 return (int) mCalls.stream().filter(call -> 2491 !phoneAccountHandle.equals(call.getTargetPhoneAccount()) && 2492 call.getParentCall() == null && 2493 !call.isExternalCall()).count(); 2494 } 2495 2496 /** 2497 * Determines if there are any managed calls. 2498 * @return {@code true} if there are managed calls, {@code false} otherwise. 2499 */ 2500 public boolean hasManagedCalls() { 2501 return mCalls.stream().filter(call -> !call.isSelfManaged() && 2502 !call.isExternalCall()).count() > 0; 2503 } 2504 2505 /** 2506 * Determines if there are any self-managed calls. 2507 * @return {@code true} if there are self-managed calls, {@code false} otherwise. 2508 */ 2509 public boolean hasSelfManagedCalls() { 2510 return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0; 2511 } 2512 2513 /** 2514 * Determines if there are any ongoing managed or self-managed calls. 2515 * Note: The {@link #ONGOING_CALL_STATES} are 2516 * @return {@code true} if there are ongoing managed or self-managed calls, {@code false} 2517 * otherwise. 2518 */ 2519 public boolean hasOngoingCalls() { 2520 return getNumCallsWithState( 2521 CALL_FILTER_ALL, null /* excludeCall */, 2522 null /* phoneAccountHandle */, 2523 ONGOING_CALL_STATES) > 0; 2524 } 2525 2526 /** 2527 * Determines if there are any ongoing managed calls. 2528 * @return {@code true} if there are ongoing managed calls, {@code false} otherwise. 2529 */ 2530 public boolean hasOngoingManagedCalls() { 2531 return getNumCallsWithState( 2532 CALL_FILTER_MANAGED, null /* excludeCall */, 2533 null /* phoneAccountHandle */, 2534 ONGOING_CALL_STATES) > 0; 2535 } 2536 2537 /** 2538 * Determines if the system incoming call UI should be shown. 2539 * The system incoming call UI will be shown if the new incoming call is self-managed, and there 2540 * are ongoing calls for another PhoneAccount. 2541 * @param incomingCall The incoming call. 2542 * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise. 2543 */ 2544 public boolean shouldShowSystemIncomingCallUi(Call incomingCall) { 2545 return incomingCall.isIncoming() && incomingCall.isSelfManaged() && 2546 hasCallsForOtherPhoneAccount(incomingCall.getTargetPhoneAccount()) && 2547 incomingCall.getHandoverSourceCall() == null; 2548 } 2549 2550 private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) { 2551 if (hasMaximumManagedLiveCalls(call)) { 2552 // NOTE: If the amount of live calls changes beyond 1, this logic will probably 2553 // have to change. 2554 Call liveCall = getFirstCallWithState(LIVE_CALL_STATES); 2555 Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " + 2556 liveCall); 2557 2558 if (call == liveCall) { 2559 // If the call is already the foreground call, then we are golden. 2560 // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT 2561 // state since the call was already populated into the list. 2562 return true; 2563 } 2564 2565 if (hasMaximumManagedOutgoingCalls(call)) { 2566 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES); 2567 if (isEmergency && !outgoingCall.isEmergencyCall()) { 2568 // Disconnect the current outgoing call if it's not an emergency call. If the 2569 // user tries to make two outgoing calls to different emergency call numbers, 2570 // we will try to connect the first outgoing call. 2571 call.getAnalytics().setCallIsAdditional(true); 2572 outgoingCall.getAnalytics().setCallIsInterrupted(true); 2573 outgoingCall.disconnect(); 2574 return true; 2575 } 2576 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) { 2577 // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT} 2578 // state, just disconnect it since the user has explicitly started a new call. 2579 call.getAnalytics().setCallIsAdditional(true); 2580 outgoingCall.getAnalytics().setCallIsInterrupted(true); 2581 outgoingCall.disconnect(); 2582 return true; 2583 } 2584 return false; 2585 } 2586 2587 if (hasMaximumManagedHoldingCalls(call)) { 2588 // There is no more room for any more calls, unless it's an emergency. 2589 if (isEmergency) { 2590 // Kill the current active call, this is easier then trying to disconnect a 2591 // holding call and hold an active call. 2592 call.getAnalytics().setCallIsAdditional(true); 2593 liveCall.getAnalytics().setCallIsInterrupted(true); 2594 liveCall.disconnect(); 2595 return true; 2596 } 2597 return false; // No more room! 2598 } 2599 2600 // We have room for at least one more holding call at this point. 2601 2602 // TODO: Remove once b/23035408 has been corrected. 2603 // If the live call is a conference, it will not have a target phone account set. This 2604 // means the check to see if the live call has the same target phone account as the new 2605 // call will not cause us to bail early. As a result, we'll end up holding the 2606 // ongoing conference call. However, the ConnectionService is already doing that. This 2607 // has caused problems with some carriers. As a workaround until b/23035408 is 2608 // corrected, we will try and get the target phone account for one of the conference's 2609 // children and use that instead. 2610 PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount(); 2611 if (liveCallPhoneAccount == null && liveCall.isConference() && 2612 !liveCall.getChildCalls().isEmpty()) { 2613 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall); 2614 Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " + 2615 liveCallPhoneAccount); 2616 } 2617 2618 // First thing, if we are trying to make a call with the same phone account as the live 2619 // call, then allow it so that the connection service can make its own decision about 2620 // how to handle the new call relative to the current one. 2621 if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) { 2622 Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches."); 2623 call.getAnalytics().setCallIsAdditional(true); 2624 liveCall.getAnalytics().setCallIsInterrupted(true); 2625 return true; 2626 } else if (call.getTargetPhoneAccount() == null) { 2627 // Without a phone account, we can't say reliably that the call will fail. 2628 // If the user chooses the same phone account as the live call, then it's 2629 // still possible that the call can be made (like with CDMA calls not supporting 2630 // hold but they still support adding a call by going immediately into conference 2631 // mode). Return true here and we'll run this code again after user chooses an 2632 // account. 2633 return true; 2634 } 2635 2636 // Try to hold the live call before attempting the new outgoing call. 2637 if (liveCall.can(Connection.CAPABILITY_HOLD)) { 2638 Log.i(this, "makeRoomForOutgoingCall: holding live call."); 2639 call.getAnalytics().setCallIsAdditional(true); 2640 liveCall.getAnalytics().setCallIsInterrupted(true); 2641 liveCall.hold(); 2642 return true; 2643 } 2644 2645 // The live call cannot be held so we're out of luck here. There's no room. 2646 return false; 2647 } 2648 return true; 2649 } 2650 2651 /** 2652 * Given a call, find the first non-null phone account handle of its children. 2653 * 2654 * @param parentCall The parent call. 2655 * @return The first non-null phone account handle of the children, or {@code null} if none. 2656 */ 2657 private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) { 2658 for (Call childCall : parentCall.getChildCalls()) { 2659 PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount(); 2660 if (childPhoneAccount != null) { 2661 return childPhoneAccount; 2662 } 2663 } 2664 return null; 2665 } 2666 2667 /** 2668 * Checks to see if the call should be on speakerphone and if so, set it. 2669 */ 2670 private void maybeMoveToSpeakerPhone(Call call) { 2671 if (call.isHandoverInProgress() && call.getState() == CallState.DIALING) { 2672 // When a new outgoing call is initiated for the purpose of handing over, do not engage 2673 // speaker automatically until the call goes active. 2674 return; 2675 } 2676 if (call.getStartWithSpeakerphoneOn()) { 2677 setAudioRoute(CallAudioState.ROUTE_SPEAKER); 2678 call.setStartWithSpeakerphoneOn(false); 2679 } 2680 } 2681 2682 /** 2683 * Creates a new call for an existing connection. 2684 * 2685 * @param callId The id of the new call. 2686 * @param connection The connection information. 2687 * @return The new call. 2688 */ 2689 Call createCallForExistingConnection(String callId, ParcelableConnection connection) { 2690 boolean isDowngradedConference = (connection.getConnectionProperties() 2691 & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0; 2692 Call call = new Call( 2693 callId, 2694 mContext, 2695 this, 2696 mLock, 2697 mConnectionServiceRepository, 2698 mContactsAsyncHelper, 2699 mCallerInfoAsyncQueryFactory, 2700 mPhoneNumberUtilsAdapter, 2701 connection.getHandle() /* handle */, 2702 null /* gatewayInfo */, 2703 null /* connectionManagerPhoneAccount */, 2704 connection.getPhoneAccount(), /* targetPhoneAccountHandle */ 2705 Call.CALL_DIRECTION_UNDEFINED /* callDirection */, 2706 false /* forceAttachToExistingConnection */, 2707 isDowngradedConference /* isConference */, 2708 connection.getConnectTimeMillis() /* connectTimeMillis */, 2709 connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */ 2710 mClockProxy); 2711 2712 call.initAnalytics(); 2713 call.getAnalytics().setCreatedFromExistingConnection(true); 2714 2715 setCallState(call, Call.getStateFromConnectionState(connection.getState()), 2716 "existing connection"); 2717 call.setConnectionCapabilities(connection.getConnectionCapabilities()); 2718 call.setConnectionProperties(connection.getConnectionProperties()); 2719 call.setHandle(connection.getHandle(), connection.getHandlePresentation()); 2720 call.setCallerDisplayName(connection.getCallerDisplayName(), 2721 connection.getCallerDisplayNamePresentation()); 2722 call.addListener(this); 2723 2724 // In case this connection was added via a ConnectionManager, keep track of the original 2725 // Connection ID as created by the originating ConnectionService. 2726 Bundle extras = connection.getExtras(); 2727 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2728 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 2729 } 2730 Log.i(this, "createCallForExistingConnection: %s", connection); 2731 Call parentCall = null; 2732 if (!TextUtils.isEmpty(connection.getParentCallId())) { 2733 String parentId = connection.getParentCallId(); 2734 parentCall = mCalls 2735 .stream() 2736 .filter(c -> c.getId().equals(parentId)) 2737 .findFirst() 2738 .orElse(null); 2739 if (parentCall != null) { 2740 Log.i(this, "createCallForExistingConnection: %s added as child of %s.", 2741 call.getId(), 2742 parentCall.getId()); 2743 // Set JUST the parent property, which won't send an update to the Incall UI. 2744 call.setParentCall(parentCall); 2745 } 2746 } 2747 addCall(call); 2748 if (parentCall != null) { 2749 // Now, set the call as a child of the parent since it has been added to Telecom. This 2750 // is where we will inform InCall. 2751 call.setChildOf(parentCall); 2752 call.notifyParentChanged(parentCall); 2753 } 2754 2755 return call; 2756 } 2757 2758 /** 2759 * Determines whether Telecom already knows about a Connection added via the 2760 * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle, 2761 * Connection)} API via a ConnectionManager. 2762 * 2763 * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}. 2764 * @param originalConnectionId The new connection ID to check. 2765 * @return {@code true} if this connection is already known by Telecom. 2766 */ 2767 Call getAlreadyAddedConnection(String originalConnectionId) { 2768 Optional<Call> existingCall = mCalls.stream() 2769 .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) || 2770 originalConnectionId.equals(call.getId())) 2771 .findFirst(); 2772 2773 if (existingCall.isPresent()) { 2774 Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s", 2775 originalConnectionId, existingCall.get().getId()); 2776 return existingCall.get(); 2777 } 2778 2779 return null; 2780 } 2781 2782 /** 2783 * @return A new unique telecom call Id. 2784 */ 2785 private String getNextCallId() { 2786 synchronized(mLock) { 2787 return TELECOM_CALL_ID_PREFIX + (++mCallId); 2788 } 2789 } 2790 2791 public int getNextRttRequestId() { 2792 synchronized (mLock) { 2793 return (++mRttRequestId); 2794 } 2795 } 2796 2797 /** 2798 * Callback when foreground user is switched. We will reload missed call in all profiles 2799 * including the user itself. There may be chances that profiles are not started yet. 2800 */ 2801 @VisibleForTesting 2802 public void onUserSwitch(UserHandle userHandle) { 2803 mCurrentUserHandle = userHandle; 2804 mMissedCallNotifier.setCurrentUserHandle(userHandle); 2805 final UserManager userManager = UserManager.get(mContext); 2806 List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier()); 2807 for (UserInfo profile : profiles) { 2808 reloadMissedCallsOfUser(profile.getUserHandle()); 2809 } 2810 } 2811 2812 /** 2813 * Because there may be chances that profiles are not started yet though its parent user is 2814 * switched, we reload missed calls of profile that are just started here. 2815 */ 2816 void onUserStarting(UserHandle userHandle) { 2817 if (UserUtil.isProfile(mContext, userHandle)) { 2818 reloadMissedCallsOfUser(userHandle); 2819 } 2820 } 2821 2822 public TelecomSystem.SyncRoot getLock() { 2823 return mLock; 2824 } 2825 2826 private void reloadMissedCallsOfUser(UserHandle userHandle) { 2827 mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper, 2828 new MissedCallNotifier.CallInfoFactory(), userHandle); 2829 } 2830 2831 public void onBootCompleted() { 2832 mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper, 2833 new MissedCallNotifier.CallInfoFactory()); 2834 } 2835 2836 public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 2837 return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle); 2838 } 2839 2840 public boolean isIncomingCallPermitted(Call excludeCall, 2841 PhoneAccountHandle phoneAccountHandle) { 2842 if (phoneAccountHandle == null) { 2843 return false; 2844 } 2845 PhoneAccount phoneAccount = 2846 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 2847 if (phoneAccount == null) { 2848 return false; 2849 } 2850 2851 if (!phoneAccount.isSelfManaged()) { 2852 return !hasMaximumManagedRingingCalls(excludeCall) && 2853 !hasMaximumManagedHoldingCalls(excludeCall); 2854 } else { 2855 return !hasEmergencyCall() && 2856 !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) && 2857 !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle); 2858 } 2859 } 2860 2861 public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 2862 return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle); 2863 } 2864 2865 public boolean isOutgoingCallPermitted(Call excludeCall, 2866 PhoneAccountHandle phoneAccountHandle) { 2867 if (phoneAccountHandle == null) { 2868 return false; 2869 } 2870 PhoneAccount phoneAccount = 2871 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 2872 if (phoneAccount == null) { 2873 return false; 2874 } 2875 2876 if (!phoneAccount.isSelfManaged()) { 2877 return !hasMaximumManagedOutgoingCalls(excludeCall) && 2878 !hasMaximumManagedDialingCalls(excludeCall) && 2879 !hasMaximumManagedLiveCalls(excludeCall) && 2880 !hasMaximumManagedHoldingCalls(excludeCall); 2881 } else { 2882 // Only permit outgoing calls if there is no ongoing emergency calls and all other calls 2883 // are associated with the current PhoneAccountHandle. 2884 return !hasEmergencyCall() && ( 2885 excludeCall.getHandoverSourceCall() != null || 2886 (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) && 2887 !hasCallsForOtherPhoneAccount(phoneAccountHandle) && 2888 !hasManagedCalls())); 2889 } 2890 } 2891 2892 /** 2893 * Blocks execution until all Telecom handlers have completed their current work. 2894 */ 2895 public void waitOnHandlers() { 2896 CountDownLatch mainHandlerLatch = new CountDownLatch(3); 2897 mHandler.post(() -> { 2898 mainHandlerLatch.countDown(); 2899 }); 2900 mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> { 2901 mainHandlerLatch.countDown(); 2902 }); 2903 mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> { 2904 mainHandlerLatch.countDown(); 2905 }); 2906 2907 try { 2908 mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS); 2909 } catch (InterruptedException e) { 2910 Log.w(this, "waitOnHandlers: interrupted %s", e); 2911 } 2912 } 2913 2914 /** 2915 * Used to confirm creation of an outgoing call which was marked as pending confirmation in 2916 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}. 2917 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 2918 * {@link ConfirmCallDialogActivity}. 2919 * @param callId The call ID of the call to confirm. 2920 */ 2921 public void confirmPendingCall(String callId) { 2922 Log.i(this, "confirmPendingCall: callId=%s", callId); 2923 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 2924 Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED); 2925 addCall(mPendingCall); 2926 2927 // We are going to place the new outgoing call, so disconnect any ongoing self-managed 2928 // calls which are ongoing at this time. 2929 disconnectSelfManagedCalls(); 2930 2931 // Kick of the new outgoing call intent from where it left off prior to confirming the 2932 // call. 2933 CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this, 2934 mPendingCall.getOriginalCallIntent()); 2935 mPendingCall = null; 2936 } 2937 } 2938 2939 /** 2940 * Used to cancel an outgoing call which was marked as pending confirmation in 2941 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}. 2942 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 2943 * {@link ConfirmCallDialogActivity}. 2944 * @param callId The call ID of the call to cancel. 2945 */ 2946 public void cancelPendingCall(String callId) { 2947 Log.i(this, "cancelPendingCall: callId=%s", callId); 2948 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 2949 Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED); 2950 markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED)); 2951 markCallAsRemoved(mPendingCall); 2952 mPendingCall = null; 2953 } 2954 } 2955 2956 /** 2957 * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when 2958 * a managed call is added while there are ongoing self-managed calls. Starts 2959 * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the 2960 * outgoing call or not. 2961 * @param call The call to confirm. 2962 */ 2963 private void startCallConfirmation(Call call) { 2964 if (mPendingCall != null) { 2965 Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s", 2966 mPendingCall.getId(), call.getId()); 2967 markCallDisconnectedDueToSelfManagedCall(call); 2968 return; 2969 } 2970 Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION); 2971 mPendingCall = call; 2972 2973 // Figure out the name of the app in charge of the self-managed call(s). 2974 Call selfManagedCall = mCalls.stream() 2975 .filter(c -> c.isSelfManaged()) 2976 .findFirst() 2977 .orElse(null); 2978 CharSequence ongoingAppName = ""; 2979 if (selfManagedCall != null) { 2980 ongoingAppName = selfManagedCall.getTargetPhoneAccountLabel(); 2981 } 2982 Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(), 2983 ongoingAppName); 2984 2985 Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class); 2986 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId()); 2987 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName); 2988 confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2989 mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT); 2990 } 2991 2992 /** 2993 * Disconnects all self-managed calls. 2994 */ 2995 private void disconnectSelfManagedCalls() { 2996 // Disconnect all self-managed calls to make priority for emergency call. 2997 // Use Call.disconnect() to command the ConnectionService to disconnect the calls. 2998 // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to 2999 // disconnect. 3000 mCalls.stream() 3001 .filter(c -> c.isSelfManaged()) 3002 .forEach(c -> c.disconnect()); 3003 } 3004 3005 /** 3006 * Dumps the state of the {@link CallsManager}. 3007 * 3008 * @param pw The {@code IndentingPrintWriter} to write the state to. 3009 */ 3010 public void dump(IndentingPrintWriter pw) { 3011 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 3012 if (mCalls != null) { 3013 pw.println("mCalls: "); 3014 pw.increaseIndent(); 3015 for (Call call : mCalls) { 3016 pw.println(call); 3017 } 3018 pw.decreaseIndent(); 3019 } 3020 3021 if (mPendingCall != null) { 3022 pw.print("mPendingCall:"); 3023 pw.println(mPendingCall.getId()); 3024 } 3025 3026 if (mCallAudioManager != null) { 3027 pw.println("mCallAudioManager:"); 3028 pw.increaseIndent(); 3029 mCallAudioManager.dump(pw); 3030 pw.decreaseIndent(); 3031 } 3032 3033 if (mTtyManager != null) { 3034 pw.println("mTtyManager:"); 3035 pw.increaseIndent(); 3036 mTtyManager.dump(pw); 3037 pw.decreaseIndent(); 3038 } 3039 3040 if (mInCallController != null) { 3041 pw.println("mInCallController:"); 3042 pw.increaseIndent(); 3043 mInCallController.dump(pw); 3044 pw.decreaseIndent(); 3045 } 3046 3047 if (mDefaultDialerCache != null) { 3048 pw.println("mDefaultDialerCache:"); 3049 pw.increaseIndent(); 3050 mDefaultDialerCache.dumpCache(pw); 3051 pw.decreaseIndent(); 3052 } 3053 3054 if (mConnectionServiceRepository != null) { 3055 pw.println("mConnectionServiceRepository:"); 3056 pw.increaseIndent(); 3057 mConnectionServiceRepository.dump(pw); 3058 pw.decreaseIndent(); 3059 } 3060 } 3061 3062 /** 3063 * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code. 3064 * 3065 * @param call The call. 3066 */ 3067 private void maybeShowErrorDialogOnDisconnect(Call call) { 3068 if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle()) 3069 || isPotentialInCallMMICode(call.getHandle()))) { 3070 DisconnectCause disconnectCause = call.getDisconnectCause(); 3071 if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode() 3072 == DisconnectCause.ERROR)) { 3073 Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 3074 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA, 3075 disconnectCause.getDescription()); 3076 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3077 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 3078 } 3079 } 3080 } 3081 3082 private void setIntentExtrasAndStartTime(Call call, Bundle extras) { 3083 // Create our own instance to modify (since extras may be Bundle.EMPTY) 3084 extras = new Bundle(extras); 3085 3086 // Specifies the time telecom began routing the call. This is used by the dialer for 3087 // analytics. 3088 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, 3089 SystemClock.elapsedRealtime()); 3090 3091 call.setIntentExtras(extras); 3092 } 3093 3094 /** 3095 * Notifies the {@link android.telecom.ConnectionService} associated with a 3096 * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. 3097 * 3098 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 3099 * @param call The {@link Call} which could not be added. 3100 */ 3101 private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) { 3102 if (phoneAccountHandle == null) { 3103 return; 3104 } 3105 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 3106 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); 3107 if (service == null) { 3108 Log.i(this, "Found no connection service."); 3109 return; 3110 } else { 3111 call.setConnectionService(service); 3112 service.createConnectionFailed(call); 3113 } 3114 } 3115 3116 /** 3117 * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)} 3118 * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the 3119 * {@link android.telecom.InCallService} has requested a handover to another 3120 * {@link android.telecom.ConnectionService}. 3121 * 3122 * We will explicitly disallow a handover when there is an emergency call present. 3123 * 3124 * @param handoverFromCall The {@link Call} to be handed over. 3125 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 3126 * @param videoState The desired video state of {@link Call} after handover. 3127 * @param initiatingExtras Extras associated with the handover, to be passed to the handover 3128 * {@link android.telecom.ConnectionService}. 3129 */ 3130 private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle, 3131 int videoState, Bundle initiatingExtras) { 3132 3133 boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported( 3134 handoverFromCall.getTargetPhoneAccount()); 3135 boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle); 3136 3137 if (!isHandoverFromSupported || !isHandoverToSupported || hasEmergencyCall()) { 3138 handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 3139 return; 3140 } 3141 3142 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle); 3143 3144 Bundle extras = new Bundle(); 3145 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 3146 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 3147 handoverFromCall.getTargetPhoneAccount()); 3148 extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 3149 if (initiatingExtras != null) { 3150 extras.putAll(initiatingExtras); 3151 } 3152 extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE, 3153 mCallAudioManager.getCallAudioState()); 3154 Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle, 3155 extras, getCurrentUserHandle(), null /* originalIntent */); 3156 Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER, 3157 "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), handoverToCall.getId()); 3158 handoverFromCall.setHandoverDestinationCall(handoverToCall); 3159 handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 3160 handoverToCall.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 3161 handoverToCall.setHandoverSourceCall(handoverFromCall); 3162 handoverToCall.setNewOutgoingCallIntentBroadcastIsDone(); 3163 placeOutgoingCall(handoverToCall, handoverToCall.getHandle(), null /* gatewayInfo */, 3164 false /* startwithSpeaker */, 3165 videoState); 3166 } 3167 3168 /** 3169 * Determines if handover from the specified {@link PhoneAccountHandle} is supported. 3170 * 3171 * @param from The {@link PhoneAccountHandle} the handover originates from. 3172 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 3173 */ 3174 private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) { 3175 return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM); 3176 } 3177 3178 /** 3179 * Determines if handover to the specified {@link PhoneAccountHandle} is supported. 3180 * 3181 * @param to The {@link PhoneAccountHandle} the handover it to. 3182 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 3183 */ 3184 private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) { 3185 return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO); 3186 } 3187 3188 /** 3189 * Retrieves a boolean phone account extra. 3190 * @param handle the {@link PhoneAccountHandle} to retrieve the extra for. 3191 * @param key The extras key. 3192 * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false} 3193 * otherwise. 3194 */ 3195 private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) { 3196 PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle); 3197 if (phoneAccount == null) { 3198 return false; 3199 } 3200 3201 Bundle fromExtras = phoneAccount.getExtras(); 3202 if (fromExtras == null) { 3203 return false; 3204 } 3205 return fromExtras.getBoolean(key); 3206 } 3207 3208 /** 3209 * Determines if there is an existing handover in process. 3210 * @return {@code true} if a call in the process of handover exists, {@code false} otherwise. 3211 */ 3212 private boolean isHandoverInProgress() { 3213 return mCalls.stream().filter(c -> c.getHandoverSourceCall() != null || 3214 c.getHandoverDestinationCall() != null).count() > 0; 3215 } 3216 3217 private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) { 3218 Intent intent = 3219 new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED); 3220 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 3221 intent.putExtra( 3222 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3223 Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle); 3224 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 3225 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 3226 3227 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 3228 getCurrentUserHandle().getIdentifier()); 3229 if (!TextUtils.isEmpty(dialerPackage)) { 3230 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED) 3231 .setPackage(dialerPackage); 3232 directedIntent.putExtra( 3233 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3234 Log.i(this, "Sending phone-account unregistered intent to default dialer"); 3235 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 3236 } 3237 return ; 3238 } 3239 3240 private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) { 3241 Intent intent = new Intent( 3242 TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED); 3243 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 3244 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 3245 accountHandle); 3246 Log.i(this, "Sending phone-account %s registered intent as user", accountHandle); 3247 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 3248 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 3249 3250 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 3251 getCurrentUserHandle().getIdentifier()); 3252 if (!TextUtils.isEmpty(dialerPackage)) { 3253 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED) 3254 .setPackage(dialerPackage); 3255 directedIntent.putExtra( 3256 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 3257 Log.i(this, "Sending phone-account registered intent to default dialer"); 3258 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 3259 } 3260 return ; 3261 } 3262} 3263