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.annotation.NonNull; 20 import android.app.ActivityManager; 21 import android.app.KeyguardManager; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.UserInfo; 29 import android.media.AudioManager; 30 import android.media.AudioSystem; 31 import android.media.ToneGenerator; 32 import android.media.MediaPlayer; 33 import android.net.Uri; 34 import android.os.AsyncTask; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.Looper; 38 import android.os.Process; 39 import android.os.SystemClock; 40 import android.os.SystemProperties; 41 import android.os.SystemVibrator; 42 import android.os.Trace; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.provider.BlockedNumberContract.SystemContract; 46 import android.provider.CallLog.Calls; 47 import android.provider.Settings; 48 import android.telecom.CallAudioState; 49 import android.telecom.Conference; 50 import android.telecom.Connection; 51 import android.telecom.DisconnectCause; 52 import android.telecom.GatewayInfo; 53 import android.telecom.Log; 54 import android.telecom.Logging.Runnable; 55 import android.telecom.Logging.Session; 56 import android.telecom.ParcelableConference; 57 import android.telecom.ParcelableConnection; 58 import android.telecom.PhoneAccount; 59 import android.telecom.PhoneAccountHandle; 60 import android.telecom.PhoneAccountSuggestion; 61 import android.telecom.TelecomManager; 62 import android.telecom.VideoProfile; 63 import android.telephony.CarrierConfigManager; 64 import android.telephony.PhoneNumberUtils; 65 import android.telephony.TelephonyManager; 66 import android.text.TextUtils; 67 import android.util.Pair; 68 69 import com.android.internal.annotations.VisibleForTesting; 70 import com.android.internal.telephony.AsyncEmergencyContactNotifier; 71 import com.android.internal.telephony.CallerInfo; 72 import com.android.internal.telephony.PhoneConstants; 73 import com.android.internal.telephony.TelephonyProperties; 74 import com.android.internal.util.IndentingPrintWriter; 75 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 76 import com.android.server.telecom.bluetooth.BluetoothStateReceiver; 77 import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter; 78 import com.android.server.telecom.callfiltering.BlockCheckerAdapter; 79 import com.android.server.telecom.callfiltering.CallFilterResultCallback; 80 import com.android.server.telecom.callfiltering.CallFilteringResult; 81 import com.android.server.telecom.callfiltering.CallScreeningServiceController; 82 import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter; 83 import com.android.server.telecom.callfiltering.IncomingCallFilter; 84 import com.android.server.telecom.callredirection.CallRedirectionProcessor; 85 import com.android.server.telecom.components.ErrorDialogActivity; 86 import com.android.server.telecom.settings.BlockedNumbersUtil; 87 import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity; 88 import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity; 89 import com.android.server.telecom.ui.ConfirmCallDialogActivity; 90 import com.android.server.telecom.ui.IncomingCallNotifier; 91 92 import java.util.ArrayList; 93 import java.util.Arrays; 94 import java.util.Collection; 95 import java.util.Collections; 96 import java.util.HashMap; 97 import java.util.HashSet; 98 import java.util.Iterator; 99 import java.util.List; 100 import java.util.Map; 101 import java.util.Objects; 102 import java.util.Optional; 103 import java.util.Set; 104 import java.util.concurrent.CompletableFuture; 105 import java.util.concurrent.ConcurrentHashMap; 106 import java.util.concurrent.CountDownLatch; 107 import java.util.concurrent.TimeUnit; 108 import java.util.stream.Collectors; 109 import java.util.stream.IntStream; 110 import java.util.stream.Stream; 111 112 /** 113 * Singleton. 114 * 115 * NOTE: by design most APIs are package private, use the relevant adapter/s to allow 116 * access from other packages specifically refraining from passing the CallsManager instance 117 * beyond the com.android.server.telecom package boundary. 118 */ 119 @VisibleForTesting 120 public class CallsManager extends Call.ListenerBase 121 implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy { 122 123 // TODO: Consider renaming this CallsManagerPlugin. 124 @VisibleForTesting 125 public interface CallsManagerListener { onCallAdded(Call call)126 void onCallAdded(Call call); onCallRemoved(Call call)127 void onCallRemoved(Call call); onCallStateChanged(Call call, int oldState, int newState)128 void onCallStateChanged(Call call, int oldState, int newState); onConnectionServiceChanged( Call call, ConnectionServiceWrapper oldService, ConnectionServiceWrapper newService)129 void onConnectionServiceChanged( 130 Call call, 131 ConnectionServiceWrapper oldService, 132 ConnectionServiceWrapper newService); onIncomingCallAnswered(Call call)133 void onIncomingCallAnswered(Call call); onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage)134 void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage); onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState)135 void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState); onRingbackRequested(Call call, boolean ringback)136 void onRingbackRequested(Call call, boolean ringback); onIsConferencedChanged(Call call)137 void onIsConferencedChanged(Call call); onIsVoipAudioModeChanged(Call call)138 void onIsVoipAudioModeChanged(Call call); onVideoStateChanged(Call call, int previousVideoState, int newVideoState)139 void onVideoStateChanged(Call call, int previousVideoState, int newVideoState); onCanAddCallChanged(boolean canAddCall)140 void onCanAddCallChanged(boolean canAddCall); onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)141 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); onHoldToneRequested(Call call)142 void onHoldToneRequested(Call call); onExternalCallChanged(Call call, boolean isExternalCall)143 void onExternalCallChanged(Call call, boolean isExternalCall); onDisconnectedTonePlaying(boolean isTonePlaying)144 void onDisconnectedTonePlaying(boolean isTonePlaying); onConnectionTimeChanged(Call call)145 void onConnectionTimeChanged(Call call); onConferenceStateChanged(Call call, boolean isConference)146 void onConferenceStateChanged(Call call, boolean isConference); 147 } 148 149 /** Interface used to define the action which is executed delay under some condition. */ 150 interface PendingAction { performAction()151 void performAction(); 152 } 153 154 private static final String TAG = "CallsManager"; 155 156 /** 157 * Call filter specifier used with 158 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 159 * self-managed calls should be included. 160 */ 161 private static final int CALL_FILTER_SELF_MANAGED = 1; 162 163 /** 164 * Call filter specifier used with 165 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 166 * managed calls should be included. 167 */ 168 private static final int CALL_FILTER_MANAGED = 2; 169 170 /** 171 * Call filter specifier used with 172 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed 173 * and self-managed calls should be included. 174 */ 175 private static final int CALL_FILTER_ALL = 3; 176 177 private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION = 178 "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"; 179 180 private static final int HANDLER_WAIT_TIMEOUT = 10000; 181 private static final int MAXIMUM_LIVE_CALLS = 1; 182 private static final int MAXIMUM_HOLD_CALLS = 1; 183 private static final int MAXIMUM_RINGING_CALLS = 1; 184 private static final int MAXIMUM_DIALING_CALLS = 1; 185 private static final int MAXIMUM_OUTGOING_CALLS = 1; 186 private static final int MAXIMUM_TOP_LEVEL_CALLS = 2; 187 private static final int MAXIMUM_SELF_MANAGED_CALLS = 10; 188 189 private static final int[] OUTGOING_CALL_STATES = 190 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 191 CallState.PULLING}; 192 193 /** 194 * These states are used by {@link #makeRoomForOutgoingCall(Call, boolean)} to determine which 195 * call should be ended first to make room for a new outgoing call. 196 */ 197 private static final int[] LIVE_CALL_STATES = 198 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 199 CallState.PULLING, CallState.ACTIVE}; 200 201 /** 202 * These states determine which calls will cause {@link TelecomManager#isInCall()} or 203 * {@link TelecomManager#isInManagedCall()} to return true. 204 * 205 * See also {@link PhoneStateBroadcaster}, which considers a similar set of states as being 206 * off-hook. 207 */ 208 public static final int[] ONGOING_CALL_STATES = 209 {CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.PULLING, CallState.ACTIVE, 210 CallState.ON_HOLD, CallState.RINGING, CallState.ANSWERED}; 211 212 private static final int[] ANY_CALL_STATE = 213 {CallState.NEW, CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 214 CallState.RINGING, CallState.ACTIVE, CallState.ON_HOLD, CallState.DISCONNECTED, 215 CallState.ABORTED, CallState.DISCONNECTING, CallState.PULLING, 216 CallState.ANSWERED}; 217 218 public static final String TELECOM_CALL_ID_PREFIX = "TC@"; 219 220 // Maps call technologies in PhoneConstants to those in Analytics. 221 private static final Map<Integer, Integer> sAnalyticsTechnologyMap; 222 static { 223 sAnalyticsTechnologyMap = new HashMap<>(5); sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE)224 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE); sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE)225 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE); sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE)226 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE); sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE)227 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE); sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY, Analytics.THIRD_PARTY_PHONE)228 sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY, 229 Analytics.THIRD_PARTY_PHONE); 230 } 231 232 /** 233 * The main call repository. Keeps an instance of all live calls. New incoming and outgoing 234 * calls are added to the map and removed when the calls move to the disconnected state. 235 * 236 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 237 * load factor before resizing, 1 means we only expect a single thread to 238 * access the map so make only a single shard 239 */ 240 private final Set<Call> mCalls = Collections.newSetFromMap( 241 new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1)); 242 243 /** 244 * A pending call is one which requires user-intervention in order to be placed. 245 * Used by {@link #startCallConfirmation}. 246 */ 247 private Call mPendingCall; 248 /** 249 * Cached latest pending redirected call which requires user-intervention in order to be placed. 250 * Used by {@link #onCallRedirectionComplete}. 251 */ 252 private Call mPendingRedirectedOutgoingCall; 253 /** 254 * Cached latest pending redirected call information which require user-intervention in order 255 * to be placed. Used by {@link #onCallRedirectionComplete}. 256 */ 257 private final Map<String, Runnable> mPendingRedirectedOutgoingCallInfo = 258 new ConcurrentHashMap<>(); 259 /** 260 * Cached latest pending Unredirected call information which require user-intervention in order 261 * to be placed. Used by {@link #onCallRedirectionComplete}. 262 */ 263 private final Map<String, Runnable> mPendingUnredirectedOutgoingCallInfo = 264 new ConcurrentHashMap<>(); 265 266 private CompletableFuture<Call> mPendingCallConfirm; 267 private CompletableFuture<Pair<Call, PhoneAccountHandle>> mPendingAccountSelection; 268 269 // Instance variables for testing -- we keep the latest copy of the outgoing call futures 270 // here so that we can wait on them in tests 271 private CompletableFuture<Call> mLatestPostSelectionProcessingFuture; 272 private CompletableFuture<Pair<Call, List<PhoneAccountSuggestion>>> 273 mLatestPreAccountSelectionFuture; 274 275 /** 276 * The current telecom call ID. Used when creating new instances of {@link Call}. Should 277 * only be accessed using the {@link #getNextCallId()} method which synchronizes on the 278 * {@link #mLock} sync root. 279 */ 280 private int mCallId = 0; 281 282 private int mRttRequestId = 0; 283 /** 284 * Stores the current foreground user. 285 */ 286 private UserHandle mCurrentUserHandle = UserHandle.of(ActivityManager.getCurrentUser()); 287 288 private final ConnectionServiceRepository mConnectionServiceRepository; 289 private final DtmfLocalTonePlayer mDtmfLocalTonePlayer; 290 private final InCallController mInCallController; 291 private final CallAudioManager mCallAudioManager; 292 private final CallRecordingTonePlayer mCallRecordingTonePlayer; 293 private RespondViaSmsManager mRespondViaSmsManager; 294 private final Ringer mRinger; 295 private final InCallWakeLockController mInCallWakeLockController; 296 // For this set initial table size to 16 because we add 13 listeners in 297 // the CallsManager constructor. 298 private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap( 299 new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1)); 300 private final HeadsetMediaButton mHeadsetMediaButton; 301 private final WiredHeadsetManager mWiredHeadsetManager; 302 private final SystemStateHelper mSystemStateHelper; 303 private final BluetoothRouteManager mBluetoothRouteManager; 304 private final DockManager mDockManager; 305 private final TtyManager mTtyManager; 306 private final ProximitySensorManager mProximitySensorManager; 307 private final PhoneStateBroadcaster mPhoneStateBroadcaster; 308 private final CallLogManager mCallLogManager; 309 private final Context mContext; 310 private final TelecomSystem.SyncRoot mLock; 311 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 312 private final MissedCallNotifier mMissedCallNotifier; 313 private IncomingCallNotifier mIncomingCallNotifier; 314 private final CallerInfoLookupHelper mCallerInfoLookupHelper; 315 private final DefaultDialerCache mDefaultDialerCache; 316 private final Timeouts.Adapter mTimeoutsAdapter; 317 private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; 318 private final ClockProxy mClockProxy; 319 private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>(); 320 private final Set<Call> mPendingCallsToDisconnect = new HashSet<>(); 321 private final ConnectionServiceFocusManager mConnectionSvrFocusMgr; 322 /* Handler tied to thread in which CallManager was initialized. */ 323 private final Handler mHandler = new Handler(Looper.getMainLooper()); 324 private final EmergencyCallHelper mEmergencyCallHelper; 325 private final RoleManagerAdapter mRoleManagerAdapter; 326 327 private final ConnectionServiceFocusManager.CallsManagerRequester mRequester = 328 new ConnectionServiceFocusManager.CallsManagerRequester() { 329 @Override 330 public void releaseConnectionService( 331 ConnectionServiceFocusManager.ConnectionServiceFocus connectionService) { 332 mCalls.stream() 333 .filter(c -> c.getConnectionServiceWrapper().equals(connectionService)) 334 .forEach(c -> c.disconnect("release " + 335 connectionService.getComponentName().getPackageName())); 336 } 337 338 @Override 339 public void setCallsManagerListener(CallsManagerListener listener) { 340 mListeners.add(listener); 341 } 342 }; 343 344 private boolean mCanAddCall = true; 345 346 private TelephonyManager.MultiSimVariants mRadioSimVariants = null; 347 348 private Runnable mStopTone; 349 350 /** 351 * Listener to PhoneAccountRegistrar events. 352 */ 353 private PhoneAccountRegistrar.Listener mPhoneAccountListener = 354 new PhoneAccountRegistrar.Listener() { 355 public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar, 356 PhoneAccountHandle handle) { 357 broadcastRegisterIntent(handle); 358 } 359 public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, 360 PhoneAccountHandle handle) { 361 broadcastUnregisterIntent(handle); 362 } 363 364 @Override 365 public void onPhoneAccountChanged(PhoneAccountRegistrar registrar, 366 PhoneAccount phoneAccount) { 367 handlePhoneAccountChanged(registrar, phoneAccount); 368 } 369 }; 370 371 /** 372 * Receiver for enhanced call blocking feature to update the emergency call notification 373 * in below cases: 374 * 1) Carrier config changed. 375 * 2) Blocking suppression state changed. 376 */ 377 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 378 @Override 379 public void onReceive(Context context, Intent intent) { 380 Log.startSession("CM.CCCR"); 381 String action = intent.getAction(); 382 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) 383 || SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED.equals(action)) { 384 new UpdateEmergencyCallNotificationTask().doInBackground( 385 Pair.create(context, Log.createSubsession())); 386 } 387 } 388 }; 389 390 private static class UpdateEmergencyCallNotificationTask 391 extends AsyncTask<Pair<Context, Session>, Void, Void> { 392 @SafeVarargs 393 @Override doInBackground(Pair<Context, Session>.... args)394 protected final Void doInBackground(Pair<Context, Session>... args) { 395 if (args == null || args.length != 1 || args[0] == null) { 396 Log.e(this, new IllegalArgumentException(), "Incorrect invocation"); 397 return null; 398 } 399 Log.continueSession(args[0].second, "CM.UECNT"); 400 Context context = args[0].first; 401 BlockedNumbersUtil.updateEmergencyCallNotification(context, 402 SystemContract.shouldShowEmergencyCallNotification(context)); 403 return null; 404 } 405 } 406 407 /** 408 * Initializes the required Telecom components. 409 */ 410 @VisibleForTesting CallsManager( Context context, TelecomSystem.SyncRoot lock, CallerInfoLookupHelper callerInfoLookupHelper, MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar, HeadsetMediaButtonFactory headsetMediaButtonFactory, ProximitySensorManagerFactory proximitySensorManagerFactory, InCallWakeLockControllerFactory inCallWakeLockControllerFactory, ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory connectionServiceFocusManagerFactory, CallAudioManager.AudioServiceFactory audioServiceFactory, BluetoothRouteManager bluetoothManager, WiredHeadsetManager wiredHeadsetManager, SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, AsyncRingtonePlayer asyncRingtonePlayer, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, EmergencyCallHelper emergencyCallHelper, InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory, ClockProxy clockProxy, BluetoothStateReceiver bluetoothStateReceiver, CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory, CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory, InCallControllerFactory inCallControllerFactory, RoleManagerAdapter roleManagerAdapter)411 public CallsManager( 412 Context context, 413 TelecomSystem.SyncRoot lock, 414 CallerInfoLookupHelper callerInfoLookupHelper, 415 MissedCallNotifier missedCallNotifier, 416 PhoneAccountRegistrar phoneAccountRegistrar, 417 HeadsetMediaButtonFactory headsetMediaButtonFactory, 418 ProximitySensorManagerFactory proximitySensorManagerFactory, 419 InCallWakeLockControllerFactory inCallWakeLockControllerFactory, 420 ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory 421 connectionServiceFocusManagerFactory, 422 CallAudioManager.AudioServiceFactory audioServiceFactory, 423 BluetoothRouteManager bluetoothManager, 424 WiredHeadsetManager wiredHeadsetManager, 425 SystemStateHelper systemStateHelper, 426 DefaultDialerCache defaultDialerCache, 427 Timeouts.Adapter timeoutsAdapter, 428 AsyncRingtonePlayer asyncRingtonePlayer, 429 PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, 430 EmergencyCallHelper emergencyCallHelper, 431 InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory, 432 ClockProxy clockProxy, 433 BluetoothStateReceiver bluetoothStateReceiver, 434 CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory, 435 CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory, 436 InCallControllerFactory inCallControllerFactory, 437 RoleManagerAdapter roleManagerAdapter) { 438 mContext = context; 439 mLock = lock; 440 mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; 441 mPhoneAccountRegistrar = phoneAccountRegistrar; 442 mPhoneAccountRegistrar.addListener(mPhoneAccountListener); 443 mMissedCallNotifier = missedCallNotifier; 444 StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this); 445 mWiredHeadsetManager = wiredHeadsetManager; 446 mSystemStateHelper = systemStateHelper; 447 mDefaultDialerCache = defaultDialerCache; 448 mBluetoothRouteManager = bluetoothManager; 449 mDockManager = new DockManager(context); 450 mTimeoutsAdapter = timeoutsAdapter; 451 mEmergencyCallHelper = emergencyCallHelper; 452 mCallerInfoLookupHelper = callerInfoLookupHelper; 453 454 mDtmfLocalTonePlayer = 455 new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy()); 456 CallAudioRouteStateMachine callAudioRouteStateMachine = 457 callAudioRouteStateMachineFactory.create( 458 context, 459 this, 460 bluetoothManager, 461 wiredHeadsetManager, 462 statusBarNotifier, 463 audioServiceFactory, 464 CallAudioRouteStateMachine.EARPIECE_AUTO_DETECT 465 ); 466 callAudioRouteStateMachine.initialize(); 467 468 CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter = 469 new CallAudioRoutePeripheralAdapter( 470 callAudioRouteStateMachine, 471 bluetoothManager, 472 wiredHeadsetManager, 473 mDockManager); 474 475 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 476 InCallTonePlayer.MediaPlayerFactory mediaPlayerFactory = 477 (resourceId, attributes) -> 478 new InCallTonePlayer.MediaPlayerAdapterImpl( 479 MediaPlayer.create(mContext, resourceId, attributes, 480 audioManager.generateAudioSessionId())); 481 InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory( 482 callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory, mediaPlayerFactory, 483 () -> audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0); 484 485 SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil(); 486 RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context); 487 SystemVibrator systemVibrator = new SystemVibrator(context); 488 mInCallController = inCallControllerFactory.create(context, mLock, this, 489 systemStateHelper, defaultDialerCache, mTimeoutsAdapter, 490 emergencyCallHelper); 491 mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer, 492 ringtoneFactory, systemVibrator, 493 new Ringer.VibrationEffectProxy(), mInCallController); 494 mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager, mLock); 495 mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine, 496 this, callAudioModeStateMachineFactory.create(systemStateHelper, 497 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)), 498 playerFactory, mRinger, new RingbackPlayer(playerFactory), 499 bluetoothStateReceiver, mDtmfLocalTonePlayer); 500 501 mConnectionSvrFocusMgr = connectionServiceFocusManagerFactory.create(mRequester); 502 mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock); 503 mTtyManager = new TtyManager(context, mWiredHeadsetManager); 504 mProximitySensorManager = proximitySensorManagerFactory.create(context, this); 505 mPhoneStateBroadcaster = new PhoneStateBroadcaster(this); 506 mCallLogManager = new CallLogManager(context, phoneAccountRegistrar, mMissedCallNotifier); 507 mConnectionServiceRepository = 508 new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this); 509 mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this); 510 mClockProxy = clockProxy; 511 mRoleManagerAdapter = roleManagerAdapter; 512 513 mListeners.add(mInCallWakeLockController); 514 mListeners.add(statusBarNotifier); 515 mListeners.add(mCallLogManager); 516 mListeners.add(mPhoneStateBroadcaster); 517 mListeners.add(mInCallController); 518 mListeners.add(mCallAudioManager); 519 mListeners.add(mCallRecordingTonePlayer); 520 mListeners.add(missedCallNotifier); 521 mListeners.add(mHeadsetMediaButton); 522 mListeners.add(mProximitySensorManager); 523 524 // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly. 525 final UserManager userManager = UserManager.get(mContext); 526 // Don't load missed call if it is run in split user model. 527 if (userManager.isPrimaryUser()) { 528 onUserSwitch(Process.myUserHandle()); 529 } 530 // Register BroadcastReceiver to handle enhanced call blocking feature related event. 531 IntentFilter intentFilter = new IntentFilter( 532 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 533 intentFilter.addAction(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED); 534 context.registerReceiver(mReceiver, intentFilter); 535 } 536 setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier)537 public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) { 538 if (mIncomingCallNotifier != null) { 539 mListeners.remove(mIncomingCallNotifier); 540 } 541 mIncomingCallNotifier = incomingCallNotifier; 542 mListeners.add(mIncomingCallNotifier); 543 } 544 setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager)545 public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) { 546 if (mRespondViaSmsManager != null) { 547 mListeners.remove(mRespondViaSmsManager); 548 } 549 mRespondViaSmsManager = respondViaSmsManager; 550 mListeners.add(respondViaSmsManager); 551 } 552 getRespondViaSmsManager()553 public RespondViaSmsManager getRespondViaSmsManager() { 554 return mRespondViaSmsManager; 555 } 556 getCallerInfoLookupHelper()557 public CallerInfoLookupHelper getCallerInfoLookupHelper() { 558 return mCallerInfoLookupHelper; 559 } 560 getRoleManagerAdapter()561 public RoleManagerAdapter getRoleManagerAdapter() { 562 return mRoleManagerAdapter; 563 } 564 565 @Override onSuccessfulOutgoingCall(Call call, int callState)566 public void onSuccessfulOutgoingCall(Call call, int callState) { 567 Log.v(this, "onSuccessfulOutgoingCall, %s", call); 568 569 setCallState(call, callState, "successful outgoing call"); 570 if (!mCalls.contains(call)) { 571 // Call was not added previously in startOutgoingCall due to it being a potential MMI 572 // code, so add it now. 573 addCall(call); 574 } 575 576 // The call's ConnectionService has been updated. 577 for (CallsManagerListener listener : mListeners) { 578 listener.onConnectionServiceChanged(call, null, call.getConnectionService()); 579 } 580 581 markCallAsDialing(call); 582 } 583 584 @Override onFailedOutgoingCall(Call call, DisconnectCause disconnectCause)585 public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) { 586 Log.v(this, "onFailedOutgoingCall, call: %s", call); 587 588 markCallAsRemoved(call); 589 } 590 591 @Override onSuccessfulIncomingCall(Call incomingCall)592 public void onSuccessfulIncomingCall(Call incomingCall) { 593 Log.d(this, "onSuccessfulIncomingCall"); 594 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 595 incomingCall.getTargetPhoneAccount()); 596 Bundle extras = 597 phoneAccount == null || phoneAccount.getExtras() == null 598 ? new Bundle() 599 : phoneAccount.getExtras(); 600 if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE) || 601 incomingCall.isSelfManaged() || 602 extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)) { 603 Log.i(this, "Skipping call filtering for %s (ecm=%b, selfMgd=%b, skipExtra=%b)", 604 incomingCall.getId(), 605 incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE), 606 incomingCall.isSelfManaged(), 607 extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)); 608 onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true)); 609 incomingCall.setIsUsingCallFiltering(false); 610 return; 611 } 612 613 incomingCall.setIsUsingCallFiltering(true); 614 List<IncomingCallFilter.CallFilter> filters = new ArrayList<>(); 615 filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper)); 616 filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter(), 617 mCallerInfoLookupHelper, null)); 618 filters.add(new CallScreeningServiceController(mContext, this, mPhoneAccountRegistrar, 619 new ParcelableCallUtils.Converter(), mLock, 620 new TelecomServiceImpl.SettingsSecureAdapterImpl(), mCallerInfoLookupHelper, 621 new CallScreeningServiceHelper.AppLabelProxy() { 622 @Override 623 public CharSequence getAppLabel(String packageName) { 624 PackageManager pm = mContext.getPackageManager(); 625 try { 626 ApplicationInfo info = pm.getApplicationInfo(packageName, 0); 627 return pm.getApplicationLabel(info); 628 } catch (PackageManager.NameNotFoundException nnfe) { 629 Log.w(this, "Could not determine package name."); 630 } 631 632 return null; 633 } 634 })); 635 new IncomingCallFilter(mContext, this, incomingCall, mLock, 636 mTimeoutsAdapter, filters).performFiltering(); 637 } 638 639 @Override onCallFilteringComplete(Call incomingCall, CallFilteringResult result)640 public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) { 641 // Only set the incoming call as ringing if it isn't already disconnected. It is possible 642 // that the connection service disconnected the call before it was even added to Telecom, in 643 // which case it makes no sense to set it back to a ringing state. 644 if (incomingCall.getState() != CallState.DISCONNECTED && 645 incomingCall.getState() != CallState.DISCONNECTING) { 646 setCallState(incomingCall, CallState.RINGING, 647 result.shouldAllowCall ? "successful incoming call" : "blocking call"); 648 } else { 649 Log.i(this, "onCallFilteringCompleted: call already disconnected."); 650 return; 651 } 652 653 if (result.shouldAllowCall) { 654 if (hasMaximumManagedRingingCalls(incomingCall)) { 655 if (shouldSilenceInsteadOfReject(incomingCall)) { 656 incomingCall.silence(); 657 } else { 658 Log.i(this, "onCallFilteringCompleted: Call rejected! " + 659 "Exceeds maximum number of ringing calls."); 660 rejectCallAndLog(incomingCall, result); 661 } 662 } else if (hasMaximumManagedDialingCalls(incomingCall)) { 663 if (shouldSilenceInsteadOfReject(incomingCall)) { 664 incomingCall.silence(); 665 } else { 666 667 Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + 668 "dialing calls."); 669 rejectCallAndLog(incomingCall, result); 670 } 671 } else if (result.shouldSilence) { 672 Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state"); 673 incomingCall.setSilentRingingRequested(true); 674 addCall(incomingCall); 675 } else { 676 addCall(incomingCall); 677 } 678 } else { 679 if (result.shouldReject) { 680 Log.i(this, "onCallFilteringCompleted: blocked call, rejecting."); 681 incomingCall.reject(false, null); 682 } 683 if (result.shouldAddToCallLog) { 684 Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log."); 685 if (result.shouldShowNotification) { 686 Log.w(this, "onCallScreeningCompleted: blocked call, showing notification."); 687 } 688 mCallLogManager.logCall(incomingCall, Calls.BLOCKED_TYPE, 689 result.shouldShowNotification, result); 690 } else if (result.shouldShowNotification) { 691 Log.i(this, "onCallScreeningCompleted: blocked call, showing notification."); 692 mMissedCallNotifier.showMissedCallNotification( 693 new MissedCallNotifier.CallInfo(incomingCall)); 694 } 695 } 696 } 697 698 /** 699 * In the event that the maximum supported calls of a given type is reached, the 700 * default behavior is to reject any additional calls of that type. This checks 701 * if the device is configured to silence instead of reject the call, provided 702 * that the incoming call is from a different source (connection service). 703 */ shouldSilenceInsteadOfReject(Call incomingCall)704 private boolean shouldSilenceInsteadOfReject(Call incomingCall) { 705 if (!mContext.getResources().getBoolean( 706 R.bool.silence_incoming_when_different_service_and_maximum_ringing)) { 707 return false; 708 } 709 710 for (Call call : mCalls) { 711 // Only operate on top-level calls 712 if (call.getParentCall() != null) { 713 continue; 714 } 715 716 if (call.isExternalCall()) { 717 continue; 718 } 719 720 if (call.getConnectionService() == incomingCall.getConnectionService()) { 721 return false; 722 } 723 } 724 725 return true; 726 } 727 728 @Override onFailedIncomingCall(Call call)729 public void onFailedIncomingCall(Call call) { 730 setCallState(call, CallState.DISCONNECTED, "failed incoming call"); 731 call.removeListener(this); 732 } 733 734 @Override onSuccessfulUnknownCall(Call call, int callState)735 public void onSuccessfulUnknownCall(Call call, int callState) { 736 setCallState(call, callState, "successful unknown call"); 737 Log.i(this, "onSuccessfulUnknownCall for call %s", call); 738 addCall(call); 739 } 740 741 @Override onFailedUnknownCall(Call call)742 public void onFailedUnknownCall(Call call) { 743 Log.i(this, "onFailedUnknownCall for call %s", call); 744 setCallState(call, CallState.DISCONNECTED, "failed unknown call"); 745 call.removeListener(this); 746 } 747 748 @Override onRingbackRequested(Call call, boolean ringback)749 public void onRingbackRequested(Call call, boolean ringback) { 750 for (CallsManagerListener listener : mListeners) { 751 listener.onRingbackRequested(call, ringback); 752 } 753 } 754 755 @Override onPostDialWait(Call call, String remaining)756 public void onPostDialWait(Call call, String remaining) { 757 mInCallController.onPostDialWait(call, remaining); 758 } 759 760 @Override onPostDialChar(final Call call, char nextChar)761 public void onPostDialChar(final Call call, char nextChar) { 762 if (PhoneNumberUtils.is12Key(nextChar)) { 763 // Play tone if it is one of the dialpad digits, canceling out the previously queued 764 // up stopTone runnable since playing a new tone automatically stops the previous tone. 765 if (mStopTone != null) { 766 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 767 mStopTone.cancel(); 768 } 769 770 mDtmfLocalTonePlayer.playTone(call, nextChar); 771 772 mStopTone = new Runnable("CM.oPDC", mLock) { 773 @Override 774 public void loggedRun() { 775 // Set a timeout to stop the tone in case there isn't another tone to 776 // follow. 777 mDtmfLocalTonePlayer.stopTone(call); 778 } 779 }; 780 mHandler.postDelayed(mStopTone.prepare(), 781 Timeouts.getDelayBetweenDtmfTonesMillis(mContext.getContentResolver())); 782 } else if (nextChar == 0 || nextChar == TelecomManager.DTMF_CHARACTER_WAIT || 783 nextChar == TelecomManager.DTMF_CHARACTER_PAUSE) { 784 // Stop the tone if a tone is playing, removing any other stopTone callbacks since 785 // the previous tone is being stopped anyway. 786 if (mStopTone != null) { 787 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 788 mStopTone.cancel(); 789 } 790 mDtmfLocalTonePlayer.stopTone(call); 791 } else { 792 Log.w(this, "onPostDialChar: invalid value %d", nextChar); 793 } 794 } 795 796 @Override onParentChanged(Call call)797 public void onParentChanged(Call call) { 798 // parent-child relationship affects which call should be foreground, so do an update. 799 updateCanAddCall(); 800 for (CallsManagerListener listener : mListeners) { 801 listener.onIsConferencedChanged(call); 802 } 803 } 804 805 @Override onChildrenChanged(Call call)806 public void onChildrenChanged(Call call) { 807 // parent-child relationship affects which call should be foreground, so do an update. 808 updateCanAddCall(); 809 for (CallsManagerListener listener : mListeners) { 810 listener.onIsConferencedChanged(call); 811 } 812 } 813 814 @Override onConferenceStateChanged(Call call, boolean isConference)815 public void onConferenceStateChanged(Call call, boolean isConference) { 816 // Conference changed whether it is treated as a conference or not. 817 updateCanAddCall(); 818 for (CallsManagerListener listener : mListeners) { 819 listener.onConferenceStateChanged(call, isConference); 820 } 821 } 822 823 @Override onIsVoipAudioModeChanged(Call call)824 public void onIsVoipAudioModeChanged(Call call) { 825 for (CallsManagerListener listener : mListeners) { 826 listener.onIsVoipAudioModeChanged(call); 827 } 828 } 829 830 @Override onVideoStateChanged(Call call, int previousVideoState, int newVideoState)831 public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) { 832 for (CallsManagerListener listener : mListeners) { 833 listener.onVideoStateChanged(call, previousVideoState, newVideoState); 834 } 835 } 836 837 @Override onCanceledViaNewOutgoingCallBroadcast(final Call call, long disconnectionTimeout)838 public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call, 839 long disconnectionTimeout) { 840 mPendingCallsToDisconnect.add(call); 841 mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) { 842 @Override 843 public void loggedRun() { 844 if (mPendingCallsToDisconnect.remove(call)) { 845 Log.i(this, "Delayed disconnection of call: %s", call); 846 call.disconnect(); 847 } 848 } 849 }.prepare(), disconnectionTimeout); 850 851 return true; 852 } 853 854 /** 855 * Handles changes to the {@link Connection.VideoProvider} for a call. Adds the 856 * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created 857 * in {@link Call#setVideoProvider(IVideoProvider)}. This allows the {@link CallsManager} to 858 * respond to callbacks from the {@link VideoProviderProxy}. 859 * 860 * @param call The call. 861 */ 862 @Override onVideoCallProviderChanged(Call call)863 public void onVideoCallProviderChanged(Call call) { 864 VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy(); 865 866 if (videoProviderProxy == null) { 867 return; 868 } 869 870 videoProviderProxy.addListener(this); 871 } 872 873 /** 874 * Handles session modification requests received via the {@link TelecomVideoCallCallback} for 875 * a call. Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session 876 * modification request. 877 * 878 * @param call The call. 879 * @param videoProfile The {@link VideoProfile}. 880 */ 881 @Override onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)882 public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) { 883 int videoState = videoProfile != null ? videoProfile.getVideoState() : 884 VideoProfile.STATE_AUDIO_ONLY; 885 Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile 886 .videoStateToString(videoState)); 887 888 for (CallsManagerListener listener : mListeners) { 889 listener.onSessionModifyRequestReceived(call, videoProfile); 890 } 891 } 892 getCalls()893 public Collection<Call> getCalls() { 894 return Collections.unmodifiableCollection(mCalls); 895 } 896 897 /** 898 * Play or stop a call hold tone for a call. Triggered via 899 * {@link Connection#sendConnectionEvent(String)} when the 900 * {@link Connection#EVENT_ON_HOLD_TONE_START} event or 901 * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the 902 * 903 * @param call The call which requested the hold tone. 904 */ 905 @Override onHoldToneRequested(Call call)906 public void onHoldToneRequested(Call call) { 907 for (CallsManagerListener listener : mListeners) { 908 listener.onHoldToneRequested(call); 909 } 910 } 911 912 /** 913 * A {@link Call} managed by the {@link CallsManager} has requested a handover to another 914 * {@link PhoneAccount}. 915 * @param call The call. 916 * @param handoverTo The {@link PhoneAccountHandle} to handover the call to. 917 * @param videoState The desired video state of the call after handover. 918 * @param extras 919 */ 920 @Override onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState, Bundle extras, boolean isLegacy)921 public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState, 922 Bundle extras, boolean isLegacy) { 923 if (isLegacy) { 924 requestHandoverViaEvents(call, handoverTo, videoState, extras); 925 } else { 926 requestHandover(call, handoverTo, videoState, extras); 927 } 928 } 929 930 @VisibleForTesting getForegroundCall()931 public Call getForegroundCall() { 932 if (mCallAudioManager == null) { 933 // Happens when getForegroundCall is called before full initialization. 934 return null; 935 } 936 return mCallAudioManager.getForegroundCall(); 937 } 938 939 @Override onCallHoldFailed(Call call)940 public void onCallHoldFailed(Call call) { 941 // Normally, we don't care whether a call hold has failed. However, if a call was held in 942 // order to answer an incoming call, that incoming call needs to be brought out of the 943 // ANSWERED state so that the user can try the operation again. 944 for (Call call1 : mCalls) { 945 if (call1 != call && call1.getState() == CallState.ANSWERED) { 946 setCallState(call1, CallState.RINGING, "hold failed on other call"); 947 } 948 } 949 } 950 951 @Override getCurrentUserHandle()952 public UserHandle getCurrentUserHandle() { 953 return mCurrentUserHandle; 954 } 955 getCallAudioManager()956 public CallAudioManager getCallAudioManager() { 957 return mCallAudioManager; 958 } 959 getInCallController()960 InCallController getInCallController() { 961 return mInCallController; 962 } 963 getEmergencyCallHelper()964 EmergencyCallHelper getEmergencyCallHelper() { 965 return mEmergencyCallHelper; 966 } 967 968 @VisibleForTesting getPhoneAccountListener()969 public PhoneAccountRegistrar.Listener getPhoneAccountListener() { 970 return mPhoneAccountListener; 971 } 972 973 @VisibleForTesting hasEmergencyCall()974 public boolean hasEmergencyCall() { 975 for (Call call : mCalls) { 976 if (call.isEmergencyCall()) { 977 return true; 978 } 979 } 980 return false; 981 } 982 hasEmergencyRttCall()983 public boolean hasEmergencyRttCall() { 984 for (Call call : mCalls) { 985 if (call.isEmergencyCall() && call.isRttCall()) { 986 return true; 987 } 988 } 989 return false; 990 } 991 992 @VisibleForTesting hasOnlyDisconnectedCalls()993 public boolean hasOnlyDisconnectedCalls() { 994 if (mCalls.size() == 0) { 995 return false; 996 } 997 for (Call call : mCalls) { 998 if (!call.isDisconnected()) { 999 return false; 1000 } 1001 } 1002 return true; 1003 } 1004 hasVideoCall()1005 public boolean hasVideoCall() { 1006 for (Call call : mCalls) { 1007 if (VideoProfile.isVideo(call.getVideoState())) { 1008 return true; 1009 } 1010 } 1011 return false; 1012 } 1013 1014 @VisibleForTesting getAudioState()1015 public CallAudioState getAudioState() { 1016 return mCallAudioManager.getCallAudioState(); 1017 } 1018 isTtySupported()1019 boolean isTtySupported() { 1020 return mTtyManager.isTtySupported(); 1021 } 1022 getCurrentTtyMode()1023 int getCurrentTtyMode() { 1024 return mTtyManager.getCurrentTtyMode(); 1025 } 1026 1027 @VisibleForTesting addListener(CallsManagerListener listener)1028 public void addListener(CallsManagerListener listener) { 1029 mListeners.add(listener); 1030 } 1031 removeListener(CallsManagerListener listener)1032 void removeListener(CallsManagerListener listener) { 1033 mListeners.remove(listener); 1034 } 1035 1036 /** 1037 * Starts the process to attach the call to a connection service. 1038 * 1039 * @param phoneAccountHandle The phone account which contains the component name of the 1040 * connection service to use for this call. 1041 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 1042 */ processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras)1043 void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 1044 Log.d(this, "processIncomingCallIntent"); 1045 boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER); 1046 Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); 1047 if (handle == null) { 1048 // Required for backwards compatibility 1049 handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER); 1050 } 1051 Call call = new Call( 1052 getNextCallId(), 1053 mContext, 1054 this, 1055 mLock, 1056 mConnectionServiceRepository, 1057 mPhoneNumberUtilsAdapter, 1058 handle, 1059 null /* gatewayInfo */, 1060 null /* connectionManagerPhoneAccount */, 1061 phoneAccountHandle, 1062 Call.CALL_DIRECTION_INCOMING /* callDirection */, 1063 false /* forceAttachToExistingConnection */, 1064 false, /* isConference */ 1065 mClockProxy); 1066 1067 // Ensure new calls related to self-managed calls/connections are set as such. This will 1068 // be overridden when the actual connection is returned in startCreateConnection, however 1069 // doing this now ensures the logs and any other logic will treat this call as self-managed 1070 // from the moment it is created. 1071 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 1072 phoneAccountHandle); 1073 if (phoneAccount != null) { 1074 call.setIsSelfManaged(phoneAccount.isSelfManaged()); 1075 if (call.isSelfManaged()) { 1076 // Self managed calls will always be voip audio mode. 1077 call.setIsVoipAudioMode(true); 1078 } else { 1079 // Incoming call is managed, the active call is self-managed and can't be held. 1080 // We need to set extras on it to indicate whether answering will cause a 1081 // active self-managed call to drop. 1082 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 1083 if (activeCall != null && !canHold(activeCall) && activeCall.isSelfManaged()) { 1084 Bundle dropCallExtras = new Bundle(); 1085 dropCallExtras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true); 1086 1087 // Include the name of the app which will drop the call. 1088 CharSequence droppedApp = activeCall.getTargetPhoneAccountLabel(); 1089 dropCallExtras.putCharSequence( 1090 Connection.EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME, droppedApp); 1091 Log.i(this, "Incoming managed call will drop %s call.", droppedApp); 1092 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, dropCallExtras); 1093 } 1094 } 1095 1096 if (extras.getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 1097 Log.d(this, "processIncomingCallIntent: defaulting to voip mode for call %s", 1098 call.getId()); 1099 call.setIsVoipAudioMode(true); 1100 } 1101 } 1102 if (isRttSettingOn() || 1103 extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) { 1104 Log.i(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn()); 1105 call.createRttStreams(); 1106 // Even if the phone account doesn't support RTT yet, the connection manager might 1107 // change that. Set this to check it later. 1108 call.setRequestedToStartWithRtt(); 1109 } 1110 // If the extras specifies a video state, set it on the call if the PhoneAccount supports 1111 // video. 1112 int videoState = VideoProfile.STATE_AUDIO_ONLY; 1113 if (extras.containsKey(TelecomManager.EXTRA_INCOMING_VIDEO_STATE) && 1114 phoneAccount != null && phoneAccount.hasCapabilities( 1115 PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 1116 videoState = extras.getInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE); 1117 call.setVideoState(videoState); 1118 } 1119 1120 call.initAnalytics(); 1121 if (getForegroundCall() != null) { 1122 getForegroundCall().getAnalytics().setCallIsInterrupted(true); 1123 call.getAnalytics().setCallIsAdditional(true); 1124 } 1125 setIntentExtrasAndStartTime(call, extras); 1126 // TODO: Move this to be a part of addCall() 1127 call.addListener(this); 1128 1129 boolean isHandoverAllowed = true; 1130 if (isHandover) { 1131 if (!isHandoverInProgress() && 1132 isHandoverToPhoneAccountSupported(phoneAccountHandle)) { 1133 final String handleScheme = handle.getSchemeSpecificPart(); 1134 Call fromCall = mCalls.stream() 1135 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 1136 (c.getHandle() == null 1137 ? null : c.getHandle().getSchemeSpecificPart()), 1138 handleScheme)) 1139 .findFirst() 1140 .orElse(null); 1141 if (fromCall != null) { 1142 if (!isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount())) { 1143 Log.w(this, "processIncomingCallIntent: From account doesn't support " + 1144 "handover."); 1145 isHandoverAllowed = false; 1146 } 1147 } else { 1148 Log.w(this, "processIncomingCallIntent: handover fail; can't find from call."); 1149 isHandoverAllowed = false; 1150 } 1151 1152 if (isHandoverAllowed) { 1153 // Link the calls so we know we're handing over. 1154 fromCall.setHandoverDestinationCall(call); 1155 call.setHandoverSourceCall(fromCall); 1156 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 1157 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 1158 Log.addEvent(fromCall, LogUtils.Events.START_HANDOVER, 1159 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 1160 Log.addEvent(call, LogUtils.Events.START_HANDOVER, 1161 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 1162 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 1163 // Ensure when the call goes active that it will go to speakerphone if the 1164 // handover to call is a video call. 1165 call.setStartWithSpeakerphoneOn(true); 1166 } 1167 } 1168 } else { 1169 Log.w(this, "processIncomingCallIntent: To account doesn't support handover."); 1170 } 1171 } 1172 1173 if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call, 1174 call.getTargetPhoneAccount()))) { 1175 notifyCreateConnectionFailed(phoneAccountHandle, call); 1176 } else { 1177 call.startCreateConnection(mPhoneAccountRegistrar); 1178 } 1179 } 1180 addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras)1181 void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 1182 Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE); 1183 Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle)); 1184 Call call = new Call( 1185 getNextCallId(), 1186 mContext, 1187 this, 1188 mLock, 1189 mConnectionServiceRepository, 1190 mPhoneNumberUtilsAdapter, 1191 handle, 1192 null /* gatewayInfo */, 1193 null /* connectionManagerPhoneAccount */, 1194 phoneAccountHandle, 1195 Call.CALL_DIRECTION_UNKNOWN /* callDirection */, 1196 // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach 1197 // to the existing connection instead of trying to create a new one. 1198 true /* forceAttachToExistingConnection */, 1199 false, /* isConference */ 1200 mClockProxy); 1201 call.initAnalytics(); 1202 1203 setIntentExtrasAndStartTime(call, extras); 1204 call.addListener(this); 1205 call.startCreateConnection(mPhoneAccountRegistrar); 1206 } 1207 areHandlesEqual(Uri handle1, Uri handle2)1208 private boolean areHandlesEqual(Uri handle1, Uri handle2) { 1209 if (handle1 == null || handle2 == null) { 1210 return handle1 == handle2; 1211 } 1212 1213 if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) { 1214 return false; 1215 } 1216 1217 final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart()); 1218 final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart()); 1219 return TextUtils.equals(number1, number2); 1220 } 1221 reuseOutgoingCall(Uri handle)1222 private Call reuseOutgoingCall(Uri handle) { 1223 // Check to see if we can reuse any of the calls that are waiting to disconnect. 1224 // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information. 1225 Call reusedCall = null; 1226 for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) { 1227 Call pendingCall = callIter.next(); 1228 if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) { 1229 callIter.remove(); 1230 Log.i(this, "Reusing disconnected call %s", pendingCall); 1231 reusedCall = pendingCall; 1232 } else { 1233 Log.i(this, "Not reusing disconnected call %s", pendingCall); 1234 callIter.remove(); 1235 pendingCall.disconnect(); 1236 } 1237 } 1238 1239 return reusedCall; 1240 } 1241 1242 /** 1243 * Kicks off the first steps to creating an outgoing call. 1244 * 1245 * For managed connections, this is the first step to launching the Incall UI. 1246 * For self-managed connections, we don't expect the Incall UI to launch, but this is still a 1247 * first step in getting the self-managed ConnectionService to create the connection. 1248 * @param handle Handle to connect the call with. 1249 * @param requestedAccountHandle The phone account which contains the component name of the 1250 * connection service to use for this call. 1251 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 1252 * @param initiatingUser {@link UserHandle} of user that place the outgoing call. 1253 * @param originalIntent 1254 * @param callingPackage the package name of the app which initiated the outgoing call. 1255 */ 1256 @VisibleForTesting 1257 public @NonNull startOutgoingCall(Uri handle, PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage)1258 CompletableFuture<Call> startOutgoingCall(Uri handle, 1259 PhoneAccountHandle requestedAccountHandle, 1260 Bundle extras, UserHandle initiatingUser, Intent originalIntent, 1261 String callingPackage) { 1262 boolean isReusedCall; 1263 Call call = reuseOutgoingCall(handle); 1264 1265 PhoneAccount account = 1266 mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser); 1267 boolean isSelfManaged = account != null && account.isSelfManaged(); 1268 1269 // Create a call with original handle. The handle may be changed when the call is attached 1270 // to a connection service, but in most cases will remain the same. 1271 if (call == null) { 1272 call = new Call(getNextCallId(), mContext, 1273 this, 1274 mLock, 1275 mConnectionServiceRepository, 1276 mPhoneNumberUtilsAdapter, 1277 handle, 1278 null /* gatewayInfo */, 1279 null /* connectionManagerPhoneAccount */, 1280 null /* requestedAccountHandle */, 1281 Call.CALL_DIRECTION_OUTGOING /* callDirection */, 1282 false /* forceAttachToExistingConnection */, 1283 false, /* isConference */ 1284 mClockProxy); 1285 call.initAnalytics(callingPackage); 1286 1287 // Ensure new calls related to self-managed calls/connections are set as such. This 1288 // will be overridden when the actual connection is returned in startCreateConnection, 1289 // however doing this now ensures the logs and any other logic will treat this call as 1290 // self-managed from the moment it is created. 1291 call.setIsSelfManaged(isSelfManaged); 1292 if (isSelfManaged) { 1293 // Self-managed calls will ALWAYS use voip audio mode. 1294 call.setIsVoipAudioMode(true); 1295 } 1296 call.setInitiatingUser(initiatingUser); 1297 isReusedCall = false; 1298 } else { 1299 isReusedCall = true; 1300 } 1301 1302 int videoState = VideoProfile.STATE_AUDIO_ONLY; 1303 if (extras != null) { 1304 // Set the video state on the call early so that when it is added to the InCall UI the 1305 // UI knows to configure itself as a video call immediately. 1306 videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 1307 VideoProfile.STATE_AUDIO_ONLY); 1308 1309 // If this is an emergency video call, we need to check if the phone account supports 1310 // emergency video calling. 1311 // Also, ensure we don't try to place an outgoing call with video if video is not 1312 // supported. 1313 if (VideoProfile.isVideo(videoState)) { 1314 if (call.isEmergencyCall() && account != null && 1315 !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) { 1316 // Phone account doesn't support emergency video calling, so fallback to 1317 // audio-only now to prevent the InCall UI from setting up video surfaces 1318 // needlessly. 1319 Log.i(this, "startOutgoingCall - emergency video calls not supported; " + 1320 "falling back to audio-only"); 1321 videoState = VideoProfile.STATE_AUDIO_ONLY; 1322 } else if (account != null && 1323 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 1324 // Phone account doesn't support video calling, so fallback to audio-only. 1325 Log.i(this, "startOutgoingCall - video calls not supported; fallback to " + 1326 "audio-only."); 1327 videoState = VideoProfile.STATE_AUDIO_ONLY; 1328 } 1329 } 1330 1331 call.setVideoState(videoState); 1332 } 1333 1334 final int finalVideoState = videoState; 1335 final Call finalCall = call; 1336 Handler outgoingCallHandler = new Handler(Looper.getMainLooper()); 1337 // Create a empty CompletableFuture and compose it with findOutgoingPhoneAccount to get 1338 // a first guess at the list of suitable outgoing PhoneAccounts. 1339 // findOutgoingPhoneAccount returns a CompletableFuture which is either already complete 1340 // (in the case where we don't need to do the per-contact lookup) or a CompletableFuture 1341 // that completes once the contact lookup via CallerInfoLookupHelper is complete. 1342 CompletableFuture<List<PhoneAccountHandle>> accountsForCall = 1343 CompletableFuture.completedFuture((Void) null).thenComposeAsync((x) -> 1344 findOutgoingCallPhoneAccount(requestedAccountHandle, handle, 1345 VideoProfile.isVideo(finalVideoState), initiatingUser), 1346 new LoggedHandlerExecutor(outgoingCallHandler, "CM.fOCP", mLock)); 1347 1348 // This is a block of code that executes after the list of potential phone accts has been 1349 // retrieved. 1350 CompletableFuture<List<PhoneAccountHandle>> setAccountHandle = 1351 accountsForCall.whenCompleteAsync((potentialPhoneAccounts, exception) -> { 1352 Log.i(CallsManager.this, "set outgoing call phone acct stage"); 1353 PhoneAccountHandle phoneAccountHandle; 1354 if (potentialPhoneAccounts.size() == 1) { 1355 phoneAccountHandle = potentialPhoneAccounts.get(0); 1356 } else { 1357 phoneAccountHandle = null; 1358 } 1359 finalCall.setTargetPhoneAccount(phoneAccountHandle); 1360 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.sOCPA", mLock)); 1361 1362 1363 // This composes the future containing the potential phone accounts with code that queries 1364 // the suggestion service if necessary (i.e. if the list is longer than 1). 1365 // If the suggestion service is queried, the inner lambda will return a future that 1366 // completes when the suggestion service calls the callback. 1367 CompletableFuture<List<PhoneAccountSuggestion>> suggestionFuture = accountsForCall. 1368 thenComposeAsync(potentialPhoneAccounts -> { 1369 Log.i(CallsManager.this, "call outgoing call suggestion service stage"); 1370 if (potentialPhoneAccounts.size() == 1) { 1371 PhoneAccountSuggestion suggestion = 1372 new PhoneAccountSuggestion(potentialPhoneAccounts.get(0), 1373 PhoneAccountSuggestion.REASON_NONE, true); 1374 return CompletableFuture.completedFuture( 1375 Collections.singletonList(suggestion)); 1376 } 1377 return PhoneAccountSuggestionHelper.bindAndGetSuggestions(mContext, 1378 finalCall.getHandle(), potentialPhoneAccounts); 1379 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.cOCSS", mLock)); 1380 1381 1382 // This future checks the status of existing calls and attempts to make room for the 1383 // outgoing call. The future returned by the inner method will usually be pre-completed -- 1384 // we only pause here if user interaction is required to disconnect a self-managed call. 1385 // It runs after the account handle is set, independently of the phone account suggestion 1386 // future. 1387 CompletableFuture<Call> makeRoomForCall = setAccountHandle.thenComposeAsync( 1388 potentialPhoneAccounts -> { 1389 Log.i(CallsManager.this, "make room for outgoing call stage"); 1390 boolean isPotentialInCallMMICode = 1391 isPotentialInCallMMICode(handle) && !isSelfManaged; 1392 // Do not support any more live calls. Our options are to move a call to hold, 1393 // disconnect a call, or cancel this call altogether. If a call is being reused, 1394 // then it has already passed the makeRoomForOutgoingCall check once and will 1395 // fail the second time due to the call transitioning into the CONNECTING state. 1396 if (!isPotentialInCallMMICode && (!isReusedCall 1397 && !makeRoomForOutgoingCall(finalCall, finalCall.isEmergencyCall()))) { 1398 Call foregroundCall = getForegroundCall(); 1399 Log.d(CallsManager.this, "No more room for outgoing call %s ", finalCall); 1400 if (foregroundCall.isSelfManaged()) { 1401 // If the ongoing call is a self-managed call, then prompt the user to 1402 // ask if they'd like to disconnect their ongoing call and place the 1403 // outgoing call. 1404 Log.i(CallsManager.this, "Prompting user to disconnect " 1405 + "self-managed call"); 1406 finalCall.setOriginalCallIntent(originalIntent); 1407 CompletableFuture<Call> completionFuture = new CompletableFuture<>(); 1408 startCallConfirmation(finalCall, completionFuture); 1409 return completionFuture; 1410 } else { 1411 // If the ongoing call is a managed call, we will prevent the outgoing 1412 // call from dialing. 1413 notifyCreateConnectionFailed( 1414 finalCall.getTargetPhoneAccount(), finalCall); 1415 } 1416 Log.i(CallsManager.this, "Aborting call since there's no room"); 1417 return CompletableFuture.completedFuture(null); 1418 } 1419 return CompletableFuture.completedFuture(finalCall); 1420 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.dSMCP", mLock)); 1421 1422 // The outgoing call can be placed, go forward. This future glues together the results of 1423 // the account suggestion stage and the make room for call stage. 1424 CompletableFuture<Pair<Call, List<PhoneAccountSuggestion>>> preSelectStage = 1425 makeRoomForCall.thenCombine(suggestionFuture, Pair::create); 1426 mLatestPreAccountSelectionFuture = preSelectStage; 1427 1428 // This future takes the list of suggested accounts and the call and determines if more 1429 // user interaction in the form of a phone account selection screen is needed. If so, it 1430 // will set the call to SELECT_PHONE_ACCOUNT, add it to our internal list/send it to dialer, 1431 // and then execution will pause pending the dialer calling phoneAccountSelected. 1432 CompletableFuture<Pair<Call, PhoneAccountHandle>> dialerSelectPhoneAccountFuture = 1433 preSelectStage.thenComposeAsync( 1434 (args) -> { 1435 Log.i(CallsManager.this, "dialer phone acct select stage"); 1436 Call callToPlace = args.first; 1437 List<PhoneAccountSuggestion> accountSuggestions = args.second; 1438 if (callToPlace == null) { 1439 return CompletableFuture.completedFuture(null); 1440 } 1441 if (accountSuggestions == null || accountSuggestions.isEmpty()) { 1442 Log.i(CallsManager.this, "Aborting call since there are no" 1443 + " available accounts."); 1444 showErrorMessage(R.string.cant_call_due_to_no_supported_service); 1445 return CompletableFuture.completedFuture(null); 1446 } 1447 boolean needsAccountSelection = accountSuggestions.size() > 1 1448 && !callToPlace.isEmergencyCall() && !isSelfManaged; 1449 if (!needsAccountSelection) { 1450 return CompletableFuture.completedFuture(Pair.create(callToPlace, 1451 accountSuggestions.get(0).getPhoneAccountHandle())); 1452 } 1453 // This is the state where the user is expected to select an account 1454 callToPlace.setState(CallState.SELECT_PHONE_ACCOUNT, 1455 "needs account selection"); 1456 // Create our own instance to modify (since extras may be Bundle.EMPTY) 1457 Bundle newExtras = new Bundle(extras); 1458 List<PhoneAccountHandle> accountsFromSuggestions = accountSuggestions 1459 .stream() 1460 .map(PhoneAccountSuggestion::getPhoneAccountHandle) 1461 .collect(Collectors.toList()); 1462 newExtras.putParcelableList( 1463 android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, 1464 accountsFromSuggestions); 1465 newExtras.putParcelableList( 1466 android.telecom.Call.EXTRA_SUGGESTED_PHONE_ACCOUNTS, 1467 accountSuggestions); 1468 // Set a future in place so that we can proceed once the dialer replies. 1469 mPendingAccountSelection = new CompletableFuture<>(); 1470 callToPlace.setIntentExtras(newExtras); 1471 1472 addCall(callToPlace); 1473 return mPendingAccountSelection; 1474 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.dSPA", mLock)); 1475 1476 // Potentially perform call identification for dialed TEL scheme numbers. 1477 if (PhoneAccount.SCHEME_TEL.equals(handle.getScheme())) { 1478 // Perform an asynchronous contacts lookup in this stage; ensure post-dial digits are 1479 // not included. 1480 CompletableFuture<Pair<Uri, CallerInfo>> contactLookupFuture = 1481 mCallerInfoLookupHelper.startLookup(Uri.fromParts(handle.getScheme(), 1482 PhoneNumberUtils.extractNetworkPortion(handle.getSchemeSpecificPart()), 1483 null)); 1484 1485 // Once the phone account selection stage has completed, we can handle the results from 1486 // that with the contacts lookup in order to determine if we should lookup bind to the 1487 // CallScreeningService in order for it to potentially provide caller ID. 1488 dialerSelectPhoneAccountFuture.thenAcceptBothAsync(contactLookupFuture, 1489 (callPhoneAccountHandlePair, uriCallerInfoPair) -> { 1490 Call theCall = callPhoneAccountHandlePair.first; 1491 boolean isInContacts = uriCallerInfoPair.second != null 1492 && uriCallerInfoPair.second.contactExists; 1493 Log.d(CallsManager.this, "outgoingCallIdStage: isInContacts=%s", 1494 isInContacts); 1495 1496 // We only want to provide a CallScreeningService with a call if its not in 1497 // contacts. 1498 if (!isInContacts) { 1499 bindForOutgoingCallerId(theCall); 1500 } 1501 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.pCSB", mLock)); 1502 } 1503 1504 // Finally, after all user interaction is complete, we execute this code to finish setting 1505 // up the outgoing call. The inner method always returns a completed future containing the 1506 // call that we've finished setting up. 1507 mLatestPostSelectionProcessingFuture = dialerSelectPhoneAccountFuture 1508 .thenComposeAsync(args -> { 1509 if (args == null) { 1510 return CompletableFuture.completedFuture(null); 1511 } 1512 Log.i(CallsManager.this, "post acct selection stage"); 1513 Call callToUse = args.first; 1514 PhoneAccountHandle phoneAccountHandle = args.second; 1515 PhoneAccount accountToUse = mPhoneAccountRegistrar 1516 .getPhoneAccount(phoneAccountHandle, initiatingUser); 1517 callToUse.setTargetPhoneAccount(phoneAccountHandle); 1518 if (accountToUse != null && accountToUse.getExtras() != null) { 1519 if (accountToUse.getExtras() 1520 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 1521 Log.d(this, "startOutgoingCall: defaulting to voip mode for call %s", 1522 callToUse.getId()); 1523 callToUse.setIsVoipAudioMode(true); 1524 } 1525 } 1526 1527 callToUse.setState( 1528 CallState.CONNECTING, 1529 phoneAccountHandle == null ? "no-handle" 1530 : phoneAccountHandle.toString()); 1531 1532 boolean isVoicemail = isVoicemail(callToUse.getHandle(), accountToUse); 1533 1534 if (!isVoicemail && (isRttSettingOn() || (extras != null 1535 && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, 1536 false)))) { 1537 Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", 1538 isRttSettingOn()); 1539 if (callToUse.isEmergencyCall() || (accountToUse != null 1540 && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT))) { 1541 // If the call requested RTT and it's an emergency call, ignore the 1542 // capability and hope that the modem will deal with it somehow. 1543 callToUse.createRttStreams(); 1544 } 1545 // Even if the phone account doesn't support RTT yet, 1546 // the connection manager might change that. Set this to check it later. 1547 callToUse.setRequestedToStartWithRtt(); 1548 } 1549 1550 setIntentExtrasAndStartTime(callToUse, extras); 1551 setCallSourceToAnalytics(callToUse, originalIntent); 1552 1553 if (isPotentialMMICode(handle) && !isSelfManaged) { 1554 // Do not add the call if it is a potential MMI code. 1555 callToUse.addListener(this); 1556 } else if (!mCalls.contains(callToUse)) { 1557 // We check if mCalls already contains the call because we could 1558 // potentially be reusing 1559 // a call which was previously added (See {@link #reuseOutgoingCall}). 1560 addCall(callToUse); 1561 } 1562 return CompletableFuture.completedFuture(callToUse); 1563 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.pASP", mLock)); 1564 return mLatestPostSelectionProcessingFuture; 1565 } 1566 1567 /** 1568 * Performs call identification for an outgoing phone call. 1569 * @param theCall The outgoing call to perform identification. 1570 */ bindForOutgoingCallerId(Call theCall)1571 private void bindForOutgoingCallerId(Call theCall) { 1572 // Find the user chosen call screening app. 1573 String callScreeningApp = 1574 mRoleManagerAdapter.getDefaultCallScreeningApp(); 1575 1576 CompletableFuture future = 1577 new CallScreeningServiceHelper(mContext, 1578 mLock, 1579 callScreeningApp, 1580 new ParcelableCallUtils.Converter(), 1581 mCurrentUserHandle, 1582 theCall, 1583 new CallScreeningServiceHelper.AppLabelProxy() { 1584 @Override 1585 public CharSequence getAppLabel(String packageName) { 1586 PackageManager pm = mContext.getPackageManager(); 1587 try { 1588 ApplicationInfo info = pm.getApplicationInfo( 1589 packageName, 0); 1590 return pm.getApplicationLabel(info); 1591 } catch (PackageManager.NameNotFoundException nnfe) { 1592 Log.w(this, "Could not determine package name."); 1593 } 1594 1595 return null; 1596 } 1597 }).process(); 1598 future.thenApply( v -> { 1599 Log.i(this, "Outgoing caller ID complete"); 1600 return null; 1601 }); 1602 } 1603 1604 /** 1605 * Finds the {@link PhoneAccountHandle}(s) which could potentially be used to place an outgoing 1606 * call. Takes into account the following: 1607 * 1. Any pre-chosen {@link PhoneAccountHandle} which was specified on the 1608 * {@link Intent#ACTION_CALL} intent. If one was chosen it will be used if possible. 1609 * 2. Whether the call is a video call. If the call being placed is a video call, an attempt is 1610 * first made to consider video capable phone accounts. If no video capable phone accounts are 1611 * found, the usual non-video capable phone accounts will be considered. 1612 * 3. Whether there is a user-chosen default phone account; that one will be used if possible. 1613 * 1614 * @param targetPhoneAccountHandle The pre-chosen {@link PhoneAccountHandle} passed in when the 1615 * call was placed. Will be {@code null} if the 1616 * {@link Intent#ACTION_CALL} intent did not specify a target 1617 * phone account. 1618 * @param handle The handle of the outgoing call; used to determine the SIP scheme when matching 1619 * phone accounts. 1620 * @param isVideo {@code true} if the call is a video call, {@code false} otherwise. 1621 * @param initiatingUser The {@link UserHandle} the call is placed on. 1622 * @return 1623 */ 1624 @VisibleForTesting findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, UserHandle initiatingUser)1625 public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( 1626 PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, 1627 UserHandle initiatingUser) { 1628 if (isSelfManaged(targetPhoneAccountHandle, initiatingUser)) { 1629 return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); 1630 } 1631 1632 List<PhoneAccountHandle> accounts; 1633 // Try to find a potential phone account, taking into account whether this is a video 1634 // call. 1635 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo); 1636 if (isVideo && accounts.size() == 0) { 1637 // Placing a video call but no video capable accounts were found, so consider any 1638 // call capable accounts (we can fallback to audio). 1639 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, 1640 false /* isVideo */); 1641 } 1642 Log.v(this, "findOutgoingCallPhoneAccount: accounts = " + accounts); 1643 1644 // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this 1645 // call as if a phoneAccount was not specified (does the default behavior instead). 1646 // Note: We will not attempt to dial with a requested phoneAccount if it is disabled. 1647 if (targetPhoneAccountHandle != null) { 1648 if (accounts.contains(targetPhoneAccountHandle)) { 1649 // The target phone account is valid and was found. 1650 return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); 1651 } 1652 } 1653 if (accounts.isEmpty() || accounts.size() == 1) { 1654 return CompletableFuture.completedFuture(accounts); 1655 } 1656 1657 // Do the query for whether there's a preferred contact 1658 final CompletableFuture<PhoneAccountHandle> userPreferredAccountForContact = 1659 new CompletableFuture<>(); 1660 final List<PhoneAccountHandle> possibleAccounts = accounts; 1661 mCallerInfoLookupHelper.startLookup(handle, 1662 new CallerInfoLookupHelper.OnQueryCompleteListener() { 1663 @Override 1664 public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { 1665 if (info.preferredPhoneAccountComponent != null && 1666 info.preferredPhoneAccountId != null && 1667 !info.preferredPhoneAccountId.isEmpty()) { 1668 PhoneAccountHandle contactDefaultHandle = new PhoneAccountHandle( 1669 info.preferredPhoneAccountComponent, 1670 info.preferredPhoneAccountId, 1671 initiatingUser); 1672 userPreferredAccountForContact.complete(contactDefaultHandle); 1673 } else { 1674 userPreferredAccountForContact.complete(null); 1675 } 1676 } 1677 1678 @Override 1679 public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { 1680 // ignore this 1681 } 1682 }); 1683 1684 return userPreferredAccountForContact.thenApply(phoneAccountHandle -> { 1685 if (phoneAccountHandle != null) { 1686 return Collections.singletonList(phoneAccountHandle); 1687 } 1688 // No preset account, check if default exists that supports the URI scheme for the 1689 // handle and verify it can be used. 1690 PhoneAccountHandle defaultPhoneAccountHandle = 1691 mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme( 1692 handle.getScheme(), initiatingUser); 1693 if (defaultPhoneAccountHandle != null && 1694 possibleAccounts.contains(defaultPhoneAccountHandle)) { 1695 return Collections.singletonList(defaultPhoneAccountHandle); 1696 } 1697 return possibleAccounts; 1698 }); 1699 } 1700 1701 /** 1702 * Determines if a {@link PhoneAccountHandle} is for a self-managed ConnectionService. 1703 * @param targetPhoneAccountHandle The phone account to check. 1704 * @param initiatingUser The user associated with the account. 1705 * @return {@code true} if the phone account is self-managed, {@code false} otherwise. 1706 */ 1707 public boolean isSelfManaged(PhoneAccountHandle targetPhoneAccountHandle, 1708 UserHandle initiatingUser) { 1709 PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount( 1710 targetPhoneAccountHandle, initiatingUser); 1711 return targetPhoneAccount != null && targetPhoneAccount.isSelfManaged(); 1712 } 1713 1714 public void onCallRedirectionComplete(Call call, Uri handle, 1715 PhoneAccountHandle phoneAccountHandle, 1716 GatewayInfo gatewayInfo, boolean speakerphoneOn, 1717 int videoState, boolean shouldCancelCall, 1718 String uiAction) { 1719 Log.i(this, "onCallRedirectionComplete for Call %s with handle %s" + 1720 " and phoneAccountHandle %s", call, handle, phoneAccountHandle); 1721 1722 boolean endEarly = false; 1723 String disconnectReason = ""; 1724 1725 String callRedirectionApp = mRoleManagerAdapter.getDefaultCallRedirectionApp(); 1726 1727 if (shouldCancelCall) { 1728 Log.w(this, "onCallRedirectionComplete: call is canceled"); 1729 endEarly = true; 1730 disconnectReason = "Canceled from Call Redirection Service"; 1731 // Show UX when user-defined call redirection service does not response; the UX 1732 // is not needed to show if the call is disconnected (e.g. by the user) 1733 if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT) 1734 && !call.isDisconnected()) { 1735 Intent timeoutIntent = new Intent(mContext, 1736 CallRedirectionTimeoutDialogActivity.class); 1737 timeoutIntent.putExtra( 1738 CallRedirectionTimeoutDialogActivity.EXTRA_REDIRECTION_APP_NAME, 1739 mRoleManagerAdapter.getApplicationLabelForPackageName(callRedirectionApp)); 1740 timeoutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1741 mContext.startActivityAsUser(timeoutIntent, UserHandle.CURRENT); 1742 } 1743 } else if (handle == null) { 1744 Log.w(this, "onCallRedirectionComplete: handle is null"); 1745 endEarly = true; 1746 disconnectReason = "Null handle from Call Redirection Service"; 1747 } else if (phoneAccountHandle == null) { 1748 Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is null"); 1749 endEarly = true; 1750 disconnectReason = "Null phoneAccountHandle from Call Redirection Service"; 1751 } else if (mPhoneNumberUtilsAdapter.isPotentialLocalEmergencyNumber(mContext, 1752 handle.getSchemeSpecificPart())) { 1753 Log.w(this, "onCallRedirectionComplete: emergency number %s is redirected from Call" 1754 + " Redirection Service", handle.getSchemeSpecificPart()); 1755 endEarly = true; 1756 disconnectReason = "Emergency number is redirected from Call Redirection Service"; 1757 } 1758 if (endEarly) { 1759 if (call != null) { 1760 call.disconnect(disconnectReason); 1761 } 1762 return; 1763 } 1764 1765 // If this call is already disconnected then we have nothing more to do. 1766 if (call.isDisconnected()) { 1767 Log.w(this, "onCallRedirectionComplete: Call has already been disconnected," 1768 + " ignore the call redirection %s", call); 1769 return; 1770 } 1771 1772 if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM)) { 1773 Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMATION); 1774 mPendingRedirectedOutgoingCall = call; 1775 1776 mPendingRedirectedOutgoingCallInfo.put(call.getId(), 1777 new Runnable("CM.oCRC", mLock) { 1778 @Override 1779 public void loggedRun() { 1780 Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMED); 1781 call.setTargetPhoneAccount(phoneAccountHandle); 1782 placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, 1783 videoState); 1784 } 1785 }); 1786 1787 mPendingUnredirectedOutgoingCallInfo.put(call.getId(), 1788 new Runnable("CM.oCRC", mLock) { 1789 @Override 1790 public void loggedRun() { 1791 call.setTargetPhoneAccount(phoneAccountHandle); 1792 placeOutgoingCall(call, handle, null, speakerphoneOn, 1793 videoState); 1794 } 1795 }); 1796 1797 Log.i(this, "onCallRedirectionComplete: UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM " 1798 + "callId=%s, callRedirectionAppName=%s", 1799 call.getId(), callRedirectionApp); 1800 1801 Intent confirmIntent = new Intent(mContext, 1802 CallRedirectionConfirmDialogActivity.class); 1803 confirmIntent.putExtra( 1804 CallRedirectionConfirmDialogActivity.EXTRA_REDIRECTION_OUTGOING_CALL_ID, 1805 call.getId()); 1806 confirmIntent.putExtra(CallRedirectionConfirmDialogActivity.EXTRA_REDIRECTION_APP_NAME, 1807 mRoleManagerAdapter.getApplicationLabelForPackageName(callRedirectionApp)); 1808 confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1809 1810 // A small delay to start the activity after any Dialer's In Call UI starts 1811 mHandler.postDelayed(new Runnable("CM.oCRC", mLock) { 1812 @Override 1813 public void loggedRun() { 1814 mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT); 1815 } 1816 }.prepare(), 500 /* Milliseconds delay */); 1817 1818 } else { 1819 call.setTargetPhoneAccount(phoneAccountHandle); 1820 placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState); 1821 } 1822 } 1823 1824 public void processRedirectedOutgoingCallAfterUserInteraction(String callId, String action) { 1825 Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for Call ID %s", callId); 1826 if (mPendingRedirectedOutgoingCall != null && mPendingRedirectedOutgoingCall.getId() 1827 .equals(callId)) { 1828 if (action.equals(TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL)) { 1829 mHandler.post(mPendingRedirectedOutgoingCallInfo.get(callId).prepare()); 1830 } else if (action.equals( 1831 TelecomBroadcastIntentProcessor.ACTION_PLACE_UNREDIRECTED_CALL)) { 1832 mHandler.post(mPendingUnredirectedOutgoingCallInfo.get(callId).prepare()); 1833 } else if (action.equals( 1834 TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL)) { 1835 Log.addEvent(mPendingRedirectedOutgoingCall, 1836 LogUtils.Events.REDIRECTION_USER_CANCELLED); 1837 mPendingRedirectedOutgoingCall.disconnect("User canceled the redirected call."); 1838 } 1839 mPendingRedirectedOutgoingCall = null; 1840 mPendingRedirectedOutgoingCallInfo.remove(callId); 1841 mPendingUnredirectedOutgoingCallInfo.remove(callId); 1842 } else { 1843 Log.w(this, "processRedirectedOutgoingCallAfterUserInteraction for non-matched Call ID" 1844 + " %s", callId); 1845 } 1846 } 1847 1848 /** 1849 * Attempts to issue/connect the specified call. 1850 * 1851 * @param handle Handle to connect the call with. 1852 * @param gatewayInfo Optional gateway information that can be used to route the call to the 1853 * actual dialed handle via a gateway provider. May be null. 1854 * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects. 1855 * @param videoState The desired video state for the outgoing call. 1856 */ 1857 @VisibleForTesting 1858 public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, 1859 boolean speakerphoneOn, int videoState) { 1860 if (call == null) { 1861 // don't do anything if the call no longer exists 1862 Log.i(this, "Canceling unknown call."); 1863 return; 1864 } 1865 1866 final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress(); 1867 1868 if (gatewayInfo == null) { 1869 Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle)); 1870 } else { 1871 Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s", 1872 Log.pii(uriHandle), Log.pii(handle)); 1873 } 1874 1875 call.setHandle(uriHandle); 1876 call.setGatewayInfo(gatewayInfo); 1877 1878 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 1879 R.bool.use_speaker_when_docked); 1880 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 1881 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 1882 1883 // Auto-enable speakerphone if the originating intent specified to do so, if the call 1884 // is a video call, of if using speaker when docked 1885 call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall 1886 || (useSpeakerWhenDocked && useSpeakerForDock)); 1887 call.setVideoState(videoState); 1888 1889 if (speakerphoneOn) { 1890 Log.i(this, "%s Starting with speakerphone as requested", call); 1891 } else if (useSpeakerWhenDocked && useSpeakerForDock) { 1892 Log.i(this, "%s Starting with speakerphone because car is docked.", call); 1893 } else if (useSpeakerForVideoCall) { 1894 Log.i(this, "%s Starting with speakerphone because its a video call.", call); 1895 } 1896 1897 if (call.isEmergencyCall()) { 1898 new AsyncEmergencyContactNotifier(mContext).execute(); 1899 } 1900 1901 final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean( 1902 com.android.internal.R.bool.config_requireCallCapableAccountForHandle); 1903 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 1904 call.getTargetPhoneAccount()); 1905 final String callHandleScheme = 1906 call.getHandle() == null ? null : call.getHandle().getScheme(); 1907 if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { 1908 // If the account has been set, proceed to place the outgoing call. 1909 // Otherwise the connection will be initiated when the account is set by the user. 1910 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 1911 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 1912 } else { 1913 if (call.isEmergencyCall()) { 1914 // Drop any ongoing self-managed calls to make way for an emergency call. 1915 disconnectSelfManagedCalls("place emerg call" /* reason */); 1916 } 1917 1918 call.startCreateConnection(mPhoneAccountRegistrar); 1919 } 1920 } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts( 1921 requireCallCapableAccountByHandle ? callHandleScheme : null, false, 1922 call.getInitiatingUser()).isEmpty()) { 1923 // If there are no call capable accounts, disconnect the call. 1924 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED, 1925 "No registered PhoneAccounts")); 1926 markCallAsRemoved(call); 1927 } 1928 } 1929 1930 /** 1931 * Attempts to start a conference call for the specified call. 1932 * 1933 * @param call The call to conference. 1934 * @param otherCall The other call to conference with. 1935 */ 1936 @VisibleForTesting 1937 public void conference(Call call, Call otherCall) { 1938 call.conferenceWith(otherCall); 1939 } 1940 1941 /** 1942 * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call 1943 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 1944 * the user opting to answer said call. 1945 * 1946 * @param call The call to answer. 1947 * @param videoState The video state in which to answer the call. 1948 */ 1949 @VisibleForTesting 1950 public void answerCall(Call call, int videoState) { 1951 if (!mCalls.contains(call)) { 1952 Log.i(this, "Request to answer a non-existent call %s", call); 1953 } else { 1954 // Hold or disconnect the active call and request call focus for the incoming call. 1955 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 1956 Log.d(this, "answerCall: Incoming call = %s Ongoing call %s", call, activeCall); 1957 holdActiveCallForNewCall(call); 1958 mConnectionSvrFocusMgr.requestFocus( 1959 call, 1960 new RequestCallback(new ActionAnswerCall(call, videoState))); 1961 } 1962 } 1963 1964 /** 1965 * Instructs Telecom to deflect the specified call. Intended to be invoked by the in-call 1966 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 1967 * the user opting to deflect said call. 1968 */ 1969 @VisibleForTesting 1970 public void deflectCall(Call call, Uri address) { 1971 if (!mCalls.contains(call)) { 1972 Log.i(this, "Request to deflect a non-existent call %s", call); 1973 } else { 1974 call.deflect(address); 1975 } 1976 } 1977 1978 /** 1979 * Determines if the speakerphone should be automatically enabled for the call. Speakerphone 1980 * should be enabled if the call is a video call and bluetooth or the wired headset are not in 1981 * use. 1982 * 1983 * @param videoState The video state of the call. 1984 * @return {@code true} if the speakerphone should be enabled. 1985 */ 1986 public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) { 1987 return VideoProfile.isVideo(videoState) && 1988 !mWiredHeadsetManager.isPluggedIn() && 1989 !mBluetoothRouteManager.isBluetoothAvailable() && 1990 isSpeakerEnabledForVideoCalls(); 1991 } 1992 1993 /** 1994 * Determines if the speakerphone should be enabled for when docked. Speakerphone 1995 * should be enabled if the device is docked and bluetooth or the wired headset are 1996 * not in use. 1997 * 1998 * @return {@code true} if the speakerphone should be enabled for the dock. 1999 */ 2000 private boolean isSpeakerphoneEnabledForDock() { 2001 return mDockManager.isDocked() && 2002 !mWiredHeadsetManager.isPluggedIn() && 2003 !mBluetoothRouteManager.isBluetoothAvailable(); 2004 } 2005 2006 /** 2007 * Determines if the speakerphone should be automatically enabled for video calls. 2008 * 2009 * @return {@code true} if the speakerphone should automatically be enabled. 2010 */ 2011 private static boolean isSpeakerEnabledForVideoCalls() { 2012 return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT, 2013 PhoneConstants.AUDIO_OUTPUT_DEFAULT) == 2014 PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER); 2015 } 2016 2017 /** 2018 * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call 2019 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 2020 * the user opting to reject said call. 2021 */ 2022 @VisibleForTesting 2023 public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) { 2024 if (!mCalls.contains(call)) { 2025 Log.i(this, "Request to reject a non-existent call %s", call); 2026 } else { 2027 for (CallsManagerListener listener : mListeners) { 2028 listener.onIncomingCallRejected(call, rejectWithMessage, textMessage); 2029 } 2030 call.reject(rejectWithMessage, textMessage); 2031 } 2032 } 2033 2034 /** 2035 * Instructs Telecom to play the specified DTMF tone within the specified call. 2036 * 2037 * @param digit The DTMF digit to play. 2038 */ 2039 @VisibleForTesting 2040 public void playDtmfTone(Call call, char digit) { 2041 if (!mCalls.contains(call)) { 2042 Log.i(this, "Request to play DTMF in a non-existent call %s", call); 2043 } else { 2044 if (call.getState() != CallState.ON_HOLD) { 2045 call.playDtmfTone(digit); 2046 mDtmfLocalTonePlayer.playTone(call, digit); 2047 } else { 2048 Log.i(this, "Request to play DTMF tone for held call %s", call.getId()); 2049 } 2050 } 2051 } 2052 2053 /** 2054 * Instructs Telecom to stop the currently playing DTMF tone, if any. 2055 */ 2056 @VisibleForTesting 2057 public void stopDtmfTone(Call call) { 2058 if (!mCalls.contains(call)) { 2059 Log.i(this, "Request to stop DTMF in a non-existent call %s", call); 2060 } else { 2061 call.stopDtmfTone(); 2062 mDtmfLocalTonePlayer.stopTone(call); 2063 } 2064 } 2065 2066 /** 2067 * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any. 2068 */ 2069 void postDialContinue(Call call, boolean proceed) { 2070 if (!mCalls.contains(call)) { 2071 Log.i(this, "Request to continue post-dial string in a non-existent call %s", call); 2072 } else { 2073 call.postDialContinue(proceed); 2074 } 2075 } 2076 2077 /** 2078 * Instructs Telecom to disconnect the specified call. Intended to be invoked by the 2079 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 2080 * the user hitting the end-call button. 2081 */ 2082 @VisibleForTesting 2083 public void disconnectCall(Call call) { 2084 Log.v(this, "disconnectCall %s", call); 2085 2086 if (!mCalls.contains(call)) { 2087 Log.w(this, "Unknown call (%s) asked to disconnect", call); 2088 } else { 2089 mLocallyDisconnectingCalls.add(call); 2090 call.disconnect(); 2091 // Cancel any of the outgoing call futures if they're still around. 2092 if (mPendingCallConfirm != null && !mPendingCallConfirm.isDone()) { 2093 mPendingCallConfirm.complete(null); 2094 mPendingCallConfirm = null; 2095 } 2096 if (mPendingAccountSelection != null && !mPendingAccountSelection.isDone()) { 2097 mPendingAccountSelection.complete(null); 2098 mPendingAccountSelection = null; 2099 } 2100 } 2101 } 2102 2103 /** 2104 * Instructs Telecom to disconnect all calls. 2105 */ 2106 void disconnectAllCalls() { 2107 Log.v(this, "disconnectAllCalls"); 2108 2109 for (Call call : mCalls) { 2110 disconnectCall(call); 2111 } 2112 } 2113 2114 /** 2115 * Disconnects calls for any other {@link PhoneAccountHandle} but the one specified. 2116 * Note: As a protective measure, will NEVER disconnect an emergency call. Although that 2117 * situation should never arise, its a good safeguard. 2118 * @param phoneAccountHandle Calls owned by {@link PhoneAccountHandle}s other than this one will 2119 * be disconnected. 2120 */ 2121 private void disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle) { 2122 mCalls.stream() 2123 .filter(c -> !c.isEmergencyCall() && 2124 !c.getTargetPhoneAccount().equals(phoneAccountHandle)) 2125 .forEach(c -> disconnectCall(c)); 2126 } 2127 2128 /** 2129 * Instructs Telecom to put the specified call on hold. Intended to be invoked by the 2130 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 2131 * the user hitting the hold button during an active call. 2132 */ 2133 @VisibleForTesting 2134 public void holdCall(Call call) { 2135 if (!mCalls.contains(call)) { 2136 Log.w(this, "Unknown call (%s) asked to be put on hold", call); 2137 } else { 2138 Log.d(this, "Putting call on hold: (%s)", call); 2139 call.hold(); 2140 } 2141 } 2142 2143 /** 2144 * Instructs Telecom to release the specified call from hold. Intended to be invoked by 2145 * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered 2146 * by the user hitting the hold button during a held call. 2147 */ 2148 @VisibleForTesting 2149 public void unholdCall(Call call) { 2150 if (!mCalls.contains(call)) { 2151 Log.w(this, "Unknown call (%s) asked to be removed from hold", call); 2152 } else { 2153 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 2154 String activeCallId = null; 2155 if (activeCall != null && !activeCall.isLocallyDisconnecting()) { 2156 activeCallId = activeCall.getId(); 2157 if (canHold(activeCall)) { 2158 activeCall.hold("Swap to " + call.getId()); 2159 Log.addEvent(activeCall, LogUtils.Events.SWAP, "To " + call.getId()); 2160 Log.addEvent(call, LogUtils.Events.SWAP, "From " + activeCall.getId()); 2161 } else { 2162 // This call does not support hold. If it is from a different connection 2163 // service, then disconnect it, otherwise invoke call.hold() and allow the 2164 // connection service to handle the situation. 2165 if (!PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(), 2166 call.getTargetPhoneAccount())) { 2167 if (!activeCall.isEmergencyCall()) { 2168 activeCall.disconnect("Swap to " + call.getId()); 2169 } else { 2170 Log.w(this, "unholdCall: % is an emergency call, aborting swap to %s", 2171 activeCall.getId(), call.getId()); 2172 // Don't unhold the call as requested; we don't want to drop an 2173 // emergency call. 2174 return; 2175 } 2176 } else { 2177 activeCall.hold("Swap to " + call.getId()); 2178 } 2179 } 2180 } 2181 mConnectionSvrFocusMgr.requestFocus( 2182 call, 2183 new RequestCallback(new ActionUnHoldCall(call, activeCallId))); 2184 } 2185 } 2186 2187 @Override 2188 public void onExtrasRemoved(Call c, int source, List<String> keys) { 2189 if (source != Call.SOURCE_CONNECTION_SERVICE) { 2190 return; 2191 } 2192 updateCanAddCall(); 2193 } 2194 2195 @Override 2196 public void onExtrasChanged(Call c, int source, Bundle extras) { 2197 if (source != Call.SOURCE_CONNECTION_SERVICE) { 2198 return; 2199 } 2200 handleCallTechnologyChange(c); 2201 handleChildAddressChange(c); 2202 updateCanAddCall(); 2203 } 2204 2205 // Construct the list of possible PhoneAccounts that the outgoing call can use based on the 2206 // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount, 2207 // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP. 2208 @VisibleForTesting 2209 public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, 2210 boolean isVideo) { 2211 if (handle == null) { 2212 return Collections.emptyList(); 2213 } 2214 // If we're specifically looking for video capable accounts, then include that capability, 2215 // otherwise specify no additional capability constraints. 2216 List<PhoneAccountHandle> allAccounts = 2217 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user, 2218 isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0 /* any */); 2219 // First check the Radio SIM Technology 2220 if(mRadioSimVariants == null) { 2221 TelephonyManager tm = (TelephonyManager) mContext.getSystemService( 2222 Context.TELEPHONY_SERVICE); 2223 // Cache Sim Variants 2224 mRadioSimVariants = tm.getMultiSimConfiguration(); 2225 } 2226 // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount 2227 // Should be available if a call is already active on the SIM account. 2228 if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) { 2229 List<PhoneAccountHandle> simAccounts = 2230 mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser(); 2231 PhoneAccountHandle ongoingCallAccount = null; 2232 for (Call c : mCalls) { 2233 if (!c.isDisconnected() && !c.isNew() && simAccounts.contains( 2234 c.getTargetPhoneAccount())) { 2235 ongoingCallAccount = c.getTargetPhoneAccount(); 2236 break; 2237 } 2238 } 2239 if (ongoingCallAccount != null) { 2240 // Remove all SIM accounts that are not the active SIM from the list. 2241 simAccounts.remove(ongoingCallAccount); 2242 allAccounts.removeAll(simAccounts); 2243 } 2244 } 2245 return allAccounts; 2246 } 2247 2248 /** 2249 * Informs listeners (notably {@link CallAudioManager} of a change to the call's external 2250 * property. 2251 * . 2252 * @param call The call whose external property changed. 2253 * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise. 2254 */ 2255 @Override 2256 public void onExternalCallChanged(Call call, boolean isExternalCall) { 2257 Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall); 2258 for (CallsManagerListener listener : mListeners) { 2259 listener.onExternalCallChanged(call, isExternalCall); 2260 } 2261 } 2262 2263 private void handleCallTechnologyChange(Call call) { 2264 if (call.getExtras() != null 2265 && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) { 2266 2267 Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get( 2268 call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)); 2269 if (analyticsCallTechnology == null) { 2270 analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE; 2271 } 2272 call.getAnalytics().addCallTechnology(analyticsCallTechnology); 2273 } 2274 } 2275 2276 public void handleChildAddressChange(Call call) { 2277 if (call.getExtras() != null 2278 && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) { 2279 2280 String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS); 2281 call.setViaNumber(viaNumber); 2282 } 2283 } 2284 2285 /** Called by the in-call UI to change the mute state. */ 2286 void mute(boolean shouldMute) { 2287 if (hasEmergencyCall() && shouldMute) { 2288 Log.i(this, "Refusing to turn on mute because we're in an emergency call"); 2289 shouldMute = false; 2290 } 2291 mCallAudioManager.mute(shouldMute); 2292 } 2293 2294 /** 2295 * Called by the in-call UI to change the audio route, for example to change from earpiece to 2296 * speaker phone. 2297 */ 2298 void setAudioRoute(int route, String bluetoothAddress) { 2299 if (hasEmergencyRttCall() && route != CallAudioState.ROUTE_SPEAKER) { 2300 Log.i(this, "In an emergency RTT call. Forcing route to speaker."); 2301 route = CallAudioState.ROUTE_SPEAKER; 2302 bluetoothAddress = null; 2303 } 2304 mCallAudioManager.setAudioRoute(route, bluetoothAddress); 2305 } 2306 2307 /** Called by the in-call UI to turn the proximity sensor on. */ 2308 void turnOnProximitySensor() { 2309 mProximitySensorManager.turnOn(); 2310 } 2311 2312 /** 2313 * Called by the in-call UI to turn the proximity sensor off. 2314 * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise, 2315 * the screen will be kept off until the proximity sensor goes negative. 2316 */ 2317 void turnOffProximitySensor(boolean screenOnImmediately) { 2318 mProximitySensorManager.turnOff(screenOnImmediately); 2319 } 2320 2321 private boolean isRttSettingOn() { 2322 return Settings.Secure.getInt(mContext.getContentResolver(), 2323 Settings.Secure.RTT_CALLING_MODE, 0) != 0; 2324 } 2325 2326 void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) { 2327 if (!mCalls.contains(call)) { 2328 Log.i(this, "Attempted to add account to unknown call %s", call); 2329 } else { 2330 if (setDefault) { 2331 mPhoneAccountRegistrar 2332 .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser()); 2333 } 2334 2335 if (mPendingAccountSelection != null) { 2336 mPendingAccountSelection.complete(Pair.create(call, account)); 2337 mPendingAccountSelection = null; 2338 } 2339 } 2340 } 2341 2342 /** Called when the audio state changes. */ 2343 @VisibleForTesting 2344 public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState 2345 newAudioState) { 2346 Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState); 2347 for (CallsManagerListener listener : mListeners) { 2348 listener.onCallAudioStateChanged(oldAudioState, newAudioState); 2349 } 2350 } 2351 2352 /** 2353 * Called when disconnect tone is started or stopped, including any InCallTone 2354 * after disconnected call. 2355 * 2356 * @param isTonePlaying true if the disconnected tone is started, otherwise the disconnected 2357 * tone is stopped. 2358 */ 2359 @VisibleForTesting 2360 public void onDisconnectedTonePlaying(boolean isTonePlaying) { 2361 Log.v(this, "onDisconnectedTonePlaying, %s", isTonePlaying ? "started" : "stopped"); 2362 for (CallsManagerListener listener : mListeners) { 2363 listener.onDisconnectedTonePlaying(isTonePlaying); 2364 } 2365 } 2366 2367 void markCallAsRinging(Call call) { 2368 setCallState(call, CallState.RINGING, "ringing set explicitly"); 2369 } 2370 2371 void markCallAsDialing(Call call) { 2372 setCallState(call, CallState.DIALING, "dialing set explicitly"); 2373 maybeMoveToSpeakerPhone(call); 2374 maybeTurnOffMute(call); 2375 ensureCallAudible(); 2376 } 2377 2378 void markCallAsPulling(Call call) { 2379 setCallState(call, CallState.PULLING, "pulling set explicitly"); 2380 maybeMoveToSpeakerPhone(call); 2381 } 2382 2383 /** 2384 * Returns true if the active call is held. 2385 */ 2386 boolean holdActiveCallForNewCall(Call call) { 2387 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 2388 if (activeCall != null && activeCall != call) { 2389 if (canHold(activeCall)) { 2390 activeCall.hold(); 2391 return true; 2392 } else if (supportsHold(activeCall) 2393 && PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(), 2394 call.getTargetPhoneAccount())) { 2395 2396 // Handle the case where the active call and the new call are from the same CS, and 2397 // the currently active call supports hold but cannot currently be held. 2398 // In this case we'll look for the other held call for this connectionService and 2399 // disconnect it prior to holding the active call. 2400 // E.g. 2401 // Call A - Held (Supports hold, can't hold) 2402 // Call B - Active (Supports hold, can't hold) 2403 // Call C - Incoming 2404 // Here we need to disconnect A prior to holding B so that C can be answered. 2405 // This case is driven by telephony requirements ultimately. 2406 Call heldCall = getHeldCallByConnectionService(call.getTargetPhoneAccount()); 2407 if (heldCall != null) { 2408 heldCall.disconnect(); 2409 Log.i(this, "holdActiveCallForNewCall: Disconnect held call %s before " 2410 + "holding active call %s.", 2411 heldCall.getId(), activeCall.getId()); 2412 } 2413 Log.i(this, "holdActiveCallForNewCall: Holding active %s before making %s active.", 2414 activeCall.getId(), call.getId()); 2415 activeCall.hold(); 2416 return true; 2417 } else { 2418 // This call does not support hold. If it is from a different connection 2419 // service, then disconnect it, otherwise allow the connection service to 2420 // figure out the right states. 2421 if (!PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(), 2422 call.getTargetPhoneAccount())) { 2423 Log.i(this, "holdActiveCallForNewCall: disconnecting %s so that %s can be " 2424 + "made active.", activeCall.getId(), call.getId()); 2425 if (!activeCall.isEmergencyCall()) { 2426 activeCall.disconnect(); 2427 } else { 2428 // It's not possible to hold the active call, and its an emergency call so 2429 // we will silently reject the incoming call instead of answering it. 2430 Log.w(this, "holdActiveCallForNewCall: rejecting incoming call %s as " 2431 + "the active call is an emergency call and it cannot be held.", 2432 call.getId()); 2433 call.reject(false /* rejectWithMessage */, "" /* message */, 2434 "active emergency call can't be held"); 2435 } 2436 } 2437 } 2438 } 2439 return false; 2440 } 2441 2442 @VisibleForTesting 2443 public void markCallAsActive(Call call) { 2444 if (call.isSelfManaged()) { 2445 // backward compatibility, the self-managed connection service will set the call state 2446 // to active directly. We should hold or disconnect the current active call based on the 2447 // holdability, and request the call focus for the self-managed call before the state 2448 // change. 2449 holdActiveCallForNewCall(call); 2450 mConnectionSvrFocusMgr.requestFocus( 2451 call, 2452 new RequestCallback(new ActionSetCallState( 2453 call, 2454 CallState.ACTIVE, 2455 "active set explicitly for self-managed"))); 2456 } else { 2457 setCallState(call, CallState.ACTIVE, "active set explicitly"); 2458 maybeMoveToSpeakerPhone(call); 2459 ensureCallAudible(); 2460 } 2461 } 2462 2463 @VisibleForTesting 2464 public void markCallAsOnHold(Call call) { 2465 setCallState(call, CallState.ON_HOLD, "on-hold set explicitly"); 2466 } 2467 2468 /** 2469 * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the 2470 * last live call, then also disconnect from the in-call controller. 2471 * 2472 * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}. 2473 */ 2474 void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) { 2475 call.setDisconnectCause(disconnectCause); 2476 setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly"); 2477 } 2478 2479 /** 2480 * Removes an existing disconnected call, and notifies the in-call app. 2481 */ 2482 void markCallAsRemoved(Call call) { 2483 mInCallController.getBindingFuture().thenRunAsync(() -> { 2484 call.maybeCleanupHandover(); 2485 removeCall(call); 2486 Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall(); 2487 if (mLocallyDisconnectingCalls.contains(call)) { 2488 boolean isDisconnectingChildCall = call.isDisconnectingChildCall(); 2489 Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = " 2490 + isDisconnectingChildCall + "call -> %s", call); 2491 mLocallyDisconnectingCalls.remove(call); 2492 // Auto-unhold the foreground call due to a locally disconnected call, except if the 2493 // call which was disconnected is a member of a conference (don't want to auto 2494 // un-hold the conference if we remove a member of the conference). 2495 if (!isDisconnectingChildCall && foregroundCall != null 2496 && foregroundCall.getState() == CallState.ON_HOLD) { 2497 foregroundCall.unhold(); 2498 } 2499 } else if (foregroundCall != null && 2500 !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD) && 2501 foregroundCall.getState() == CallState.ON_HOLD) { 2502 2503 // The new foreground call is on hold, however the carrier does not display the hold 2504 // button in the UI. Therefore, we need to auto unhold the held call since the user 2505 // has no means of unholding it themselves. 2506 Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)"); 2507 foregroundCall.unhold(); 2508 } 2509 }, new LoggedHandlerExecutor(mHandler, "CM.mCAR", mLock)); 2510 } 2511 2512 /** 2513 * Given a call, marks the call as disconnected and removes it. Set the error message to 2514 * indicate to the user that the call cannot me placed due to an ongoing call in another app. 2515 * 2516 * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed 2517 * call. Called by {@link #startCallConfirmation} when the user is already confirming an 2518 * outgoing call. Realistically this should almost never be called since in practice the user 2519 * won't make multiple outgoing calls at the same time. 2520 * 2521 * @param call The call to mark as disconnected. 2522 */ 2523 void markCallDisconnectedDueToSelfManagedCall(Call call) { 2524 Call activeCall = getActiveCall(); 2525 CharSequence errorMessage; 2526 if (activeCall == null) { 2527 // Realistically this shouldn't happen, but best to handle gracefully 2528 errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call); 2529 } else { 2530 errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call, 2531 activeCall.getTargetPhoneAccountLabel()); 2532 } 2533 // Call is managed and there are ongoing self-managed calls. 2534 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 2535 errorMessage, errorMessage, "Ongoing call in another app.")); 2536 markCallAsRemoved(call); 2537 } 2538 2539 /** 2540 * Cleans up any calls currently associated with the specified connection service when the 2541 * service binder disconnects unexpectedly. 2542 * 2543 * @param service The connection service that disconnected. 2544 */ 2545 void handleConnectionServiceDeath(ConnectionServiceWrapper service) { 2546 if (service != null) { 2547 Log.i(this, "handleConnectionServiceDeath: service %s died", service); 2548 for (Call call : mCalls) { 2549 if (call.getConnectionService() == service) { 2550 if (call.getState() != CallState.DISCONNECTED) { 2551 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 2552 null /* message */, null /* description */, "CS_DEATH", 2553 ToneGenerator.TONE_PROP_PROMPT)); 2554 } 2555 markCallAsRemoved(call); 2556 } 2557 } 2558 } 2559 } 2560 2561 /** 2562 * Determines if the {@link CallsManager} has any non-external calls. 2563 * 2564 * @return {@code True} if there are any non-external calls, {@code false} otherwise. 2565 */ 2566 boolean hasAnyCalls() { 2567 if (mCalls.isEmpty()) { 2568 return false; 2569 } 2570 2571 for (Call call : mCalls) { 2572 if (!call.isExternalCall()) { 2573 return true; 2574 } 2575 } 2576 return false; 2577 } 2578 2579 boolean hasActiveOrHoldingCall() { 2580 return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null; 2581 } 2582 2583 boolean hasRingingCall() { 2584 return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED) != null; 2585 } 2586 2587 @VisibleForTesting 2588 public boolean onMediaButton(int type) { 2589 if (hasAnyCalls()) { 2590 Call ringingCall = getFirstCallWithState(CallState.RINGING); 2591 if (HeadsetMediaButton.SHORT_PRESS == type) { 2592 if (ringingCall == null) { 2593 Call activeCall = getFirstCallWithState(CallState.ACTIVE); 2594 Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD); 2595 if (activeCall != null && onHoldCall != null) { 2596 // Two calls, short-press -> switch calls 2597 Log.addEvent(onHoldCall, LogUtils.Events.INFO, 2598 "two calls, media btn short press - switch call."); 2599 unholdCall(onHoldCall); 2600 return true; 2601 } 2602 2603 Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING, 2604 CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD); 2605 Log.addEvent(callToHangup, LogUtils.Events.INFO, 2606 "media btn short press - end call."); 2607 if (callToHangup != null) { 2608 disconnectCall(callToHangup); 2609 return true; 2610 } 2611 } else { 2612 ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY); 2613 return true; 2614 } 2615 } else if (HeadsetMediaButton.LONG_PRESS == type) { 2616 if (ringingCall != null) { 2617 Log.addEvent(getForegroundCall(), 2618 LogUtils.Events.INFO, "media btn long press - reject"); 2619 ringingCall.reject(false, null); 2620 } else { 2621 Call activeCall = getFirstCallWithState(CallState.ACTIVE); 2622 Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD); 2623 if (activeCall != null && onHoldCall != null) { 2624 // Two calls, long-press -> end current call 2625 Log.addEvent(activeCall, LogUtils.Events.INFO, 2626 "two calls, media btn long press - end current call."); 2627 disconnectCall(activeCall); 2628 return true; 2629 } 2630 2631 Log.addEvent(getForegroundCall(), LogUtils.Events.INFO, 2632 "media btn long press - mute"); 2633 mCallAudioManager.toggleMute(); 2634 } 2635 return true; 2636 } 2637 } 2638 return false; 2639 } 2640 2641 /** 2642 * Returns true if telecom supports adding another top-level call. 2643 */ 2644 @VisibleForTesting 2645 public boolean canAddCall() { 2646 boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 2647 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 2648 if (!isDeviceProvisioned) { 2649 Log.d(TAG, "Device not provisioned, canAddCall is false."); 2650 return false; 2651 } 2652 2653 if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) { 2654 return false; 2655 } 2656 2657 int count = 0; 2658 for (Call call : mCalls) { 2659 if (call.isEmergencyCall()) { 2660 // We never support add call if one of the calls is an emergency call. 2661 return false; 2662 } else if (call.isExternalCall()) { 2663 // External calls don't count. 2664 continue; 2665 } else if (call.getParentCall() == null) { 2666 count++; 2667 } 2668 Bundle extras = call.getExtras(); 2669 if (extras != null) { 2670 if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) { 2671 return false; 2672 } 2673 } 2674 2675 // We do not check states for canAddCall. We treat disconnected calls the same 2676 // and wait until they are removed instead. If we didn't count disconnected calls, 2677 // we could put InCallServices into a state where they are showing two calls but 2678 // also support add-call. Technically it's right, but overall looks better (UI-wise) 2679 // and acts better if we wait until the call is removed. 2680 if (count >= MAXIMUM_TOP_LEVEL_CALLS) { 2681 return false; 2682 } 2683 } 2684 2685 return true; 2686 } 2687 2688 @VisibleForTesting 2689 public Call getRingingCall() { 2690 return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED); 2691 } 2692 2693 public Call getActiveCall() { 2694 return getFirstCallWithState(CallState.ACTIVE); 2695 } 2696 2697 Call getDialingCall() { 2698 return getFirstCallWithState(CallState.DIALING); 2699 } 2700 2701 @VisibleForTesting 2702 public Call getHeldCall() { 2703 return getFirstCallWithState(CallState.ON_HOLD); 2704 } 2705 2706 public Call getHeldCallByConnectionService(PhoneAccountHandle targetPhoneAccount) { 2707 Optional<Call> heldCall = mCalls.stream() 2708 .filter(call -> PhoneAccountHandle.areFromSamePackage(call.getTargetPhoneAccount(), 2709 targetPhoneAccount) 2710 && call.getParentCall() == null 2711 && call.getState() == CallState.ON_HOLD) 2712 .findFirst(); 2713 return heldCall.isPresent() ? heldCall.get() : null; 2714 } 2715 2716 @VisibleForTesting 2717 public int getNumHeldCalls() { 2718 int count = 0; 2719 for (Call call : mCalls) { 2720 if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) { 2721 count++; 2722 } 2723 } 2724 return count; 2725 } 2726 2727 @VisibleForTesting 2728 public Call getOutgoingCall() { 2729 return getFirstCallWithState(OUTGOING_CALL_STATES); 2730 } 2731 2732 @VisibleForTesting 2733 public Call getFirstCallWithState(int... states) { 2734 return getFirstCallWithState(null, states); 2735 } 2736 2737 @VisibleForTesting 2738 public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() { 2739 return mPhoneNumberUtilsAdapter; 2740 } 2741 2742 @VisibleForTesting 2743 public CompletableFuture<Call> getLatestPostSelectionProcessingFuture() { 2744 return mLatestPostSelectionProcessingFuture; 2745 } 2746 2747 @VisibleForTesting 2748 public CompletableFuture getLatestPreAccountSelectionFuture() { 2749 return mLatestPreAccountSelectionFuture; 2750 } 2751 2752 /** 2753 * Returns the first call that it finds with the given states. The states are treated as having 2754 * priority order so that any call with the first state will be returned before any call with 2755 * states listed later in the parameter list. 2756 * 2757 * @param callToSkip Call that this method should skip while searching 2758 */ 2759 Call getFirstCallWithState(Call callToSkip, int... states) { 2760 for (int currentState : states) { 2761 // check the foreground first 2762 Call foregroundCall = getForegroundCall(); 2763 if (foregroundCall != null && foregroundCall.getState() == currentState) { 2764 return foregroundCall; 2765 } 2766 2767 for (Call call : mCalls) { 2768 if (Objects.equals(callToSkip, call)) { 2769 continue; 2770 } 2771 2772 // Only operate on top-level calls 2773 if (call.getParentCall() != null) { 2774 continue; 2775 } 2776 2777 if (call.isExternalCall()) { 2778 continue; 2779 } 2780 2781 if (currentState == call.getState()) { 2782 return call; 2783 } 2784 } 2785 } 2786 return null; 2787 } 2788 2789 Call createConferenceCall( 2790 String callId, 2791 PhoneAccountHandle phoneAccount, 2792 ParcelableConference parcelableConference) { 2793 2794 // If the parceled conference specifies a connect time, use it; otherwise default to 0, 2795 // which is the default value for new Calls. 2796 long connectTime = 2797 parcelableConference.getConnectTimeMillis() == 2798 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2799 parcelableConference.getConnectTimeMillis(); 2800 long connectElapsedTime = 2801 parcelableConference.getConnectElapsedTimeMillis() == 2802 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 2803 parcelableConference.getConnectElapsedTimeMillis(); 2804 2805 Call call = new Call( 2806 callId, 2807 mContext, 2808 this, 2809 mLock, 2810 mConnectionServiceRepository, 2811 mPhoneNumberUtilsAdapter, 2812 null /* handle */, 2813 null /* gatewayInfo */, 2814 null /* connectionManagerPhoneAccount */, 2815 phoneAccount, 2816 Call.CALL_DIRECTION_UNDEFINED /* callDirection */, 2817 false /* forceAttachToExistingConnection */, 2818 true /* isConference */, 2819 connectTime, 2820 connectElapsedTime, 2821 mClockProxy); 2822 2823 setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()), 2824 "new conference call"); 2825 call.setHandle(parcelableConference.getHandle(), 2826 parcelableConference.getHandlePresentation()); 2827 call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities()); 2828 call.setConnectionProperties(parcelableConference.getConnectionProperties()); 2829 call.setVideoState(parcelableConference.getVideoState()); 2830 call.setVideoProvider(parcelableConference.getVideoProvider()); 2831 call.setStatusHints(parcelableConference.getStatusHints()); 2832 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras()); 2833 // In case this Conference was added via a ConnectionManager, keep track of the original 2834 // Connection ID as created by the originating ConnectionService. 2835 Bundle extras = parcelableConference.getExtras(); 2836 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2837 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 2838 } 2839 2840 // TODO: Move this to be a part of addCall() 2841 call.addListener(this); 2842 addCall(call); 2843 return call; 2844 } 2845 2846 /** 2847 * @return the call state currently tracked by {@link PhoneStateBroadcaster} 2848 */ 2849 int getCallState() { 2850 return mPhoneStateBroadcaster.getCallState(); 2851 } 2852 2853 /** 2854 * Retrieves the {@link PhoneAccountRegistrar}. 2855 * 2856 * @return The {@link PhoneAccountRegistrar}. 2857 */ 2858 @VisibleForTesting 2859 public PhoneAccountRegistrar getPhoneAccountRegistrar() { 2860 return mPhoneAccountRegistrar; 2861 } 2862 2863 /** 2864 * Retrieves the {@link MissedCallNotifier} 2865 * @return The {@link MissedCallNotifier}. 2866 */ 2867 MissedCallNotifier getMissedCallNotifier() { 2868 return mMissedCallNotifier; 2869 } 2870 2871 /** 2872 * Retrieves the {@link IncomingCallNotifier}. 2873 * @return The {@link IncomingCallNotifier}. 2874 */ 2875 IncomingCallNotifier getIncomingCallNotifier() { 2876 return mIncomingCallNotifier; 2877 } 2878 2879 /** 2880 * Reject an incoming call and manually add it to the Call Log. 2881 * @param incomingCall Incoming call that has been rejected 2882 */ 2883 private void rejectCallAndLog(Call incomingCall, CallFilteringResult result) { 2884 if (incomingCall.getConnectionService() != null) { 2885 // Only reject the call if it has not already been destroyed. If a call ends while 2886 // incoming call filtering is taking place, it is possible that the call has already 2887 // been destroyed, and as such it will be impossible to send the reject to the 2888 // associated ConnectionService. 2889 incomingCall.reject(false, null); 2890 } else { 2891 Log.i(this, "rejectCallAndLog - call already destroyed."); 2892 } 2893 2894 // Since the call was not added to the list of calls, we have to call the missed 2895 // call notifier and the call logger manually. 2896 // Do we need missed call notification for direct to Voicemail calls? 2897 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, 2898 true /*showNotificationForMissedCall*/, result); 2899 } 2900 2901 /** 2902 * Adds the specified call to the main list of live calls. 2903 * 2904 * @param call The call to add. 2905 */ 2906 @VisibleForTesting 2907 public void addCall(Call call) { 2908 Trace.beginSection("addCall"); 2909 Log.v(this, "addCall(%s)", call); 2910 call.addListener(this); 2911 mCalls.add(call); 2912 2913 // Specifies the time telecom finished routing the call. This is used by the dialer for 2914 // analytics. 2915 Bundle extras = call.getIntentExtras(); 2916 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS, 2917 SystemClock.elapsedRealtime()); 2918 2919 updateCanAddCall(); 2920 // onCallAdded for calls which immediately take the foreground (like the first call). 2921 for (CallsManagerListener listener : mListeners) { 2922 if (LogUtils.SYSTRACE_DEBUG) { 2923 Trace.beginSection(listener.getClass().toString() + " addCall"); 2924 } 2925 listener.onCallAdded(call); 2926 if (LogUtils.SYSTRACE_DEBUG) { 2927 Trace.endSection(); 2928 } 2929 } 2930 Trace.endSection(); 2931 } 2932 2933 private void removeCall(Call call) { 2934 Trace.beginSection("removeCall"); 2935 Log.v(this, "removeCall(%s)", call); 2936 2937 call.setParentAndChildCall(null); // clean up parent relationship before destroying. 2938 call.removeListener(this); 2939 call.clearConnectionService(); 2940 // TODO: clean up RTT pipes 2941 2942 boolean shouldNotify = false; 2943 if (mCalls.contains(call)) { 2944 mCalls.remove(call); 2945 shouldNotify = true; 2946 } 2947 2948 call.destroy(); 2949 2950 // Only broadcast changes for calls that are being tracked. 2951 if (shouldNotify) { 2952 updateCanAddCall(); 2953 for (CallsManagerListener listener : mListeners) { 2954 if (LogUtils.SYSTRACE_DEBUG) { 2955 Trace.beginSection(listener.getClass().toString() + " onCallRemoved"); 2956 } 2957 listener.onCallRemoved(call); 2958 if (LogUtils.SYSTRACE_DEBUG) { 2959 Trace.endSection(); 2960 } 2961 } 2962 } 2963 Trace.endSection(); 2964 } 2965 2966 /** 2967 * Sets the specified state on the specified call. 2968 * 2969 * @param call The call. 2970 * @param newState The new state of the call. 2971 */ 2972 private void setCallState(Call call, int newState, String tag) { 2973 if (call == null) { 2974 return; 2975 } 2976 int oldState = call.getState(); 2977 Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState), 2978 CallState.toString(newState), call); 2979 if (newState != oldState) { 2980 // If the call switches to held state while a DTMF tone is playing, stop the tone to 2981 // ensure that the tone generator stops playing the tone. 2982 if (newState == CallState.ON_HOLD && call.isDtmfTonePlaying()) { 2983 stopDtmfTone(call); 2984 } 2985 2986 // Unfortunately, in the telephony world the radio is king. So if the call notifies 2987 // us that the call is in a particular state, we allow it even if it doesn't make 2988 // sense (e.g., STATE_ACTIVE -> STATE_RINGING). 2989 // TODO: Consider putting a stop to the above and turning CallState 2990 // into a well-defined state machine. 2991 // TODO: Define expected state transitions here, and log when an 2992 // unexpected transition occurs. 2993 if (call.setState(newState, tag)) { 2994 maybeShowErrorDialogOnDisconnect(call); 2995 2996 Trace.beginSection("onCallStateChanged"); 2997 2998 maybeHandleHandover(call, newState); 2999 3000 // Only broadcast state change for calls that are being tracked. 3001 if (mCalls.contains(call)) { 3002 updateCanAddCall(); 3003 for (CallsManagerListener listener : mListeners) { 3004 if (LogUtils.SYSTRACE_DEBUG) { 3005 Trace.beginSection(listener.getClass().toString() + 3006 " onCallStateChanged"); 3007 } 3008 listener.onCallStateChanged(call, oldState, newState); 3009 if (LogUtils.SYSTRACE_DEBUG) { 3010 Trace.endSection(); 3011 } 3012 } 3013 } 3014 Trace.endSection(); 3015 } else { 3016 Log.i(this, "failed in setting the state to new state"); 3017 } 3018 } 3019 } 3020 3021 /** 3022 * Identifies call state transitions for a call which trigger handover events. 3023 * - If this call has a handover to it which just started and this call goes active, treat 3024 * this as if the user accepted the handover. 3025 * - If this call has a handover to it which just started and this call is disconnected, treat 3026 * this as if the user rejected the handover. 3027 * - If this call has a handover from it which just started and this call is disconnected, do 3028 * nothing as the call prematurely disconnected before the user accepted the handover. 3029 * - If this call has a handover from it which was already accepted by the user and this call is 3030 * disconnected, mark the handover as complete. 3031 * 3032 * @param call A call whose state is changing. 3033 * @param newState The new state of the call. 3034 */ 3035 private void maybeHandleHandover(Call call, int newState) { 3036 if (call.getHandoverSourceCall() != null) { 3037 // We are handing over another call to this one. 3038 if (call.getHandoverState() == HandoverState.HANDOVER_TO_STARTED) { 3039 // A handover to this call has just been initiated. 3040 if (newState == CallState.ACTIVE) { 3041 // This call went active, so the user has accepted the handover. 3042 Log.i(this, "setCallState: handover to accepted"); 3043 acceptHandoverTo(call); 3044 } else if (newState == CallState.DISCONNECTED) { 3045 // The call was disconnected, so the user has rejected the handover. 3046 Log.i(this, "setCallState: handover to rejected"); 3047 rejectHandoverTo(call); 3048 } 3049 } 3050 // If this call was disconnected because it was handed over TO another call, report the 3051 // handover as complete. 3052 } else if (call.getHandoverDestinationCall() != null 3053 && newState == CallState.DISCONNECTED) { 3054 int handoverState = call.getHandoverState(); 3055 if (handoverState == HandoverState.HANDOVER_FROM_STARTED) { 3056 // Disconnect before handover was accepted. 3057 Log.i(this, "setCallState: disconnect before handover accepted"); 3058 // Let the handover destination know that the source has disconnected prior to 3059 // completion of the handover. 3060 call.getHandoverDestinationCall().sendCallEvent( 3061 android.telecom.Call.EVENT_HANDOVER_SOURCE_DISCONNECTED, null); 3062 } else if (handoverState == HandoverState.HANDOVER_ACCEPTED) { 3063 Log.i(this, "setCallState: handover from complete"); 3064 completeHandoverFrom(call); 3065 } 3066 } 3067 } 3068 3069 private void completeHandoverFrom(Call call) { 3070 Call handoverTo = call.getHandoverDestinationCall(); 3071 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 3072 call.getId(), handoverTo.getId()); 3073 Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 3074 call.getId(), handoverTo.getId()); 3075 3076 // Inform the "from" Call (ie the source call) that the handover from it has 3077 // completed; this allows the InCallService to be notified that a handover it 3078 // initiated completed. 3079 call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null); 3080 call.onHandoverComplete(); 3081 3082 // Inform the "to" ConnectionService that handover to it has completed. 3083 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null); 3084 handoverTo.onHandoverComplete(); 3085 answerCall(handoverTo, handoverTo.getVideoState()); 3086 call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE); 3087 3088 // If the call we handed over to is self-managed, we need to disconnect the calls for other 3089 // ConnectionServices. 3090 if (handoverTo.isSelfManaged()) { 3091 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 3092 } 3093 } 3094 3095 private void rejectHandoverTo(Call handoverTo) { 3096 Call handoverFrom = handoverTo.getHandoverSourceCall(); 3097 Log.i(this, "rejectHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 3098 Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s, rejected", 3099 handoverTo.getId(), handoverFrom.getId()); 3100 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s, rejected", 3101 handoverTo.getId(), handoverFrom.getId()); 3102 3103 // Inform the "from" Call (ie the source call) that the handover from it has 3104 // failed; this allows the InCallService to be notified that a handover it 3105 // initiated failed. 3106 handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null); 3107 handoverFrom.onHandoverFailed(android.telecom.Call.Callback.HANDOVER_FAILURE_USER_REJECTED); 3108 3109 // Inform the "to" ConnectionService that handover to it has failed. This 3110 // allows the ConnectionService the call was being handed over 3111 if (handoverTo.getConnectionService() != null) { 3112 // Only attempt if the call has a bound ConnectionService if handover failed 3113 // early on in the handover process, the CS will be unbound and we won't be 3114 // able to send the call event. 3115 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 3116 handoverTo.getConnectionService().handoverFailed(handoverTo, 3117 android.telecom.Call.Callback.HANDOVER_FAILURE_USER_REJECTED); 3118 } 3119 handoverTo.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_FAILED); 3120 } 3121 3122 private void acceptHandoverTo(Call handoverTo) { 3123 Call handoverFrom = handoverTo.getHandoverSourceCall(); 3124 Log.i(this, "acceptHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 3125 handoverTo.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 3126 handoverTo.onHandoverComplete(); 3127 handoverFrom.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 3128 handoverFrom.onHandoverComplete(); 3129 3130 Log.addEvent(handoverTo, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 3131 handoverFrom.getId(), handoverTo.getId()); 3132 Log.addEvent(handoverFrom, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 3133 handoverFrom.getId(), handoverTo.getId()); 3134 3135 // Disconnect the call we handed over from. 3136 disconnectCall(handoverFrom); 3137 // If we handed over to a self-managed ConnectionService, we need to disconnect calls for 3138 // other ConnectionServices. 3139 if (handoverTo.isSelfManaged()) { 3140 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 3141 } 3142 } 3143 3144 private void updateCanAddCall() { 3145 boolean newCanAddCall = canAddCall(); 3146 if (newCanAddCall != mCanAddCall) { 3147 mCanAddCall = newCanAddCall; 3148 for (CallsManagerListener listener : mListeners) { 3149 if (LogUtils.SYSTRACE_DEBUG) { 3150 Trace.beginSection(listener.getClass().toString() + " updateCanAddCall"); 3151 } 3152 listener.onCanAddCallChanged(mCanAddCall); 3153 if (LogUtils.SYSTRACE_DEBUG) { 3154 Trace.endSection(); 3155 } 3156 } 3157 } 3158 } 3159 3160 private boolean isPotentialMMICode(Uri handle) { 3161 return (handle != null && handle.getSchemeSpecificPart() != null 3162 && handle.getSchemeSpecificPart().contains("#")); 3163 } 3164 3165 /** 3166 * Determines if a dialed number is potentially an In-Call MMI code. In-Call MMI codes are 3167 * MMI codes which can be dialed when one or more calls are in progress. 3168 * <P> 3169 * Checks for numbers formatted similar to the MMI codes defined in: 3170 * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)} 3171 * 3172 * @param handle The URI to call. 3173 * @return {@code True} if the URI represents a number which could be an in-call MMI code. 3174 */ 3175 private boolean isPotentialInCallMMICode(Uri handle) { 3176 if (handle != null && handle.getSchemeSpecificPart() != null && 3177 handle.getScheme() != null && 3178 handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) { 3179 3180 String dialedNumber = handle.getSchemeSpecificPart(); 3181 return (dialedNumber.equals("0") || 3182 (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) || 3183 (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) || 3184 dialedNumber.equals("3") || 3185 dialedNumber.equals("4") || 3186 dialedNumber.equals("5")); 3187 } 3188 return false; 3189 } 3190 3191 @VisibleForTesting 3192 public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall, 3193 PhoneAccountHandle phoneAccountHandle, int... states) { 3194 return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED, 3195 excludeCall, phoneAccountHandle, states); 3196 } 3197 3198 /** 3199 * Determines the number of calls matching the specified criteria. 3200 * @param callFilter indicates whether to include just managed calls 3201 * ({@link #CALL_FILTER_MANAGED}), self-managed calls 3202 * ({@link #CALL_FILTER_SELF_MANAGED}), or all calls 3203 * ({@link #CALL_FILTER_ALL}). 3204 * @param excludeCall Where {@code non-null}, this call is excluded from the count. 3205 * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle} 3206 * are excluded from the count. 3207 * @param states The list of {@link CallState}s to include in the count. 3208 * @return Count of calls matching criteria. 3209 */ 3210 @VisibleForTesting 3211 public int getNumCallsWithState(final int callFilter, Call excludeCall, 3212 PhoneAccountHandle phoneAccountHandle, int... states) { 3213 3214 Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet()); 3215 3216 Stream<Call> callsStream = mCalls.stream() 3217 .filter(call -> desiredStates.contains(call.getState()) && 3218 call.getParentCall() == null && !call.isExternalCall()); 3219 3220 if (callFilter == CALL_FILTER_MANAGED) { 3221 callsStream = callsStream.filter(call -> !call.isSelfManaged()); 3222 } else if (callFilter == CALL_FILTER_SELF_MANAGED) { 3223 callsStream = callsStream.filter(call -> call.isSelfManaged()); 3224 } 3225 3226 // If a call to exclude was specified, filter it out. 3227 if (excludeCall != null) { 3228 callsStream = callsStream.filter(call -> call != excludeCall); 3229 } 3230 3231 // If a phone account handle was specified, only consider calls for that phone account. 3232 if (phoneAccountHandle != null) { 3233 callsStream = callsStream.filter( 3234 call -> phoneAccountHandle.equals(call.getTargetPhoneAccount())); 3235 } 3236 3237 return (int) callsStream.count(); 3238 } 3239 3240 private boolean hasMaximumLiveCalls(Call exceptCall) { 3241 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 3242 exceptCall, null /* phoneAccountHandle*/, LIVE_CALL_STATES); 3243 } 3244 3245 private boolean hasMaximumManagedLiveCalls(Call exceptCall) { 3246 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */, 3247 exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES); 3248 } 3249 3250 private boolean hasMaximumSelfManagedCalls(Call exceptCall, 3251 PhoneAccountHandle phoneAccountHandle) { 3252 return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */, 3253 exceptCall, phoneAccountHandle, ANY_CALL_STATE); 3254 } 3255 3256 private boolean hasMaximumManagedHoldingCalls(Call exceptCall) { 3257 return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 3258 null /* phoneAccountHandle */, CallState.ON_HOLD); 3259 } 3260 3261 private boolean hasMaximumManagedRingingCalls(Call exceptCall) { 3262 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 3263 null /* phoneAccountHandle */, CallState.RINGING, CallState.ANSWERED); 3264 } 3265 3266 private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall, 3267 PhoneAccountHandle phoneAccountHandle) { 3268 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall, 3269 phoneAccountHandle, CallState.RINGING, CallState.ANSWERED); 3270 } 3271 3272 private boolean hasMaximumOutgoingCalls(Call exceptCall) { 3273 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 3274 exceptCall, null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 3275 } 3276 3277 private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) { 3278 return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 3279 null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 3280 } 3281 3282 private boolean hasMaximumManagedDialingCalls(Call exceptCall) { 3283 return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 3284 null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING); 3285 } 3286 3287 /** 3288 * Given a {@link PhoneAccountHandle} determines if there are other unholdable calls owned by 3289 * another connection service. 3290 * @param phoneAccountHandle The {@link PhoneAccountHandle} to check. 3291 * @return {@code true} if there are other unholdable calls, {@code false} otherwise. 3292 */ 3293 public boolean hasUnholdableCallsForOtherConnectionService( 3294 PhoneAccountHandle phoneAccountHandle) { 3295 return getNumUnholdableCallsForOtherConnectionService(phoneAccountHandle) > 0; 3296 } 3297 3298 /** 3299 * Determines the number of unholdable calls present in a connection service other than the one 3300 * the passed phone account belonds to. 3301 * @param phoneAccountHandle The handle of the PhoneAccount. 3302 * @return Number of unholdable calls owned by other connection service. 3303 */ 3304 public int getNumUnholdableCallsForOtherConnectionService( 3305 PhoneAccountHandle phoneAccountHandle) { 3306 return (int) mCalls.stream().filter(call -> 3307 !phoneAccountHandle.getComponentName().equals( 3308 call.getTargetPhoneAccount().getComponentName()) 3309 && call.getParentCall() == null 3310 && !call.isExternalCall() 3311 && !canHold(call)).count(); 3312 } 3313 3314 /** 3315 * Determines if there are any managed calls. 3316 * @return {@code true} if there are managed calls, {@code false} otherwise. 3317 */ 3318 public boolean hasManagedCalls() { 3319 return mCalls.stream().filter(call -> !call.isSelfManaged() && 3320 !call.isExternalCall()).count() > 0; 3321 } 3322 3323 /** 3324 * Determines if there are any self-managed calls. 3325 * @return {@code true} if there are self-managed calls, {@code false} otherwise. 3326 */ 3327 public boolean hasSelfManagedCalls() { 3328 return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0; 3329 } 3330 3331 /** 3332 * Determines if there are any ongoing managed or self-managed calls. 3333 * Note: The {@link #ONGOING_CALL_STATES} are 3334 * @return {@code true} if there are ongoing managed or self-managed calls, {@code false} 3335 * otherwise. 3336 */ 3337 public boolean hasOngoingCalls() { 3338 return getNumCallsWithState( 3339 CALL_FILTER_ALL, null /* excludeCall */, 3340 null /* phoneAccountHandle */, 3341 ONGOING_CALL_STATES) > 0; 3342 } 3343 3344 /** 3345 * Determines if there are any ongoing managed calls. 3346 * @return {@code true} if there are ongoing managed calls, {@code false} otherwise. 3347 */ 3348 public boolean hasOngoingManagedCalls() { 3349 return getNumCallsWithState( 3350 CALL_FILTER_MANAGED, null /* excludeCall */, 3351 null /* phoneAccountHandle */, 3352 ONGOING_CALL_STATES) > 0; 3353 } 3354 3355 /** 3356 * Determines if the system incoming call UI should be shown. 3357 * The system incoming call UI will be shown if the new incoming call is self-managed, and there 3358 * are ongoing calls for another PhoneAccount. 3359 * @param incomingCall The incoming call. 3360 * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise. 3361 */ 3362 public boolean shouldShowSystemIncomingCallUi(Call incomingCall) { 3363 return incomingCall.isIncoming() && incomingCall.isSelfManaged() 3364 && hasUnholdableCallsForOtherConnectionService(incomingCall.getTargetPhoneAccount()) 3365 && incomingCall.getHandoverSourceCall() == null; 3366 } 3367 3368 private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) { 3369 if (hasMaximumLiveCalls(call)) { 3370 // NOTE: If the amount of live calls changes beyond 1, this logic will probably 3371 // have to change. 3372 Call liveCall = getFirstCallWithState(LIVE_CALL_STATES); 3373 Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " + 3374 liveCall); 3375 3376 if (call == liveCall) { 3377 // If the call is already the foreground call, then we are golden. 3378 // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT 3379 // state since the call was already populated into the list. 3380 return true; 3381 } 3382 3383 if (hasMaximumOutgoingCalls(call)) { 3384 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES); 3385 if (isEmergency && !outgoingCall.isEmergencyCall()) { 3386 // Disconnect the current outgoing call if it's not an emergency call. If the 3387 // user tries to make two outgoing calls to different emergency call numbers, 3388 // we will try to connect the first outgoing call. 3389 call.getAnalytics().setCallIsAdditional(true); 3390 outgoingCall.getAnalytics().setCallIsInterrupted(true); 3391 outgoingCall.disconnect(); 3392 return true; 3393 } 3394 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) { 3395 // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT} 3396 // state, just disconnect it since the user has explicitly started a new call. 3397 call.getAnalytics().setCallIsAdditional(true); 3398 outgoingCall.getAnalytics().setCallIsInterrupted(true); 3399 outgoingCall.disconnect(); 3400 return true; 3401 } 3402 return false; 3403 } 3404 3405 // If we have the max number of held managed calls and we're placing an emergency call, 3406 // we'll disconnect the ongoing call if it cannot be held. 3407 if (hasMaximumManagedHoldingCalls(call) && isEmergency && !canHold(liveCall)) { 3408 call.getAnalytics().setCallIsAdditional(true); 3409 liveCall.getAnalytics().setCallIsInterrupted(true); 3410 liveCall.disconnect("disconnecting to make room for emergency call " 3411 + call.getId()); 3412 return true; 3413 } 3414 3415 // TODO: Remove once b/23035408 has been corrected. 3416 // If the live call is a conference, it will not have a target phone account set. This 3417 // means the check to see if the live call has the same target phone account as the new 3418 // call will not cause us to bail early. As a result, we'll end up holding the 3419 // ongoing conference call. However, the ConnectionService is already doing that. This 3420 // has caused problems with some carriers. As a workaround until b/23035408 is 3421 // corrected, we will try and get the target phone account for one of the conference's 3422 // children and use that instead. 3423 PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount(); 3424 if (liveCallPhoneAccount == null && liveCall.isConference() && 3425 !liveCall.getChildCalls().isEmpty()) { 3426 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall); 3427 Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " + 3428 liveCallPhoneAccount); 3429 } 3430 3431 // First thing, if we are trying to make a call with the same phone account as the live 3432 // call, then allow it so that the connection service can make its own decision about 3433 // how to handle the new call relative to the current one. 3434 if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount, 3435 call.getTargetPhoneAccount())) { 3436 Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches."); 3437 call.getAnalytics().setCallIsAdditional(true); 3438 liveCall.getAnalytics().setCallIsInterrupted(true); 3439 return true; 3440 } else if (call.getTargetPhoneAccount() == null) { 3441 // Without a phone account, we can't say reliably that the call will fail. 3442 // If the user chooses the same phone account as the live call, then it's 3443 // still possible that the call can be made (like with CDMA calls not supporting 3444 // hold but they still support adding a call by going immediately into conference 3445 // mode). Return true here and we'll run this code again after user chooses an 3446 // account. 3447 return true; 3448 } 3449 3450 // Try to hold the live call before attempting the new outgoing call. 3451 if (canHold(liveCall)) { 3452 Log.i(this, "makeRoomForOutgoingCall: holding live call."); 3453 call.getAnalytics().setCallIsAdditional(true); 3454 liveCall.getAnalytics().setCallIsInterrupted(true); 3455 liveCall.hold("calling " + call.getId()); 3456 return true; 3457 } 3458 3459 // The live call cannot be held so we're out of luck here. There's no room. 3460 return false; 3461 } 3462 return true; 3463 } 3464 3465 /** 3466 * Given a call, find the first non-null phone account handle of its children. 3467 * 3468 * @param parentCall The parent call. 3469 * @return The first non-null phone account handle of the children, or {@code null} if none. 3470 */ 3471 private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) { 3472 for (Call childCall : parentCall.getChildCalls()) { 3473 PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount(); 3474 if (childPhoneAccount != null) { 3475 return childPhoneAccount; 3476 } 3477 } 3478 return null; 3479 } 3480 3481 /** 3482 * Checks to see if the call should be on speakerphone and if so, set it. 3483 */ 3484 private void maybeMoveToSpeakerPhone(Call call) { 3485 if (call.isHandoverInProgress() && call.getState() == CallState.DIALING) { 3486 // When a new outgoing call is initiated for the purpose of handing over, do not engage 3487 // speaker automatically until the call goes active. 3488 return; 3489 } 3490 if (call.getStartWithSpeakerphoneOn()) { 3491 setAudioRoute(CallAudioState.ROUTE_SPEAKER, null); 3492 call.setStartWithSpeakerphoneOn(false); 3493 } 3494 } 3495 3496 /** 3497 * Checks to see if the call is an emergency call and if so, turn off mute. 3498 */ 3499 private void maybeTurnOffMute(Call call) { 3500 if (call.isEmergencyCall()) { 3501 mute(false); 3502 } 3503 } 3504 3505 private void ensureCallAudible() { 3506 AudioManager am = mContext.getSystemService(AudioManager.class); 3507 if (am == null) { 3508 Log.w(this, "ensureCallAudible: audio manager is null"); 3509 return; 3510 } 3511 if (am.getStreamVolume(AudioManager.STREAM_VOICE_CALL) == 0) { 3512 Log.i(this, "ensureCallAudible: voice call stream has volume 0. Adjusting to default."); 3513 am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 3514 AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL), 0); 3515 } 3516 } 3517 3518 /** 3519 * Creates a new call for an existing connection. 3520 * 3521 * @param callId The id of the new call. 3522 * @param connection The connection information. 3523 * @return The new call. 3524 */ 3525 Call createCallForExistingConnection(String callId, ParcelableConnection connection) { 3526 boolean isDowngradedConference = (connection.getConnectionProperties() 3527 & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0; 3528 Call call = new Call( 3529 callId, 3530 mContext, 3531 this, 3532 mLock, 3533 mConnectionServiceRepository, 3534 mPhoneNumberUtilsAdapter, 3535 connection.getHandle() /* handle */, 3536 null /* gatewayInfo */, 3537 null /* connectionManagerPhoneAccount */, 3538 connection.getPhoneAccount(), /* targetPhoneAccountHandle */ 3539 Call.getRemappedCallDirection(connection.getCallDirection()) /* callDirection */, 3540 false /* forceAttachToExistingConnection */, 3541 isDowngradedConference /* isConference */, 3542 connection.getConnectTimeMillis() /* connectTimeMillis */, 3543 connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */ 3544 mClockProxy); 3545 3546 call.initAnalytics(); 3547 call.getAnalytics().setCreatedFromExistingConnection(true); 3548 3549 setCallState(call, Call.getStateFromConnectionState(connection.getState()), 3550 "existing connection"); 3551 call.setVideoState(connection.getVideoState()); 3552 call.setConnectionCapabilities(connection.getConnectionCapabilities()); 3553 call.setConnectionProperties(connection.getConnectionProperties()); 3554 call.setHandle(connection.getHandle(), connection.getHandlePresentation()); 3555 call.setCallerDisplayName(connection.getCallerDisplayName(), 3556 connection.getCallerDisplayNamePresentation()); 3557 call.addListener(this); 3558 3559 // In case this connection was added via a ConnectionManager, keep track of the original 3560 // Connection ID as created by the originating ConnectionService. 3561 Bundle extras = connection.getExtras(); 3562 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 3563 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 3564 } 3565 Log.i(this, "createCallForExistingConnection: %s", connection); 3566 Call parentCall = null; 3567 if (!TextUtils.isEmpty(connection.getParentCallId())) { 3568 String parentId = connection.getParentCallId(); 3569 parentCall = mCalls 3570 .stream() 3571 .filter(c -> c.getId().equals(parentId)) 3572 .findFirst() 3573 .orElse(null); 3574 if (parentCall != null) { 3575 Log.i(this, "createCallForExistingConnection: %s added as child of %s.", 3576 call.getId(), 3577 parentCall.getId()); 3578 // Set JUST the parent property, which won't send an update to the Incall UI. 3579 call.setParentCall(parentCall); 3580 } 3581 } 3582 addCall(call); 3583 if (parentCall != null) { 3584 // Now, set the call as a child of the parent since it has been added to Telecom. This 3585 // is where we will inform InCall. 3586 call.setChildOf(parentCall); 3587 call.notifyParentChanged(parentCall); 3588 } 3589 3590 return call; 3591 } 3592 3593 /** 3594 * Determines whether Telecom already knows about a Connection added via the 3595 * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle, 3596 * Connection)} API via a ConnectionManager. 3597 * 3598 * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}. 3599 * @param originalConnectionId The new connection ID to check. 3600 * @return {@code true} if this connection is already known by Telecom. 3601 */ 3602 Call getAlreadyAddedConnection(String originalConnectionId) { 3603 Optional<Call> existingCall = mCalls.stream() 3604 .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) || 3605 originalConnectionId.equals(call.getId())) 3606 .findFirst(); 3607 3608 if (existingCall.isPresent()) { 3609 Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s", 3610 originalConnectionId, existingCall.get().getId()); 3611 return existingCall.get(); 3612 } 3613 3614 return null; 3615 } 3616 3617 /** 3618 * @return A new unique telecom call Id. 3619 */ 3620 private String getNextCallId() { 3621 synchronized(mLock) { 3622 return TELECOM_CALL_ID_PREFIX + (++mCallId); 3623 } 3624 } 3625 3626 public int getNextRttRequestId() { 3627 synchronized (mLock) { 3628 return (++mRttRequestId); 3629 } 3630 } 3631 3632 /** 3633 * Callback when foreground user is switched. We will reload missed call in all profiles 3634 * including the user itself. There may be chances that profiles are not started yet. 3635 */ 3636 @VisibleForTesting 3637 public void onUserSwitch(UserHandle userHandle) { 3638 mCurrentUserHandle = userHandle; 3639 mMissedCallNotifier.setCurrentUserHandle(userHandle); 3640 mRoleManagerAdapter.setCurrentUserHandle(userHandle); 3641 final UserManager userManager = UserManager.get(mContext); 3642 List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier()); 3643 for (UserInfo profile : profiles) { 3644 reloadMissedCallsOfUser(profile.getUserHandle()); 3645 } 3646 } 3647 3648 /** 3649 * Because there may be chances that profiles are not started yet though its parent user is 3650 * switched, we reload missed calls of profile that are just started here. 3651 */ 3652 void onUserStarting(UserHandle userHandle) { 3653 if (UserUtil.isProfile(mContext, userHandle)) { 3654 reloadMissedCallsOfUser(userHandle); 3655 } 3656 } 3657 3658 public TelecomSystem.SyncRoot getLock() { 3659 return mLock; 3660 } 3661 3662 public Timeouts.Adapter getTimeoutsAdapter() { 3663 return mTimeoutsAdapter; 3664 } 3665 3666 public SystemStateHelper getSystemStateHelper() { 3667 return mSystemStateHelper; 3668 } 3669 3670 private void reloadMissedCallsOfUser(UserHandle userHandle) { 3671 mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper, 3672 new MissedCallNotifier.CallInfoFactory(), userHandle); 3673 } 3674 3675 public void onBootCompleted() { 3676 mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper, 3677 new MissedCallNotifier.CallInfoFactory()); 3678 } 3679 3680 public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 3681 return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle); 3682 } 3683 3684 public boolean isIncomingCallPermitted(Call excludeCall, 3685 PhoneAccountHandle phoneAccountHandle) { 3686 if (phoneAccountHandle == null) { 3687 return false; 3688 } 3689 PhoneAccount phoneAccount = 3690 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 3691 if (phoneAccount == null) { 3692 return false; 3693 } 3694 3695 if (!phoneAccount.isSelfManaged()) { 3696 return !hasMaximumManagedRingingCalls(excludeCall) && 3697 !hasMaximumManagedHoldingCalls(excludeCall); 3698 } else { 3699 return !hasEmergencyCall() && 3700 !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) && 3701 !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle); 3702 } 3703 } 3704 3705 public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 3706 return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle); 3707 } 3708 3709 public boolean isOutgoingCallPermitted(Call excludeCall, 3710 PhoneAccountHandle phoneAccountHandle) { 3711 if (phoneAccountHandle == null) { 3712 return false; 3713 } 3714 PhoneAccount phoneAccount = 3715 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 3716 if (phoneAccount == null) { 3717 return false; 3718 } 3719 3720 if (!phoneAccount.isSelfManaged()) { 3721 return !hasMaximumManagedOutgoingCalls(excludeCall) && 3722 !hasMaximumManagedDialingCalls(excludeCall) && 3723 !hasMaximumManagedLiveCalls(excludeCall) && 3724 !hasMaximumManagedHoldingCalls(excludeCall); 3725 } else { 3726 // Only permit self-managed outgoing calls if 3727 // 1. there is no emergency ongoing call 3728 // 2. The outgoing call is an handover call or it not hit the self-managed call limit 3729 // and the current active call can be held. 3730 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3731 return !hasEmergencyCall() && 3732 ((excludeCall != null && excludeCall.getHandoverSourceCall() != null) || 3733 (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) && 3734 (activeCall == null || canHold(activeCall)))); 3735 } 3736 } 3737 3738 public boolean isReplyWithSmsAllowed(int uid) { 3739 UserHandle callingUser = UserHandle.of(UserHandle.getUserId(uid)); 3740 UserManager userManager = mContext.getSystemService(UserManager.class); 3741 KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class); 3742 3743 boolean isUserRestricted = userManager != null 3744 && userManager.hasUserRestriction(UserManager.DISALLOW_SMS, callingUser); 3745 boolean isLockscreenRestricted = keyguardManager != null 3746 && keyguardManager.isDeviceLocked(); 3747 Log.d(this, "isReplyWithSmsAllowed: isUserRestricted: %s, isLockscreenRestricted: %s", 3748 isUserRestricted, isLockscreenRestricted); 3749 3750 // TODO(hallliu): actually check the lockscreen once b/77731473 is fixed 3751 return !isUserRestricted; 3752 } 3753 /** 3754 * Blocks execution until all Telecom handlers have completed their current work. 3755 */ 3756 public void waitOnHandlers() { 3757 CountDownLatch mainHandlerLatch = new CountDownLatch(3); 3758 mHandler.post(() -> { 3759 mainHandlerLatch.countDown(); 3760 }); 3761 mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> { 3762 mainHandlerLatch.countDown(); 3763 }); 3764 mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> { 3765 mainHandlerLatch.countDown(); 3766 }); 3767 3768 try { 3769 mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS); 3770 } catch (InterruptedException e) { 3771 Log.w(this, "waitOnHandlers: interrupted %s", e); 3772 } 3773 } 3774 3775 /** 3776 * Used to confirm creation of an outgoing call which was marked as pending confirmation in 3777 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)}. 3778 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 3779 * {@link ConfirmCallDialogActivity}. 3780 * @param callId The call ID of the call to confirm. 3781 */ 3782 public void confirmPendingCall(String callId) { 3783 Log.i(this, "confirmPendingCall: callId=%s", callId); 3784 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 3785 Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED); 3786 3787 // We are going to place the new outgoing call, so disconnect any ongoing self-managed 3788 // calls which are ongoing at this time. 3789 disconnectSelfManagedCalls("outgoing call " + callId); 3790 3791 mPendingCallConfirm.complete(mPendingCall); 3792 mPendingCallConfirm = null; 3793 mPendingCall = null; 3794 } 3795 } 3796 3797 /** 3798 * Used to cancel an outgoing call which was marked as pending confirmation in 3799 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)}. 3800 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 3801 * {@link ConfirmCallDialogActivity}. 3802 * @param callId The call ID of the call to cancel. 3803 */ 3804 public void cancelPendingCall(String callId) { 3805 Log.i(this, "cancelPendingCall: callId=%s", callId); 3806 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 3807 Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED); 3808 markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED)); 3809 markCallAsRemoved(mPendingCall); 3810 mPendingCall = null; 3811 mPendingCallConfirm.complete(null); 3812 mPendingCallConfirm = null; 3813 } 3814 } 3815 3816 /** 3817 * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)} when 3818 * a managed call is added while there are ongoing self-managed calls. Starts 3819 * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the 3820 * outgoing call or not. 3821 * @param call The call to confirm. 3822 */ 3823 private void startCallConfirmation(Call call, CompletableFuture<Call> confirmationFuture) { 3824 if (mPendingCall != null) { 3825 Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s", 3826 mPendingCall.getId(), call.getId()); 3827 markCallDisconnectedDueToSelfManagedCall(call); 3828 confirmationFuture.complete(null); 3829 return; 3830 } 3831 Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION); 3832 mPendingCall = call; 3833 mPendingCallConfirm = confirmationFuture; 3834 3835 // Figure out the name of the app in charge of the self-managed call(s). 3836 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3837 if (activeCall != null) { 3838 CharSequence ongoingAppName = activeCall.getTargetPhoneAccountLabel(); 3839 Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(), 3840 ongoingAppName); 3841 3842 Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class); 3843 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId()); 3844 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName); 3845 confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3846 mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT); 3847 } 3848 } 3849 3850 /** 3851 * Disconnects all self-managed calls. 3852 */ 3853 private void disconnectSelfManagedCalls(String reason) { 3854 // Disconnect all self-managed calls to make priority for emergency call. 3855 // Use Call.disconnect() to command the ConnectionService to disconnect the calls. 3856 // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to 3857 // disconnect. 3858 mCalls.stream() 3859 .filter(c -> c.isSelfManaged()) 3860 .forEach(c -> c.disconnect(reason)); 3861 3862 // When disconnecting all self-managed calls, switch audio routing back to the baseline 3863 // route. This ensures if, for example, the self-managed ConnectionService was routed to 3864 // speakerphone that we'll switch back to earpiece for the managed call which necessitated 3865 // disconnecting the self-managed calls. 3866 mCallAudioManager.switchBaseline(); 3867 } 3868 3869 /** 3870 * Dumps the state of the {@link CallsManager}. 3871 * 3872 * @param pw The {@code IndentingPrintWriter} to write the state to. 3873 */ 3874 public void dump(IndentingPrintWriter pw) { 3875 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 3876 if (mCalls != null) { 3877 pw.println("mCalls: "); 3878 pw.increaseIndent(); 3879 for (Call call : mCalls) { 3880 pw.println(call); 3881 } 3882 pw.decreaseIndent(); 3883 } 3884 3885 if (mPendingCall != null) { 3886 pw.print("mPendingCall:"); 3887 pw.println(mPendingCall.getId()); 3888 } 3889 3890 if (mCallAudioManager != null) { 3891 pw.println("mCallAudioManager:"); 3892 pw.increaseIndent(); 3893 mCallAudioManager.dump(pw); 3894 pw.decreaseIndent(); 3895 } 3896 3897 if (mTtyManager != null) { 3898 pw.println("mTtyManager:"); 3899 pw.increaseIndent(); 3900 mTtyManager.dump(pw); 3901 pw.decreaseIndent(); 3902 } 3903 3904 if (mInCallController != null) { 3905 pw.println("mInCallController:"); 3906 pw.increaseIndent(); 3907 mInCallController.dump(pw); 3908 pw.decreaseIndent(); 3909 } 3910 3911 if (mDefaultDialerCache != null) { 3912 pw.println("mDefaultDialerCache:"); 3913 pw.increaseIndent(); 3914 mDefaultDialerCache.dumpCache(pw); 3915 pw.decreaseIndent(); 3916 } 3917 3918 if (mConnectionServiceRepository != null) { 3919 pw.println("mConnectionServiceRepository:"); 3920 pw.increaseIndent(); 3921 mConnectionServiceRepository.dump(pw); 3922 pw.decreaseIndent(); 3923 } 3924 3925 if (mRoleManagerAdapter != null && mRoleManagerAdapter instanceof RoleManagerAdapterImpl) { 3926 RoleManagerAdapterImpl impl = (RoleManagerAdapterImpl) mRoleManagerAdapter; 3927 pw.println("mRoleManager:"); 3928 pw.increaseIndent(); 3929 impl.dump(pw); 3930 pw.decreaseIndent(); 3931 } 3932 } 3933 3934 /** 3935 * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code. 3936 * 3937 * @param call The call. 3938 */ 3939 private void maybeShowErrorDialogOnDisconnect(Call call) { 3940 if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle()) 3941 || isPotentialInCallMMICode(call.getHandle())) && !mCalls.contains(call)) { 3942 DisconnectCause disconnectCause = call.getDisconnectCause(); 3943 if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode() 3944 == DisconnectCause.ERROR)) { 3945 Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 3946 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA, 3947 disconnectCause.getDescription()); 3948 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3949 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 3950 } 3951 } 3952 } 3953 3954 private void setIntentExtrasAndStartTime(Call call, Bundle extras) { 3955 if (extras != null) { 3956 // Create our own instance to modify (since extras may be Bundle.EMPTY) 3957 extras = new Bundle(extras); 3958 } else { 3959 extras = new Bundle(); 3960 } 3961 3962 // Specifies the time telecom began routing the call. This is used by the dialer for 3963 // analytics. 3964 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, 3965 SystemClock.elapsedRealtime()); 3966 3967 call.setIntentExtras(extras); 3968 } 3969 3970 private void setCallSourceToAnalytics(Call call, Intent originalIntent) { 3971 if (originalIntent == null) { 3972 return; 3973 } 3974 3975 int callSource = originalIntent.getIntExtra(TelecomManager.EXTRA_CALL_SOURCE, 3976 Analytics.CALL_SOURCE_UNSPECIFIED); 3977 3978 // Call source is only used by metrics, so we simply set it to Analytics directly. 3979 call.getAnalytics().setCallSource(callSource); 3980 } 3981 3982 private boolean isVoicemail(Uri callHandle, PhoneAccount phoneAccount) { 3983 if (callHandle == null) { 3984 return false; 3985 } 3986 if (PhoneAccount.SCHEME_VOICEMAIL.equals(callHandle.getScheme())) { 3987 return true; 3988 } 3989 return phoneAccount != null && mPhoneAccountRegistrar.isVoiceMailNumber( 3990 phoneAccount.getAccountHandle(), 3991 callHandle.getSchemeSpecificPart()); 3992 } 3993 3994 /** 3995 * Notifies the {@link android.telecom.ConnectionService} associated with a 3996 * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. 3997 * 3998 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 3999 * @param call The {@link Call} which could not be added. 4000 */ 4001 private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) { 4002 if (phoneAccountHandle == null) { 4003 return; 4004 } 4005 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 4006 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); 4007 if (service == null) { 4008 Log.i(this, "Found no connection service."); 4009 return; 4010 } else { 4011 call.setConnectionService(service); 4012 service.createConnectionFailed(call); 4013 } 4014 } 4015 4016 /** 4017 * Notifies the {@link android.telecom.ConnectionService} associated with a 4018 * {@link PhoneAccountHandle} that the attempt to handover a call has failed. 4019 * 4020 * @param call The handover call 4021 * @param reason The error reason code for handover failure 4022 */ 4023 private void notifyHandoverFailed(Call call, int reason) { 4024 ConnectionServiceWrapper service = call.getConnectionService(); 4025 service.handoverFailed(call, reason); 4026 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 4027 call.disconnect("handover failed"); 4028 } 4029 4030 /** 4031 * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)} 4032 * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the 4033 * {@link android.telecom.InCallService} has requested a handover to another 4034 * {@link android.telecom.ConnectionService}. 4035 * 4036 * We will explicitly disallow a handover when there is an emergency call present. 4037 * 4038 * @param handoverFromCall The {@link Call} to be handed over. 4039 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 4040 * @param videoState The desired video state of {@link Call} after handover. 4041 * @param initiatingExtras Extras associated with the handover, to be passed to the handover 4042 * {@link android.telecom.ConnectionService}. 4043 */ 4044 private void requestHandoverViaEvents(Call handoverFromCall, 4045 PhoneAccountHandle handoverToHandle, 4046 int videoState, Bundle initiatingExtras) { 4047 4048 handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 4049 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, "legacy request denied"); 4050 } 4051 4052 public Call createHandoverCall(Uri handle, PhoneAccountHandle handoverToHandle, 4053 Bundle extras, UserHandle initiatingUser) { 4054 boolean isReusedCall = true; 4055 Call call = reuseOutgoingCall(handle); 4056 4057 PhoneAccount account = 4058 mPhoneAccountRegistrar.getPhoneAccount(handoverToHandle, initiatingUser); 4059 boolean isSelfManaged = account != null && account.isSelfManaged(); 4060 4061 // Create a call with original handle. The handle may be changed when the call is attached 4062 // to a connection service, but in most cases will remain the same. 4063 if (call == null) { 4064 call = new Call(getNextCallId(), mContext, 4065 this, 4066 mLock, 4067 mConnectionServiceRepository, 4068 mPhoneNumberUtilsAdapter, 4069 handle, 4070 null /* gatewayInfo */, 4071 null /* connectionManagerPhoneAccount */, 4072 null /* handoverToHandle */, 4073 Call.CALL_DIRECTION_OUTGOING /* callDirection */, 4074 false /* forceAttachToExistingConnection */, 4075 false, /* isConference */ 4076 mClockProxy); 4077 call.initAnalytics(null); 4078 4079 // Ensure new calls related to self-managed calls/connections are set as such. This 4080 // will be overridden when the actual connection is returned in startCreateConnection, 4081 // however doing this now ensures the logs and any other logic will treat this call as 4082 // self-managed from the moment it is created. 4083 call.setIsSelfManaged(isSelfManaged); 4084 if (isSelfManaged) { 4085 // Self-managed calls will ALWAYS use voip audio mode. 4086 call.setIsVoipAudioMode(true); 4087 } 4088 call.setInitiatingUser(initiatingUser); 4089 isReusedCall = false; 4090 } 4091 4092 int videoState = VideoProfile.STATE_AUDIO_ONLY; 4093 if (extras != null) { 4094 // Set the video state on the call early so that when it is added to the InCall UI the 4095 // UI knows to configure itself as a video call immediately. 4096 videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 4097 VideoProfile.STATE_AUDIO_ONLY); 4098 4099 // If this is an emergency video call, we need to check if the phone account supports 4100 // emergency video calling. 4101 // Also, ensure we don't try to place an outgoing call with video if video is not 4102 // supported. 4103 if (VideoProfile.isVideo(videoState)) { 4104 if (call.isEmergencyCall() && account != null && 4105 !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) { 4106 // Phone account doesn't support emergency video calling, so fallback to 4107 // audio-only now to prevent the InCall UI from setting up video surfaces 4108 // needlessly. 4109 Log.i(this, "startOutgoingCall - emergency video calls not supported; " + 4110 "falling back to audio-only"); 4111 videoState = VideoProfile.STATE_AUDIO_ONLY; 4112 } else if (account != null && 4113 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 4114 // Phone account doesn't support video calling, so fallback to audio-only. 4115 Log.i(this, "startOutgoingCall - video calls not supported; fallback to " + 4116 "audio-only."); 4117 videoState = VideoProfile.STATE_AUDIO_ONLY; 4118 } 4119 } 4120 4121 call.setVideoState(videoState); 4122 } 4123 4124 call.setTargetPhoneAccount(handoverToHandle); 4125 4126 // If there's no more room for a handover, just fail. 4127 if ((!isReusedCall && !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) { 4128 return null; 4129 } 4130 4131 PhoneAccount accountToUse = 4132 mPhoneAccountRegistrar.getPhoneAccount(handoverToHandle, initiatingUser); 4133 if (accountToUse != null && accountToUse.getExtras() != null) { 4134 if (accountToUse.getExtras() 4135 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 4136 Log.d(this, "startOutgoingCall: defaulting to voip mode for call %s", 4137 call.getId()); 4138 call.setIsVoipAudioMode(true); 4139 } 4140 } 4141 4142 call.setState( 4143 CallState.CONNECTING, 4144 handoverToHandle == null ? "no-handle" : handoverToHandle.toString()); 4145 4146 setIntentExtrasAndStartTime(call, extras); 4147 4148 if (!mCalls.contains(call)) { 4149 // We check if mCalls already contains the call because we could potentially be reusing 4150 // a call which was previously added (See {@link #reuseOutgoingCall}). 4151 addCall(call); 4152 } 4153 4154 return call; 4155 } 4156 /** 4157 * Called in response to a {@link Call} receiving a {@link Call#handoverTo(PhoneAccountHandle, 4158 * int, Bundle)} indicating the {@link android.telecom.InCallService} has requested a 4159 * handover to another {@link android.telecom.ConnectionService}. 4160 * 4161 * We will explicitly disallow a handover when there is an emergency call present. 4162 * 4163 * @param handoverFromCall The {@link Call} to be handed over. 4164 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 4165 * @param videoState The desired video state of {@link Call} after handover. 4166 * @param extras Extras associated with the handover, to be passed to the handover 4167 * {@link android.telecom.ConnectionService}. 4168 */ 4169 private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle, 4170 int videoState, Bundle extras) { 4171 4172 // Send an error back if there are any ongoing emergency calls. 4173 if (hasEmergencyCall()) { 4174 handoverFromCall.onHandoverFailed( 4175 android.telecom.Call.Callback.HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL); 4176 return; 4177 } 4178 4179 // If source and destination phone accounts don't support handover, send an error back. 4180 boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported( 4181 handoverFromCall.getTargetPhoneAccount()); 4182 boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle); 4183 if (!isHandoverFromSupported || !isHandoverToSupported) { 4184 handoverFromCall.onHandoverFailed( 4185 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 4186 return; 4187 } 4188 4189 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle); 4190 4191 // Create a new instance of Call 4192 PhoneAccount account = 4193 mPhoneAccountRegistrar.getPhoneAccount(handoverToHandle, getCurrentUserHandle()); 4194 boolean isSelfManaged = account != null && account.isSelfManaged(); 4195 4196 Call call = new Call(getNextCallId(), mContext, 4197 this, mLock, mConnectionServiceRepository, 4198 mPhoneNumberUtilsAdapter, 4199 handoverFromCall.getHandle(), null, 4200 null, null, 4201 Call.CALL_DIRECTION_OUTGOING, false, 4202 false, mClockProxy); 4203 call.initAnalytics(); 4204 4205 // Set self-managed and voipAudioMode if destination is self-managed CS 4206 call.setIsSelfManaged(isSelfManaged); 4207 if (isSelfManaged) { 4208 call.setIsVoipAudioMode(true); 4209 } 4210 call.setInitiatingUser(getCurrentUserHandle()); 4211 4212 // Ensure we don't try to place an outgoing call with video if video is not 4213 // supported. 4214 if (VideoProfile.isVideo(videoState) && account != null && 4215 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 4216 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 4217 } else { 4218 call.setVideoState(videoState); 4219 } 4220 4221 // Set target phone account to destAcct. 4222 call.setTargetPhoneAccount(handoverToHandle); 4223 4224 if (account != null && account.getExtras() != null && account.getExtras() 4225 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 4226 Log.d(this, "requestHandover: defaulting to voip mode for call %s", 4227 call.getId()); 4228 call.setIsVoipAudioMode(true); 4229 } 4230 4231 // Set call state to connecting 4232 call.setState( 4233 CallState.CONNECTING, 4234 handoverToHandle == null ? "no-handle" : handoverToHandle.toString()); 4235 4236 // Mark as handover so that the ConnectionService knows this is a handover request. 4237 if (extras == null) { 4238 extras = new Bundle(); 4239 } 4240 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 4241 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 4242 handoverFromCall.getTargetPhoneAccount()); 4243 setIntentExtrasAndStartTime(call, extras); 4244 4245 // Add call to call tracker 4246 if (!mCalls.contains(call)) { 4247 addCall(call); 4248 } 4249 4250 Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER, 4251 "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), call.getId()); 4252 4253 handoverFromCall.setHandoverDestinationCall(call); 4254 handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 4255 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 4256 call.setHandoverSourceCall(handoverFromCall); 4257 call.setNewOutgoingCallIntentBroadcastIsDone(); 4258 4259 // Auto-enable speakerphone if the originating intent specified to do so, if the call 4260 // is a video call, of if using speaker when docked 4261 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 4262 R.bool.use_speaker_when_docked); 4263 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 4264 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 4265 call.setStartWithSpeakerphoneOn(false || useSpeakerForVideoCall 4266 || (useSpeakerWhenDocked && useSpeakerForDock)); 4267 call.setVideoState(videoState); 4268 4269 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 4270 call.getTargetPhoneAccount()); 4271 4272 // If the account has been set, proceed to place the outgoing call. 4273 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 4274 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 4275 } else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) { 4276 markCallDisconnectedDueToSelfManagedCall(call); 4277 } else { 4278 if (call.isEmergencyCall()) { 4279 // Disconnect all self-managed calls to make priority for emergency call. 4280 disconnectSelfManagedCalls("emergency call"); 4281 } 4282 4283 call.startCreateConnection(mPhoneAccountRegistrar); 4284 } 4285 4286 } 4287 4288 /** 4289 * Determines if handover from the specified {@link PhoneAccountHandle} is supported. 4290 * 4291 * @param from The {@link PhoneAccountHandle} the handover originates from. 4292 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 4293 */ 4294 private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) { 4295 return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM); 4296 } 4297 4298 /** 4299 * Determines if handover to the specified {@link PhoneAccountHandle} is supported. 4300 * 4301 * @param to The {@link PhoneAccountHandle} the handover it to. 4302 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 4303 */ 4304 private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) { 4305 return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO); 4306 } 4307 4308 /** 4309 * Retrieves a boolean phone account extra. 4310 * @param handle the {@link PhoneAccountHandle} to retrieve the extra for. 4311 * @param key The extras key. 4312 * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false} 4313 * otherwise. 4314 */ 4315 private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) { 4316 PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle); 4317 if (phoneAccount == null) { 4318 return false; 4319 } 4320 4321 Bundle fromExtras = phoneAccount.getExtras(); 4322 if (fromExtras == null) { 4323 return false; 4324 } 4325 return fromExtras.getBoolean(key); 4326 } 4327 4328 /** 4329 * Determines if there is an existing handover in process. 4330 * @return {@code true} if a call in the process of handover exists, {@code false} otherwise. 4331 */ 4332 private boolean isHandoverInProgress() { 4333 return mCalls.stream().filter(c -> c.getHandoverSourceCall() != null || 4334 c.getHandoverDestinationCall() != null).count() > 0; 4335 } 4336 4337 private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) { 4338 Intent intent = 4339 new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED); 4340 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 4341 intent.putExtra( 4342 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 4343 Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle); 4344 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 4345 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 4346 4347 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 4348 getCurrentUserHandle().getIdentifier()); 4349 if (!TextUtils.isEmpty(dialerPackage)) { 4350 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED) 4351 .setPackage(dialerPackage); 4352 directedIntent.putExtra( 4353 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 4354 Log.i(this, "Sending phone-account unregistered intent to default dialer"); 4355 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 4356 } 4357 return ; 4358 } 4359 4360 private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) { 4361 Intent intent = new Intent( 4362 TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED); 4363 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 4364 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 4365 accountHandle); 4366 Log.i(this, "Sending phone-account %s registered intent as user", accountHandle); 4367 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 4368 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 4369 4370 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 4371 getCurrentUserHandle().getIdentifier()); 4372 if (!TextUtils.isEmpty(dialerPackage)) { 4373 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED) 4374 .setPackage(dialerPackage); 4375 directedIntent.putExtra( 4376 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 4377 Log.i(this, "Sending phone-account registered intent to default dialer"); 4378 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 4379 } 4380 return ; 4381 } 4382 4383 public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) { 4384 final String handleScheme = srcAddr.getSchemeSpecificPart(); 4385 Call fromCall = mCalls.stream() 4386 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 4387 (c.getHandle() == null ? null : c.getHandle().getSchemeSpecificPart()), 4388 handleScheme)) 4389 .findFirst() 4390 .orElse(null); 4391 4392 Call call = new Call( 4393 getNextCallId(), 4394 mContext, 4395 this, 4396 mLock, 4397 mConnectionServiceRepository, 4398 mPhoneNumberUtilsAdapter, 4399 srcAddr, 4400 null /* gatewayInfo */, 4401 null /* connectionManagerPhoneAccount */, 4402 destAcct, 4403 Call.CALL_DIRECTION_INCOMING /* callDirection */, 4404 false /* forceAttachToExistingConnection */, 4405 false, /* isConference */ 4406 mClockProxy); 4407 4408 if (fromCall == null || isHandoverInProgress() || 4409 !isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount()) || 4410 !isHandoverToPhoneAccountSupported(destAcct) || 4411 hasEmergencyCall()) { 4412 Log.w(this, "acceptHandover: Handover not supported"); 4413 notifyHandoverFailed(call, 4414 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 4415 return; 4416 } 4417 4418 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(destAcct); 4419 if (phoneAccount == null) { 4420 Log.w(this, "acceptHandover: Handover not supported. phoneAccount = null"); 4421 notifyHandoverFailed(call, 4422 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 4423 return; 4424 } 4425 call.setIsSelfManaged(phoneAccount.isSelfManaged()); 4426 if (call.isSelfManaged() || (phoneAccount.getExtras() != null && 4427 phoneAccount.getExtras().getBoolean( 4428 PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE))) { 4429 call.setIsVoipAudioMode(true); 4430 } 4431 if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 4432 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 4433 } else { 4434 call.setVideoState(videoState); 4435 } 4436 4437 call.initAnalytics(); 4438 call.addListener(this); 4439 4440 fromCall.setHandoverDestinationCall(call); 4441 call.setHandoverSourceCall(fromCall); 4442 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 4443 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 4444 4445 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 4446 // Ensure when the call goes active that it will go to speakerphone if the 4447 // handover to call is a video call. 4448 call.setStartWithSpeakerphoneOn(true); 4449 } 4450 4451 Bundle extras = call.getIntentExtras(); 4452 if (extras == null) { 4453 extras = new Bundle(); 4454 } 4455 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 4456 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 4457 fromCall.getTargetPhoneAccount()); 4458 4459 call.startCreateConnection(mPhoneAccountRegistrar); 4460 } 4461 4462 public ConnectionServiceFocusManager getConnectionServiceFocusManager() { 4463 return mConnectionSvrFocusMgr; 4464 } 4465 4466 private boolean canHold(Call call) { 4467 return call.can(Connection.CAPABILITY_HOLD) && call.getState() != CallState.DIALING; 4468 } 4469 4470 private boolean supportsHold(Call call) { 4471 return call.can(Connection.CAPABILITY_SUPPORT_HOLD); 4472 } 4473 4474 private final class ActionSetCallState implements PendingAction { 4475 4476 private final Call mCall; 4477 private final int mState; 4478 private final String mTag; 4479 4480 ActionSetCallState(Call call, int state, String tag) { 4481 mCall = call; 4482 mState = state; 4483 mTag = tag; 4484 } 4485 4486 @Override 4487 public void performAction() { 4488 Log.d(this, "perform set call state for %s, state = %s", mCall, mState); 4489 setCallState(mCall, mState, mTag); 4490 } 4491 } 4492 4493 private final class ActionUnHoldCall implements PendingAction { 4494 private final Call mCall; 4495 private final String mPreviouslyHeldCallId; 4496 4497 ActionUnHoldCall(Call call, String previouslyHeldCallId) { 4498 mCall = call; 4499 mPreviouslyHeldCallId = previouslyHeldCallId; 4500 } 4501 4502 @Override 4503 public void performAction() { 4504 Log.d(this, "perform unhold call for %s", mCall); 4505 mCall.unhold("held " + mPreviouslyHeldCallId); 4506 } 4507 } 4508 4509 private final class ActionAnswerCall implements PendingAction { 4510 private final Call mCall; 4511 private final int mVideoState; 4512 4513 ActionAnswerCall(Call call, int videoState) { 4514 mCall = call; 4515 mVideoState = videoState; 4516 } 4517 4518 @Override 4519 public void performAction() { 4520 Log.d(this, "perform answer call for %s, videoState = %d", mCall, mVideoState); 4521 for (CallsManagerListener listener : mListeners) { 4522 listener.onIncomingCallAnswered(mCall); 4523 } 4524 4525 // We do not update the UI until we get confirmation of the answer() through 4526 // {@link #markCallAsActive}. 4527 mCall.answer(mVideoState); 4528 if (mCall.getState() == CallState.RINGING) { 4529 setCallState(mCall, CallState.ANSWERED, "answered"); 4530 } 4531 if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) { 4532 mCall.setStartWithSpeakerphoneOn(true); 4533 } 4534 } 4535 } 4536 4537 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 4538 public static final class RequestCallback implements 4539 ConnectionServiceFocusManager.RequestFocusCallback { 4540 private PendingAction mPendingAction; 4541 4542 RequestCallback(PendingAction pendingAction) { 4543 mPendingAction = pendingAction; 4544 } 4545 4546 @Override 4547 public void onRequestFocusDone(ConnectionServiceFocusManager.CallFocus call) { 4548 if (mPendingAction != null) { 4549 mPendingAction.performAction(); 4550 } 4551 } 4552 } 4553 4554 public void resetConnectionTime(Call call) { 4555 call.setConnectTimeMillis(System.currentTimeMillis()); 4556 call.setConnectElapsedTimeMillis(SystemClock.elapsedRealtime()); 4557 if (mCalls.contains(call)) { 4558 for (CallsManagerListener listener : mListeners) { 4559 listener.onConnectionTimeChanged(call); 4560 } 4561 } 4562 } 4563 4564 /** 4565 * Determines if there is an ongoing emergency call. This can be either an outgoing emergency 4566 * call, or a number which has been identified by the number as an emergency call. 4567 * @return {@code true} if there is an ongoing emergency call, {@code false} otherwise. 4568 */ 4569 public boolean isInEmergencyCall() { 4570 return mCalls.stream().filter(c -> c.isEmergencyCall() 4571 || c.isNetworkIdentifiedEmergencyCall()).count() > 0; 4572 } 4573 4574 /** 4575 * Trigger display of an error message to the user; we do this outside of dialer for calls which 4576 * fail to be created and added to Dialer. 4577 * @param messageId The string resource id. 4578 */ 4579 private void showErrorMessage(int messageId) { 4580 final Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 4581 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, messageId); 4582 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 4583 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 4584 } 4585 4586 /** 4587 * Handles changes to a {@link PhoneAccount}. 4588 * 4589 * Checks for changes to video calling availability and updates whether calls for that phone 4590 * account are video capable. 4591 * 4592 * @param registrar The {@link PhoneAccountRegistrar} originating the change. 4593 * @param phoneAccount The {@link PhoneAccount} which changed. 4594 */ 4595 private void handlePhoneAccountChanged(PhoneAccountRegistrar registrar, 4596 PhoneAccount phoneAccount) { 4597 Log.i(this, "handlePhoneAccountChanged: phoneAccount=%s", phoneAccount); 4598 boolean isVideoNowSupported = phoneAccount.hasCapabilities( 4599 PhoneAccount.CAPABILITY_VIDEO_CALLING); 4600 mCalls.stream() 4601 .filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount())) 4602 .forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported)); 4603 } 4604 } 4605