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