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