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