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 static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL; 20 import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING; 21 import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING; 22 import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED; 23 import static android.provider.CallLog.Calls.SHORT_RING_THRESHOLD; 24 import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT; 25 import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED; 26 import static android.provider.CallLog.Calls.USER_MISSED_NEVER_RANG; 27 import static android.provider.CallLog.Calls.USER_MISSED_NOT_RUNNING; 28 import static android.provider.CallLog.Calls.USER_MISSED_NO_ANSWER; 29 import static android.provider.CallLog.Calls.USER_MISSED_SHORT_RING; 30 import static android.telecom.TelecomManager.ACTION_POST_CALL; 31 import static android.telecom.TelecomManager.DURATION_LONG; 32 import static android.telecom.TelecomManager.DURATION_MEDIUM; 33 import static android.telecom.TelecomManager.DURATION_SHORT; 34 import static android.telecom.TelecomManager.DURATION_VERY_SHORT; 35 import static android.telecom.TelecomManager.EXTRA_CALL_DURATION; 36 import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE; 37 import static android.telecom.TelecomManager.EXTRA_HANDLE; 38 import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS; 39 import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS; 40 import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS; 41 42 import android.Manifest; 43 import android.annotation.NonNull; 44 import android.annotation.Nullable; 45 import android.app.ActivityManager; 46 import android.app.AlertDialog; 47 import android.app.KeyguardManager; 48 import android.app.NotificationManager; 49 import android.content.ActivityNotFoundException; 50 import android.content.BroadcastReceiver; 51 import android.content.ComponentName; 52 import android.content.Context; 53 import android.content.DialogInterface; 54 import android.content.Intent; 55 import android.content.IntentFilter; 56 import android.content.pm.PackageManager; 57 import android.content.pm.PackageManager.ResolveInfoFlags; 58 import android.content.pm.ResolveInfo; 59 import android.content.pm.UserInfo; 60 import android.graphics.Color; 61 import android.graphics.drawable.ColorDrawable; 62 import android.media.AudioManager; 63 import android.media.AudioSystem; 64 import android.media.MediaPlayer; 65 import android.media.ToneGenerator; 66 import android.net.Uri; 67 import android.os.Bundle; 68 import android.os.Handler; 69 import android.os.HandlerThread; 70 import android.os.Looper; 71 import android.os.OutcomeReceiver; 72 import android.os.PersistableBundle; 73 import android.os.Process; 74 import android.os.ResultReceiver; 75 import android.os.SystemClock; 76 import android.os.SystemVibrator; 77 import android.os.Trace; 78 import android.os.UserHandle; 79 import android.os.UserManager; 80 import android.provider.BlockedNumberContract; 81 import android.provider.BlockedNumberContract.SystemContract; 82 import android.provider.CallLog.Calls; 83 import android.provider.Settings; 84 import android.sysprop.TelephonyProperties; 85 import android.telecom.CallAttributes; 86 import android.telecom.CallAudioState; 87 import android.telecom.CallEndpoint; 88 import android.telecom.CallException; 89 import android.telecom.CallScreeningService; 90 import android.telecom.CallerInfo; 91 import android.telecom.Conference; 92 import android.telecom.Connection; 93 import android.telecom.DisconnectCause; 94 import android.telecom.GatewayInfo; 95 import android.telecom.Log; 96 import android.telecom.Logging.Runnable; 97 import android.telecom.Logging.Session; 98 import android.telecom.ParcelableConference; 99 import android.telecom.ParcelableConnection; 100 import android.telecom.PhoneAccount; 101 import android.telecom.PhoneAccountHandle; 102 import android.telecom.PhoneAccountSuggestion; 103 import android.telecom.TelecomManager; 104 import android.telecom.VideoProfile; 105 import android.telephony.CarrierConfigManager; 106 import android.telephony.CellIdentity; 107 import android.telephony.PhoneNumberUtils; 108 import android.telephony.SubscriptionManager; 109 import android.telephony.TelephonyManager; 110 import android.text.TextUtils; 111 import android.util.Pair; 112 import android.view.LayoutInflater; 113 import android.view.View; 114 import android.view.WindowManager; 115 import android.widget.Button; 116 117 import com.android.internal.annotations.VisibleForTesting; 118 import com.android.internal.app.IntentForwarderActivity; 119 import com.android.internal.util.IndentingPrintWriter; 120 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 121 import com.android.server.telecom.bluetooth.BluetoothStateReceiver; 122 import com.android.server.telecom.callfiltering.BlockCheckerAdapter; 123 import com.android.server.telecom.callfiltering.BlockCheckerFilter; 124 import com.android.server.telecom.callfiltering.BlockedNumbersAdapter; 125 import com.android.server.telecom.callfiltering.CallFilterResultCallback; 126 import com.android.server.telecom.callfiltering.CallFilteringResult; 127 import com.android.server.telecom.callfiltering.CallFilteringResult.Builder; 128 import com.android.server.telecom.callfiltering.CallScreeningServiceFilter; 129 import com.android.server.telecom.callfiltering.DirectToVoicemailFilter; 130 import com.android.server.telecom.callfiltering.DndCallFilter; 131 import com.android.server.telecom.callfiltering.IncomingCallFilterGraph; 132 import com.android.server.telecom.callredirection.CallRedirectionProcessor; 133 import com.android.server.telecom.components.ErrorDialogActivity; 134 import com.android.server.telecom.components.TelecomBroadcastReceiver; 135 import com.android.server.telecom.components.UserCallIntentProcessor; 136 import com.android.server.telecom.stats.CallFailureCause; 137 import com.android.server.telecom.ui.AudioProcessingNotification; 138 import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity; 139 import com.android.server.telecom.ui.CallStreamingNotification; 140 import com.android.server.telecom.ui.ConfirmCallDialogActivity; 141 import com.android.server.telecom.ui.DisconnectedCallNotifier; 142 import com.android.server.telecom.ui.IncomingCallNotifier; 143 import com.android.server.telecom.ui.ToastFactory; 144 import com.android.server.telecom.voip.TransactionManager; 145 import com.android.server.telecom.voip.VoipCallMonitor; 146 147 import java.util.ArrayList; 148 import java.util.Arrays; 149 import java.util.Collection; 150 import java.util.Collections; 151 import java.util.HashMap; 152 import java.util.HashSet; 153 import java.util.Iterator; 154 import java.util.LinkedList; 155 import java.util.List; 156 import java.util.Map; 157 import java.util.Objects; 158 import java.util.Optional; 159 import java.util.Set; 160 import java.util.UUID; 161 import java.util.concurrent.CompletableFuture; 162 import java.util.concurrent.ConcurrentHashMap; 163 import java.util.concurrent.CopyOnWriteArrayList; 164 import java.util.concurrent.CountDownLatch; 165 import java.util.concurrent.Executor; 166 import java.util.concurrent.Executors; 167 import java.util.concurrent.TimeUnit; 168 import java.util.stream.Collectors; 169 import java.util.stream.IntStream; 170 import java.util.stream.Stream; 171 172 /** 173 * Singleton. 174 * 175 * NOTE: by design most APIs are package private, use the relevant adapter/s to allow 176 * access from other packages specifically refraining from passing the CallsManager instance 177 * beyond the com.android.server.telecom package boundary. 178 */ 179 public class CallsManager extends Call.ListenerBase 180 implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy { 181 182 // TODO: Consider renaming this CallsManagerPlugin. 183 @VisibleForTesting 184 public interface CallsManagerListener { 185 /** 186 * Informs listeners when a {@link Call} is newly created, but not yet returned by a 187 * {@link android.telecom.ConnectionService} implementation. 188 * @param call the call. 189 */ onStartCreateConnection(Call call)190 default void onStartCreateConnection(Call call) {} onCallAdded(Call call)191 void onCallAdded(Call call); onCreateConnectionFailed(Call call)192 void onCreateConnectionFailed(Call call); onCallRemoved(Call call)193 void onCallRemoved(Call call); onCallStateChanged(Call call, int oldState, int newState)194 void onCallStateChanged(Call call, int oldState, int newState); onConnectionServiceChanged( Call call, ConnectionServiceWrapper oldService, ConnectionServiceWrapper newService)195 void onConnectionServiceChanged( 196 Call call, 197 ConnectionServiceWrapper oldService, 198 ConnectionServiceWrapper newService); onIncomingCallAnswered(Call call)199 void onIncomingCallAnswered(Call call); onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage)200 void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage); onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState)201 void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState); onCallEndpointChanged(CallEndpoint callEndpoint)202 void onCallEndpointChanged(CallEndpoint callEndpoint); onAvailableCallEndpointsChanged(Set<CallEndpoint> availableCallEndpoints)203 void onAvailableCallEndpointsChanged(Set<CallEndpoint> availableCallEndpoints); onMuteStateChanged(boolean isMuted)204 void onMuteStateChanged(boolean isMuted); onRingbackRequested(Call call, boolean ringback)205 void onRingbackRequested(Call call, boolean ringback); onIsConferencedChanged(Call call)206 void onIsConferencedChanged(Call call); onIsVoipAudioModeChanged(Call call)207 void onIsVoipAudioModeChanged(Call call); onVideoStateChanged(Call call, int previousVideoState, int newVideoState)208 void onVideoStateChanged(Call call, int previousVideoState, int newVideoState); onCanAddCallChanged(boolean canAddCall)209 void onCanAddCallChanged(boolean canAddCall); onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)210 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); onHoldToneRequested(Call call)211 void onHoldToneRequested(Call call); onExternalCallChanged(Call call, boolean isExternalCall)212 void onExternalCallChanged(Call call, boolean isExternalCall); onCallStreamingStateChanged(Call call, boolean isStreaming)213 void onCallStreamingStateChanged(Call call, boolean isStreaming); onDisconnectedTonePlaying(boolean isTonePlaying)214 void onDisconnectedTonePlaying(boolean isTonePlaying); onConnectionTimeChanged(Call call)215 void onConnectionTimeChanged(Call call); onConferenceStateChanged(Call call, boolean isConference)216 void onConferenceStateChanged(Call call, boolean isConference); onCdmaConferenceSwap(Call call)217 void onCdmaConferenceSwap(Call call); onSetCamera(Call call, String cameraId)218 void onSetCamera(Call call, String cameraId); 219 } 220 221 /** Interface used to define the action which is executed delay under some condition. */ 222 interface PendingAction { performAction()223 void performAction(); 224 } 225 226 private static final String TAG = "CallsManager"; 227 228 /** 229 * Call filter specifier used with 230 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 231 * self-managed calls should be included. 232 */ 233 private static final int CALL_FILTER_SELF_MANAGED = 1; 234 235 /** 236 * Call filter specifier used with 237 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only 238 * managed calls should be included. 239 */ 240 private static final int CALL_FILTER_MANAGED = 2; 241 242 /** 243 * Call filter specifier used with 244 * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed 245 * and self-managed calls should be included. 246 */ 247 private static final int CALL_FILTER_ALL = 3; 248 249 private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION = 250 "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"; 251 252 private static final int HANDLER_WAIT_TIMEOUT = 10000; 253 private static final int MAXIMUM_LIVE_CALLS = 1; 254 private static final int MAXIMUM_HOLD_CALLS = 1; 255 private static final int MAXIMUM_RINGING_CALLS = 1; 256 private static final int MAXIMUM_DIALING_CALLS = 1; 257 private static final int MAXIMUM_OUTGOING_CALLS = 1; 258 private static final int MAXIMUM_TOP_LEVEL_CALLS = 2; 259 private static final int MAXIMUM_SELF_MANAGED_CALLS = 10; 260 261 /** 262 * Anomaly Report UUIDs and corresponding error descriptions specific to CallsManager. 263 */ 264 public static final UUID LIVE_CALL_STUCK_CONNECTING_ERROR_UUID = 265 UUID.fromString("3f95808c-9134-11ed-a1eb-0242ac120002"); 266 public static final String LIVE_CALL_STUCK_CONNECTING_ERROR_MSG = 267 "Force disconnected a live call that was stuck in CONNECTING state."; 268 public static final UUID LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_UUID = 269 UUID.fromString("744fdf86-9137-11ed-a1eb-0242ac120002"); 270 public static final String LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_MSG = 271 "Found a live call that was stuck in CONNECTING state while attempting to place an " 272 + "emergency call."; 273 public static final UUID CALL_REMOVAL_EXECUTION_ERROR_UUID = 274 UUID.fromString("030b8b16-9139-11ed-a1eb-0242ac120002"); 275 public static final String CALL_REMOVAL_EXECUTION_ERROR_MSG = 276 "Exception thrown while executing call removal"; 277 public static final UUID EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_UUID = 278 UUID.fromString("1c4eed7c-9132-11ed-a1eb-0242ac120002"); 279 public static final String EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_MSG = 280 "Exception thrown while establishing connection."; 281 public static final UUID EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_ERROR_UUID = 282 UUID.fromString("b68c881d-0ed8-4f31-9342-8bf416c96d18"); 283 public static final String EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_ERROR_MSG = 284 "Exception thrown while retrieving list of potential phone accounts."; 285 public static final UUID EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_EMERGENCY_ERROR_UUID = 286 UUID.fromString("f272f89d-fb3a-4004-aa2d-20b8d679467e"); 287 public static final String EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_EMERGENCY_ERROR_MSG = 288 "Exception thrown while retrieving list of potential phone accounts when placing an " 289 + "emergency call."; 290 public static final UUID EMERGENCY_CALL_DISCONNECTED_BEFORE_BEING_ADDED_ERROR_UUID = 291 UUID.fromString("f9a916c8-8d61-4550-9ad3-11c2e84f6364"); 292 public static final String EMERGENCY_CALL_DISCONNECTED_BEFORE_BEING_ADDED_ERROR_MSG = 293 "An emergency call was disconnected after the connection was created but before the " 294 + "call was successfully added to CallsManager."; 295 public static final UUID EMERGENCY_CALL_ABORTED_NO_PHONE_ACCOUNTS_ERROR_UUID = 296 UUID.fromString("2e994acb-1997-4345-8bf3-bad04303de26"); 297 public static final String EMERGENCY_CALL_ABORTED_NO_PHONE_ACCOUNTS_ERROR_MSG = 298 "An emergency call was aborted since there were no available phone accounts."; 299 300 private static final int[] OUTGOING_CALL_STATES = 301 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 302 CallState.PULLING}; 303 304 /** 305 * These states are used by {@link #makeRoomForOutgoingCall(Call, boolean)} to determine which 306 * call should be ended first to make room for a new outgoing call. 307 */ 308 private static final int[] LIVE_CALL_STATES = 309 {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 310 CallState.PULLING, CallState.ACTIVE, CallState.AUDIO_PROCESSING}; 311 312 /** 313 * These states determine which calls will cause {@link TelecomManager#isInCall()} or 314 * {@link TelecomManager#isInManagedCall()} to return true. 315 * 316 * See also {@link PhoneStateBroadcaster}, which considers a similar set of states as being 317 * off-hook. 318 */ 319 public static final int[] ONGOING_CALL_STATES = 320 {CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.PULLING, CallState.ACTIVE, 321 CallState.ON_HOLD, CallState.RINGING, CallState.SIMULATED_RINGING, 322 CallState.ANSWERED, CallState.AUDIO_PROCESSING}; 323 324 private static final int[] ANY_CALL_STATE = 325 {CallState.NEW, CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, 326 CallState.RINGING, CallState.SIMULATED_RINGING, CallState.ACTIVE, 327 CallState.ON_HOLD, CallState.DISCONNECTED, CallState.ABORTED, 328 CallState.DISCONNECTING, CallState.PULLING, CallState.ANSWERED, 329 CallState.AUDIO_PROCESSING}; 330 331 public static final String TELECOM_CALL_ID_PREFIX = "TC@"; 332 333 // Maps call technologies in TelephonyManager to those in Analytics. 334 private static final Map<Integer, Integer> sAnalyticsTechnologyMap; 335 static { 336 sAnalyticsTechnologyMap = new HashMap<>(5); sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE)337 sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE); sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_GSM, Analytics.GSM_PHONE)338 sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_GSM, Analytics.GSM_PHONE); sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_IMS, Analytics.IMS_PHONE)339 sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_IMS, Analytics.IMS_PHONE); sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_SIP, Analytics.SIP_PHONE)340 sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_SIP, Analytics.SIP_PHONE); sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_THIRD_PARTY, Analytics.THIRD_PARTY_PHONE)341 sAnalyticsTechnologyMap.put(TelephonyManager.PHONE_TYPE_THIRD_PARTY, 342 Analytics.THIRD_PARTY_PHONE); 343 } 344 345 /** 346 * The main call repository. Keeps an instance of all live calls. New incoming and outgoing 347 * calls are added to the map and removed when the calls move to the disconnected state. 348 * 349 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 350 * load factor before resizing, 1 means we only expect a single thread to 351 * access the map so make only a single shard 352 */ 353 private final Set<Call> mCalls = Collections.newSetFromMap( 354 new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1)); 355 356 /** 357 * List of self-managed calls that have been initialized but not yet added to 358 * CallsManager#addCall(Call). There is a window of time when a Call has been added to Telecom 359 * (e.g. TelecomManager#addNewIncomingCall) to actually added in CallsManager#addCall(Call). 360 * This list is helpful for the NotificationManagerService to know that Telecom is currently 361 * setting up a call which is an important set in making notifications non-dismissible. 362 */ 363 private final Set<Call> mSelfManagedCallsBeingSetup = Collections.newSetFromMap( 364 new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1)); 365 366 /** 367 * A pending call is one which requires user-intervention in order to be placed. 368 * Used by {@link #startCallConfirmation}. 369 */ 370 private Call mPendingCall; 371 /** 372 * Cached latest pending redirected call which requires user-intervention in order to be placed. 373 * Used by {@link #onCallRedirectionComplete}. 374 */ 375 private Call mPendingRedirectedOutgoingCall; 376 377 /** 378 * Cached call that's been answered but will be added to mCalls pending confirmation of active 379 * status from the connection service. 380 */ 381 private Call mPendingAudioProcessingCall; 382 383 /** 384 * Cached latest pending redirected call information which require user-intervention in order 385 * to be placed. Used by {@link #onCallRedirectionComplete}. 386 */ 387 private final Map<String, Runnable> mPendingRedirectedOutgoingCallInfo = 388 new ConcurrentHashMap<>(); 389 /** 390 * Cached latest pending Unredirected call information which require user-intervention in order 391 * to be placed. Used by {@link #onCallRedirectionComplete}. 392 */ 393 private final Map<String, Runnable> mPendingUnredirectedOutgoingCallInfo = 394 new ConcurrentHashMap<>(); 395 396 private CompletableFuture<Call> mPendingCallConfirm; 397 private CompletableFuture<Pair<Call, PhoneAccountHandle>> mPendingAccountSelection; 398 399 // Instance variables for testing -- we keep the latest copy of the outgoing call futures 400 // here so that we can wait on them in tests 401 private CompletableFuture<Call> mLatestPostSelectionProcessingFuture; 402 private CompletableFuture<Pair<Call, List<PhoneAccountSuggestion>>> 403 mLatestPreAccountSelectionFuture; 404 405 /** 406 * The current telecom call ID. Used when creating new instances of {@link Call}. Should 407 * only be accessed using the {@link #getNextCallId()} method which synchronizes on the 408 * {@link #mLock} sync root. 409 */ 410 private int mCallId = 0; 411 412 private int mRttRequestId = 0; 413 /** 414 * Stores the current foreground user. 415 */ 416 private UserHandle mCurrentUserHandle = UserHandle.of(ActivityManager.getCurrentUser()); 417 418 private final ConnectionServiceRepository mConnectionServiceRepository; 419 private final DtmfLocalTonePlayer mDtmfLocalTonePlayer; 420 private final InCallController mInCallController; 421 private final CallDiagnosticServiceController mCallDiagnosticServiceController; 422 private final CallAudioManager mCallAudioManager; 423 private final CallRecordingTonePlayer mCallRecordingTonePlayer; 424 private RespondViaSmsManager mRespondViaSmsManager; 425 private final Ringer mRinger; 426 private final InCallWakeLockController mInCallWakeLockController; 427 private final CopyOnWriteArrayList<CallsManagerListener> mListeners = 428 new CopyOnWriteArrayList<>(); 429 private final HeadsetMediaButton mHeadsetMediaButton; 430 private final WiredHeadsetManager mWiredHeadsetManager; 431 private final SystemStateHelper mSystemStateHelper; 432 private final BluetoothRouteManager mBluetoothRouteManager; 433 private final DockManager mDockManager; 434 private final TtyManager mTtyManager; 435 private final ProximitySensorManager mProximitySensorManager; 436 private final PhoneStateBroadcaster mPhoneStateBroadcaster; 437 private final CallLogManager mCallLogManager; 438 private final Context mContext; 439 private final TelecomSystem.SyncRoot mLock; 440 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 441 private final MissedCallNotifier mMissedCallNotifier; 442 private final DisconnectedCallNotifier mDisconnectedCallNotifier; 443 private IncomingCallNotifier mIncomingCallNotifier; 444 private final CallerInfoLookupHelper mCallerInfoLookupHelper; 445 private final DefaultDialerCache mDefaultDialerCache; 446 private final Timeouts.Adapter mTimeoutsAdapter; 447 private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; 448 private final ClockProxy mClockProxy; 449 private final ToastFactory mToastFactory; 450 private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>(); 451 private final Set<Call> mPendingCallsToDisconnect = new HashSet<>(); 452 private final ConnectionServiceFocusManager mConnectionSvrFocusMgr; 453 /* Handler tied to thread in which CallManager was initialized. */ 454 private final Handler mHandler = new Handler(Looper.getMainLooper()); 455 private final EmergencyCallHelper mEmergencyCallHelper; 456 private final RoleManagerAdapter mRoleManagerAdapter; 457 private final VoipCallMonitor mVoipCallMonitor; 458 private final CallEndpointController mCallEndpointController; 459 private final CallAnomalyWatchdog mCallAnomalyWatchdog; 460 461 private final EmergencyCallDiagnosticLogger mEmergencyCallDiagnosticLogger; 462 private final CallStreamingController mCallStreamingController; 463 private final BlockedNumbersAdapter mBlockedNumbersAdapter; 464 private final TransactionManager mTransactionManager; 465 private final UserManager mUserManager; 466 private final CallStreamingNotification mCallStreamingNotification; 467 468 private final ConnectionServiceFocusManager.CallsManagerRequester mRequester = 469 new ConnectionServiceFocusManager.CallsManagerRequester() { 470 @Override 471 public void releaseConnectionService( 472 ConnectionServiceFocusManager.ConnectionServiceFocus connectionService) { 473 mCalls.stream() 474 .filter(c -> c.getConnectionServiceWrapper().equals(connectionService)) 475 .forEach(c -> c.disconnect("release " + 476 connectionService.getComponentName().getPackageName())); 477 } 478 479 @Override 480 public void setCallsManagerListener(CallsManagerListener listener) { 481 mListeners.add(listener); 482 } 483 }; 484 485 private boolean mCanAddCall = true; 486 487 private Runnable mStopTone; 488 489 private LinkedList<HandlerThread> mGraphHandlerThreads; 490 491 // An executor that can be used to fire off async tasks that do not block Telecom in any manner. 492 private final Executor mAsyncTaskExecutor; 493 494 private boolean mHasActiveRttCall = false; 495 496 private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl(); 497 498 private final MmiUtils mMmiUtils = new MmiUtils(); 499 /** 500 * Listener to PhoneAccountRegistrar events. 501 */ 502 private PhoneAccountRegistrar.Listener mPhoneAccountListener = 503 new PhoneAccountRegistrar.Listener() { 504 public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar, 505 PhoneAccountHandle handle) { 506 broadcastRegisterIntent(handle); 507 } 508 public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, 509 PhoneAccountHandle handle) { 510 broadcastUnregisterIntent(handle); 511 } 512 513 @Override 514 public void onPhoneAccountChanged(PhoneAccountRegistrar registrar, 515 PhoneAccount phoneAccount) { 516 handlePhoneAccountChanged(registrar, phoneAccount); 517 } 518 }; 519 520 /** 521 * Receiver for enhanced call blocking feature to update the emergency call notification 522 * in below cases: 523 * 1) Carrier config changed. 524 * 2) Blocking suppression state changed. 525 */ 526 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 527 @Override 528 public void onReceive(Context context, Intent intent) { 529 String action = intent.getAction(); 530 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) 531 || SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED.equals(action)) { 532 updateEmergencyCallNotificationAsync(context); 533 } 534 } 535 }; 536 537 /** 538 * Initializes the required Telecom components. 539 */ 540 @VisibleForTesting CallsManager( Context context, TelecomSystem.SyncRoot lock, CallerInfoLookupHelper callerInfoLookupHelper, MissedCallNotifier missedCallNotifier, DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory, 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, AudioProcessingNotification audioProcessingNotification, BluetoothStateReceiver bluetoothStateReceiver, CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory, CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory, InCallControllerFactory inCallControllerFactory, CallDiagnosticServiceController callDiagnosticServiceController, RoleManagerAdapter roleManagerAdapter, ToastFactory toastFactory, CallEndpointControllerFactory callEndpointControllerFactory, CallAnomalyWatchdog callAnomalyWatchdog, Ringer.AccessibilityManagerAdapter accessibilityManagerAdapter, Executor asyncTaskExecutor, Executor asyncCallAudioTaskExecutor, BlockedNumbersAdapter blockedNumbersAdapter, TransactionManager transactionManager, EmergencyCallDiagnosticLogger emergencyCallDiagnosticLogger, CallStreamingNotification callStreamingNotification)541 public CallsManager( 542 Context context, 543 TelecomSystem.SyncRoot lock, 544 CallerInfoLookupHelper callerInfoLookupHelper, 545 MissedCallNotifier missedCallNotifier, 546 DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory, 547 PhoneAccountRegistrar phoneAccountRegistrar, 548 HeadsetMediaButtonFactory headsetMediaButtonFactory, 549 ProximitySensorManagerFactory proximitySensorManagerFactory, 550 InCallWakeLockControllerFactory inCallWakeLockControllerFactory, 551 ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory 552 connectionServiceFocusManagerFactory, 553 CallAudioManager.AudioServiceFactory audioServiceFactory, 554 BluetoothRouteManager bluetoothManager, 555 WiredHeadsetManager wiredHeadsetManager, 556 SystemStateHelper systemStateHelper, 557 DefaultDialerCache defaultDialerCache, 558 Timeouts.Adapter timeoutsAdapter, 559 AsyncRingtonePlayer asyncRingtonePlayer, 560 PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, 561 EmergencyCallHelper emergencyCallHelper, 562 InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory, 563 ClockProxy clockProxy, 564 AudioProcessingNotification audioProcessingNotification, 565 BluetoothStateReceiver bluetoothStateReceiver, 566 CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory, 567 CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory, 568 InCallControllerFactory inCallControllerFactory, 569 CallDiagnosticServiceController callDiagnosticServiceController, 570 RoleManagerAdapter roleManagerAdapter, 571 ToastFactory toastFactory, 572 CallEndpointControllerFactory callEndpointControllerFactory, 573 CallAnomalyWatchdog callAnomalyWatchdog, 574 Ringer.AccessibilityManagerAdapter accessibilityManagerAdapter, 575 Executor asyncTaskExecutor, 576 Executor asyncCallAudioTaskExecutor, 577 BlockedNumbersAdapter blockedNumbersAdapter, 578 TransactionManager transactionManager, 579 EmergencyCallDiagnosticLogger emergencyCallDiagnosticLogger, 580 CallStreamingNotification callStreamingNotification) { 581 582 mContext = context; 583 mLock = lock; 584 mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; 585 mPhoneAccountRegistrar = phoneAccountRegistrar; 586 mPhoneAccountRegistrar.addListener(mPhoneAccountListener); 587 mMissedCallNotifier = missedCallNotifier; 588 mDisconnectedCallNotifier = disconnectedCallNotifierFactory.create(mContext, this); 589 StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this); 590 mWiredHeadsetManager = wiredHeadsetManager; 591 mSystemStateHelper = systemStateHelper; 592 mDefaultDialerCache = defaultDialerCache; 593 mBluetoothRouteManager = bluetoothManager; 594 mDockManager = new DockManager(context); 595 mTimeoutsAdapter = timeoutsAdapter; 596 mEmergencyCallHelper = emergencyCallHelper; 597 mCallerInfoLookupHelper = callerInfoLookupHelper; 598 mEmergencyCallDiagnosticLogger = emergencyCallDiagnosticLogger; 599 600 mDtmfLocalTonePlayer = 601 new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy()); 602 CallAudioRouteStateMachine callAudioRouteStateMachine = 603 callAudioRouteStateMachineFactory.create( 604 context, 605 this, 606 bluetoothManager, 607 wiredHeadsetManager, 608 statusBarNotifier, 609 audioServiceFactory, 610 CallAudioRouteStateMachine.EARPIECE_AUTO_DETECT, 611 asyncCallAudioTaskExecutor 612 ); 613 callAudioRouteStateMachine.initialize(); 614 615 CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter = 616 new CallAudioRoutePeripheralAdapter( 617 callAudioRouteStateMachine, 618 bluetoothManager, 619 wiredHeadsetManager, 620 mDockManager, 621 asyncRingtonePlayer); 622 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 623 InCallTonePlayer.MediaPlayerFactory mediaPlayerFactory = 624 (resourceId, attributes) -> 625 new InCallTonePlayer.MediaPlayerAdapterImpl( 626 MediaPlayer.create(mContext, resourceId, attributes, 627 audioManager.generateAudioSessionId())); 628 InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory( 629 callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory, mediaPlayerFactory, 630 () -> audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0); 631 632 SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil(); 633 RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context); 634 SystemVibrator systemVibrator = new SystemVibrator(context); 635 mInCallController = inCallControllerFactory.create(context, mLock, this, 636 systemStateHelper, defaultDialerCache, mTimeoutsAdapter, 637 emergencyCallHelper); 638 mCallEndpointController = callEndpointControllerFactory.create(context, mLock, this); 639 mCallDiagnosticServiceController = callDiagnosticServiceController; 640 mCallDiagnosticServiceController.setInCallTonePlayerFactory(playerFactory); 641 mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer, 642 ringtoneFactory, systemVibrator, 643 new Ringer.VibrationEffectProxy(), mInCallController, 644 mContext.getSystemService(NotificationManager.class), 645 accessibilityManagerAdapter); 646 mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager, 647 mTimeoutsAdapter, mLock); 648 mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine, 649 this, callAudioModeStateMachineFactory.create(systemStateHelper, 650 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)), 651 playerFactory, mRinger, new RingbackPlayer(playerFactory), 652 bluetoothStateReceiver, mDtmfLocalTonePlayer); 653 654 mConnectionSvrFocusMgr = connectionServiceFocusManagerFactory.create(mRequester); 655 mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock); 656 mTtyManager = new TtyManager(context, mWiredHeadsetManager); 657 mProximitySensorManager = proximitySensorManagerFactory.create(context, this); 658 mPhoneStateBroadcaster = new PhoneStateBroadcaster(this); 659 mCallLogManager = new CallLogManager(context, phoneAccountRegistrar, mMissedCallNotifier, 660 mAnomalyReporter); 661 mConnectionServiceRepository = 662 new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this); 663 mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this); 664 mClockProxy = clockProxy; 665 mToastFactory = toastFactory; 666 mRoleManagerAdapter = roleManagerAdapter; 667 mTransactionManager = transactionManager; 668 mBlockedNumbersAdapter = blockedNumbersAdapter; 669 mCallStreamingController = new CallStreamingController(mContext, mLock); 670 mVoipCallMonitor = new VoipCallMonitor(mContext, mLock); 671 mCallStreamingNotification = callStreamingNotification; 672 673 mListeners.add(mInCallWakeLockController); 674 mListeners.add(statusBarNotifier); 675 mListeners.add(mCallLogManager); 676 mListeners.add(mInCallController); 677 mListeners.add(mCallEndpointController); 678 mListeners.add(mCallDiagnosticServiceController); 679 mListeners.add(mCallAudioManager); 680 mListeners.add(mCallRecordingTonePlayer); 681 mListeners.add(missedCallNotifier); 682 mListeners.add(mDisconnectedCallNotifier); 683 mListeners.add(mHeadsetMediaButton); 684 mListeners.add(mProximitySensorManager); 685 mListeners.add(audioProcessingNotification); 686 mListeners.add(callAnomalyWatchdog); 687 mListeners.add(mEmergencyCallDiagnosticLogger); 688 mListeners.add(mCallStreamingController); 689 690 // this needs to be after the mCallAudioManager 691 mListeners.add(mPhoneStateBroadcaster); 692 mListeners.add(mVoipCallMonitor); 693 mListeners.add(mCallStreamingNotification); 694 695 mVoipCallMonitor.startMonitor(); 696 697 // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly. 698 final UserManager userManager = UserManager.get(mContext); 699 // Don't load missed call if it is run in split user model. 700 if (userManager.isPrimaryUser()) { 701 onUserSwitch(Process.myUserHandle()); 702 } 703 // Register BroadcastReceiver to handle enhanced call blocking feature related event. 704 IntentFilter intentFilter = new IntentFilter( 705 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 706 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 707 intentFilter.addAction(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED); 708 context.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_EXPORTED); 709 mGraphHandlerThreads = new LinkedList<>(); 710 711 mCallAnomalyWatchdog = callAnomalyWatchdog; 712 mAsyncTaskExecutor = asyncTaskExecutor; 713 mUserManager = mContext.getSystemService(UserManager.class); 714 } 715 setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier)716 public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) { 717 if (mIncomingCallNotifier != null) { 718 mListeners.remove(mIncomingCallNotifier); 719 } 720 mIncomingCallNotifier = incomingCallNotifier; 721 mListeners.add(mIncomingCallNotifier); 722 } 723 setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager)724 public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) { 725 if (mRespondViaSmsManager != null) { 726 mListeners.remove(mRespondViaSmsManager); 727 } 728 mRespondViaSmsManager = respondViaSmsManager; 729 mListeners.add(respondViaSmsManager); 730 } 731 getRespondViaSmsManager()732 public RespondViaSmsManager getRespondViaSmsManager() { 733 return mRespondViaSmsManager; 734 } 735 getCallerInfoLookupHelper()736 public CallerInfoLookupHelper getCallerInfoLookupHelper() { 737 return mCallerInfoLookupHelper; 738 } 739 getRoleManagerAdapter()740 public RoleManagerAdapter getRoleManagerAdapter() { 741 return mRoleManagerAdapter; 742 } 743 getCallDiagnosticServiceController()744 public CallDiagnosticServiceController getCallDiagnosticServiceController() { 745 return mCallDiagnosticServiceController; 746 } 747 748 @Override 749 @VisibleForTesting onSuccessfulOutgoingCall(Call call, int callState)750 public void onSuccessfulOutgoingCall(Call call, int callState) { 751 Log.v(this, "onSuccessfulOutgoingCall, %s", call); 752 call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp( 753 call.getAssociatedUser())); 754 755 setCallState(call, callState, "successful outgoing call"); 756 if (!mCalls.contains(call)) { 757 // Call was not added previously in startOutgoingCall due to it being a potential MMI 758 // code, so add it now. 759 addCall(call); 760 } 761 762 // The call's ConnectionService has been updated. 763 for (CallsManagerListener listener : mListeners) { 764 listener.onConnectionServiceChanged(call, null, call.getConnectionService()); 765 } 766 767 markCallAsDialing(call); 768 } 769 770 @Override onFailedOutgoingCall(Call call, DisconnectCause disconnectCause)771 public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) { 772 Log.i(this, "onFailedOutgoingCall for call %s", call); 773 markCallAsRemoved(call); 774 } 775 776 @Override onSuccessfulIncomingCall(Call incomingCall)777 public void onSuccessfulIncomingCall(Call incomingCall) { 778 Log.d(this, "onSuccessfulIncomingCall"); 779 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 780 incomingCall.getTargetPhoneAccount()); 781 Bundle extras = 782 phoneAccount == null || phoneAccount.getExtras() == null 783 ? new Bundle() 784 : phoneAccount.getExtras(); 785 TelephonyManager telephonyManager = getTelephonyManager(); 786 if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE) || 787 incomingCall.hasProperty(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL) || 788 telephonyManager.isInEmergencySmsMode() || 789 incomingCall.isSelfManaged() || 790 extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)) { 791 Log.i(this, "Skipping call filtering for %s (ecm=%b, " 792 + "networkIdentifiedEmergencyCall = %b, emergencySmsMode = %b, " 793 + "selfMgd=%b, skipExtra=%b)", 794 incomingCall.getId(), 795 incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE), 796 incomingCall.hasProperty(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL), 797 telephonyManager.isInEmergencySmsMode(), 798 incomingCall.isSelfManaged(), 799 extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)); 800 onCallFilteringComplete(incomingCall, new Builder() 801 .setShouldAllowCall(true) 802 .setShouldReject(false) 803 .setShouldAddToCallLog(true) 804 .setShouldShowNotification(true) 805 .build(), false); 806 incomingCall.setIsUsingCallFiltering(false); 807 return; 808 } 809 810 IncomingCallFilterGraph graph = setUpCallFilterGraph(incomingCall); 811 graph.performFiltering(); 812 } 813 setUpCallFilterGraph(Call incomingCall)814 private IncomingCallFilterGraph setUpCallFilterGraph(Call incomingCall) { 815 incomingCall.setIsUsingCallFiltering(true); 816 String carrierPackageName = getCarrierPackageName(); 817 UserHandle userHandle = incomingCall.getAssociatedUser(); 818 String defaultDialerPackageName = TelecomManager.from(mContext). 819 getDefaultDialerPackage(userHandle); 820 String userChosenPackageName = getRoleManagerAdapter(). 821 getDefaultCallScreeningApp(userHandle); 822 AppLabelProxy appLabelProxy = packageName -> AppLabelProxy.Util.getAppLabel( 823 mContext.getPackageManager(), packageName); 824 ParcelableCallUtils.Converter converter = new ParcelableCallUtils.Converter(); 825 826 IncomingCallFilterGraph graph = new IncomingCallFilterGraph(incomingCall, 827 this::onCallFilteringComplete, mContext, mTimeoutsAdapter, mLock); 828 DirectToVoicemailFilter voicemailFilter = new DirectToVoicemailFilter(incomingCall, 829 mCallerInfoLookupHelper); 830 BlockCheckerFilter blockCheckerFilter = new BlockCheckerFilter(mContext, incomingCall, 831 mCallerInfoLookupHelper, new BlockCheckerAdapter()); 832 DndCallFilter dndCallFilter = new DndCallFilter(incomingCall, getRinger()); 833 CallScreeningServiceFilter carrierCallScreeningServiceFilter = 834 new CallScreeningServiceFilter(incomingCall, carrierPackageName, 835 CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, this, 836 appLabelProxy, converter); 837 CallScreeningServiceFilter callScreeningServiceFilter; 838 if ((userChosenPackageName != null) 839 && (!userChosenPackageName.equals(defaultDialerPackageName))) { 840 callScreeningServiceFilter = new CallScreeningServiceFilter(incomingCall, 841 userChosenPackageName, CallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN, 842 mContext, this, appLabelProxy, converter); 843 } else { 844 callScreeningServiceFilter = new CallScreeningServiceFilter(incomingCall, 845 defaultDialerPackageName, 846 CallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER, 847 mContext, this, appLabelProxy, converter); 848 } 849 graph.addFilter(voicemailFilter); 850 graph.addFilter(dndCallFilter); 851 graph.addFilter(blockCheckerFilter); 852 graph.addFilter(carrierCallScreeningServiceFilter); 853 graph.addFilter(callScreeningServiceFilter); 854 IncomingCallFilterGraph.addEdge(voicemailFilter, carrierCallScreeningServiceFilter); 855 IncomingCallFilterGraph.addEdge(blockCheckerFilter, carrierCallScreeningServiceFilter); 856 IncomingCallFilterGraph.addEdge(carrierCallScreeningServiceFilter, 857 callScreeningServiceFilter); 858 mGraphHandlerThreads.add(graph.getHandlerThread()); 859 return graph; 860 } 861 getCarrierPackageName()862 private String getCarrierPackageName() { 863 ComponentName componentName = null; 864 CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService 865 (Context.CARRIER_CONFIG_SERVICE); 866 PersistableBundle configBundle = configManager.getConfig(); 867 if (configBundle != null) { 868 componentName = ComponentName.unflattenFromString(configBundle.getString 869 (CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, "")); 870 } 871 872 return componentName != null ? componentName.getPackageName() : null; 873 } 874 875 @Override onCallFilteringComplete(Call incomingCall, CallFilteringResult result, boolean timeout)876 public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result, 877 boolean timeout) { 878 // Only set the incoming call as ringing if it isn't already disconnected. It is possible 879 // that the connection service disconnected the call before it was even added to Telecom, in 880 // which case it makes no sense to set it back to a ringing state. 881 Log.i(this, "onCallFilteringComplete"); 882 mGraphHandlerThreads.clear(); 883 884 if (timeout) { 885 Log.i(this, "onCallFilteringCompleted: Call filters timeout!"); 886 incomingCall.setUserMissed(USER_MISSED_CALL_FILTERS_TIMEOUT); 887 } 888 889 if (incomingCall.getState() != CallState.DISCONNECTED && 890 incomingCall.getState() != CallState.DISCONNECTING) { 891 setCallState(incomingCall, CallState.RINGING, 892 result.shouldAllowCall ? "successful incoming call" : "blocking call"); 893 } else { 894 Log.i(this, "onCallFilteringCompleted: call already disconnected."); 895 return; 896 } 897 898 // Store the shouldSuppress value in the call object which will be passed to InCallServices 899 incomingCall.setCallIsSuppressedByDoNotDisturb(result.shouldSuppressCallDueToDndStatus); 900 901 // Inform our connection service that call filtering is done (if it was performed at all). 902 if (incomingCall.isUsingCallFiltering()) { 903 boolean isInContacts = incomingCall.getCallerInfo() != null 904 && incomingCall.getCallerInfo().contactExists; 905 Connection.CallFilteringCompletionInfo completionInfo = 906 new Connection.CallFilteringCompletionInfo(!result.shouldAllowCall, 907 isInContacts, 908 result.mCallScreeningResponse == null 909 ? null : result.mCallScreeningResponse.toCallResponse(), 910 result.mCallScreeningComponentName == null ? null 911 : ComponentName.unflattenFromString( 912 result.mCallScreeningComponentName)); 913 incomingCall.getConnectionService().onCallFilteringCompleted(incomingCall, 914 completionInfo); 915 } 916 917 // Get rid of the call composer attachments that aren't wanted 918 if (result.mIsResponseFromSystemDialer && result.mCallScreeningResponse != null) { 919 int attachmentMask = result.mCallScreeningResponse.getCallComposerAttachmentsToShow(); 920 if ((attachmentMask 921 & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_LOCATION) == 0) { 922 incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_LOCATION); 923 } 924 925 if ((attachmentMask 926 & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_SUBJECT) == 0) { 927 incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_CALL_SUBJECT); 928 } 929 930 if ((attachmentMask 931 & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_PRIORITY) == 0) { 932 incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_PRIORITY); 933 } 934 } 935 936 if (result.shouldAllowCall) { 937 incomingCall.setPostCallPackageName( 938 getRoleManagerAdapter().getDefaultCallScreeningApp( 939 incomingCall.getAssociatedUser() 940 )); 941 942 Log.i(this, "onCallFilteringComplete: allow call."); 943 if (hasMaximumManagedRingingCalls(incomingCall)) { 944 if (shouldSilenceInsteadOfReject(incomingCall)) { 945 incomingCall.silence(); 946 } else { 947 Log.i(this, "onCallFilteringCompleted: Call rejected! " + 948 "Exceeds maximum number of ringing calls."); 949 incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING); 950 autoMissCallAndLog(incomingCall, result); 951 return; 952 } 953 } else if (hasMaximumManagedDialingCalls(incomingCall)) { 954 if (shouldSilenceInsteadOfReject(incomingCall)) { 955 incomingCall.silence(); 956 } else { 957 Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + 958 "dialing calls."); 959 incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_DIALING); 960 autoMissCallAndLog(incomingCall, result); 961 return; 962 } 963 } else if (result.shouldScreenViaAudio) { 964 Log.i(this, "onCallFilteringCompleted: starting background audio processing"); 965 answerCallForAudioProcessing(incomingCall); 966 incomingCall.setAudioProcessingRequestingApp(result.mCallScreeningAppName); 967 } else if (result.shouldSilence) { 968 Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state"); 969 incomingCall.setSilentRingingRequested(true); 970 incomingCall.setUserMissed(USER_MISSED_CALL_SCREENING_SERVICE_SILENCED); 971 incomingCall.setCallScreeningAppName(result.mCallScreeningAppName); 972 incomingCall.setCallScreeningComponentName(result.mCallScreeningComponentName); 973 addCall(incomingCall); 974 } else { 975 addCall(incomingCall); 976 } 977 } else { 978 if (result.shouldReject) { 979 Log.i(this, "onCallFilteringCompleted: blocked call, rejecting."); 980 incomingCall.reject(false, null); 981 } 982 if (result.shouldAddToCallLog) { 983 Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log."); 984 if (result.shouldShowNotification) { 985 Log.w(this, "onCallScreeningCompleted: blocked call, showing notification."); 986 } 987 mCallLogManager.logCall(incomingCall, Calls.BLOCKED_TYPE, 988 result.shouldShowNotification, result); 989 } 990 if (result.shouldShowNotification) { 991 Log.i(this, "onCallScreeningCompleted: blocked call, showing notification."); 992 mMissedCallNotifier.showMissedCallNotification( 993 new MissedCallNotifier.CallInfo(incomingCall)); 994 } 995 } 996 } 997 998 /** 999 * In the event that the maximum supported calls of a given type is reached, the 1000 * default behavior is to reject any additional calls of that type. This checks 1001 * if the device is configured to silence instead of reject the call, provided 1002 * that the incoming call is from a different source (connection service). 1003 */ shouldSilenceInsteadOfReject(Call incomingCall)1004 private boolean shouldSilenceInsteadOfReject(Call incomingCall) { 1005 if (!mContext.getResources().getBoolean( 1006 R.bool.silence_incoming_when_different_service_and_maximum_ringing)) { 1007 return false; 1008 } 1009 1010 for (Call call : mCalls) { 1011 // Only operate on top-level calls 1012 if (call.getParentCall() != null) { 1013 continue; 1014 } 1015 1016 if (call.isExternalCall()) { 1017 continue; 1018 } 1019 1020 if (call.getConnectionService() == incomingCall.getConnectionService()) { 1021 return false; 1022 } 1023 } 1024 1025 return true; 1026 } 1027 1028 @Override onFailedIncomingCall(Call call)1029 public void onFailedIncomingCall(Call call) { 1030 Log.i(this, "onFailedIncomingCall for call %s", call); 1031 setCallState(call, CallState.DISCONNECTED, "failed incoming call"); 1032 call.removeListener(this); 1033 } 1034 1035 @Override onSuccessfulUnknownCall(Call call, int callState)1036 public void onSuccessfulUnknownCall(Call call, int callState) { 1037 Log.i(this, "onSuccessfulUnknownCall for call %s", call); 1038 setCallState(call, callState, "successful unknown call"); 1039 addCall(call); 1040 } 1041 1042 @Override onFailedUnknownCall(Call call)1043 public void onFailedUnknownCall(Call call) { 1044 Log.i(this, "onFailedUnknownCall for call %s", call); 1045 setCallState(call, CallState.DISCONNECTED, "failed unknown call"); 1046 call.removeListener(this); 1047 } 1048 1049 @Override onRingbackRequested(Call call, boolean ringback)1050 public void onRingbackRequested(Call call, boolean ringback) { 1051 for (CallsManagerListener listener : mListeners) { 1052 listener.onRingbackRequested(call, ringback); 1053 } 1054 } 1055 1056 @Override onPostDialWait(Call call, String remaining)1057 public void onPostDialWait(Call call, String remaining) { 1058 mInCallController.onPostDialWait(call, remaining); 1059 } 1060 1061 @Override onPostDialChar(final Call call, char nextChar)1062 public void onPostDialChar(final Call call, char nextChar) { 1063 if (PhoneNumberUtils.is12Key(nextChar)) { 1064 // Play tone if it is one of the dialpad digits, canceling out the previously queued 1065 // up stopTone runnable since playing a new tone automatically stops the previous tone. 1066 if (mStopTone != null) { 1067 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 1068 mStopTone.cancel(); 1069 } 1070 1071 mDtmfLocalTonePlayer.playTone(call, nextChar); 1072 1073 mStopTone = new Runnable("CM.oPDC", mLock) { 1074 @Override 1075 public void loggedRun() { 1076 // Set a timeout to stop the tone in case there isn't another tone to 1077 // follow. 1078 mDtmfLocalTonePlayer.stopTone(call); 1079 } 1080 }; 1081 mHandler.postDelayed(mStopTone.prepare(), 1082 Timeouts.getDelayBetweenDtmfTonesMillis(mContext.getContentResolver())); 1083 } else if (nextChar == 0 || nextChar == TelecomManager.DTMF_CHARACTER_WAIT || 1084 nextChar == TelecomManager.DTMF_CHARACTER_PAUSE) { 1085 // Stop the tone if a tone is playing, removing any other stopTone callbacks since 1086 // the previous tone is being stopped anyway. 1087 if (mStopTone != null) { 1088 mHandler.removeCallbacks(mStopTone.getRunnableToCancel()); 1089 mStopTone.cancel(); 1090 } 1091 mDtmfLocalTonePlayer.stopTone(call); 1092 } else { 1093 Log.w(this, "onPostDialChar: invalid value %d", nextChar); 1094 } 1095 } 1096 1097 @Override onConnectionPropertiesChanged(Call call, boolean didRttChange)1098 public void onConnectionPropertiesChanged(Call call, boolean didRttChange) { 1099 if (didRttChange) { 1100 updateHasActiveRttCall(); 1101 } 1102 } 1103 1104 @Override onParentChanged(Call call)1105 public void onParentChanged(Call call) { 1106 // parent-child relationship affects which call should be foreground, so do an update. 1107 updateCanAddCall(); 1108 for (CallsManagerListener listener : mListeners) { 1109 listener.onIsConferencedChanged(call); 1110 } 1111 } 1112 1113 @Override onChildrenChanged(Call call)1114 public void onChildrenChanged(Call call) { 1115 // parent-child relationship affects which call should be foreground, so do an update. 1116 updateCanAddCall(); 1117 for (CallsManagerListener listener : mListeners) { 1118 listener.onIsConferencedChanged(call); 1119 } 1120 } 1121 1122 @Override onConferenceStateChanged(Call call, boolean isConference)1123 public void onConferenceStateChanged(Call call, boolean isConference) { 1124 // Conference changed whether it is treated as a conference or not. 1125 updateCanAddCall(); 1126 for (CallsManagerListener listener : mListeners) { 1127 listener.onConferenceStateChanged(call, isConference); 1128 } 1129 } 1130 1131 @Override onCdmaConferenceSwap(Call call)1132 public void onCdmaConferenceSwap(Call call) { 1133 // SWAP was executed on a CDMA conference 1134 for (CallsManagerListener listener : mListeners) { 1135 listener.onCdmaConferenceSwap(call); 1136 } 1137 } 1138 1139 @Override onIsVoipAudioModeChanged(Call call)1140 public void onIsVoipAudioModeChanged(Call call) { 1141 for (CallsManagerListener listener : mListeners) { 1142 listener.onIsVoipAudioModeChanged(call); 1143 } 1144 } 1145 1146 @Override onVideoStateChanged(Call call, int previousVideoState, int newVideoState)1147 public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) { 1148 for (CallsManagerListener listener : mListeners) { 1149 listener.onVideoStateChanged(call, previousVideoState, newVideoState); 1150 } 1151 } 1152 1153 @Override onCanceledViaNewOutgoingCallBroadcast(final Call call, long disconnectionTimeout)1154 public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call, 1155 long disconnectionTimeout) { 1156 mPendingCallsToDisconnect.add(call); 1157 mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) { 1158 @Override 1159 public void loggedRun() { 1160 if (mPendingCallsToDisconnect.remove(call)) { 1161 Log.i(this, "Delayed disconnection of call: %s", call); 1162 call.disconnect(); 1163 } 1164 } 1165 }.prepare(), disconnectionTimeout); 1166 1167 return true; 1168 } 1169 1170 /** 1171 * Handles changes to the {@link Connection.VideoProvider} for a call. Adds the 1172 * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created 1173 * in {@link Call#setVideoProvider(IVideoProvider)}. This allows the {@link CallsManager} to 1174 * respond to callbacks from the {@link VideoProviderProxy}. 1175 * 1176 * @param call The call. 1177 */ 1178 @Override onVideoCallProviderChanged(Call call)1179 public void onVideoCallProviderChanged(Call call) { 1180 VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy(); 1181 1182 if (videoProviderProxy == null) { 1183 return; 1184 } 1185 1186 videoProviderProxy.addListener(this); 1187 } 1188 1189 /** 1190 * Handles session modification requests received via the {@link TelecomVideoCallCallback} for 1191 * a call. Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session 1192 * modification request. 1193 * 1194 * @param call The call. 1195 * @param videoProfile The {@link VideoProfile}. 1196 */ 1197 @Override onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)1198 public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) { 1199 int videoState = videoProfile != null ? videoProfile.getVideoState() : 1200 VideoProfile.STATE_AUDIO_ONLY; 1201 Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile 1202 .videoStateToString(videoState)); 1203 1204 for (CallsManagerListener listener : mListeners) { 1205 listener.onSessionModifyRequestReceived(call, videoProfile); 1206 } 1207 } 1208 1209 /** 1210 * Handles a change to the currently active camera for a call by notifying listeners. 1211 * @param call The call. 1212 * @param cameraId The ID of the camera in use, or {@code null} if no camera is in use. 1213 */ 1214 @Override onSetCamera(Call call, String cameraId)1215 public void onSetCamera(Call call, String cameraId) { 1216 for (CallsManagerListener listener : mListeners) { 1217 listener.onSetCamera(call, cameraId); 1218 } 1219 } 1220 getCalls()1221 public Collection<Call> getCalls() { 1222 return Collections.unmodifiableCollection(mCalls); 1223 } 1224 1225 /** 1226 * Play or stop a call hold tone for a call. Triggered via 1227 * {@link Connection#sendConnectionEvent(String)} when the 1228 * {@link Connection#EVENT_ON_HOLD_TONE_START} event or 1229 * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the 1230 * 1231 * @param call The call which requested the hold tone. 1232 */ 1233 @Override onHoldToneRequested(Call call)1234 public void onHoldToneRequested(Call call) { 1235 for (CallsManagerListener listener : mListeners) { 1236 listener.onHoldToneRequested(call); 1237 } 1238 } 1239 1240 /** 1241 * A {@link Call} managed by the {@link CallsManager} has requested a handover to another 1242 * {@link PhoneAccount}. 1243 * @param call The call. 1244 * @param handoverTo The {@link PhoneAccountHandle} to handover the call to. 1245 * @param videoState The desired video state of the call after handover. 1246 * @param extras 1247 */ 1248 @Override onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState, Bundle extras, boolean isLegacy)1249 public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState, 1250 Bundle extras, boolean isLegacy) { 1251 if (isLegacy) { 1252 requestHandoverViaEvents(call, handoverTo, videoState, extras); 1253 } else { 1254 requestHandover(call, handoverTo, videoState, extras); 1255 } 1256 } 1257 getForegroundCall()1258 public Call getForegroundCall() { 1259 if (mCallAudioManager == null) { 1260 // Happens when getForegroundCall is called before full initialization. 1261 return null; 1262 } 1263 return mCallAudioManager.getForegroundCall(); 1264 } 1265 1266 @VisibleForTesting getTrackedCalls()1267 public Set<Call> getTrackedCalls() { 1268 if (mCallAudioManager == null) { 1269 // Happens when getTrackedCalls is called before full initialization. 1270 return null; 1271 } 1272 return mCallAudioManager.getTrackedCalls(); 1273 } 1274 1275 @Override onCallHoldFailed(Call call)1276 public void onCallHoldFailed(Call call) { 1277 markAllAnsweredCallAsRinging(call, "hold"); 1278 } 1279 1280 @Override onCallSwitchFailed(Call call)1281 public void onCallSwitchFailed(Call call) { 1282 markAllAnsweredCallAsRinging(call, "switch"); 1283 } 1284 markAllAnsweredCallAsRinging(Call call, String actionName)1285 private void markAllAnsweredCallAsRinging(Call call, String actionName) { 1286 // Normally, we don't care whether a call hold or switch has failed. 1287 // However, if a call was held or switched in order to answer an incoming call, that 1288 // incoming call needs to be brought out of the ANSWERED state so that the user can 1289 // try the operation again. 1290 for (Call call1 : mCalls) { 1291 if (call1 != call && call1.getState() == CallState.ANSWERED) { 1292 setCallState(call1, CallState.RINGING, actionName + " failed on other call"); 1293 } 1294 } 1295 } 1296 1297 @Override getCurrentUserHandle()1298 public UserHandle getCurrentUserHandle() { 1299 return mCurrentUserHandle; 1300 } 1301 getCallAudioManager()1302 public CallAudioManager getCallAudioManager() { 1303 return mCallAudioManager; 1304 } 1305 getInCallController()1306 InCallController getInCallController() { 1307 return mInCallController; 1308 } 1309 getCallEndpointController()1310 public CallEndpointController getCallEndpointController() { 1311 return mCallEndpointController; 1312 } 1313 getEmergencyCallHelper()1314 EmergencyCallHelper getEmergencyCallHelper() { 1315 return mEmergencyCallHelper; 1316 } 1317 getEmergencyCallDiagnosticLogger()1318 EmergencyCallDiagnosticLogger getEmergencyCallDiagnosticLogger() { 1319 return mEmergencyCallDiagnosticLogger; 1320 } 1321 getDefaultDialerCache()1322 public DefaultDialerCache getDefaultDialerCache() { 1323 return mDefaultDialerCache; 1324 } 1325 1326 @VisibleForTesting getPhoneAccountListener()1327 public PhoneAccountRegistrar.Listener getPhoneAccountListener() { 1328 return mPhoneAccountListener; 1329 } 1330 hasEmergencyRttCall()1331 public boolean hasEmergencyRttCall() { 1332 for (Call call : mCalls) { 1333 if (call.isEmergencyCall() && call.isRttCall()) { 1334 return true; 1335 } 1336 } 1337 return false; 1338 } 1339 1340 @VisibleForTesting hasOnlyDisconnectedCalls()1341 public boolean hasOnlyDisconnectedCalls() { 1342 if (mCalls.size() == 0) { 1343 return false; 1344 } 1345 for (Call call : mCalls) { 1346 if (!call.isDisconnected()) { 1347 return false; 1348 } 1349 } 1350 return true; 1351 } 1352 hasVideoCall()1353 public boolean hasVideoCall() { 1354 for (Call call : mCalls) { 1355 if (VideoProfile.isVideo(call.getVideoState())) { 1356 return true; 1357 } 1358 } 1359 return false; 1360 } 1361 1362 @VisibleForTesting getAudioState()1363 public CallAudioState getAudioState() { 1364 return mCallAudioManager.getCallAudioState(); 1365 } 1366 isTtySupported()1367 boolean isTtySupported() { 1368 return mTtyManager.isTtySupported(); 1369 } 1370 getCurrentTtyMode()1371 int getCurrentTtyMode() { 1372 return mTtyManager.getCurrentTtyMode(); 1373 } 1374 1375 @VisibleForTesting addListener(CallsManagerListener listener)1376 public void addListener(CallsManagerListener listener) { 1377 mListeners.add(listener); 1378 } 1379 1380 @VisibleForTesting removeListener(CallsManagerListener listener)1381 public void removeListener(CallsManagerListener listener) { 1382 mListeners.remove(listener); 1383 } 1384 1385 @VisibleForTesting setAnomalyReporterAdapter(AnomalyReporterAdapter anomalyReporterAdapter)1386 public void setAnomalyReporterAdapter(AnomalyReporterAdapter anomalyReporterAdapter){ 1387 mAnomalyReporter = anomalyReporterAdapter; 1388 if (mCallLogManager != null) { 1389 mCallLogManager.setAnomalyReporterAdapter(anomalyReporterAdapter); 1390 } 1391 } 1392 processIncomingConference(PhoneAccountHandle phoneAccountHandle, Bundle extras)1393 void processIncomingConference(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 1394 Log.d(this, "processIncomingCallConference"); 1395 processIncomingCallIntent(phoneAccountHandle, extras, true); 1396 } 1397 1398 /** 1399 * Starts the process to attach the call to a connection service. 1400 * 1401 * @param phoneAccountHandle The phone account which contains the component name of the 1402 * connection service to use for this call. 1403 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 1404 */ processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras)1405 void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 1406 processIncomingCallIntent(phoneAccountHandle, extras, false); 1407 } 1408 processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras, boolean isConference)1409 public Call processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras, 1410 boolean isConference) { 1411 Log.d(this, "processIncomingCallIntent"); 1412 boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER); 1413 Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); 1414 if (handle == null) { 1415 // Required for backwards compatibility 1416 handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER); 1417 } 1418 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 1419 phoneAccountHandle); 1420 Call call = new Call( 1421 generateNextCallId(extras), 1422 mContext, 1423 this, 1424 mLock, 1425 mConnectionServiceRepository, 1426 mPhoneNumberUtilsAdapter, 1427 handle, 1428 null /* gatewayInfo */, 1429 null /* connectionManagerPhoneAccount */, 1430 phoneAccountHandle, 1431 Call.CALL_DIRECTION_INCOMING /* callDirection */, 1432 false /* forceAttachToExistingConnection */, 1433 isConference, /* isConference */ 1434 mClockProxy, 1435 mToastFactory); 1436 // Ensure new calls related to self-managed calls/connections are set as such. This will 1437 // be overridden when the actual connection is returned in startCreateConnection, however 1438 // doing this now ensures the logs and any other logic will treat this call as self-managed 1439 // from the moment it is created. 1440 boolean isSelfManaged = phoneAccount != null && phoneAccount.isSelfManaged(); 1441 call.setIsSelfManaged(isSelfManaged); 1442 // It's important to start tracking self-managed calls as soon as the Call object is 1443 // initialized so NotificationManagerService is aware Telecom is setting up a call 1444 if (isSelfManaged) mSelfManagedCallsBeingSetup.add(call); 1445 1446 // set properties for transactional call 1447 if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) { 1448 call.setIsTransactionalCall(true); 1449 call.setCallingPackageIdentity(extras); 1450 call.setConnectionCapabilities( 1451 extras.getInt(CallAttributes.CALL_CAPABILITIES_KEY, 1452 CallAttributes.SUPPORTS_SET_INACTIVE), true); 1453 call.setTargetPhoneAccount(phoneAccountHandle); 1454 if (extras.containsKey(CallAttributes.DISPLAY_NAME_KEY)) { 1455 CharSequence displayName = extras.getCharSequence(CallAttributes.DISPLAY_NAME_KEY); 1456 if (!TextUtils.isEmpty(displayName)) { 1457 call.setCallerDisplayName(displayName.toString(), 1458 TelecomManager.PRESENTATION_ALLOWED); 1459 } 1460 } 1461 // Incoming address was set via EXTRA_INCOMING_CALL_ADDRESS above. 1462 call.setAssociatedUser(phoneAccountHandle.getUserHandle()); 1463 } 1464 1465 if (phoneAccount != null) { 1466 Bundle phoneAccountExtras = phoneAccount.getExtras(); 1467 if (call.isSelfManaged()) { 1468 // Self managed calls will always be voip audio mode. 1469 call.setIsVoipAudioMode(true); 1470 call.setVisibleToInCallService(phoneAccountExtras == null 1471 || phoneAccountExtras.getBoolean( 1472 PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true)); 1473 } else { 1474 // Incoming call is managed, the active call is self-managed and can't be held. 1475 // We need to set extras on it to indicate whether answering will cause a 1476 // active self-managed call to drop. 1477 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 1478 if (activeCall != null && !canHold(activeCall) && activeCall.isSelfManaged()) { 1479 Bundle dropCallExtras = new Bundle(); 1480 dropCallExtras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true); 1481 1482 // Include the name of the app which will drop the call. 1483 CharSequence droppedApp = activeCall.getTargetPhoneAccountLabel(); 1484 dropCallExtras.putCharSequence( 1485 Connection.EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME, droppedApp); 1486 Log.i(this, "Incoming managed call will drop %s call.", droppedApp); 1487 call.putConnectionServiceExtras(dropCallExtras); 1488 } 1489 } 1490 1491 if (phoneAccountExtras != null 1492 && phoneAccountExtras.getBoolean( 1493 PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 1494 Log.d(this, "processIncomingCallIntent: defaulting to voip mode for call %s", 1495 call.getId()); 1496 call.setIsVoipAudioMode(true); 1497 } 1498 } 1499 1500 boolean isRttSettingOn = isRttSettingOn(phoneAccountHandle); 1501 if (isRttSettingOn || 1502 extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) { 1503 Log.i(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn); 1504 call.createRttStreams(); 1505 // Even if the phone account doesn't support RTT yet, the connection manager might 1506 // change that. Set this to check it later. 1507 call.setRequestedToStartWithRtt(); 1508 } 1509 // If the extras specifies a video state, set it on the call if the PhoneAccount supports 1510 // video. 1511 int videoState = VideoProfile.STATE_AUDIO_ONLY; 1512 if (extras.containsKey(TelecomManager.EXTRA_INCOMING_VIDEO_STATE) && 1513 phoneAccount != null && phoneAccount.hasCapabilities( 1514 PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 1515 videoState = extras.getInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE); 1516 call.setVideoState(videoState); 1517 } 1518 1519 call.initAnalytics(); 1520 if (getForegroundCall() != null) { 1521 getForegroundCall().getAnalytics().setCallIsInterrupted(true); 1522 call.getAnalytics().setCallIsAdditional(true); 1523 } 1524 setIntentExtrasAndStartTime(call, extras); 1525 // TODO: Move this to be a part of addCall() 1526 call.addListener(this); 1527 1528 if (extras.containsKey(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE)) { 1529 String disconnectMessage = extras.getString(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE); 1530 Log.i(this, "processIncomingCallIntent Disconnect message " + disconnectMessage); 1531 } 1532 1533 boolean isHandoverAllowed = true; 1534 if (isHandover) { 1535 if (!isHandoverInProgress() && 1536 isHandoverToPhoneAccountSupported(phoneAccountHandle)) { 1537 final String handleScheme = handle.getSchemeSpecificPart(); 1538 Call fromCall = mCalls.stream() 1539 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 1540 (c.getHandle() == null 1541 ? null : c.getHandle().getSchemeSpecificPart()), 1542 handleScheme)) 1543 .findFirst() 1544 .orElse(null); 1545 if (fromCall != null) { 1546 if (!isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount())) { 1547 Log.w(this, "processIncomingCallIntent: From account doesn't support " + 1548 "handover."); 1549 isHandoverAllowed = false; 1550 } 1551 } else { 1552 Log.w(this, "processIncomingCallIntent: handover fail; can't find from call."); 1553 isHandoverAllowed = false; 1554 } 1555 1556 if (isHandoverAllowed) { 1557 // Link the calls so we know we're handing over. 1558 fromCall.setHandoverDestinationCall(call); 1559 call.setHandoverSourceCall(fromCall); 1560 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 1561 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 1562 Log.addEvent(fromCall, LogUtils.Events.START_HANDOVER, 1563 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 1564 Log.addEvent(call, LogUtils.Events.START_HANDOVER, 1565 "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId()); 1566 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 1567 // Ensure when the call goes active that it will go to speakerphone if the 1568 // handover to call is a video call. 1569 call.setStartWithSpeakerphoneOn(true); 1570 } 1571 } 1572 } else { 1573 Log.w(this, "processIncomingCallIntent: To account doesn't support handover."); 1574 } 1575 } 1576 1577 CallFailureCause startFailCause = 1578 checkIncomingCallPermitted(call, call.getTargetPhoneAccount()); 1579 // Check if the target phone account is possibly in ECBM. 1580 call.setIsInECBM(getEmergencyCallHelper() 1581 .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount())); 1582 // If the phone account user profile is paused or the call isn't visible to the secondary/ 1583 // guest user, reject the non-emergency incoming call. When the current user is the admin, 1584 // we need to allow the calls to go through if the work profile isn't paused. We should 1585 // always allow emergency calls and also allow non-emergency calls when ECBM is active for 1586 // the phone account. 1587 if ((mUserManager.isQuietModeEnabled(call.getAssociatedUser()) 1588 || (!mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier()) 1589 && !isCallVisibleForUser(call, mCurrentUserHandle))) 1590 && !call.isEmergencyCall() && !call.isInECBM()) { 1591 Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.", 1592 phoneAccountHandle.getUserHandle()); 1593 call.setMissedReason(USER_MISSED_NOT_RUNNING); 1594 call.setStartFailCause(CallFailureCause.INVALID_USE); 1595 if (isConference) { 1596 notifyCreateConferenceFailed(phoneAccountHandle, call); 1597 } else { 1598 notifyCreateConnectionFailed(phoneAccountHandle, call); 1599 } 1600 } 1601 else if (!isHandoverAllowed || 1602 (call.isSelfManaged() && !startFailCause.isSuccess())) { 1603 if (isConference) { 1604 notifyCreateConferenceFailed(phoneAccountHandle, call); 1605 } else { 1606 if (hasMaximumManagedRingingCalls(call)) { 1607 call.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING); 1608 call.setStartFailCause(CallFailureCause.MAX_RINGING_CALLS); 1609 mCallLogManager.logCall(call, Calls.MISSED_TYPE, 1610 true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/); 1611 } 1612 call.setStartFailCause(startFailCause); 1613 notifyCreateConnectionFailed(phoneAccountHandle, call); 1614 } 1615 } else if (isInEmergencyCall()) { 1616 // The incoming call is implicitly being rejected so the user does not get any incoming 1617 // call UI during an emergency call. In this case, log the call as missed instead of 1618 // rejected since the user did not explicitly reject. 1619 call.setMissedReason(AUTO_MISSED_EMERGENCY_CALL); 1620 call.getAnalytics().setMissedReason(call.getMissedReason()); 1621 call.setStartFailCause(CallFailureCause.IN_EMERGENCY_CALL); 1622 mCallLogManager.logCall(call, Calls.MISSED_TYPE, 1623 true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/); 1624 if (isConference) { 1625 notifyCreateConferenceFailed(phoneAccountHandle, call); 1626 } else { 1627 notifyCreateConnectionFailed(phoneAccountHandle, call); 1628 } 1629 } else if (call.isTransactionalCall()) { 1630 // transactional calls should skip Call#startCreateConnection below 1631 // as that is meant for Call objects with a ConnectionServiceWrapper 1632 call.setState(CallState.RINGING, "explicitly set new incoming to ringing"); 1633 // Transactional calls don't get created via a connection service; they are added now. 1634 call.setIsCreateConnectionComplete(true); 1635 addCall(call); 1636 } else { 1637 notifyStartCreateConnection(call); 1638 call.startCreateConnection(mPhoneAccountRegistrar); 1639 } 1640 return call; 1641 } 1642 addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras)1643 void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 1644 Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE); 1645 Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle)); 1646 Call call = new Call( 1647 getNextCallId(), 1648 mContext, 1649 this, 1650 mLock, 1651 mConnectionServiceRepository, 1652 mPhoneNumberUtilsAdapter, 1653 handle, 1654 null /* gatewayInfo */, 1655 null /* connectionManagerPhoneAccount */, 1656 phoneAccountHandle, 1657 Call.CALL_DIRECTION_UNKNOWN /* callDirection */, 1658 // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach 1659 // to the existing connection instead of trying to create a new one. 1660 true /* forceAttachToExistingConnection */, 1661 false, /* isConference */ 1662 mClockProxy, 1663 mToastFactory); 1664 call.initAnalytics(); 1665 1666 // For unknown calls, base the associated user off of the target phone account handle. 1667 call.setAssociatedUser(phoneAccountHandle.getUserHandle()); 1668 setIntentExtrasAndStartTime(call, extras); 1669 call.addListener(this); 1670 notifyStartCreateConnection(call); 1671 call.startCreateConnection(mPhoneAccountRegistrar); 1672 } 1673 areHandlesEqual(Uri handle1, Uri handle2)1674 private boolean areHandlesEqual(Uri handle1, Uri handle2) { 1675 if (handle1 == null || handle2 == null) { 1676 return handle1 == handle2; 1677 } 1678 1679 if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) { 1680 return false; 1681 } 1682 1683 final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart()); 1684 final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart()); 1685 return TextUtils.equals(number1, number2); 1686 } 1687 reuseOutgoingCall(Uri handle)1688 private Call reuseOutgoingCall(Uri handle) { 1689 // Check to see if we can reuse any of the calls that are waiting to disconnect. 1690 // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information. 1691 Call reusedCall = null; 1692 for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) { 1693 Call pendingCall = callIter.next(); 1694 if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) { 1695 callIter.remove(); 1696 Log.i(this, "Reusing disconnected call %s", pendingCall); 1697 reusedCall = pendingCall; 1698 } else { 1699 Log.i(this, "Not reusing disconnected call %s", pendingCall); 1700 callIter.remove(); 1701 pendingCall.disconnect(); 1702 } 1703 } 1704 1705 return reusedCall; 1706 } 1707 1708 /** 1709 * Kicks off the first steps to creating an outgoing call. 1710 * 1711 * For managed connections, this is the first step to launching the Incall UI. 1712 * For self-managed connections, we don't expect the Incall UI to launch, but this is still a 1713 * first step in getting the self-managed ConnectionService to create the connection. 1714 * @param handle Handle to connect the call with. 1715 * @param requestedAccountHandle The phone account which contains the component name of the 1716 * connection service to use for this call. 1717 * @param extras The optional extras Bundle passed with the intent used for the incoming call. 1718 * @param initiatingUser {@link UserHandle} of user that place the outgoing call. 1719 * @param originalIntent 1720 * @param callingPackage the package name of the app which initiated the outgoing call. 1721 */ 1722 @VisibleForTesting 1723 public @NonNull startOutgoingCall(Uri handle, PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage)1724 CompletableFuture<Call> startOutgoingCall(Uri handle, 1725 PhoneAccountHandle requestedAccountHandle, 1726 Bundle extras, UserHandle initiatingUser, Intent originalIntent, 1727 String callingPackage) { 1728 final List<Uri> callee = new ArrayList<>(); 1729 callee.add(handle); 1730 return startOutgoingCall(callee, requestedAccountHandle, extras, initiatingUser, 1731 originalIntent, callingPackage, false); 1732 } 1733 generateNextCallId(Bundle extras)1734 private String generateNextCallId(Bundle extras) { 1735 if (extras != null && extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) { 1736 return extras.getString(TelecomManager.TRANSACTION_CALL_ID_KEY); 1737 } else { 1738 return getNextCallId(); 1739 } 1740 } 1741 startOutgoingCall(List<Uri> participants, PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage, boolean isConference)1742 private CompletableFuture<Call> startOutgoingCall(List<Uri> participants, 1743 PhoneAccountHandle requestedAccountHandle, 1744 Bundle extras, UserHandle initiatingUser, Intent originalIntent, 1745 String callingPackage, boolean isConference) { 1746 boolean isReusedCall; 1747 Uri handle = isConference ? Uri.parse("tel:conf-factory") : participants.get(0); 1748 Call call = reuseOutgoingCall(handle); 1749 PhoneAccount account = 1750 mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser); 1751 Bundle phoneAccountExtra = account != null ? account.getExtras() : null; 1752 boolean isSelfManaged = account != null && account.isSelfManaged(); 1753 1754 StringBuffer creationLogs = new StringBuffer(); 1755 creationLogs.append("requestedAcct:"); 1756 if (requestedAccountHandle == null) { 1757 creationLogs.append("none"); 1758 } else { 1759 creationLogs.append(requestedAccountHandle); 1760 } 1761 creationLogs.append(", selfMgd:"); 1762 creationLogs.append(isSelfManaged); 1763 1764 // Create a call with original handle. The handle may be changed when the call is attached 1765 // to a connection service, but in most cases will remain the same. 1766 if (call == null) { 1767 call = new Call(generateNextCallId(extras), mContext, 1768 this, 1769 mLock, 1770 mConnectionServiceRepository, 1771 mPhoneNumberUtilsAdapter, 1772 handle, 1773 isConference ? participants : null, 1774 null /* gatewayInfo */, 1775 null /* connectionManagerPhoneAccount */, 1776 requestedAccountHandle /* targetPhoneAccountHandle */, 1777 Call.CALL_DIRECTION_OUTGOING /* callDirection */, 1778 false /* forceAttachToExistingConnection */, 1779 isConference, /* isConference */ 1780 mClockProxy, 1781 mToastFactory); 1782 1783 if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) { 1784 call.setIsTransactionalCall(true); 1785 call.setCallingPackageIdentity(extras); 1786 call.setConnectionCapabilities( 1787 extras.getInt(CallAttributes.CALL_CAPABILITIES_KEY, 1788 CallAttributes.SUPPORTS_SET_INACTIVE), true); 1789 if (extras.containsKey(CallAttributes.DISPLAY_NAME_KEY)) { 1790 CharSequence displayName = extras.getCharSequence( 1791 CallAttributes.DISPLAY_NAME_KEY); 1792 if (!TextUtils.isEmpty(displayName)) { 1793 call.setCallerDisplayName(displayName.toString(), 1794 TelecomManager.PRESENTATION_ALLOWED); 1795 } 1796 } 1797 } 1798 1799 call.initAnalytics(callingPackage, creationLogs.toString()); 1800 1801 // Log info for emergency call 1802 if (call.isEmergencyCall()) { 1803 String simNumeric = ""; 1804 String networkNumeric = ""; 1805 int defaultVoiceSubId = SubscriptionManager.getDefaultVoiceSubscriptionId(); 1806 if (defaultVoiceSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1807 TelephonyManager tm = getTelephonyManager().createForSubscriptionId( 1808 defaultVoiceSubId); 1809 CellIdentity cellIdentity = tm.getLastKnownCellIdentity(); 1810 simNumeric = tm.getSimOperatorNumeric(); 1811 networkNumeric = (cellIdentity != null) ? cellIdentity.getPlmn() : ""; 1812 } 1813 TelecomStatsLog.write(TelecomStatsLog.EMERGENCY_NUMBER_DIALED, 1814 handle.getSchemeSpecificPart(), 1815 callingPackage, simNumeric, networkNumeric); 1816 } 1817 1818 // Ensure new calls related to self-managed calls/connections are set as such. This 1819 // will be overridden when the actual connection is returned in startCreateConnection, 1820 // however doing this now ensures the logs and any other logic will treat this call as 1821 // self-managed from the moment it is created. 1822 call.setIsSelfManaged(isSelfManaged); 1823 if (isSelfManaged) { 1824 // Self-managed calls will ALWAYS use voip audio mode. 1825 call.setIsVoipAudioMode(true); 1826 call.setVisibleToInCallService(phoneAccountExtra == null 1827 || phoneAccountExtra.getBoolean( 1828 PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true)); 1829 } 1830 call.setAssociatedUser(initiatingUser); 1831 isReusedCall = false; 1832 } else { 1833 isReusedCall = true; 1834 } 1835 // It's important to start tracking self-managed calls as soon as the Call object is 1836 // initialized so NotificationManagerService is aware Telecom is setting up a call 1837 if (isSelfManaged) mSelfManagedCallsBeingSetup.add(call); 1838 1839 int videoState = VideoProfile.STATE_AUDIO_ONLY; 1840 if (extras != null) { 1841 // Set the video state on the call early so that when it is added to the InCall UI the 1842 // UI knows to configure itself as a video call immediately. 1843 videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 1844 VideoProfile.STATE_AUDIO_ONLY); 1845 1846 // If this is an emergency video call, we need to check if the phone account supports 1847 // emergency video calling. 1848 // Also, ensure we don't try to place an outgoing call with video if video is not 1849 // supported. 1850 if (VideoProfile.isVideo(videoState)) { 1851 if (call.isEmergencyCall() && account != null && 1852 !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) { 1853 // Phone account doesn't support emergency video calling, so fallback to 1854 // audio-only now to prevent the InCall UI from setting up video surfaces 1855 // needlessly. 1856 Log.i(this, "startOutgoingCall - emergency video calls not supported; " + 1857 "falling back to audio-only"); 1858 videoState = VideoProfile.STATE_AUDIO_ONLY; 1859 } else if (account != null && 1860 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 1861 // Phone account doesn't support video calling, so fallback to audio-only. 1862 Log.i(this, "startOutgoingCall - video calls not supported; fallback to " + 1863 "audio-only."); 1864 videoState = VideoProfile.STATE_AUDIO_ONLY; 1865 } 1866 } 1867 1868 call.setVideoState(videoState); 1869 } 1870 1871 final int finalVideoState = videoState; 1872 final Call finalCall = call; 1873 Handler outgoingCallHandler = new Handler(Looper.getMainLooper()); 1874 // Create a empty CompletableFuture and compose it with findOutgoingPhoneAccount to get 1875 // a first guess at the list of suitable outgoing PhoneAccounts. 1876 // findOutgoingPhoneAccount returns a CompletableFuture which is either already complete 1877 // (in the case where we don't need to do the per-contact lookup) or a CompletableFuture 1878 // that completes once the contact lookup via CallerInfoLookupHelper is complete. 1879 CompletableFuture<List<PhoneAccountHandle>> accountsForCall = 1880 CompletableFuture.completedFuture((Void) null).thenComposeAsync((x) -> 1881 findOutgoingCallPhoneAccount(requestedAccountHandle, handle, 1882 VideoProfile.isVideo(finalVideoState), 1883 finalCall.isEmergencyCall(), initiatingUser, 1884 isConference), 1885 new LoggedHandlerExecutor(outgoingCallHandler, "CM.fOCP", mLock)); 1886 1887 // This is a block of code that executes after the list of potential phone accts has been 1888 // retrieved. 1889 CompletableFuture<List<PhoneAccountHandle>> setAccountHandle = 1890 accountsForCall.whenCompleteAsync((potentialPhoneAccounts, exception) -> { 1891 if (exception != null){ 1892 Log.e(TAG, exception, "Error retrieving list of potential phone accounts."); 1893 if (finalCall.isEmergencyCall()) { 1894 mAnomalyReporter.reportAnomaly( 1895 EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_EMERGENCY_ERROR_UUID, 1896 EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_EMERGENCY_ERROR_MSG); 1897 } else { 1898 mAnomalyReporter.reportAnomaly( 1899 EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_ERROR_UUID, 1900 EXCEPTION_RETRIEVING_PHONE_ACCOUNTS_ERROR_MSG); 1901 } 1902 } 1903 Log.i(CallsManager.this, "set outgoing call phone acct; potentialAccts=%s", 1904 potentialPhoneAccounts); 1905 PhoneAccountHandle phoneAccountHandle; 1906 if (potentialPhoneAccounts.size() == 1) { 1907 phoneAccountHandle = potentialPhoneAccounts.get(0); 1908 } else { 1909 phoneAccountHandle = null; 1910 } 1911 finalCall.setTargetPhoneAccount(phoneAccountHandle); 1912 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.sOCPA", mLock)); 1913 1914 1915 // This composes the future containing the potential phone accounts with code that queries 1916 // the suggestion service if necessary (i.e. if the list is longer than 1). 1917 // If the suggestion service is queried, the inner lambda will return a future that 1918 // completes when the suggestion service calls the callback. 1919 CompletableFuture<List<PhoneAccountSuggestion>> suggestionFuture = accountsForCall. 1920 thenComposeAsync(potentialPhoneAccounts -> { 1921 Log.i(CallsManager.this, "call outgoing call suggestion service stage"); 1922 if (potentialPhoneAccounts.size() == 1) { 1923 PhoneAccountSuggestion suggestion = 1924 new PhoneAccountSuggestion(potentialPhoneAccounts.get(0), 1925 PhoneAccountSuggestion.REASON_NONE, true); 1926 return CompletableFuture.completedFuture( 1927 Collections.singletonList(suggestion)); 1928 } 1929 return PhoneAccountSuggestionHelper.bindAndGetSuggestions(mContext, 1930 finalCall.getHandle(), potentialPhoneAccounts); 1931 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.cOCSS", mLock)); 1932 1933 1934 // This future checks the status of existing calls and attempts to make room for the 1935 // outgoing call. The future returned by the inner method will usually be pre-completed -- 1936 // we only pause here if user interaction is required to disconnect a self-managed call. 1937 // It runs after the account handle is set, independently of the phone account suggestion 1938 // future. 1939 CompletableFuture<Call> makeRoomForCall = setAccountHandle.thenComposeAsync( 1940 potentialPhoneAccounts -> { 1941 Log.i(CallsManager.this, "make room for outgoing call stage"); 1942 if (mMmiUtils.isPotentialInCallMMICode(handle) && !isSelfManaged) { 1943 return CompletableFuture.completedFuture(finalCall); 1944 } 1945 // If a call is being reused, then it has already passed the 1946 // makeRoomForOutgoingCall check once and will fail the second time due to the 1947 // call transitioning into the CONNECTING state. 1948 if (isReusedCall) { 1949 return CompletableFuture.completedFuture(finalCall); 1950 } else { 1951 Call reusableCall = reuseOutgoingCall(handle); 1952 if (reusableCall != null) { 1953 Log.i(CallsManager.this, 1954 "reusable call %s came in later; disconnect it.", 1955 reusableCall.getId()); 1956 mPendingCallsToDisconnect.remove(reusableCall); 1957 reusableCall.disconnect(); 1958 markCallAsDisconnected(reusableCall, 1959 new DisconnectCause(DisconnectCause.CANCELED)); 1960 } 1961 } 1962 1963 if (!finalCall.isEmergencyCall() && isInEmergencyCall()) { 1964 Log.i(CallsManager.this, "Aborting call since there's an" 1965 + " ongoing emergency call"); 1966 // If the ongoing call is a managed call, we will prevent the outgoing 1967 // call from dialing. 1968 if (isConference) { 1969 notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(), 1970 finalCall); 1971 } else { 1972 notifyCreateConnectionFailed( 1973 finalCall.getTargetPhoneAccount(), finalCall); 1974 } 1975 finalCall.setStartFailCause(CallFailureCause.IN_EMERGENCY_CALL); 1976 return CompletableFuture.completedFuture(null); 1977 } 1978 1979 // If we can not supportany more active calls, our options are to move a call 1980 // to hold, disconnect a call, or cancel this call altogether. 1981 boolean isRoomForCall = finalCall.isEmergencyCall() ? 1982 makeRoomForOutgoingEmergencyCall(finalCall) : 1983 makeRoomForOutgoingCall(finalCall); 1984 if (!isRoomForCall) { 1985 Call foregroundCall = getForegroundCall(); 1986 Log.d(CallsManager.this, "No more room for outgoing call %s ", finalCall); 1987 if (foregroundCall.isSelfManaged()) { 1988 // If the ongoing call is a self-managed call, then prompt the user to 1989 // ask if they'd like to disconnect their ongoing call and place the 1990 // outgoing call. 1991 Log.i(CallsManager.this, "Prompting user to disconnect " 1992 + "self-managed call"); 1993 finalCall.setOriginalCallIntent(originalIntent); 1994 CompletableFuture<Call> completionFuture = new CompletableFuture<>(); 1995 startCallConfirmation(finalCall, completionFuture); 1996 return completionFuture; 1997 } else { 1998 // If the ongoing call is a managed call, we will prevent the outgoing 1999 // call from dialing. 2000 if (isConference) { 2001 notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(), 2002 finalCall); 2003 } else { 2004 notifyCreateConnectionFailed( 2005 finalCall.getTargetPhoneAccount(), finalCall); 2006 } 2007 } 2008 Log.i(CallsManager.this, "Aborting call since there's no room"); 2009 return CompletableFuture.completedFuture(null); 2010 } 2011 return CompletableFuture.completedFuture(finalCall); 2012 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.dSMCP", mLock)); 2013 2014 // The outgoing call can be placed, go forward. This future glues together the results of 2015 // the account suggestion stage and the make room for call stage. 2016 CompletableFuture<Pair<Call, List<PhoneAccountSuggestion>>> preSelectStage = 2017 makeRoomForCall.thenCombine(suggestionFuture, Pair::create); 2018 mLatestPreAccountSelectionFuture = preSelectStage; 2019 2020 // This future takes the list of suggested accounts and the call and determines if more 2021 // user interaction in the form of a phone account selection screen is needed. If so, it 2022 // will set the call to SELECT_PHONE_ACCOUNT, add it to our internal list/send it to dialer, 2023 // and then execution will pause pending the dialer calling phoneAccountSelected. 2024 CompletableFuture<Pair<Call, PhoneAccountHandle>> dialerSelectPhoneAccountFuture = 2025 preSelectStage.thenComposeAsync( 2026 (args) -> { 2027 Log.i(CallsManager.this, "dialer phone acct select stage"); 2028 Call callToPlace = args.first; 2029 List<PhoneAccountSuggestion> accountSuggestions = args.second; 2030 if (callToPlace == null) { 2031 return CompletableFuture.completedFuture(null); 2032 } 2033 if (accountSuggestions == null || accountSuggestions.isEmpty()) { 2034 Uri callUri = callToPlace.getHandle(); 2035 if (PhoneAccount.SCHEME_TEL.equals(callUri.getScheme())) { 2036 int managedProfileUserId = getManagedProfileUserId(mContext, 2037 initiatingUser.getIdentifier()); 2038 if (managedProfileUserId != UserHandle.USER_NULL 2039 && 2040 mPhoneAccountRegistrar.getCallCapablePhoneAccounts( 2041 handle.getScheme(), false, 2042 UserHandle.of(managedProfileUserId), 2043 false).size() 2044 != 0) { 2045 boolean dialogShown = showSwitchToManagedProfileDialog( 2046 callUri, initiatingUser, managedProfileUserId); 2047 if (dialogShown) { 2048 return CompletableFuture.completedFuture(null); 2049 } 2050 } 2051 } 2052 2053 Log.i(CallsManager.this, "Aborting call since there are no" 2054 + " available accounts."); 2055 showErrorMessage(R.string.cant_call_due_to_no_supported_service); 2056 mListeners.forEach(l -> l.onCreateConnectionFailed(callToPlace)); 2057 if (callToPlace.isEmergencyCall()){ 2058 mAnomalyReporter.reportAnomaly( 2059 EMERGENCY_CALL_ABORTED_NO_PHONE_ACCOUNTS_ERROR_UUID, 2060 EMERGENCY_CALL_ABORTED_NO_PHONE_ACCOUNTS_ERROR_MSG); 2061 } 2062 return CompletableFuture.completedFuture(null); 2063 } 2064 boolean needsAccountSelection = accountSuggestions.size() > 1 2065 && !callToPlace.isEmergencyCall() && !isSelfManaged; 2066 if (!needsAccountSelection) { 2067 return CompletableFuture.completedFuture(Pair.create(callToPlace, 2068 accountSuggestions.get(0).getPhoneAccountHandle())); 2069 } 2070 // This is the state where the user is expected to select an account 2071 callToPlace.setState(CallState.SELECT_PHONE_ACCOUNT, 2072 "needs account selection"); 2073 // Create our own instance to modify (since extras may be Bundle.EMPTY) 2074 Bundle newExtras = new Bundle(extras); 2075 List<PhoneAccountHandle> accountsFromSuggestions = accountSuggestions 2076 .stream() 2077 .map(PhoneAccountSuggestion::getPhoneAccountHandle) 2078 .collect(Collectors.toList()); 2079 newExtras.putParcelableList( 2080 android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, 2081 accountsFromSuggestions); 2082 newExtras.putParcelableList( 2083 android.telecom.Call.EXTRA_SUGGESTED_PHONE_ACCOUNTS, 2084 accountSuggestions); 2085 // Set a future in place so that we can proceed once the dialer replies. 2086 mPendingAccountSelection = new CompletableFuture<>(); 2087 callToPlace.setIntentExtras(newExtras); 2088 2089 addCall(callToPlace); 2090 return mPendingAccountSelection; 2091 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.dSPA", mLock)); 2092 2093 // Potentially perform call identification for dialed TEL scheme numbers. 2094 if (PhoneAccount.SCHEME_TEL.equals(handle.getScheme())) { 2095 // Perform an asynchronous contacts lookup in this stage; ensure post-dial digits are 2096 // not included. 2097 CompletableFuture<Pair<Uri, CallerInfo>> contactLookupFuture = 2098 mCallerInfoLookupHelper.startLookup(Uri.fromParts(handle.getScheme(), 2099 PhoneNumberUtils.extractNetworkPortion(handle.getSchemeSpecificPart()), 2100 null)); 2101 2102 // Once the phone account selection stage has completed, we can handle the results from 2103 // that with the contacts lookup in order to determine if we should lookup bind to the 2104 // CallScreeningService in order for it to potentially provide caller ID. 2105 dialerSelectPhoneAccountFuture.thenAcceptBothAsync(contactLookupFuture, 2106 (callPhoneAccountHandlePair, uriCallerInfoPair) -> { 2107 Call theCall = callPhoneAccountHandlePair.first; 2108 UserHandle userHandleForCallScreening = theCall. 2109 getAssociatedUser(); 2110 boolean isInContacts = uriCallerInfoPair.second != null 2111 && uriCallerInfoPair.second.contactExists; 2112 Log.d(CallsManager.this, "outgoingCallIdStage: isInContacts=%s", 2113 isInContacts); 2114 2115 // We only want to provide a CallScreeningService with a call if its not in 2116 // contacts or the package has READ_CONTACT permission. 2117 PackageManager packageManager = mContext.getPackageManager(); 2118 int permission = packageManager.checkPermission( 2119 Manifest.permission.READ_CONTACTS, 2120 mRoleManagerAdapter. 2121 getDefaultCallScreeningApp(userHandleForCallScreening)); 2122 Log.d(CallsManager.this, 2123 "default call screening service package %s has permissions=%s", 2124 mRoleManagerAdapter. 2125 getDefaultCallScreeningApp(userHandleForCallScreening), 2126 permission == PackageManager.PERMISSION_GRANTED); 2127 if ((!isInContacts) || (permission == PackageManager.PERMISSION_GRANTED)) { 2128 bindForOutgoingCallerId(theCall); 2129 } 2130 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.pCSB", mLock)); 2131 } 2132 2133 // Finally, after all user interaction is complete, we execute this code to finish setting 2134 // up the outgoing call. The inner method always returns a completed future containing the 2135 // call that we've finished setting up. 2136 mLatestPostSelectionProcessingFuture = dialerSelectPhoneAccountFuture 2137 .thenComposeAsync(args -> { 2138 if (args == null) { 2139 return CompletableFuture.completedFuture(null); 2140 } 2141 Log.i(CallsManager.this, "post acct selection stage"); 2142 Call callToUse = args.first; 2143 PhoneAccountHandle phoneAccountHandle = args.second; 2144 PhoneAccount accountToUse = mPhoneAccountRegistrar 2145 .getPhoneAccount(phoneAccountHandle, initiatingUser); 2146 callToUse.setTargetPhoneAccount(phoneAccountHandle); 2147 if (accountToUse != null && accountToUse.getExtras() != null) { 2148 if (accountToUse.getExtras() 2149 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 2150 Log.d(this, "startOutgoingCall: defaulting to voip mode for call %s", 2151 callToUse.getId()); 2152 callToUse.setIsVoipAudioMode(true); 2153 } 2154 } 2155 2156 callToUse.setState( 2157 CallState.CONNECTING, 2158 phoneAccountHandle == null ? "no-handle" 2159 : phoneAccountHandle.toString()); 2160 2161 boolean isVoicemail = isVoicemail(callToUse.getHandle(), accountToUse); 2162 2163 boolean isRttSettingOn = isRttSettingOn(phoneAccountHandle); 2164 if (!isVoicemail && (isRttSettingOn || (extras != null 2165 && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, 2166 false)))) { 2167 Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", 2168 isRttSettingOn); 2169 if (callToUse.isEmergencyCall() || (accountToUse != null 2170 && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT))) { 2171 // If the call requested RTT and it's an emergency call, ignore the 2172 // capability and hope that the modem will deal with it somehow. 2173 callToUse.createRttStreams(); 2174 } 2175 // Even if the phone account doesn't support RTT yet, 2176 // the connection manager might change that. Set this to check it later. 2177 callToUse.setRequestedToStartWithRtt(); 2178 } 2179 2180 setIntentExtrasAndStartTime(callToUse, extras); 2181 setCallSourceToAnalytics(callToUse, originalIntent); 2182 2183 if (mMmiUtils.isPotentialMMICode(handle) && !isSelfManaged) { 2184 // Do not add the call if it is a potential MMI code. 2185 callToUse.addListener(this); 2186 } else if (!mCalls.contains(callToUse)) { 2187 // We check if mCalls already contains the call because we could 2188 // potentially be reusing 2189 // a call which was previously added (See {@link #reuseOutgoingCall}). 2190 addCall(callToUse); 2191 } 2192 return CompletableFuture.completedFuture(callToUse); 2193 }, new LoggedHandlerExecutor(outgoingCallHandler, "CM.pASP", mLock)); 2194 return mLatestPostSelectionProcessingFuture; 2195 } 2196 getManagedProfileUserId(Context context, int userId)2197 private static int getManagedProfileUserId(Context context, int userId) { 2198 UserManager um = context.getSystemService(UserManager.class); 2199 List<UserInfo> userProfiles = um.getProfiles(userId); 2200 for (UserInfo uInfo : userProfiles) { 2201 if (uInfo.id == userId) { 2202 continue; 2203 } 2204 if (uInfo.isManagedProfile()) { 2205 return uInfo.id; 2206 } 2207 } 2208 return UserHandle.USER_NULL; 2209 } 2210 showSwitchToManagedProfileDialog(Uri callUri, UserHandle initiatingUser, int managedProfileUserId)2211 private boolean showSwitchToManagedProfileDialog(Uri callUri, UserHandle initiatingUser, 2212 int managedProfileUserId) { 2213 // Note that the ACTION_CALL intent will resolve to Telecomm's UserCallActivity 2214 // even if there is no dialer. Hence we explicitly check for whether a default dialer 2215 // exists instead of relying on ActivityNotFound when sending the call intent. 2216 if (TextUtils.isEmpty( 2217 mDefaultDialerCache.getDefaultDialerApplication(managedProfileUserId))) { 2218 Log.i( 2219 this, 2220 "Work profile telephony: default dialer app missing, showing error dialog."); 2221 return maybeShowErrorDialog(callUri, managedProfileUserId, initiatingUser); 2222 } 2223 2224 UserManager userManager = mContext.getSystemService(UserManager.class); 2225 if (userManager.isQuietModeEnabled(UserHandle.of(managedProfileUserId))) { 2226 Log.i( 2227 this, 2228 "Work profile telephony: quiet mode enabled, showing error dialog"); 2229 return maybeShowErrorDialog(callUri, managedProfileUserId, initiatingUser); 2230 } 2231 Log.i( 2232 this, 2233 "Work profile telephony: show forwarding call to managed profile dialog"); 2234 return maybeRedirectToIntentForwarder(callUri, initiatingUser); 2235 } 2236 maybeRedirectToIntentForwarder( Uri callUri, UserHandle initiatingUser)2237 private boolean maybeRedirectToIntentForwarder( 2238 Uri callUri, 2239 UserHandle initiatingUser) { 2240 // Note: This intent is selected to match the CALL_MANAGED_PROFILE filter in 2241 // DefaultCrossProfileIntentFiltersUtils. This ensures that it is redirected to 2242 // IntentForwarderActivity. 2243 Intent forwardCallIntent = new Intent(Intent.ACTION_CALL, callUri); 2244 forwardCallIntent.addCategory(Intent.CATEGORY_DEFAULT); 2245 ResolveInfo resolveInfos = 2246 mContext.getPackageManager() 2247 .resolveActivityAsUser( 2248 forwardCallIntent, 2249 ResolveInfoFlags.of(0), 2250 initiatingUser.getIdentifier()); 2251 // Check that the intent will actually open the resolver rather than looping to the personal 2252 // profile. This should not happen due to the cross profile intent filters. 2253 if (resolveInfos == null 2254 || !resolveInfos 2255 .getComponentInfo() 2256 .getComponentName() 2257 .getShortClassName() 2258 .equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) { 2259 Log.w( 2260 this, 2261 "Work profile telephony: Intent would not resolve to forwarder activity."); 2262 return false; 2263 } 2264 2265 try { 2266 mContext.startActivityAsUser(forwardCallIntent, initiatingUser); 2267 return true; 2268 } catch (ActivityNotFoundException e) { 2269 Log.e(this, e, "Unable to start call intent for work telephony"); 2270 return false; 2271 } 2272 } 2273 maybeShowErrorDialog( Uri callUri, int managedProfileUserId, UserHandle initiatingUser)2274 private boolean maybeShowErrorDialog( 2275 Uri callUri, 2276 int managedProfileUserId, 2277 UserHandle initiatingUser) { 2278 Intent showErrorIntent = 2279 new Intent( 2280 TelecomManager.ACTION_SHOW_SWITCH_TO_WORK_PROFILE_FOR_CALL_DIALOG, 2281 callUri); 2282 showErrorIntent.addCategory(Intent.CATEGORY_DEFAULT); 2283 showErrorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2284 showErrorIntent.putExtra( 2285 TelecomManager.EXTRA_MANAGED_PROFILE_USER_ID, managedProfileUserId); 2286 if (mContext.getPackageManager() 2287 .queryIntentActivitiesAsUser( 2288 showErrorIntent, 2289 ResolveInfoFlags.of(0), 2290 initiatingUser) 2291 .isEmpty()) { 2292 return false; 2293 } 2294 try { 2295 mContext.startActivityAsUser(showErrorIntent, initiatingUser); 2296 return true; 2297 } catch (ActivityNotFoundException e) { 2298 Log.e( 2299 this, e,"Work profile telephony: Unable to show error dialog"); 2300 return false; 2301 } 2302 } 2303 startConference(List<Uri> participants, Bundle clientExtras, String callingPackage, UserHandle initiatingUser)2304 public void startConference(List<Uri> participants, Bundle clientExtras, String callingPackage, 2305 UserHandle initiatingUser) { 2306 2307 if (clientExtras == null) { 2308 clientExtras = new Bundle(); 2309 } 2310 2311 PhoneAccountHandle phoneAccountHandle = clientExtras.getParcelable( 2312 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); 2313 PhoneAccount account = 2314 mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser); 2315 boolean isSelfManaged = account != null && account.isSelfManaged(); 2316 // Enforce outgoing call restriction for conference calls. This is handled via 2317 // UserCallIntentProcessor for normal MO calls. 2318 if (UserUtil.hasOutgoingCallsUserRestriction(mContext, initiatingUser, 2319 null, isSelfManaged, CallsManager.class.getCanonicalName())) { 2320 return; 2321 } 2322 CompletableFuture<Call> callFuture = startOutgoingCall(participants, phoneAccountHandle, 2323 clientExtras, initiatingUser, null/* originalIntent */, callingPackage, 2324 true/* isconference*/); 2325 2326 final boolean speakerphoneOn = clientExtras.getBoolean( 2327 TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE); 2328 final int videoState = clientExtras.getInt( 2329 TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE); 2330 2331 final Session logSubsession = Log.createSubsession(); 2332 callFuture.thenAccept((call) -> { 2333 if (call != null) { 2334 Log.continueSession(logSubsession, "CM.pOGC"); 2335 try { 2336 placeOutgoingCall(call, call.getHandle(), null/* gatewayInfo */, 2337 speakerphoneOn, videoState); 2338 } finally { 2339 Log.endSession(); 2340 } 2341 } 2342 }); 2343 } 2344 2345 /** 2346 * Performs call identification for an outgoing phone call. 2347 * @param theCall The outgoing call to perform identification. 2348 */ bindForOutgoingCallerId(Call theCall)2349 private void bindForOutgoingCallerId(Call theCall) { 2350 // Find the user chosen call screening app. 2351 String callScreeningApp = 2352 mRoleManagerAdapter.getDefaultCallScreeningApp( 2353 theCall.getAssociatedUser()); 2354 2355 CompletableFuture future = 2356 new CallScreeningServiceHelper(mContext, 2357 mLock, 2358 callScreeningApp, 2359 new ParcelableCallUtils.Converter(), 2360 mCurrentUserHandle, 2361 theCall, 2362 new AppLabelProxy() { 2363 @Override 2364 public CharSequence getAppLabel(String packageName) { 2365 return Util.getAppLabel(mContext.getPackageManager(), packageName); 2366 } 2367 }).process(); 2368 future.thenApply( v -> { 2369 Log.i(this, "Outgoing caller ID complete"); 2370 return null; 2371 }); 2372 } 2373 2374 /** 2375 * Finds the {@link PhoneAccountHandle}(s) which could potentially be used to place an outgoing 2376 * call. Takes into account the following: 2377 * 1. Any pre-chosen {@link PhoneAccountHandle} which was specified on the 2378 * {@link Intent#ACTION_CALL} intent. If one was chosen it will be used if possible. 2379 * 2. Whether the call is a video call. If the call being placed is a video call, an attempt is 2380 * first made to consider video capable phone accounts. If no video capable phone accounts are 2381 * found, the usual non-video capable phone accounts will be considered. 2382 * 3. Whether there is a user-chosen default phone account; that one will be used if possible. 2383 * 2384 * @param targetPhoneAccountHandle The pre-chosen {@link PhoneAccountHandle} passed in when the 2385 * call was placed. Will be {@code null} if the 2386 * {@link Intent#ACTION_CALL} intent did not specify a target 2387 * phone account. 2388 * @param handle The handle of the outgoing call; used to determine the SIP scheme when matching 2389 * phone accounts. 2390 * @param isVideo {@code true} if the call is a video call, {@code false} otherwise. 2391 * @param isEmergency {@code true} if the call is an emergency call. 2392 * @param initiatingUser The {@link UserHandle} the call is placed on. 2393 * @return 2394 */ 2395 @VisibleForTesting findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser)2396 public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( 2397 PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, 2398 boolean isEmergency, UserHandle initiatingUser) { 2399 return findOutgoingCallPhoneAccount(targetPhoneAccountHandle, handle, isVideo, 2400 isEmergency, initiatingUser, false/* isConference */); 2401 } 2402 findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser, boolean isConference)2403 public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( 2404 PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, 2405 boolean isEmergency, UserHandle initiatingUser, boolean isConference) { 2406 2407 if (isSelfManaged(targetPhoneAccountHandle, initiatingUser)) { 2408 return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); 2409 } 2410 2411 List<PhoneAccountHandle> accounts; 2412 // Try to find a potential phone account, taking into account whether this is a video 2413 // call. 2414 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo, isEmergency, 2415 isConference); 2416 if (isVideo && accounts.size() == 0) { 2417 // Placing a video call but no video capable accounts were found, so consider any 2418 // call capable accounts (we can fallback to audio). 2419 accounts = constructPossiblePhoneAccounts(handle, initiatingUser, 2420 false /* isVideo */, isEmergency /* isEmergency */, isConference); 2421 } 2422 Log.v(this, "findOutgoingCallPhoneAccount: accounts = " + accounts); 2423 2424 // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this 2425 // call as if a phoneAccount was not specified (does the default behavior instead). 2426 // Note: We will not attempt to dial with a requested phoneAccount if it is disabled. 2427 if (targetPhoneAccountHandle != null) { 2428 if (accounts.contains(targetPhoneAccountHandle)) { 2429 // The target phone account is valid and was found. 2430 return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); 2431 } 2432 } 2433 if (accounts.isEmpty() || accounts.size() == 1) { 2434 return CompletableFuture.completedFuture(accounts); 2435 } 2436 2437 // Do the query for whether there's a preferred contact 2438 final CompletableFuture<PhoneAccountHandle> userPreferredAccountForContact = 2439 new CompletableFuture<>(); 2440 final List<PhoneAccountHandle> possibleAccounts = accounts; 2441 mCallerInfoLookupHelper.startLookup(handle, 2442 new CallerInfoLookupHelper.OnQueryCompleteListener() { 2443 @Override 2444 public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { 2445 if (info != null && 2446 info.preferredPhoneAccountComponent != null && 2447 info.preferredPhoneAccountId != null && 2448 !info.preferredPhoneAccountId.isEmpty()) { 2449 PhoneAccountHandle contactDefaultHandle = new PhoneAccountHandle( 2450 info.preferredPhoneAccountComponent, 2451 info.preferredPhoneAccountId, 2452 initiatingUser); 2453 userPreferredAccountForContact.complete(contactDefaultHandle); 2454 } else { 2455 userPreferredAccountForContact.complete(null); 2456 } 2457 } 2458 2459 @Override 2460 public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { 2461 // ignore this 2462 } 2463 }); 2464 2465 return userPreferredAccountForContact.thenApply(phoneAccountHandle -> { 2466 if (phoneAccountHandle != null) { 2467 Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; contactPrefAcct=%s", 2468 phoneAccountHandle); 2469 return Collections.singletonList(phoneAccountHandle); 2470 } 2471 // No preset account, check if default exists that supports the URI scheme for the 2472 // handle and verify it can be used. 2473 PhoneAccountHandle defaultPhoneAccountHandle = 2474 mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme( 2475 handle.getScheme(), initiatingUser); 2476 if (defaultPhoneAccountHandle != null && 2477 possibleAccounts.contains(defaultPhoneAccountHandle)) { 2478 Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; defaultAcctForScheme=%s", 2479 defaultPhoneAccountHandle); 2480 return Collections.singletonList(defaultPhoneAccountHandle); 2481 } 2482 return possibleAccounts; 2483 }); 2484 } 2485 2486 /** 2487 * Determines if a {@link PhoneAccountHandle} is for a self-managed ConnectionService. 2488 * @param targetPhoneAccountHandle The phone account to check. 2489 * @param initiatingUser The user associated with the account. 2490 * @return {@code true} if the phone account is self-managed, {@code false} otherwise. 2491 */ 2492 public boolean isSelfManaged(PhoneAccountHandle targetPhoneAccountHandle, 2493 UserHandle initiatingUser) { 2494 PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount( 2495 targetPhoneAccountHandle, initiatingUser); 2496 return targetPhoneAccount != null && targetPhoneAccount.isSelfManaged(); 2497 } 2498 2499 public void onCallRedirectionComplete(Call call, Uri handle, 2500 PhoneAccountHandle phoneAccountHandle, 2501 GatewayInfo gatewayInfo, boolean speakerphoneOn, 2502 int videoState, boolean shouldCancelCall, 2503 String uiAction) { 2504 Log.i(this, "onCallRedirectionComplete for Call %s with handle %s" + 2505 " and phoneAccountHandle %s", call, Log.pii(handle), phoneAccountHandle); 2506 2507 boolean endEarly = false; 2508 String disconnectReason = ""; 2509 String callRedirectionApp = mRoleManagerAdapter.getDefaultCallRedirectionApp( 2510 phoneAccountHandle.getUserHandle()); 2511 PhoneAccount phoneAccount = mPhoneAccountRegistrar 2512 .getPhoneAccountUnchecked(phoneAccountHandle); 2513 if (phoneAccount != null 2514 && !phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) { 2515 // Note that mCurrentUserHandle may not actually be the current user, i.e. 2516 // in the case of work profiles 2517 UserHandle currentUserHandle = call.getAssociatedUser(); 2518 // Check if the phoneAccountHandle belongs to the current user 2519 if (phoneAccountHandle != null && 2520 !phoneAccountHandle.getUserHandle().equals(currentUserHandle)) { 2521 phoneAccountHandle = null; 2522 } 2523 } 2524 2525 boolean isEmergencyNumber; 2526 try { 2527 isEmergencyNumber = 2528 handle != null && getTelephonyManager().isEmergencyNumber( 2529 handle.getSchemeSpecificPart()); 2530 } catch (IllegalStateException ise) { 2531 isEmergencyNumber = false; 2532 } catch (RuntimeException r) { 2533 isEmergencyNumber = false; 2534 } 2535 2536 if (shouldCancelCall) { 2537 Log.w(this, "onCallRedirectionComplete: call is canceled"); 2538 endEarly = true; 2539 disconnectReason = "Canceled from Call Redirection Service"; 2540 2541 // Show UX when user-defined call redirection service does not response; the UX 2542 // is not needed to show if the call is disconnected (e.g. by the user) 2543 if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT) 2544 && !call.isDisconnected()) { 2545 Intent timeoutIntent = new Intent(mContext, 2546 CallRedirectionTimeoutDialogActivity.class); 2547 timeoutIntent.putExtra( 2548 CallRedirectionTimeoutDialogActivity.EXTRA_REDIRECTION_APP_NAME, 2549 mRoleManagerAdapter.getApplicationLabelForPackageName(callRedirectionApp)); 2550 timeoutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2551 mContext.startActivityAsUser(timeoutIntent, UserHandle.CURRENT); 2552 } 2553 } else if (handle == null) { 2554 Log.w(this, "onCallRedirectionComplete: handle is null"); 2555 endEarly = true; 2556 disconnectReason = "Null handle from Call Redirection Service"; 2557 } else if (phoneAccountHandle == null) { 2558 Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is unavailable"); 2559 endEarly = true; 2560 disconnectReason = "Unavailable phoneAccountHandle from Call Redirection Service"; 2561 } else if (isEmergencyNumber) { 2562 Log.w(this, "onCallRedirectionComplete: emergency number %s is redirected from Call" 2563 + " Redirection Service", handle.getSchemeSpecificPart()); 2564 endEarly = true; 2565 disconnectReason = "Emergency number is redirected from Call Redirection Service"; 2566 } 2567 if (endEarly) { 2568 if (call != null) { 2569 call.disconnect(disconnectReason); 2570 } 2571 return; 2572 } 2573 2574 // If this call is already disconnected then we have nothing more to do. 2575 if (call.isDisconnected()) { 2576 Log.w(this, "onCallRedirectionComplete: Call has already been disconnected," 2577 + " ignore the call redirection %s", call); 2578 return; 2579 } 2580 2581 final PhoneAccountHandle finalPhoneAccountHandle = phoneAccountHandle; 2582 if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM)) { 2583 Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMATION); 2584 mPendingRedirectedOutgoingCall = call; 2585 2586 mPendingRedirectedOutgoingCallInfo.put(call.getId(), 2587 new Runnable("CM.oCRC", mLock) { 2588 @Override 2589 public void loggedRun() { 2590 Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMED); 2591 call.setTargetPhoneAccount(finalPhoneAccountHandle); 2592 placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, 2593 videoState); 2594 } 2595 }); 2596 2597 mPendingUnredirectedOutgoingCallInfo.put(call.getId(), 2598 new Runnable("CM.oCRC", mLock) { 2599 @Override 2600 public void loggedRun() { 2601 call.setTargetPhoneAccount(finalPhoneAccountHandle); 2602 placeOutgoingCall(call, handle, null, speakerphoneOn, 2603 videoState); 2604 } 2605 }); 2606 2607 Log.i(this, "onCallRedirectionComplete: UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM " 2608 + "callId=%s, callRedirectionAppName=%s", 2609 call.getId(), callRedirectionApp); 2610 2611 showRedirectionDialog(call.getId(), 2612 mRoleManagerAdapter.getApplicationLabelForPackageName(callRedirectionApp)); 2613 } else { 2614 call.setTargetPhoneAccount(phoneAccountHandle); 2615 placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState); 2616 } 2617 } 2618 2619 /** 2620 * Shows the call redirection confirmation dialog. This is explicitly done here instead of in 2621 * an activity class such as {@link ConfirmCallDialogActivity}. This was originally done with 2622 * an activity class, however due to the fact that the InCall UI is being spun up at the same 2623 * time as the dialog activity, there is a potential race condition where the InCall UI will 2624 * often be shown instead of the dialog. Activity manager chooses not to show the redirection 2625 * dialog in that case since the new top activity from dialer is going to show. 2626 * By showing the dialog here we're able to set the dialog's window type to 2627 * {@link WindowManager.LayoutParams#TYPE_SYSTEM_ALERT} which guarantees it shows above other 2628 * content on the screen. 2629 * @param callId The ID of the call to show the redirection dialog for. 2630 */ 2631 private void showRedirectionDialog(@NonNull String callId, @NonNull CharSequence appName) { 2632 AlertDialog confirmDialog = (new AlertDialog.Builder(mContext)).create(); 2633 LayoutInflater layoutInflater = LayoutInflater.from(mContext); 2634 View dialogView = layoutInflater.inflate(R.layout.call_redirection_confirm_dialog, null); 2635 2636 Button buttonFirstLine = (Button) dialogView.findViewById(R.id.buttonFirstLine); 2637 buttonFirstLine.setOnClickListener(new View.OnClickListener() { 2638 @Override 2639 public void onClick(View v) { 2640 Intent proceedWithoutRedirectedCall = new Intent( 2641 TelecomBroadcastIntentProcessor.ACTION_PLACE_UNREDIRECTED_CALL, 2642 null, mContext, 2643 TelecomBroadcastReceiver.class); 2644 proceedWithoutRedirectedCall.putExtra( 2645 TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID, 2646 callId); 2647 mContext.sendBroadcast(proceedWithoutRedirectedCall); 2648 confirmDialog.dismiss(); 2649 } 2650 }); 2651 2652 Button buttonSecondLine = (Button) dialogView.findViewById(R.id.buttonSecondLine); 2653 buttonSecondLine.setText(mContext.getString( 2654 R.string.alert_place_outgoing_call_with_redirection, appName)); 2655 buttonSecondLine.setOnClickListener(new View.OnClickListener() { 2656 @Override 2657 public void onClick(View v) { 2658 Intent proceedWithRedirectedCall = new Intent( 2659 TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL, null, 2660 mContext, 2661 TelecomBroadcastReceiver.class); 2662 proceedWithRedirectedCall.putExtra( 2663 TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID, 2664 callId); 2665 mContext.sendBroadcast(proceedWithRedirectedCall); 2666 confirmDialog.dismiss(); 2667 } 2668 }); 2669 2670 Button buttonThirdLine = (Button) dialogView.findViewById(R.id.buttonThirdLine); 2671 buttonThirdLine.setOnClickListener(new View.OnClickListener() { 2672 public void onClick(View v) { 2673 cancelRedirection(callId); 2674 confirmDialog.dismiss(); 2675 } 2676 }); 2677 2678 confirmDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 2679 @Override 2680 public void onCancel(DialogInterface dialog) { 2681 cancelRedirection(callId); 2682 confirmDialog.dismiss(); 2683 } 2684 }); 2685 2686 confirmDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 2687 confirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2688 2689 confirmDialog.setCancelable(false); 2690 confirmDialog.setCanceledOnTouchOutside(false); 2691 confirmDialog.setView(dialogView); 2692 2693 confirmDialog.show(); 2694 } 2695 2696 /** 2697 * Signals to Telecom that redirection of the call is to be cancelled. 2698 */ 2699 private void cancelRedirection(String callId) { 2700 Intent cancelRedirectedCall = new Intent( 2701 TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL, 2702 null, mContext, 2703 TelecomBroadcastReceiver.class); 2704 cancelRedirectedCall.putExtra( 2705 TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID, callId); 2706 mContext.sendBroadcastAsUser(cancelRedirectedCall, UserHandle.CURRENT); 2707 } 2708 2709 public void processRedirectedOutgoingCallAfterUserInteraction(String callId, String action) { 2710 Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for Call ID %s, action=%s", 2711 callId, action); 2712 if (mPendingRedirectedOutgoingCall != null) { 2713 String pendingCallId = mPendingRedirectedOutgoingCall.getId(); 2714 if (!pendingCallId.equals(callId)) { 2715 Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for new Call ID %s, " 2716 + "cancel the previous pending Call with ID %s", callId, pendingCallId); 2717 mPendingRedirectedOutgoingCall.disconnect("Another call redirection requested"); 2718 mPendingRedirectedOutgoingCallInfo.remove(pendingCallId); 2719 mPendingUnredirectedOutgoingCallInfo.remove(pendingCallId); 2720 } 2721 switch (action) { 2722 case TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL: { 2723 Runnable r = mPendingRedirectedOutgoingCallInfo.get(callId); 2724 if (r != null) { 2725 mHandler.post(r.prepare()); 2726 } else { 2727 Log.w(this, "Processing %s for canceled Call ID %s", 2728 action, callId); 2729 } 2730 break; 2731 } 2732 case TelecomBroadcastIntentProcessor.ACTION_PLACE_UNREDIRECTED_CALL: { 2733 Runnable r = mPendingUnredirectedOutgoingCallInfo.get(callId); 2734 if (r != null) { 2735 mHandler.post(r.prepare()); 2736 } else { 2737 Log.w(this, "Processing %s for canceled Call ID %s", 2738 action, callId); 2739 } 2740 break; 2741 } 2742 case TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL: { 2743 Log.addEvent(mPendingRedirectedOutgoingCall, 2744 LogUtils.Events.REDIRECTION_USER_CANCELLED); 2745 mPendingRedirectedOutgoingCall.disconnect("User canceled the redirected call."); 2746 break; 2747 } 2748 default: { 2749 // Unexpected, ignore 2750 } 2751 2752 } 2753 mPendingRedirectedOutgoingCall = null; 2754 mPendingRedirectedOutgoingCallInfo.remove(callId); 2755 mPendingUnredirectedOutgoingCallInfo.remove(callId); 2756 } else { 2757 Log.w(this, "processRedirectedOutgoingCallAfterUserInteraction for non-matched Call ID" 2758 + " %s", callId); 2759 } 2760 } 2761 2762 /** 2763 * Attempts to issue/connect the specified call. 2764 * 2765 * @param handle Handle to connect the call with. 2766 * @param gatewayInfo Optional gateway information that can be used to route the call to the 2767 * actual dialed handle via a gateway provider. May be null. 2768 * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects. 2769 * @param videoState The desired video state for the outgoing call. 2770 */ 2771 @VisibleForTesting 2772 public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, 2773 boolean speakerphoneOn, int videoState) { 2774 if (call == null) { 2775 // don't do anything if the call no longer exists 2776 Log.i(this, "Canceling unknown call."); 2777 return; 2778 } 2779 2780 final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress(); 2781 2782 if (gatewayInfo == null) { 2783 Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle)); 2784 } else { 2785 Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s", 2786 Log.pii(uriHandle), Log.pii(handle)); 2787 } 2788 2789 call.setHandle(uriHandle); 2790 call.setGatewayInfo(gatewayInfo); 2791 2792 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 2793 R.bool.use_speaker_when_docked); 2794 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 2795 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 2796 2797 // Auto-enable speakerphone if the originating intent specified to do so, if the call 2798 // is a video call, of if using speaker when docked 2799 PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount( 2800 call.getTargetPhoneAccount(), call.getAssociatedUser()); 2801 boolean allowVideo = false; 2802 if (account != null) { 2803 allowVideo = account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING); 2804 } 2805 call.setStartWithSpeakerphoneOn(speakerphoneOn || (useSpeakerForVideoCall && allowVideo) 2806 || (useSpeakerWhenDocked && useSpeakerForDock)); 2807 call.setVideoState(videoState); 2808 2809 if (speakerphoneOn) { 2810 Log.i(this, "%s Starting with speakerphone as requested", call); 2811 } else if (useSpeakerWhenDocked && useSpeakerForDock) { 2812 Log.i(this, "%s Starting with speakerphone because car is docked.", call); 2813 } else if (useSpeakerForVideoCall) { 2814 Log.i(this, "%s Starting with speakerphone because its a video call.", call); 2815 } 2816 2817 if (call.isEmergencyCall()) { 2818 Executors.defaultThreadFactory().newThread(() -> 2819 BlockedNumberContract.SystemContract.notifyEmergencyContact(mContext)) 2820 .start(); 2821 } 2822 2823 final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean( 2824 com.android.internal.R.bool.config_requireCallCapableAccountForHandle); 2825 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 2826 call.getTargetPhoneAccount()); 2827 final String callHandleScheme = 2828 call.getHandle() == null ? null : call.getHandle().getScheme(); 2829 if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { 2830 // If the account has been set, proceed to place the outgoing call. 2831 // Otherwise the connection will be initiated when the account is set by the user. 2832 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 2833 if (call.isAdhocConferenceCall()) { 2834 notifyCreateConferenceFailed(call.getTargetPhoneAccount(), call); 2835 } else { 2836 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 2837 } 2838 } else { 2839 if (call.isEmergencyCall()) { 2840 // Drop any ongoing self-managed calls to make way for an emergency call. 2841 disconnectSelfManagedCalls("place emerg call" /* reason */); 2842 } 2843 try { 2844 notifyStartCreateConnection(call); 2845 call.startCreateConnection(mPhoneAccountRegistrar); 2846 } catch (Exception exception) { 2847 // If an exceptions is thrown while creating the connection, prompt the user to 2848 // generate a bugreport and force disconnect. 2849 Log.e(TAG, exception, "Exception thrown while establishing connection."); 2850 mAnomalyReporter.reportAnomaly( 2851 EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_UUID, 2852 EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_MSG); 2853 markCallAsDisconnected(call, 2854 new DisconnectCause(DisconnectCause.ERROR, 2855 "Failed to create the connection.")); 2856 markCallAsRemoved(call); 2857 } 2858 2859 } 2860 } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts( 2861 requireCallCapableAccountByHandle ? callHandleScheme : null, false, 2862 call.getAssociatedUser(), false).isEmpty()) { 2863 // If there are no call capable accounts, disconnect the call. 2864 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED, 2865 "No registered PhoneAccounts")); 2866 markCallAsRemoved(call); 2867 } 2868 } 2869 2870 /** 2871 * Attempts to start a conference call for the specified call. 2872 * 2873 * @param call The call to conference. 2874 * @param otherCall The other call to conference with. 2875 */ 2876 @VisibleForTesting 2877 public void conference(Call call, Call otherCall) { 2878 call.conferenceWith(otherCall); 2879 } 2880 2881 /** 2882 * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call 2883 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 2884 * the user opting to answer said call. 2885 * 2886 * @param call The call to answer. 2887 * @param videoState The video state in which to answer the call. 2888 */ 2889 @VisibleForTesting 2890 public void answerCall(Call call, int videoState) { 2891 if (!mCalls.contains(call)) { 2892 Log.i(this, "Request to answer a non-existent call %s", call); 2893 } else if (call.isTransactionalCall()) { 2894 // InCallAdapter is requesting to answer the given transactioanl call. Must get an ack 2895 // from the client via a transaction before answering. 2896 call.answer(videoState); 2897 } else { 2898 // Hold or disconnect the active call and request call focus for the incoming call. 2899 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 2900 Log.d(this, "answerCall: Incoming call = %s Ongoing call %s", call, activeCall); 2901 holdActiveCallForNewCall(call); 2902 mConnectionSvrFocusMgr.requestFocus( 2903 call, 2904 new RequestCallback(new ActionAnswerCall(call, videoState))); 2905 } 2906 } 2907 2908 private void answerCallForAudioProcessing(Call call) { 2909 // We don't check whether the call has been added to the internal lists yet -- it's optional 2910 // until the call is actually in the AUDIO_PROCESSING state. 2911 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 2912 if (activeCall != null && activeCall != call) { 2913 Log.w(this, "answerCallForAudioProcessing: another active call already exists. " 2914 + "Ignoring request for audio processing and letting the incoming call " 2915 + "through."); 2916 // The call should already be in the RINGING state, so all we have to do is add the 2917 // call to the internal tracker. 2918 addCall(call); 2919 return; 2920 } 2921 Log.d(this, "answerCallForAudioProcessing: Incoming call = %s", call); 2922 mConnectionSvrFocusMgr.requestFocus( 2923 call, 2924 new RequestCallback(() -> { 2925 synchronized (mLock) { 2926 Log.d(this, "answering call %s for audio processing with cs focus", call); 2927 call.answerForAudioProcessing(); 2928 // Skip setting the call state to ANSWERED -- that's only for calls that 2929 // were answered by user intervention. 2930 mPendingAudioProcessingCall = call; 2931 } 2932 })); 2933 2934 } 2935 2936 /** 2937 * Instructs Telecom to bring a call into the AUDIO_PROCESSING state. 2938 * 2939 * Used by the background audio call screener (also the default dialer) to signal that 2940 * they want to manually enter the AUDIO_PROCESSING state. The user will be aware that there is 2941 * an ongoing call at this time. 2942 * 2943 * @param call The call to manipulate 2944 */ 2945 public void enterBackgroundAudioProcessing(Call call, String requestingPackageName) { 2946 if (!mCalls.contains(call)) { 2947 Log.w(this, "Trying to exit audio processing on an untracked call"); 2948 return; 2949 } 2950 2951 Call activeCall = getActiveCall(); 2952 if (activeCall != null && activeCall != call) { 2953 Log.w(this, "Ignoring enter audio processing because there's already a call active"); 2954 return; 2955 } 2956 2957 CharSequence requestingAppName = AppLabelProxy.Util.getAppLabel( 2958 mContext.getPackageManager(), requestingPackageName); 2959 if (requestingAppName == null) { 2960 requestingAppName = requestingPackageName; 2961 } 2962 2963 // We only want this to work on active or ringing calls 2964 if (call.getState() == CallState.RINGING) { 2965 // After the connection service sets up the call with the other end, it'll set the call 2966 // state to AUDIO_PROCESSING 2967 answerCallForAudioProcessing(call); 2968 call.setAudioProcessingRequestingApp(requestingAppName); 2969 } else if (call.getState() == CallState.ACTIVE) { 2970 setCallState(call, CallState.AUDIO_PROCESSING, 2971 "audio processing set by dialer request"); 2972 call.setAudioProcessingRequestingApp(requestingAppName); 2973 } 2974 } 2975 2976 /** 2977 * Instructs Telecom to bring a call out of the AUDIO_PROCESSING state. 2978 * 2979 * Used by the background audio call screener (also the default dialer) to signal that it's 2980 * finished doing its thing and the user should be made aware of the call. 2981 * 2982 * @param call The call to manipulate 2983 * @param shouldRing if true, puts the call into SIMULATED_RINGING. Otherwise, makes the call 2984 * active. 2985 */ 2986 public void exitBackgroundAudioProcessing(Call call, boolean shouldRing) { 2987 if (!mCalls.contains(call)) { 2988 Log.w(this, "Trying to exit audio processing on an untracked call"); 2989 return; 2990 } 2991 2992 Call activeCall = getActiveCall(); 2993 if (activeCall != null) { 2994 Log.w(this, "Ignoring exit audio processing because there's already a call active"); 2995 } 2996 2997 if (shouldRing) { 2998 setCallState(call, CallState.SIMULATED_RINGING, "exitBackgroundAudioProcessing"); 2999 } else { 3000 setCallState(call, CallState.ACTIVE, "exitBackgroundAudioProcessing"); 3001 } 3002 } 3003 3004 /** 3005 * Instructs Telecom to deflect the specified call. Intended to be invoked by the in-call 3006 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 3007 * the user opting to deflect said call. 3008 */ 3009 @VisibleForTesting 3010 public void deflectCall(Call call, Uri address) { 3011 if (!mCalls.contains(call)) { 3012 Log.i(this, "Request to deflect a non-existent call %s", call); 3013 } else { 3014 call.deflect(address); 3015 } 3016 } 3017 3018 /** 3019 * Determines if the speakerphone should be automatically enabled for the call. Speakerphone 3020 * should be enabled if the call is a video call and bluetooth or the wired headset are not in 3021 * use. 3022 * 3023 * @param videoState The video state of the call. 3024 * @return {@code true} if the speakerphone should be enabled. 3025 */ 3026 public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) { 3027 return VideoProfile.isVideo(videoState) && 3028 !mWiredHeadsetManager.isPluggedIn() && 3029 !mBluetoothRouteManager.isBluetoothAvailable() && 3030 isSpeakerEnabledForVideoCalls(); 3031 } 3032 3033 /** 3034 * Determines if the speakerphone should be enabled for when docked. Speakerphone 3035 * should be enabled if the device is docked and bluetooth or the wired headset are 3036 * not in use. 3037 * 3038 * @return {@code true} if the speakerphone should be enabled for the dock. 3039 */ 3040 private boolean isSpeakerphoneEnabledForDock() { 3041 return mDockManager.isDocked() && 3042 !mWiredHeadsetManager.isPluggedIn() && 3043 !mBluetoothRouteManager.isBluetoothAvailable(); 3044 } 3045 3046 /** 3047 * Determines if the speakerphone should be automatically enabled for video calls. 3048 * 3049 * @return {@code true} if the speakerphone should automatically be enabled. 3050 */ 3051 private static boolean isSpeakerEnabledForVideoCalls() { 3052 return TelephonyProperties.videocall_audio_output() 3053 .orElse(TelecomManager.AUDIO_OUTPUT_DEFAULT) 3054 == TelecomManager.AUDIO_OUTPUT_ENABLE_SPEAKER; 3055 } 3056 3057 /** 3058 * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call 3059 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 3060 * the user opting to reject said call. 3061 */ 3062 @VisibleForTesting 3063 public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) { 3064 if (!mCalls.contains(call)) { 3065 Log.i(this, "Request to reject a non-existent call %s", call); 3066 } else { 3067 for (CallsManagerListener listener : mListeners) { 3068 listener.onIncomingCallRejected(call, rejectWithMessage, textMessage); 3069 } 3070 call.reject(rejectWithMessage, textMessage); 3071 } 3072 } 3073 3074 /** 3075 * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call 3076 * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by 3077 * the user opting to reject said call. 3078 */ 3079 @VisibleForTesting 3080 public void rejectCall(Call call, @android.telecom.Call.RejectReason int rejectReason) { 3081 if (!mCalls.contains(call)) { 3082 Log.i(this, "Request to reject a non-existent call %s", call); 3083 } else { 3084 for (CallsManagerListener listener : mListeners) { 3085 listener.onIncomingCallRejected(call, false /* rejectWithMessage */, 3086 null /* textMessage */); 3087 } 3088 call.reject(rejectReason); 3089 } 3090 } 3091 3092 /** 3093 * Instructs Telecom to transfer the specified call. Intended to be invoked by the in-call 3094 * app through {@link InCallAdapter} after the user opts to transfer the said call. 3095 */ 3096 @VisibleForTesting 3097 public void transferCall(Call call, Uri number, boolean isConfirmationRequired) { 3098 if (!mCalls.contains(call)) { 3099 Log.i(this, "transferCall - Request to transfer a non-existent call %s", call); 3100 } else { 3101 call.transfer(number, isConfirmationRequired); 3102 } 3103 } 3104 3105 /** 3106 * Instructs Telecom to transfer the specified call to another ongoing call. 3107 * Intended to be invoked by the in-call app through {@link InCallAdapter} after the user opts 3108 * to transfer the said call (consultative transfer). 3109 */ 3110 @VisibleForTesting 3111 public void transferCall(Call call, Call otherCall) { 3112 if (!mCalls.contains(call) || !mCalls.contains(otherCall)) { 3113 Log.i(this, "transferCall - Non-existent call %s or %s", call, otherCall); 3114 } else { 3115 call.transfer(otherCall); 3116 } 3117 } 3118 3119 /** 3120 * Instructs Telecom to play the specified DTMF tone within the specified call. 3121 * 3122 * @param digit The DTMF digit to play. 3123 */ 3124 @VisibleForTesting 3125 public void playDtmfTone(Call call, char digit) { 3126 if (!mCalls.contains(call)) { 3127 Log.i(this, "Request to play DTMF in a non-existent call %s", call); 3128 } else { 3129 if (call.getState() != CallState.ON_HOLD) { 3130 call.playDtmfTone(digit); 3131 mDtmfLocalTonePlayer.playTone(call, digit); 3132 } else { 3133 Log.i(this, "Request to play DTMF tone for held call %s", call.getId()); 3134 } 3135 } 3136 } 3137 3138 /** 3139 * Instructs Telecom to stop the currently playing DTMF tone, if any. 3140 */ 3141 @VisibleForTesting 3142 public void stopDtmfTone(Call call) { 3143 if (!mCalls.contains(call)) { 3144 Log.i(this, "Request to stop DTMF in a non-existent call %s", call); 3145 } else { 3146 call.stopDtmfTone(); 3147 mDtmfLocalTonePlayer.stopTone(call); 3148 } 3149 } 3150 3151 /** 3152 * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any. 3153 */ 3154 void postDialContinue(Call call, boolean proceed) { 3155 if (!mCalls.contains(call)) { 3156 Log.i(this, "Request to continue post-dial string in a non-existent call %s", call); 3157 } else { 3158 call.postDialContinue(proceed); 3159 } 3160 } 3161 3162 /** 3163 * Instructs Telecom to disconnect the specified call. Intended to be invoked by the 3164 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 3165 * the user hitting the end-call button. 3166 */ 3167 @VisibleForTesting 3168 public void disconnectCall(Call call) { 3169 Log.v(this, "disconnectCall %s", call); 3170 3171 if (!mCalls.contains(call)) { 3172 Log.w(this, "Unknown call (%s) asked to disconnect", call); 3173 } else { 3174 mLocallyDisconnectingCalls.add(call); 3175 int previousState = call.getState(); 3176 call.disconnect(); 3177 for (CallsManagerListener listener : mListeners) { 3178 listener.onCallStateChanged(call, previousState, call.getState()); 3179 } 3180 // Cancel any of the outgoing call futures if they're still around. 3181 if (mPendingCallConfirm != null && !mPendingCallConfirm.isDone()) { 3182 mPendingCallConfirm.complete(null); 3183 mPendingCallConfirm = null; 3184 } 3185 if (mPendingAccountSelection != null && !mPendingAccountSelection.isDone()) { 3186 mPendingAccountSelection.complete(null); 3187 mPendingAccountSelection = null; 3188 } 3189 } 3190 } 3191 3192 /** 3193 * Instructs Telecom to disconnect all calls. 3194 */ 3195 void disconnectAllCalls() { 3196 Log.v(this, "disconnectAllCalls"); 3197 3198 for (Call call : mCalls) { 3199 disconnectCall(call); 3200 } 3201 } 3202 3203 /** 3204 * Disconnects calls for any other {@link PhoneAccountHandle} but the one specified. 3205 * Note: As a protective measure, will NEVER disconnect an emergency call. Although that 3206 * situation should never arise, its a good safeguard. 3207 * @param phoneAccountHandle Calls owned by {@link PhoneAccountHandle}s other than this one will 3208 * be disconnected. 3209 */ 3210 private void disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle) { 3211 mCalls.stream() 3212 .filter(c -> !c.isEmergencyCall() && 3213 !c.getTargetPhoneAccount().equals(phoneAccountHandle)) 3214 .forEach(c -> disconnectCall(c)); 3215 } 3216 3217 /** 3218 * Instructs Telecom to put the specified call on hold. Intended to be invoked by the 3219 * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by 3220 * the user hitting the hold button during an active call. 3221 */ 3222 @VisibleForTesting 3223 public void holdCall(Call call) { 3224 if (!mCalls.contains(call)) { 3225 Log.w(this, "Unknown call (%s) asked to be put on hold", call); 3226 } else { 3227 Log.d(this, "Putting call on hold: (%s)", call); 3228 call.hold(); 3229 } 3230 } 3231 3232 /** 3233 * Instructs Telecom to release the specified call from hold. Intended to be invoked by 3234 * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered 3235 * by the user hitting the hold button during a held call. 3236 */ 3237 @VisibleForTesting 3238 public void unholdCall(Call call) { 3239 if (!mCalls.contains(call)) { 3240 Log.w(this, "Unknown call (%s) asked to be removed from hold", call); 3241 } else { 3242 if (getOutgoingCall() != null) { 3243 Log.w(this, "There is an outgoing call, so it is unable to unhold this call %s", 3244 call); 3245 return; 3246 } 3247 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3248 String activeCallId = null; 3249 if (activeCall != null && !activeCall.isLocallyDisconnecting()) { 3250 activeCallId = activeCall.getId(); 3251 if (canHold(activeCall)) { 3252 activeCall.hold("Swap to " + call.getId()); 3253 Log.addEvent(activeCall, LogUtils.Events.SWAP, "To " + call.getId()); 3254 Log.addEvent(call, LogUtils.Events.SWAP, "From " + activeCall.getId()); 3255 } else { 3256 // This call does not support hold. If it is from a different connection 3257 // service or connection manager, then disconnect it, otherwise invoke 3258 // call.hold() and allow the connection service or connection manager to handle 3259 // the situation. 3260 if (!areFromSameSource(activeCall, call)) { 3261 if (!activeCall.isEmergencyCall()) { 3262 activeCall.disconnect("Swap to " + call.getId()); 3263 } else { 3264 Log.w(this, "unholdCall: % is an emergency call, aborting swap to %s", 3265 activeCall.getId(), call.getId()); 3266 // Don't unhold the call as requested; we don't want to drop an 3267 // emergency call. 3268 return; 3269 } 3270 } else { 3271 activeCall.hold("Swap to " + call.getId()); 3272 } 3273 } 3274 } 3275 mConnectionSvrFocusMgr.requestFocus( 3276 call, 3277 new RequestCallback(new ActionUnHoldCall(call, activeCallId))); 3278 } 3279 } 3280 3281 @Override 3282 public void onExtrasRemoved(Call c, int source, List<String> keys) { 3283 if (source != Call.SOURCE_CONNECTION_SERVICE) { 3284 return; 3285 } 3286 updateCanAddCall(); 3287 } 3288 3289 @Override 3290 public void onExtrasChanged(Call c, int source, Bundle extras, String requestingPackageName) { 3291 if (source != Call.SOURCE_CONNECTION_SERVICE) { 3292 return; 3293 } 3294 handleCallTechnologyChange(c); 3295 handleChildAddressChange(c); 3296 updateCanAddCall(); 3297 } 3298 3299 @Override 3300 public void onRemoteRttRequest(Call call, int requestId) { 3301 Log.i(this, "onRemoteRttRequest: call %s", call.getId()); 3302 playRttUpgradeToneForCall(call); 3303 } 3304 3305 public void playRttUpgradeToneForCall(Call call) { 3306 mCallAudioManager.playRttUpgradeTone(call); 3307 } 3308 3309 // Construct the list of possible PhoneAccounts that the outgoing call can use based on the 3310 // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount, 3311 // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP. 3312 @VisibleForTesting 3313 public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, 3314 boolean isVideo, boolean isEmergency) { 3315 return constructPossiblePhoneAccounts(handle, user, isVideo, isEmergency, false); 3316 } 3317 3318 // Returns whether the device is capable of 2 simultaneous active voice calls on different subs. 3319 private boolean isDsdaCallingPossible() { 3320 try { 3321 return getTelephonyManager().getMaxNumberOfSimultaneouslyActiveSims() > 1 3322 || getTelephonyManager().getPhoneCapability() 3323 .getMaxActiveVoiceSubscriptions() > 1; 3324 } catch (Exception e) { 3325 Log.w(this, "exception in isDsdaCallingPossible(): ", e); 3326 return false; 3327 } 3328 } 3329 3330 public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, 3331 boolean isVideo, boolean isEmergency, boolean isConference) { 3332 3333 if (handle == null) { 3334 return Collections.emptyList(); 3335 } 3336 // If we're specifically looking for video capable accounts, then include that capability, 3337 // otherwise specify no additional capability constraints. When handling the emergency call, 3338 // it also needs to find the phone accounts excluded by CAPABILITY_EMERGENCY_CALLS_ONLY. 3339 int capabilities = isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0; 3340 capabilities |= isConference ? PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING : 0; 3341 List<PhoneAccountHandle> allAccounts = 3342 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user, 3343 capabilities, 3344 isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY, 3345 isEmergency); 3346 // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount 3347 // should be available if a call is already active on the SIM account. 3348 // Similarly, the emergency call should be attempted over the same PhoneAccount as the 3349 // ongoing call. However, if the ongoing call is over cross-SIM registration, then the 3350 // emergency call will be attempted over a different Phone object at a later stage. 3351 if (isEmergency || !isDsdaCallingPossible()) { 3352 List<PhoneAccountHandle> simAccounts = 3353 mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser(); 3354 PhoneAccountHandle ongoingCallAccount = null; 3355 for (Call c : mCalls) { 3356 if (!c.isDisconnected() && !c.isNew() && simAccounts.contains( 3357 c.getTargetPhoneAccount())) { 3358 ongoingCallAccount = c.getTargetPhoneAccount(); 3359 break; 3360 } 3361 } 3362 if (ongoingCallAccount != null) { 3363 // Remove all SIM accounts that are not the active SIM from the list. 3364 simAccounts.remove(ongoingCallAccount); 3365 allAccounts.removeAll(simAccounts); 3366 } 3367 } 3368 return allAccounts; 3369 } 3370 3371 private TelephonyManager getTelephonyManager() { 3372 return mContext.getSystemService(TelephonyManager.class); 3373 } 3374 3375 /** 3376 * Informs listeners (notably {@link CallAudioManager} of a change to the call's external 3377 * property. 3378 * . 3379 * @param call The call whose external property changed. 3380 * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise. 3381 */ 3382 @Override 3383 public void onExternalCallChanged(Call call, boolean isExternalCall) { 3384 Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall); 3385 for (CallsManagerListener listener : mListeners) { 3386 listener.onExternalCallChanged(call, isExternalCall); 3387 } 3388 } 3389 3390 @Override 3391 public void onCallStreamingStateChanged(Call call, boolean isStreaming) { 3392 Log.v(this, "onCallStreamingStateChanged: %b", isStreaming); 3393 for (CallsManagerListener listener : mListeners) { 3394 listener.onCallStreamingStateChanged(call, isStreaming); 3395 } 3396 } 3397 3398 private void handleCallTechnologyChange(Call call) { 3399 if (call.getExtras() != null 3400 && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) { 3401 3402 Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get( 3403 call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)); 3404 if (analyticsCallTechnology == null) { 3405 analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE; 3406 } 3407 call.getAnalytics().addCallTechnology(analyticsCallTechnology); 3408 } 3409 } 3410 3411 public void handleChildAddressChange(Call call) { 3412 if (call.getExtras() != null 3413 && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) { 3414 3415 String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS); 3416 call.setViaNumber(viaNumber); 3417 } 3418 } 3419 3420 /** Called by the in-call UI to change the mute state. */ 3421 void mute(boolean shouldMute) { 3422 if (isInEmergencyCall() && shouldMute) { 3423 Log.i(this, "Refusing to turn on mute because we're in an emergency call"); 3424 shouldMute = false; 3425 } 3426 mCallAudioManager.mute(shouldMute); 3427 } 3428 3429 /** 3430 * Called by the in-call UI to change the audio route, for example to change from earpiece to 3431 * speaker phone. 3432 */ 3433 void setAudioRoute(int route, String bluetoothAddress) { 3434 mCallAudioManager.setAudioRoute(route, bluetoothAddress); 3435 } 3436 3437 /** 3438 * Called by the in-call UI to change the CallEndpoint 3439 */ 3440 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 3441 public void requestCallEndpointChange(CallEndpoint endpoint, ResultReceiver callback) { 3442 mCallEndpointController.requestCallEndpointChange(endpoint, callback); 3443 } 3444 3445 /** Called by the in-call UI to turn the proximity sensor on. */ 3446 void turnOnProximitySensor() { 3447 mProximitySensorManager.turnOn(); 3448 } 3449 3450 /** 3451 * Called by the in-call UI to turn the proximity sensor off. 3452 * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise, 3453 * the screen will be kept off until the proximity sensor goes negative. 3454 */ 3455 void turnOffProximitySensor(boolean screenOnImmediately) { 3456 mProximitySensorManager.turnOff(screenOnImmediately); 3457 } 3458 3459 private boolean isRttSettingOn(PhoneAccountHandle handle) { 3460 boolean isRttModeSettingOn = Settings.Secure.getIntForUser(mContext.getContentResolver(), 3461 Settings.Secure.RTT_CALLING_MODE, 0, mContext.getUserId()) != 0; 3462 // If the carrier config says that we should ignore the RTT mode setting from the user, 3463 // assume that it's off (i.e. only make an RTT call if it's requested through the extra). 3464 boolean shouldIgnoreRttModeSetting = getCarrierConfigForPhoneAccount(handle) 3465 .getBoolean(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false); 3466 return isRttModeSettingOn && !shouldIgnoreRttModeSetting; 3467 } 3468 3469 private PersistableBundle getCarrierConfigForPhoneAccount(PhoneAccountHandle handle) { 3470 int subscriptionId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle); 3471 CarrierConfigManager carrierConfigManager = 3472 mContext.getSystemService(CarrierConfigManager.class); 3473 PersistableBundle result = carrierConfigManager.getConfigForSubId(subscriptionId); 3474 return result == null ? new PersistableBundle() : result; 3475 } 3476 3477 void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) { 3478 if (!mCalls.contains(call)) { 3479 Log.i(this, "Attempted to add account to unknown call %s", call); 3480 } else { 3481 if (setDefault) { 3482 mPhoneAccountRegistrar 3483 .setUserSelectedOutgoingPhoneAccount(account, call.getAssociatedUser()); 3484 } 3485 3486 if (mPendingAccountSelection != null) { 3487 mPendingAccountSelection.complete(Pair.create(call, account)); 3488 mPendingAccountSelection = null; 3489 } 3490 } 3491 } 3492 3493 /** Called when the audio state changes. */ 3494 @VisibleForTesting 3495 public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState 3496 newAudioState) { 3497 Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState); 3498 for (CallsManagerListener listener : mListeners) { 3499 listener.onCallAudioStateChanged(oldAudioState, newAudioState); 3500 } 3501 } 3502 3503 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 3504 public void updateCallEndpoint(CallEndpoint callEndpoint) { 3505 Log.v(this, "updateCallEndpoint"); 3506 for (CallsManagerListener listener : mListeners) { 3507 listener.onCallEndpointChanged(callEndpoint); 3508 } 3509 } 3510 3511 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 3512 public void updateAvailableCallEndpoints(Set<CallEndpoint> availableCallEndpoints) { 3513 Log.v(this, "updateAvailableCallEndpoints"); 3514 for (CallsManagerListener listener : mListeners) { 3515 listener.onAvailableCallEndpointsChanged(availableCallEndpoints); 3516 } 3517 } 3518 3519 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 3520 public void updateMuteState(boolean isMuted) { 3521 Log.v(this, "updateMuteState"); 3522 for (CallsManagerListener listener : mListeners) { 3523 listener.onMuteStateChanged(isMuted); 3524 } 3525 } 3526 3527 /** 3528 * Called when disconnect tone is started or stopped, including any InCallTone 3529 * after disconnected call. 3530 * 3531 * @param isTonePlaying true if the disconnected tone is started, otherwise the disconnected 3532 * tone is stopped. 3533 */ 3534 @VisibleForTesting 3535 public void onDisconnectedTonePlaying(boolean isTonePlaying) { 3536 Log.v(this, "onDisconnectedTonePlaying, %s", isTonePlaying ? "started" : "stopped"); 3537 for (CallsManagerListener listener : mListeners) { 3538 listener.onDisconnectedTonePlaying(isTonePlaying); 3539 } 3540 } 3541 3542 void markCallAsRinging(Call call) { 3543 setCallState(call, CallState.RINGING, "ringing set explicitly"); 3544 } 3545 3546 @VisibleForTesting 3547 public void markCallAsDialing(Call call) { 3548 setCallState(call, CallState.DIALING, "dialing set explicitly"); 3549 maybeMoveToSpeakerPhone(call); 3550 maybeTurnOffMute(call); 3551 ensureCallAudible(); 3552 } 3553 3554 void markCallAsPulling(Call call) { 3555 setCallState(call, CallState.PULLING, "pulling set explicitly"); 3556 maybeMoveToSpeakerPhone(call); 3557 } 3558 3559 /** 3560 * Returns true if the active call is held. 3561 */ 3562 boolean holdActiveCallForNewCall(Call call) { 3563 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3564 Log.i(this, "holdActiveCallForNewCall, newCall: %s, activeCall: %s", call.getId(), 3565 (activeCall == null ? "<none>" : activeCall.getId())); 3566 if (activeCall != null && activeCall != call) { 3567 if (canHold(activeCall)) { 3568 activeCall.hold("swap to " + call.getId()); 3569 return true; 3570 } else if (supportsHold(activeCall) 3571 && areFromSameSource(activeCall, call)) { 3572 3573 // Handle the case where the active call and the new call are from the same CS or 3574 // connection manager, and the currently active call supports hold but cannot 3575 // currently be held. 3576 // In this case we'll look for the other held call for this connectionService and 3577 // disconnect it prior to holding the active call. 3578 // E.g. 3579 // Call A - Held (Supports hold, can't hold) 3580 // Call B - Active (Supports hold, can't hold) 3581 // Call C - Incoming 3582 // Here we need to disconnect A prior to holding B so that C can be answered. 3583 // This case is driven by telephony requirements ultimately. 3584 Call heldCall = getHeldCallByConnectionService(call.getTargetPhoneAccount()); 3585 if (heldCall != null) { 3586 heldCall.disconnect(); 3587 Log.i(this, "holdActiveCallForNewCall: Disconnect held call %s before " 3588 + "holding active call %s.", 3589 heldCall.getId(), activeCall.getId()); 3590 } 3591 Log.i(this, "holdActiveCallForNewCall: Holding active %s before making %s active.", 3592 activeCall.getId(), call.getId()); 3593 activeCall.hold(); 3594 call.increaseHeldByThisCallCount(); 3595 return true; 3596 } else { 3597 // This call does not support hold. If it is from a different connection 3598 // service or connection manager, then disconnect it, otherwise allow the connection 3599 // service or connection manager to figure out the right states. 3600 if (!areFromSameSource(activeCall, call)) { 3601 Log.i(this, "holdActiveCallForNewCall: disconnecting %s so that %s can be " 3602 + "made active.", activeCall.getId(), call.getId()); 3603 if (!activeCall.isEmergencyCall()) { 3604 activeCall.disconnect(); 3605 } else { 3606 // It's not possible to hold the active call, and its an emergency call so 3607 // we will silently reject the incoming call instead of answering it. 3608 Log.w(this, "holdActiveCallForNewCall: rejecting incoming call %s as " 3609 + "the active call is an emergency call and it cannot be held.", 3610 call.getId()); 3611 call.reject(false /* rejectWithMessage */, "" /* message */, 3612 "active emergency call can't be held"); 3613 } 3614 } 3615 } 3616 } 3617 return false; 3618 } 3619 3620 // attempt to hold the requested call and complete the callback on the result 3621 public void transactionHoldPotentialActiveCallForNewCall(Call newCall, 3622 OutcomeReceiver<Boolean, CallException> callback) { 3623 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 3624 Log.i(this, "transactionHoldPotentialActiveCallForNewCall: " 3625 + "newCall=[%s], activeCall=[%s]", newCall, activeCall); 3626 3627 // early exit if there is no need to hold an active call 3628 if (activeCall == null || activeCall == newCall) { 3629 Log.i(this, "transactionHoldPotentialActiveCallForNewCall:" 3630 + " no need to hold activeCall"); 3631 callback.onResult(true); 3632 return; 3633 } 3634 3635 // before attempting CallsManager#holdActiveCallForNewCall(Call), check if it'll fail early 3636 if (!canHold(activeCall) && 3637 !(supportsHold(activeCall) && areFromSameSource(activeCall, newCall))) { 3638 Log.i(this, "transactionHoldPotentialActiveCallForNewCall: " 3639 + "conditions show the call cannot be held."); 3640 callback.onError(new CallException("call does not support hold", 3641 CallException.CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL)); 3642 return; 3643 } 3644 3645 // attempt to hold the active call 3646 if (!holdActiveCallForNewCall(newCall)) { 3647 Log.i(this, "transactionHoldPotentialActiveCallForNewCall: " 3648 + "attempted to hold call but failed."); 3649 callback.onError(new CallException("cannot hold active call failed", 3650 CallException.CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL)); 3651 return; 3652 } 3653 3654 // officially mark the activeCall as held 3655 markCallAsOnHold(activeCall); 3656 callback.onResult(true); 3657 } 3658 3659 @VisibleForTesting 3660 public void markCallAsActive(Call call) { 3661 Log.i(this, "markCallAsActive, isSelfManaged: " + call.isSelfManaged()); 3662 if (call.isSelfManaged()) { 3663 // backward compatibility, the self-managed connection service will set the call state 3664 // to active directly. We should hold or disconnect the current active call based on the 3665 // holdability, and request the call focus for the self-managed call before the state 3666 // change. 3667 holdActiveCallForNewCall(call); 3668 mConnectionSvrFocusMgr.requestFocus( 3669 call, 3670 new RequestCallback(new ActionSetCallState( 3671 call, 3672 CallState.ACTIVE, 3673 "active set explicitly for self-managed"))); 3674 } else { 3675 if (mPendingAudioProcessingCall == call) { 3676 if (mCalls.contains(call)) { 3677 setCallState(call, CallState.AUDIO_PROCESSING, "active set explicitly"); 3678 } else { 3679 call.setState(CallState.AUDIO_PROCESSING, "active set explicitly and adding"); 3680 addCall(call); 3681 } 3682 // Clear mPendingAudioProcessingCall so that future attempts to mark the call as 3683 // active (e.g. coming off of hold) don't put the call into audio processing instead 3684 mPendingAudioProcessingCall = null; 3685 return; 3686 } 3687 setCallState(call, CallState.ACTIVE, "active set explicitly"); 3688 maybeMoveToSpeakerPhone(call); 3689 ensureCallAudible(); 3690 } 3691 } 3692 3693 public void markCallAsOnHold(Call call) { 3694 setCallState(call, CallState.ON_HOLD, "on-hold set explicitly"); 3695 } 3696 3697 /** 3698 * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the 3699 * last live call, then also disconnect from the in-call controller. 3700 * 3701 * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}. 3702 */ 3703 public void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) { 3704 Log.i(this, "markCallAsDisconnected: call=%s; disconnectCause=%s", 3705 call.toString(), disconnectCause.toString()); 3706 int oldState = call.getState(); 3707 if (call.getState() == CallState.SIMULATED_RINGING 3708 && disconnectCause.getCode() == DisconnectCause.REMOTE) { 3709 // If the remote end hangs up while in SIMULATED_RINGING, the call should 3710 // be marked as missed. 3711 call.setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.MISSED)); 3712 } 3713 if (call.getState() == CallState.NEW 3714 && disconnectCause.getCode() == DisconnectCause.MISSED) { 3715 Log.i(this, "markCallAsDisconnected: missed call never rang ", call.getId()); 3716 call.setMissedReason(USER_MISSED_NEVER_RANG); 3717 } 3718 if (call.getState() == CallState.RINGING 3719 || call.getState() == CallState.SIMULATED_RINGING) { 3720 if (call.getStartRingTime() > 0 3721 && (mClockProxy.elapsedRealtime() - call.getStartRingTime()) 3722 < SHORT_RING_THRESHOLD) { 3723 Log.i(this, "markCallAsDisconnected; callid=%s, short ring.", call.getId()); 3724 call.setUserMissed(USER_MISSED_SHORT_RING); 3725 } else if (call.getStartRingTime() > 0) { 3726 call.setUserMissed(USER_MISSED_NO_ANSWER); 3727 } 3728 } 3729 3730 // Notify listeners that the call was disconnected before being added to CallsManager. 3731 // Listeners will not receive onAdded or onRemoved callbacks. 3732 if (!mCalls.contains(call)) { 3733 if (call.isEmergencyCall()) { 3734 mAnomalyReporter.reportAnomaly( 3735 EMERGENCY_CALL_DISCONNECTED_BEFORE_BEING_ADDED_ERROR_UUID, 3736 EMERGENCY_CALL_DISCONNECTED_BEFORE_BEING_ADDED_ERROR_MSG); 3737 } 3738 mListeners.forEach(l -> l.onCreateConnectionFailed(call)); 3739 } 3740 3741 // If a call diagnostic service is in use, we will log the original telephony-provided 3742 // disconnect cause, inform the CDS of the disconnection, and then chain the update of the 3743 // call state until AFTER the CDS reports it's result back. 3744 if ((oldState == CallState.ACTIVE || oldState == CallState.DIALING) 3745 && disconnectCause.getCode() != DisconnectCause.MISSED 3746 && mCallDiagnosticServiceController.isConnected() 3747 && mCallDiagnosticServiceController.onCallDisconnected(call, disconnectCause)) { 3748 Log.i(this, "markCallAsDisconnected; callid=%s, postingToFuture.", call.getId()); 3749 3750 // Log the original disconnect reason prior to calling into the 3751 // CallDiagnosticService. 3752 Log.addEvent(call, LogUtils.Events.SET_DISCONNECTED_ORIG, disconnectCause); 3753 3754 // Setup the future with a timeout so that the CDS is time boxed. 3755 CompletableFuture<Boolean> future = call.initializeDisconnectFuture( 3756 mTimeoutsAdapter.getCallDiagnosticServiceTimeoutMillis( 3757 mContext.getContentResolver())); 3758 3759 // Post the disconnection updates to the future for completion once the CDS returns 3760 // with it's overridden disconnect message. 3761 future.thenRunAsync(() -> { 3762 call.setDisconnectCause(disconnectCause); 3763 setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly"); 3764 }, new LoggedHandlerExecutor(mHandler, "CM.mCAD", mLock)) 3765 .exceptionally((throwable) -> { 3766 Log.e(TAG, throwable, "Error while executing disconnect future."); 3767 return null; 3768 }); 3769 } else { 3770 // No CallDiagnosticService, or it doesn't handle this call, so just do this 3771 // synchronously as always. 3772 call.setDisconnectCause(disconnectCause); 3773 setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly"); 3774 } 3775 3776 if (oldState == CallState.NEW && disconnectCause.getCode() == DisconnectCause.MISSED) { 3777 Log.i(this, "markCallAsDisconnected: logging missed call "); 3778 mCallLogManager.logCall(call, Calls.MISSED_TYPE, true, null); 3779 } 3780 } 3781 3782 /** 3783 * Removes an existing disconnected call, and notifies the in-call app. 3784 */ 3785 public void markCallAsRemoved(Call call) { 3786 if (call.isDisconnectHandledViaFuture()) { 3787 Log.i(this, "markCallAsRemoved; callid=%s, postingToFuture.", call.getId()); 3788 // A future is being used due to a CallDiagnosticService handling the call. We will 3789 // chain the removal operation to the end of any outstanding disconnect work. 3790 call.getDisconnectFuture().thenRunAsync(() -> { 3791 performRemoval(call); 3792 }, new LoggedHandlerExecutor(mHandler, "CM.mCAR", mLock)) 3793 .exceptionally((throwable) -> { 3794 Log.e(TAG, throwable, "Error while executing disconnect future"); 3795 return null; 3796 }); 3797 3798 } else { 3799 Log.i(this, "markCallAsRemoved; callid=%s, immediate.", call.getId()); 3800 performRemoval(call); 3801 } 3802 } 3803 3804 /** 3805 * Work which is completed when a call is to be removed. Can either be be run synchronously or 3806 * posted to a {@link Call#getDisconnectFuture()}. 3807 * @param call The call. 3808 */ 3809 private void performRemoval(Call call) { 3810 if (mInCallController.getBindingFuture() != null) { 3811 mInCallController.getBindingFuture().thenRunAsync(() -> { 3812 doRemoval(call); 3813 }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock)) 3814 .exceptionally((throwable) -> { 3815 Log.e(TAG, throwable, "Error while executing call removal"); 3816 mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID, 3817 CALL_REMOVAL_EXECUTION_ERROR_MSG); 3818 return null; 3819 }); 3820 } else { 3821 doRemoval(call); 3822 } 3823 } 3824 3825 /** 3826 * Code to perform removal of a call. Called above from {@link #performRemoval(Call)} either 3827 * async (in live code) or sync (in testing). 3828 * @param call the call to remove. 3829 */ 3830 private void doRemoval(Call call) { 3831 call.maybeCleanupHandover(); 3832 removeCall(call); 3833 Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall(); 3834 if (mLocallyDisconnectingCalls.contains(call)) { 3835 boolean isDisconnectingChildCall = call.isDisconnectingChildCall(); 3836 Log.v(this, "performRemoval: isDisconnectingChildCall = " 3837 + isDisconnectingChildCall + "call -> %s", call); 3838 mLocallyDisconnectingCalls.remove(call); 3839 // Auto-unhold the foreground call due to a locally disconnected call, except if the 3840 // call which was disconnected is a member of a conference (don't want to auto 3841 // un-hold the conference if we remove a member of the conference). 3842 // Also, ensure that the call we're removing is from the same ConnectionService as 3843 // the one we're removing. We don't want to auto-unhold between ConnectionService 3844 // implementations, especially if one is managed and the other is a VoIP CS. 3845 if (!isDisconnectingChildCall && foregroundCall != null 3846 && foregroundCall.getState() == CallState.ON_HOLD 3847 && areFromSameSource(foregroundCall, call)) { 3848 foregroundCall.unhold(); 3849 } 3850 } else if (foregroundCall != null && 3851 !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD) && 3852 foregroundCall.getState() == CallState.ON_HOLD) { 3853 3854 // The new foreground call is on hold, however the carrier does not display the hold 3855 // button in the UI. Therefore, we need to auto unhold the held call since the user 3856 // has no means of unholding it themselves. 3857 Log.i(this, "performRemoval: Auto-unholding held foreground call (call doesn't " 3858 + "support hold)"); 3859 foregroundCall.unhold(); 3860 } 3861 } 3862 3863 /** 3864 * Given a call, marks the call as disconnected and removes it. Set the error message to 3865 * indicate to the user that the call cannot me placed due to an ongoing call in another app. 3866 * 3867 * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed 3868 * call. Called by {@link #startCallConfirmation} when the user is already confirming an 3869 * outgoing call. Realistically this should almost never be called since in practice the user 3870 * won't make multiple outgoing calls at the same time. 3871 * 3872 * @param call The call to mark as disconnected. 3873 */ 3874 void markCallDisconnectedDueToSelfManagedCall(Call call) { 3875 Call activeCall = getActiveCall(); 3876 CharSequence errorMessage; 3877 if (activeCall == null) { 3878 // Realistically this shouldn't happen, but best to handle gracefully 3879 errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call); 3880 } else { 3881 errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call, 3882 activeCall.getTargetPhoneAccountLabel()); 3883 } 3884 // Call is managed and there are ongoing self-managed calls. 3885 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 3886 errorMessage, errorMessage, "Ongoing call in another app.")); 3887 markCallAsRemoved(call); 3888 } 3889 3890 /** 3891 * Cleans up any calls currently associated with the specified connection service when the 3892 * service binder disconnects unexpectedly. 3893 * 3894 * @param service The connection service that disconnected. 3895 */ 3896 void handleConnectionServiceDeath(ConnectionServiceWrapper service) { 3897 if (service != null) { 3898 Log.i(this, "handleConnectionServiceDeath: service %s died", service); 3899 for (Call call : mCalls) { 3900 if (call.getConnectionService() == service) { 3901 if (call.getState() != CallState.DISCONNECTED) { 3902 markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR, 3903 null /* message */, null /* description */, "CS_DEATH", 3904 ToneGenerator.TONE_PROP_PROMPT)); 3905 } 3906 markCallAsRemoved(call); 3907 } 3908 } 3909 } 3910 } 3911 3912 /** 3913 * Determines if the {@link CallsManager} has any non-external calls. 3914 * 3915 * @return {@code True} if there are any non-external calls, {@code false} otherwise. 3916 */ 3917 public boolean hasAnyCalls() { 3918 if (mCalls.isEmpty()) { 3919 return false; 3920 } 3921 3922 for (Call call : mCalls) { 3923 if (!call.isExternalCall()) { 3924 return true; 3925 } 3926 } 3927 return false; 3928 } 3929 3930 boolean hasRingingCall() { 3931 return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED) != null; 3932 } 3933 3934 boolean hasRingingOrSimulatedRingingCall() { 3935 return getFirstCallWithState( 3936 CallState.SIMULATED_RINGING, CallState.RINGING, CallState.ANSWERED) != null; 3937 } 3938 3939 @VisibleForTesting 3940 public boolean onMediaButton(int type) { 3941 if (hasAnyCalls()) { 3942 Call ringingCall = getFirstCallWithState(CallState.RINGING, 3943 CallState.SIMULATED_RINGING); 3944 if (HeadsetMediaButton.SHORT_PRESS == type) { 3945 if (ringingCall == null) { 3946 Call activeCall = getFirstCallWithState(CallState.ACTIVE); 3947 Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD); 3948 if (activeCall != null && onHoldCall != null) { 3949 // Two calls, short-press -> switch calls 3950 Log.addEvent(onHoldCall, LogUtils.Events.INFO, 3951 "two calls, media btn short press - switch call."); 3952 unholdCall(onHoldCall); 3953 return true; 3954 } 3955 3956 Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING, 3957 CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD); 3958 Log.addEvent(callToHangup, LogUtils.Events.INFO, 3959 "media btn short press - end call."); 3960 if (callToHangup != null) { 3961 disconnectCall(callToHangup); 3962 return true; 3963 } 3964 } else { 3965 answerCall(ringingCall, VideoProfile.STATE_AUDIO_ONLY); 3966 return true; 3967 } 3968 } else if (HeadsetMediaButton.LONG_PRESS == type) { 3969 if (ringingCall != null) { 3970 Log.addEvent(getForegroundCall(), 3971 LogUtils.Events.INFO, "media btn long press - reject"); 3972 ringingCall.reject(false, null); 3973 } else { 3974 Call activeCall = getFirstCallWithState(CallState.ACTIVE); 3975 Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD); 3976 if (activeCall != null && onHoldCall != null) { 3977 // Two calls, long-press -> end current call 3978 Log.addEvent(activeCall, LogUtils.Events.INFO, 3979 "two calls, media btn long press - end current call."); 3980 disconnectCall(activeCall); 3981 return true; 3982 } 3983 3984 Log.addEvent(getForegroundCall(), LogUtils.Events.INFO, 3985 "media btn long press - mute"); 3986 mCallAudioManager.toggleMute(); 3987 } 3988 return true; 3989 } 3990 } 3991 return false; 3992 } 3993 3994 /** 3995 * Returns true if telecom supports adding another top-level call. 3996 */ 3997 @VisibleForTesting 3998 public boolean canAddCall() { 3999 boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 4000 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 4001 if (!isDeviceProvisioned) { 4002 Log.d(TAG, "Device not provisioned, canAddCall is false."); 4003 return false; 4004 } 4005 4006 if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) { 4007 return false; 4008 } 4009 4010 int count = 0; 4011 for (Call call : mCalls) { 4012 if (call.isEmergencyCall()) { 4013 // We never support add call if one of the calls is an emergency call. 4014 return false; 4015 } else if (call.isExternalCall()) { 4016 // External calls don't count. 4017 continue; 4018 } else if (call.getParentCall() == null) { 4019 count++; 4020 } 4021 Bundle extras = call.getExtras(); 4022 if (extras != null) { 4023 if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) { 4024 return false; 4025 } 4026 } 4027 4028 // We do not check states for canAddCall. We treat disconnected calls the same 4029 // and wait until they are removed instead. If we didn't count disconnected calls, 4030 // we could put InCallServices into a state where they are showing two calls but 4031 // also support add-call. Technically it's right, but overall looks better (UI-wise) 4032 // and acts better if we wait until the call is removed. 4033 if (count >= MAXIMUM_TOP_LEVEL_CALLS) { 4034 return false; 4035 } 4036 } 4037 4038 return true; 4039 } 4040 4041 @VisibleForTesting 4042 public Call getRingingOrSimulatedRingingCall() { 4043 return getFirstCallWithState(CallState.RINGING, 4044 CallState.ANSWERED, CallState.SIMULATED_RINGING); 4045 } 4046 4047 public Call getActiveCall() { 4048 return getFirstCallWithState(CallState.ACTIVE); 4049 } 4050 4051 public Call getHeldCallByConnectionService(PhoneAccountHandle targetPhoneAccount) { 4052 Optional<Call> heldCall = mCalls.stream() 4053 .filter(call -> PhoneAccountHandle.areFromSamePackage(call.getTargetPhoneAccount(), 4054 targetPhoneAccount) 4055 && call.getParentCall() == null 4056 && call.getState() == CallState.ON_HOLD) 4057 .findFirst(); 4058 return heldCall.isPresent() ? heldCall.get() : null; 4059 } 4060 4061 @VisibleForTesting 4062 public int getNumHeldCalls() { 4063 int count = 0; 4064 for (Call call : mCalls) { 4065 if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) { 4066 count++; 4067 } 4068 } 4069 return count; 4070 } 4071 4072 @VisibleForTesting 4073 public Call getOutgoingCall() { 4074 return getFirstCallWithState(OUTGOING_CALL_STATES); 4075 } 4076 4077 @VisibleForTesting 4078 public Call getFirstCallWithState(int... states) { 4079 return getFirstCallWithState(null, states); 4080 } 4081 4082 @VisibleForTesting 4083 public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() { 4084 return mPhoneNumberUtilsAdapter; 4085 } 4086 4087 @VisibleForTesting 4088 public CompletableFuture<Call> getLatestPostSelectionProcessingFuture() { 4089 return mLatestPostSelectionProcessingFuture; 4090 } 4091 4092 @VisibleForTesting 4093 public CompletableFuture getLatestPreAccountSelectionFuture() { 4094 return mLatestPreAccountSelectionFuture; 4095 } 4096 4097 /** 4098 * Returns the first call that it finds with the given states. The states are treated as having 4099 * priority order so that any call with the first state will be returned before any call with 4100 * states listed later in the parameter list. 4101 * 4102 * @param callToSkip Call that this method should skip while searching 4103 */ 4104 Call getFirstCallWithState(Call callToSkip, int... states) { 4105 for (int currentState : states) { 4106 // check the foreground first 4107 Call foregroundCall = getForegroundCall(); 4108 if (foregroundCall != null && foregroundCall.getState() == currentState) { 4109 return foregroundCall; 4110 } 4111 4112 for (Call call : mCalls) { 4113 if (Objects.equals(callToSkip, call)) { 4114 continue; 4115 } 4116 4117 // Only operate on top-level calls 4118 if (call.getParentCall() != null) { 4119 continue; 4120 } 4121 4122 if (call.isExternalCall()) { 4123 continue; 4124 } 4125 4126 if (currentState == call.getState()) { 4127 return call; 4128 } 4129 } 4130 } 4131 return null; 4132 } 4133 4134 Call createConferenceCall( 4135 String callId, 4136 PhoneAccountHandle phoneAccount, 4137 ParcelableConference parcelableConference) { 4138 4139 // If the parceled conference specifies a connect time, use it; otherwise default to 0, 4140 // which is the default value for new Calls. 4141 long connectTime = 4142 parcelableConference.getConnectTimeMillis() == 4143 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 4144 parcelableConference.getConnectTimeMillis(); 4145 long connectElapsedTime = 4146 parcelableConference.getConnectElapsedTimeMillis() == 4147 Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 : 4148 parcelableConference.getConnectElapsedTimeMillis(); 4149 4150 int callDirection = Call.getRemappedCallDirection(parcelableConference.getCallDirection()); 4151 4152 PhoneAccountHandle connectionMgr = 4153 mPhoneAccountRegistrar.getSimCallManagerFromHandle(phoneAccount, 4154 mCurrentUserHandle); 4155 Call call = new Call( 4156 callId, 4157 mContext, 4158 this, 4159 mLock, 4160 mConnectionServiceRepository, 4161 mPhoneNumberUtilsAdapter, 4162 null /* handle */, 4163 null /* gatewayInfo */, 4164 connectionMgr, 4165 phoneAccount, 4166 callDirection, 4167 false /* forceAttachToExistingConnection */, 4168 true /* isConference */, 4169 connectTime, 4170 connectElapsedTime, 4171 mClockProxy, 4172 mToastFactory); 4173 4174 // Unlike connections, conferences are not created first and then notified as create 4175 // connection complete from the CS. They originate from the CS and are reported directly to 4176 // telecom where they're added (see below). 4177 call.setIsCreateConnectionComplete(true); 4178 4179 setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()), 4180 "new conference call"); 4181 call.setHandle(parcelableConference.getHandle(), 4182 parcelableConference.getHandlePresentation()); 4183 call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities()); 4184 call.setConnectionProperties(parcelableConference.getConnectionProperties()); 4185 call.setVideoState(parcelableConference.getVideoState()); 4186 call.setVideoProvider(parcelableConference.getVideoProvider()); 4187 call.setStatusHints(parcelableConference.getStatusHints()); 4188 call.putConnectionServiceExtras(parcelableConference.getExtras()); 4189 // For conference calls, set the associated user from the target phone account user handle. 4190 call.setAssociatedUser(phoneAccount.getUserHandle()); 4191 // In case this Conference was added via a ConnectionManager, keep track of the original 4192 // Connection ID as created by the originating ConnectionService. 4193 Bundle extras = parcelableConference.getExtras(); 4194 if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 4195 call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID)); 4196 } 4197 4198 // TODO: Move this to be a part of addCall() 4199 call.addListener(this); 4200 addCall(call); 4201 return call; 4202 } 4203 4204 /** 4205 * @return the call state currently tracked by {@link PhoneStateBroadcaster} 4206 */ 4207 int getCallState() { 4208 return mPhoneStateBroadcaster.getCallState(); 4209 } 4210 4211 /** 4212 * Retrieves the {@link PhoneAccountRegistrar}. 4213 * 4214 * @return The {@link PhoneAccountRegistrar}. 4215 */ 4216 @VisibleForTesting 4217 public PhoneAccountRegistrar getPhoneAccountRegistrar() { 4218 return mPhoneAccountRegistrar; 4219 } 4220 4221 /** 4222 * Retrieves the {@link DisconnectedCallNotifier} 4223 * @return The {@link DisconnectedCallNotifier}. 4224 */ 4225 DisconnectedCallNotifier getDisconnectedCallNotifier() { 4226 return mDisconnectedCallNotifier; 4227 } 4228 4229 /** 4230 * Retrieves the {@link MissedCallNotifier} 4231 * @return The {@link MissedCallNotifier}. 4232 */ 4233 MissedCallNotifier getMissedCallNotifier() { 4234 return mMissedCallNotifier; 4235 } 4236 4237 /** 4238 * Retrieves the {@link IncomingCallNotifier}. 4239 * @return The {@link IncomingCallNotifier}. 4240 */ 4241 IncomingCallNotifier getIncomingCallNotifier() { 4242 return mIncomingCallNotifier; 4243 } 4244 4245 /** 4246 * Reject an incoming call and manually add it to the Call Log. 4247 * @param incomingCall Incoming call that has been rejected 4248 */ 4249 private void autoMissCallAndLog(Call incomingCall, CallFilteringResult result) { 4250 incomingCall.getAnalytics().setMissedReason(incomingCall.getMissedReason()); 4251 if (incomingCall.getConnectionService() != null) { 4252 // Only reject the call if it has not already been destroyed. If a call ends while 4253 // incoming call filtering is taking place, it is possible that the call has already 4254 // been destroyed, and as such it will be impossible to send the reject to the 4255 // associated ConnectionService. 4256 incomingCall.reject(false, null); 4257 } else { 4258 Log.i(this, "rejectCallAndLog - call already destroyed."); 4259 } 4260 4261 // Since the call was not added to the list of calls, we have to call the missed 4262 // call notifier and the call logger manually. 4263 // Do we need missed call notification for direct to Voicemail calls? 4264 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, 4265 true /*showNotificationForMissedCall*/, result); 4266 } 4267 4268 /** 4269 * Adds the specified call to the main list of live calls. 4270 * 4271 * @param call The call to add. 4272 */ 4273 @VisibleForTesting 4274 public void addCall(Call call) { 4275 if (mCalls.contains(call)) { 4276 Log.i(this, "addCall(%s) is already added"); 4277 return; 4278 } 4279 Trace.beginSection("addCall"); 4280 Log.i(this, "addCall(%s)", call); 4281 call.addListener(this); 4282 mCalls.add(call); 4283 mSelfManagedCallsBeingSetup.remove(call); 4284 4285 // Specifies the time telecom finished routing the call. This is used by the dialer for 4286 // analytics. 4287 Bundle extras = call.getIntentExtras(); 4288 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS, 4289 SystemClock.elapsedRealtime()); 4290 4291 updateCanAddCall(); 4292 updateHasActiveRttCall(); 4293 updateExternalCallCanPullSupport(); 4294 // onCallAdded for calls which immediately take the foreground (like the first call). 4295 for (CallsManagerListener listener : mListeners) { 4296 if (LogUtils.SYSTRACE_DEBUG) { 4297 Trace.beginSection(listener.getClass().toString() + " addCall"); 4298 } 4299 listener.onCallAdded(call); 4300 if (LogUtils.SYSTRACE_DEBUG) { 4301 Trace.endSection(); 4302 } 4303 } 4304 Trace.endSection(); 4305 } 4306 4307 @VisibleForTesting 4308 public void removeCall(Call call) { 4309 Trace.beginSection("removeCall"); 4310 Log.v(this, "removeCall(%s)", call); 4311 4312 if (call.isTransactionalCall() && call.getTransactionServiceWrapper() != null) { 4313 // remove call from wrappers 4314 call.getTransactionServiceWrapper().removeCallFromWrappers(call); 4315 } 4316 4317 call.setParentAndChildCall(null); // clean up parent relationship before destroying. 4318 call.removeListener(this); 4319 call.clearConnectionService(); 4320 // TODO: clean up RTT pipes 4321 4322 boolean shouldNotify = false; 4323 if (mCalls.contains(call)) { 4324 mCalls.remove(call); 4325 shouldNotify = true; 4326 } 4327 mSelfManagedCallsBeingSetup.remove(call); 4328 4329 call.destroy(); 4330 updateExternalCallCanPullSupport(); 4331 // Only broadcast changes for calls that are being tracked. 4332 if (shouldNotify) { 4333 updateCanAddCall(); 4334 updateHasActiveRttCall(); 4335 for (CallsManagerListener listener : mListeners) { 4336 if (LogUtils.SYSTRACE_DEBUG) { 4337 Trace.beginSection(listener.getClass().toString() + " onCallRemoved"); 4338 } 4339 listener.onCallRemoved(call); 4340 if (LogUtils.SYSTRACE_DEBUG) { 4341 Trace.endSection(); 4342 } 4343 } 4344 } 4345 Trace.endSection(); 4346 } 4347 4348 private void updateHasActiveRttCall() { 4349 boolean hasActiveRttCall = hasActiveRttCall(); 4350 if (hasActiveRttCall != mHasActiveRttCall) { 4351 Log.i(this, "updateHasActiveRttCall %s -> %s", mHasActiveRttCall, hasActiveRttCall); 4352 AudioManager.setRttEnabled(hasActiveRttCall); 4353 mHasActiveRttCall = hasActiveRttCall; 4354 } 4355 } 4356 4357 private boolean hasActiveRttCall() { 4358 for (Call call : mCalls) { 4359 if (call.isActive() && call.isRttCall()) { 4360 return true; 4361 } 4362 } 4363 return false; 4364 } 4365 4366 /** 4367 * Sets the specified state on the specified call. 4368 * 4369 * @param call The call. 4370 * @param newState The new state of the call. 4371 */ 4372 private void setCallState(Call call, int newState, String tag) { 4373 if (call == null) { 4374 return; 4375 } 4376 int oldState = call.getState(); 4377 Log.i(this, "setCallState %s -> %s, call: %s", 4378 CallState.toString(call.getParcelableCallState()), 4379 CallState.toString(newState), call); 4380 if (newState != oldState) { 4381 // If the call switches to held state while a DTMF tone is playing, stop the tone to 4382 // ensure that the tone generator stops playing the tone. 4383 if (newState == CallState.ON_HOLD && call.isDtmfTonePlaying()) { 4384 stopDtmfTone(call); 4385 } 4386 4387 // Unfortunately, in the telephony world the radio is king. So if the call notifies 4388 // us that the call is in a particular state, we allow it even if it doesn't make 4389 // sense (e.g., STATE_ACTIVE -> STATE_RINGING). 4390 // TODO: Consider putting a stop to the above and turning CallState 4391 // into a well-defined state machine. 4392 // TODO: Define expected state transitions here, and log when an 4393 // unexpected transition occurs. 4394 if (call.setState(newState, tag)) { 4395 if ((oldState != CallState.AUDIO_PROCESSING) && 4396 (newState == CallState.DISCONNECTED)) { 4397 maybeSendPostCallScreenIntent(call); 4398 } 4399 int disconnectCode = call.getDisconnectCause().getCode(); 4400 if ((newState == CallState.ABORTED || newState == CallState.DISCONNECTED) 4401 && ((disconnectCode != DisconnectCause.MISSED) 4402 && (disconnectCode != DisconnectCause.CANCELED))) { 4403 call.setMissedReason(MISSED_REASON_NOT_MISSED); 4404 } 4405 call.getAnalytics().setMissedReason(call.getMissedReason()); 4406 4407 maybeShowErrorDialogOnDisconnect(call); 4408 4409 Trace.beginSection("onCallStateChanged"); 4410 4411 maybeHandleHandover(call, newState); 4412 notifyCallStateChanged(call, oldState, newState); 4413 4414 Trace.endSection(); 4415 } else { 4416 Log.i(this, "failed in setting the state to new state"); 4417 } 4418 } 4419 } 4420 4421 private void notifyCallStateChanged(Call call, int oldState, int newState) { 4422 // Only broadcast state change for calls that are being tracked. 4423 if (mCalls.contains(call)) { 4424 updateCanAddCall(); 4425 updateHasActiveRttCall(); 4426 for (CallsManagerListener listener : mListeners) { 4427 if (LogUtils.SYSTRACE_DEBUG) { 4428 Trace.beginSection(listener.getClass().toString() + 4429 " onCallStateChanged"); 4430 } 4431 listener.onCallStateChanged(call, oldState, newState); 4432 if (LogUtils.SYSTRACE_DEBUG) { 4433 Trace.endSection(); 4434 } 4435 } 4436 } 4437 } 4438 4439 /** 4440 * Identifies call state transitions for a call which trigger handover events. 4441 * - If this call has a handover to it which just started and this call goes active, treat 4442 * this as if the user accepted the handover. 4443 * - If this call has a handover to it which just started and this call is disconnected, treat 4444 * this as if the user rejected the handover. 4445 * - If this call has a handover from it which just started and this call is disconnected, do 4446 * nothing as the call prematurely disconnected before the user accepted the handover. 4447 * - If this call has a handover from it which was already accepted by the user and this call is 4448 * disconnected, mark the handover as complete. 4449 * 4450 * @param call A call whose state is changing. 4451 * @param newState The new state of the call. 4452 */ 4453 private void maybeHandleHandover(Call call, int newState) { 4454 if (call.getHandoverSourceCall() != null) { 4455 // We are handing over another call to this one. 4456 if (call.getHandoverState() == HandoverState.HANDOVER_TO_STARTED) { 4457 // A handover to this call has just been initiated. 4458 if (newState == CallState.ACTIVE) { 4459 // This call went active, so the user has accepted the handover. 4460 Log.i(this, "setCallState: handover to accepted"); 4461 acceptHandoverTo(call); 4462 } else if (newState == CallState.DISCONNECTED) { 4463 // The call was disconnected, so the user has rejected the handover. 4464 Log.i(this, "setCallState: handover to rejected"); 4465 rejectHandoverTo(call); 4466 } 4467 } 4468 // If this call was disconnected because it was handed over TO another call, report the 4469 // handover as complete. 4470 } else if (call.getHandoverDestinationCall() != null 4471 && newState == CallState.DISCONNECTED) { 4472 int handoverState = call.getHandoverState(); 4473 if (handoverState == HandoverState.HANDOVER_FROM_STARTED) { 4474 // Disconnect before handover was accepted. 4475 Log.i(this, "setCallState: disconnect before handover accepted"); 4476 // Let the handover destination know that the source has disconnected prior to 4477 // completion of the handover. 4478 call.getHandoverDestinationCall().sendCallEvent( 4479 android.telecom.Call.EVENT_HANDOVER_SOURCE_DISCONNECTED, null); 4480 } else if (handoverState == HandoverState.HANDOVER_ACCEPTED) { 4481 Log.i(this, "setCallState: handover from complete"); 4482 completeHandoverFrom(call); 4483 } 4484 } 4485 } 4486 4487 private void completeHandoverFrom(Call call) { 4488 Call handoverTo = call.getHandoverDestinationCall(); 4489 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 4490 call.getId(), handoverTo.getId()); 4491 Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s", 4492 call.getId(), handoverTo.getId()); 4493 4494 // Inform the "from" Call (ie the source call) that the handover from it has 4495 // completed; this allows the InCallService to be notified that a handover it 4496 // initiated completed. 4497 call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null); 4498 call.onHandoverComplete(); 4499 4500 // Inform the "to" ConnectionService that handover to it has completed. 4501 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null); 4502 handoverTo.onHandoverComplete(); 4503 answerCall(handoverTo, handoverTo.getVideoState()); 4504 call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE); 4505 4506 // If the call we handed over to is self-managed, we need to disconnect the calls for other 4507 // ConnectionServices. 4508 if (handoverTo.isSelfManaged()) { 4509 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 4510 } 4511 } 4512 4513 private void rejectHandoverTo(Call handoverTo) { 4514 Call handoverFrom = handoverTo.getHandoverSourceCall(); 4515 Log.i(this, "rejectHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 4516 Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s, rejected", 4517 handoverTo.getId(), handoverFrom.getId()); 4518 Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s, rejected", 4519 handoverTo.getId(), handoverFrom.getId()); 4520 4521 // Inform the "from" Call (ie the source call) that the handover from it has 4522 // failed; this allows the InCallService to be notified that a handover it 4523 // initiated failed. 4524 handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null); 4525 handoverFrom.onHandoverFailed(android.telecom.Call.Callback.HANDOVER_FAILURE_USER_REJECTED); 4526 4527 // Inform the "to" ConnectionService that handover to it has failed. This 4528 // allows the ConnectionService the call was being handed over 4529 if (handoverTo.getConnectionService() != null) { 4530 // Only attempt if the call has a bound ConnectionService if handover failed 4531 // early on in the handover process, the CS will be unbound and we won't be 4532 // able to send the call event. 4533 handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 4534 handoverTo.getConnectionService().handoverFailed(handoverTo, 4535 android.telecom.Call.Callback.HANDOVER_FAILURE_USER_REJECTED); 4536 } 4537 handoverTo.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_FAILED); 4538 } 4539 4540 private void acceptHandoverTo(Call handoverTo) { 4541 Call handoverFrom = handoverTo.getHandoverSourceCall(); 4542 Log.i(this, "acceptHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId()); 4543 handoverTo.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 4544 handoverTo.onHandoverComplete(); 4545 handoverFrom.setHandoverState(HandoverState.HANDOVER_ACCEPTED); 4546 handoverFrom.onHandoverComplete(); 4547 4548 Log.addEvent(handoverTo, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 4549 handoverFrom.getId(), handoverTo.getId()); 4550 Log.addEvent(handoverFrom, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s", 4551 handoverFrom.getId(), handoverTo.getId()); 4552 4553 // Disconnect the call we handed over from. 4554 disconnectCall(handoverFrom); 4555 // If we handed over to a self-managed ConnectionService, we need to disconnect calls for 4556 // other ConnectionServices. 4557 if (handoverTo.isSelfManaged()) { 4558 disconnectOtherCalls(handoverTo.getTargetPhoneAccount()); 4559 } 4560 } 4561 4562 private void updateCanAddCall() { 4563 boolean newCanAddCall = canAddCall(); 4564 if (newCanAddCall != mCanAddCall) { 4565 mCanAddCall = newCanAddCall; 4566 for (CallsManagerListener listener : mListeners) { 4567 if (LogUtils.SYSTRACE_DEBUG) { 4568 Trace.beginSection(listener.getClass().toString() + " updateCanAddCall"); 4569 } 4570 listener.onCanAddCallChanged(mCanAddCall); 4571 if (LogUtils.SYSTRACE_DEBUG) { 4572 Trace.endSection(); 4573 } 4574 } 4575 } 4576 } 4577 4578 /** 4579 * Determines if there are any ongoing self managed calls for the given package/user. 4580 * @param packageName The package name to check. 4581 * @param userHandle The userhandle to check. 4582 * @return {@code true} if the app has ongoing calls, or {@code false} otherwise. 4583 */ 4584 public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) { 4585 return mSelfManagedCallsBeingSetup.stream().anyMatch(c -> c.isSelfManaged() 4586 && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName) 4587 && c.getTargetPhoneAccount().getUserHandle().equals(userHandle)) || 4588 mCalls.stream().anyMatch(c -> c.isSelfManaged() 4589 && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName) 4590 && c.getTargetPhoneAccount().getUserHandle().equals(userHandle)); 4591 } 4592 4593 @VisibleForTesting 4594 public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall, 4595 PhoneAccountHandle phoneAccountHandle, int... states) { 4596 return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED, 4597 excludeCall, phoneAccountHandle, states); 4598 } 4599 4600 /** 4601 * Determines the number of calls matching the specified criteria. 4602 * @param callFilter indicates whether to include just managed calls 4603 * ({@link #CALL_FILTER_MANAGED}), self-managed calls 4604 * ({@link #CALL_FILTER_SELF_MANAGED}), or all calls 4605 * ({@link #CALL_FILTER_ALL}). 4606 * @param excludeCall Where {@code non-null}, this call is excluded from the count. 4607 * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle} 4608 * are excluded from the count. 4609 * @param states The list of {@link CallState}s to include in the count. 4610 * @return Count of calls matching criteria. 4611 */ 4612 @VisibleForTesting 4613 public int getNumCallsWithState(final int callFilter, Call excludeCall, 4614 PhoneAccountHandle phoneAccountHandle, int... states) { 4615 4616 Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet()); 4617 4618 Stream<Call> callsStream = mCalls.stream() 4619 .filter(call -> desiredStates.contains(call.getState()) && 4620 call.getParentCall() == null && !call.isExternalCall()); 4621 4622 if (callFilter == CALL_FILTER_MANAGED) { 4623 callsStream = callsStream.filter(call -> !call.isSelfManaged()); 4624 } else if (callFilter == CALL_FILTER_SELF_MANAGED) { 4625 callsStream = callsStream.filter(call -> call.isSelfManaged()); 4626 } 4627 4628 // If a call to exclude was specified, filter it out. 4629 if (excludeCall != null) { 4630 callsStream = callsStream.filter(call -> call != excludeCall); 4631 } 4632 4633 // If a phone account handle was specified, only consider calls for that phone account. 4634 if (phoneAccountHandle != null) { 4635 callsStream = callsStream.filter( 4636 call -> phoneAccountHandle.equals(call.getTargetPhoneAccount())); 4637 } 4638 4639 return (int) callsStream.count(); 4640 } 4641 4642 /** 4643 * Determines the number of calls (visible to the calling user) matching the specified criteria. 4644 * This is an overloaded method which is being used in a security patch to fix up the call 4645 * state type APIs which are acting across users when they should not be. 4646 * 4647 * See {@link TelecomManager#isInCall()} and {@link TelecomManager#isInManagedCall()}. 4648 * 4649 * @param callFilter indicates whether to include just managed calls 4650 * ({@link #CALL_FILTER_MANAGED}), self-managed calls 4651 * ({@link #CALL_FILTER_SELF_MANAGED}), or all calls 4652 * ({@link #CALL_FILTER_ALL}). 4653 * @param excludeCall Where {@code non-null}, this call is excluded from the count. 4654 * @param callingUser Where {@code non-null}, call visibility is scoped to this 4655 * {@link UserHandle}. 4656 * @param hasCrossUserAccess indicates if calling user has the INTERACT_ACROSS_USERS permission. 4657 * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle} 4658 * are excluded from the count. 4659 * @param states The list of {@link CallState}s to include in the count. 4660 * @return Count of calls matching criteria. 4661 */ 4662 @VisibleForTesting 4663 public int getNumCallsWithState(final int callFilter, Call excludeCall, 4664 UserHandle callingUser, boolean hasCrossUserAccess, 4665 PhoneAccountHandle phoneAccountHandle, int... states) { 4666 4667 Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet()); 4668 4669 Stream<Call> callsStream = mCalls.stream() 4670 .filter(call -> desiredStates.contains(call.getState()) && 4671 call.getParentCall() == null && !call.isExternalCall()); 4672 4673 if (callFilter == CALL_FILTER_MANAGED) { 4674 callsStream = callsStream.filter(call -> !call.isSelfManaged()); 4675 } else if (callFilter == CALL_FILTER_SELF_MANAGED) { 4676 callsStream = callsStream.filter(call -> call.isSelfManaged()); 4677 } 4678 4679 // If a call to exclude was specified, filter it out. 4680 if (excludeCall != null) { 4681 callsStream = callsStream.filter(call -> call != excludeCall); 4682 } 4683 4684 // If a phone account handle was specified, only consider calls for that phone account. 4685 if (phoneAccountHandle != null) { 4686 callsStream = callsStream.filter( 4687 call -> phoneAccountHandle.equals(call.getTargetPhoneAccount())); 4688 } 4689 4690 callsStream = callsStream.filter( 4691 call -> hasCrossUserAccess || isCallVisibleForUser(call, callingUser)); 4692 4693 return (int) callsStream.count(); 4694 } 4695 4696 private boolean hasMaximumLiveCalls(Call exceptCall) { 4697 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 4698 exceptCall, null /* phoneAccountHandle*/, LIVE_CALL_STATES); 4699 } 4700 4701 private boolean hasMaximumManagedLiveCalls(Call exceptCall) { 4702 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */, 4703 exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES); 4704 } 4705 4706 private boolean hasMaximumSelfManagedCalls(Call exceptCall, 4707 PhoneAccountHandle phoneAccountHandle) { 4708 return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */, 4709 exceptCall, phoneAccountHandle, ANY_CALL_STATE); 4710 } 4711 4712 private boolean hasMaximumManagedHoldingCalls(Call exceptCall) { 4713 return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 4714 null /* phoneAccountHandle */, CallState.ON_HOLD); 4715 } 4716 4717 private boolean hasMaximumManagedRingingCalls(Call exceptCall) { 4718 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 4719 null /* phoneAccountHandle */, CallState.RINGING, CallState.ANSWERED); 4720 } 4721 4722 private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall, 4723 PhoneAccountHandle phoneAccountHandle) { 4724 return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall, 4725 phoneAccountHandle, CallState.RINGING, CallState.ANSWERED); 4726 } 4727 4728 private boolean hasMaximumOutgoingCalls(Call exceptCall) { 4729 return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(CALL_FILTER_ALL, 4730 exceptCall, null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 4731 } 4732 4733 private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) { 4734 return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 4735 null /* phoneAccountHandle */, OUTGOING_CALL_STATES); 4736 } 4737 4738 private boolean hasMaximumManagedDialingCalls(Call exceptCall) { 4739 return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall, 4740 null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING); 4741 } 4742 4743 /** 4744 * Given a {@link PhoneAccountHandle} determines if there are other unholdable calls owned by 4745 * another connection service. 4746 * @param phoneAccountHandle The {@link PhoneAccountHandle} to check. 4747 * @return {@code true} if there are other unholdable calls, {@code false} otherwise. 4748 */ 4749 public boolean hasUnholdableCallsForOtherConnectionService( 4750 PhoneAccountHandle phoneAccountHandle) { 4751 return getNumUnholdableCallsForOtherConnectionService(phoneAccountHandle) > 0; 4752 } 4753 4754 /** 4755 * Determines the number of unholdable calls present in a connection service other than the one 4756 * the passed phone account belongs to. If a ConnectionService has not been associated with an 4757 * outgoing call yet (for example, it is in the SELECT_PHONE_ACCOUNT state), then we do not 4758 * count that call because it is not tracked as an active call yet. 4759 * @param phoneAccountHandle The handle of the PhoneAccount. 4760 * @return Number of unholdable calls owned by other connection service. 4761 */ 4762 public int getNumUnholdableCallsForOtherConnectionService( 4763 PhoneAccountHandle phoneAccountHandle) { 4764 return (int) mCalls.stream().filter(call -> 4765 // If this convention needs to be changed, answerCall will need to be modified to 4766 // change what an "active call" is so that the call in SELECT_PHONE_ACCOUNT state 4767 // will be properly cancelled. 4768 call.getTargetPhoneAccount() != null 4769 && !phoneAccountHandle.getComponentName().equals( 4770 call.getTargetPhoneAccount().getComponentName()) 4771 && call.getParentCall() == null 4772 && !call.isExternalCall() 4773 && !canHold(call)).count(); 4774 } 4775 4776 /** 4777 * Determines if there are any managed calls. 4778 * @return {@code true} if there are managed calls, {@code false} otherwise. 4779 */ 4780 public boolean hasManagedCalls() { 4781 return mCalls.stream().filter(call -> !call.isSelfManaged() && 4782 !call.isExternalCall()).count() > 0; 4783 } 4784 4785 /** 4786 * Note: isInSelfManagedCall(packageName, UserHandle) should always be used in favor or this 4787 * method. This method determines if there are any self-managed calls globally. 4788 * @return {@code true} if there are self-managed calls, {@code false} otherwise. 4789 */ 4790 @VisibleForTesting 4791 public boolean hasSelfManagedCalls() { 4792 return mSelfManagedCallsBeingSetup.size() > 0 || 4793 mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0; 4794 } 4795 4796 /** 4797 * Determines if there are any ongoing managed or self-managed calls. 4798 * Note: The {@link #ONGOING_CALL_STATES} are 4799 * @param callingUser The user to scope the calls to. 4800 * @param hasCrossUserAccess indicates if user has the INTERACT_ACROSS_USERS permission. 4801 * @return {@code true} if there are ongoing managed or self-managed calls, {@code false} 4802 * otherwise. 4803 */ 4804 public boolean hasOngoingCalls(UserHandle callingUser, boolean hasCrossUserAccess) { 4805 return getNumCallsWithState( 4806 CALL_FILTER_ALL, null /* excludeCall */, 4807 callingUser, hasCrossUserAccess, 4808 null /* phoneAccountHandle */, 4809 ONGOING_CALL_STATES) > 0; 4810 } 4811 4812 /** 4813 * Determines if there are any ongoing managed calls. 4814 * @param callingUser The user to scope the calls to. 4815 * @param hasCrossUserAccess indicates if user has the INTERACT_ACROSS_USERS permission. 4816 * @return {@code true} if there are ongoing managed calls, {@code false} otherwise. 4817 */ 4818 public boolean hasOngoingManagedCalls(UserHandle callingUser, boolean hasCrossUserAccess) { 4819 return getNumCallsWithState( 4820 CALL_FILTER_MANAGED, null /* excludeCall */, 4821 callingUser, hasCrossUserAccess, 4822 null /* phoneAccountHandle */, 4823 ONGOING_CALL_STATES) > 0; 4824 } 4825 4826 /** 4827 * Determines if the system incoming call UI should be shown. 4828 * The system incoming call UI will be shown if the new incoming call is self-managed, and there 4829 * are ongoing calls for another PhoneAccount. 4830 * @param incomingCall The incoming call. 4831 * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise. 4832 */ 4833 public boolean shouldShowSystemIncomingCallUi(Call incomingCall) { 4834 return incomingCall.isIncoming() && incomingCall.isSelfManaged() 4835 && hasUnholdableCallsForOtherConnectionService(incomingCall.getTargetPhoneAccount()) 4836 && incomingCall.getHandoverSourceCall() == null; 4837 } 4838 4839 @VisibleForTesting 4840 public boolean makeRoomForOutgoingEmergencyCall(Call emergencyCall) { 4841 // Always disconnect any ringing/incoming calls when an emergency call is placed to minimize 4842 // distraction. This does not affect live call count. 4843 if (hasRingingOrSimulatedRingingCall()) { 4844 Call ringingCall = getRingingOrSimulatedRingingCall(); 4845 ringingCall.getAnalytics().setCallIsAdditional(true); 4846 ringingCall.getAnalytics().setCallIsInterrupted(true); 4847 if (ringingCall.getState() == CallState.SIMULATED_RINGING) { 4848 if (!ringingCall.hasGoneActiveBefore()) { 4849 // If this is an incoming call that is currently in SIMULATED_RINGING only 4850 // after a call screen, disconnect to make room and mark as missed, since 4851 // the user didn't get a chance to accept/reject. 4852 ringingCall.disconnect("emergency call dialed during simulated ringing " 4853 + "after screen."); 4854 } else { 4855 // If this is a simulated ringing call after being active and put in 4856 // AUDIO_PROCESSING state again, disconnect normally. 4857 ringingCall.reject(false, null, "emergency call dialed during simulated " 4858 + "ringing."); 4859 } 4860 } else { // normal incoming ringing call. 4861 // Hang up the ringing call to make room for the emergency call and mark as missed, 4862 // since the user did not reject. 4863 ringingCall.setOverrideDisconnectCauseCode( 4864 new DisconnectCause(DisconnectCause.MISSED)); 4865 ringingCall.reject(false, null, "emergency call dialed during ringing."); 4866 } 4867 } 4868 4869 // There is already room! 4870 if (!hasMaximumLiveCalls(emergencyCall)) return true; 4871 4872 Call liveCall = getFirstCallWithState(LIVE_CALL_STATES); 4873 Log.i(this, "makeRoomForOutgoingEmergencyCall call = " + emergencyCall 4874 + " livecall = " + liveCall); 4875 4876 if (emergencyCall == liveCall) { 4877 // Not likely, but a good correctness check. 4878 return true; 4879 } 4880 4881 if (hasMaximumOutgoingCalls(emergencyCall)) { 4882 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES); 4883 if (!outgoingCall.isEmergencyCall()) { 4884 emergencyCall.getAnalytics().setCallIsAdditional(true); 4885 outgoingCall.getAnalytics().setCallIsInterrupted(true); 4886 outgoingCall.disconnect("Disconnecting dialing call in favor of new dialing" 4887 + " emergency call."); 4888 return true; 4889 } 4890 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) { 4891 // Correctness check: if there is an orphaned emergency call in the 4892 // {@link CallState#SELECT_PHONE_ACCOUNT} state, just disconnect it since the user 4893 // has explicitly started a new call. 4894 emergencyCall.getAnalytics().setCallIsAdditional(true); 4895 outgoingCall.getAnalytics().setCallIsInterrupted(true); 4896 outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor" 4897 + " of new outgoing call."); 4898 return true; 4899 } 4900 // If the user tries to make two outgoing calls to different emergency call numbers, 4901 // we will try to connect the first outgoing call and reject the second. 4902 emergencyCall.setStartFailCause(CallFailureCause.IN_EMERGENCY_CALL); 4903 return false; 4904 } 4905 4906 if (liveCall.getState() == CallState.AUDIO_PROCESSING) { 4907 emergencyCall.getAnalytics().setCallIsAdditional(true); 4908 liveCall.getAnalytics().setCallIsInterrupted(true); 4909 liveCall.disconnect("disconnecting audio processing call for emergency"); 4910 return true; 4911 } 4912 4913 // If the live call is stuck in a connecting state, prompt the user to generate a bugreport. 4914 if (liveCall.getState() == CallState.CONNECTING) { 4915 mAnomalyReporter.reportAnomaly(LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_UUID, 4916 LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_MSG); 4917 } 4918 4919 // If we have the max number of held managed calls and we're placing an emergency call, 4920 // we'll disconnect the ongoing call if it cannot be held. 4921 if (hasMaximumManagedHoldingCalls(emergencyCall) && !canHold(liveCall)) { 4922 emergencyCall.getAnalytics().setCallIsAdditional(true); 4923 liveCall.getAnalytics().setCallIsInterrupted(true); 4924 // Disconnect the active call instead of the holding call because it is historically 4925 // easier to do, rather than disconnect a held call. 4926 liveCall.disconnect("disconnecting to make room for emergency call " 4927 + emergencyCall.getId()); 4928 return true; 4929 } 4930 4931 // TODO: Remove once b/23035408 has been corrected. 4932 // If the live call is a conference, it will not have a target phone account set. This 4933 // means the check to see if the live call has the same target phone account as the new 4934 // call will not cause us to bail early. As a result, we'll end up holding the 4935 // ongoing conference call. However, the ConnectionService is already doing that. This 4936 // has caused problems with some carriers. As a workaround until b/23035408 is 4937 // corrected, we will try and get the target phone account for one of the conference's 4938 // children and use that instead. 4939 PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount(); 4940 if (liveCallPhoneAccount == null && liveCall.isConference() && 4941 !liveCall.getChildCalls().isEmpty()) { 4942 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall); 4943 Log.i(this, "makeRoomForOutgoingEmergencyCall: using child call PhoneAccount = " + 4944 liveCallPhoneAccount); 4945 } 4946 4947 // We may not know which PhoneAccount the emergency call will be placed on yet, but if 4948 // the liveCall PhoneAccount does not support placing emergency calls, then we know it 4949 // will not be that one and we do not want multiple PhoneAccounts active during an 4950 // emergency call if possible. Disconnect the active call in favor of the emergency call 4951 // instead of trying to hold. 4952 if (liveCall.getTargetPhoneAccount() != null) { 4953 PhoneAccount pa = mPhoneAccountRegistrar.getPhoneAccountUnchecked( 4954 liveCall.getTargetPhoneAccount()); 4955 if((pa.getCapabilities() & PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) == 0) { 4956 liveCall.setOverrideDisconnectCauseCode(new DisconnectCause( 4957 DisconnectCause.LOCAL, DisconnectCause.REASON_EMERGENCY_CALL_PLACED)); 4958 liveCall.disconnect("outgoing call does not support emergency calls, " 4959 + "disconnecting."); 4960 } 4961 return true; 4962 } 4963 4964 // First thing, if we are trying to make an emergency call with the same package name as 4965 // the live call, then allow it so that the connection service can make its own decision 4966 // about how to handle the new call relative to the current one. 4967 // By default, for telephony, it will try to hold the existing call before placing the new 4968 // emergency call except for if the carrier does not support holding calls for emergency. 4969 // In this case, telephony will disconnect the call. 4970 if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount, 4971 emergencyCall.getTargetPhoneAccount())) { 4972 Log.i(this, "makeRoomForOutgoingEmergencyCall: phoneAccount matches."); 4973 emergencyCall.getAnalytics().setCallIsAdditional(true); 4974 liveCall.getAnalytics().setCallIsInterrupted(true); 4975 return true; 4976 } else if (emergencyCall.getTargetPhoneAccount() == null) { 4977 // Without a phone account, we can't say reliably that the call will fail. 4978 // If the user chooses the same phone account as the live call, then it's 4979 // still possible that the call can be made (like with CDMA calls not supporting 4980 // hold but they still support adding a call by going immediately into conference 4981 // mode). Return true here and we'll run this code again after user chooses an 4982 // account. 4983 return true; 4984 } 4985 4986 // Hold the live call if possible before attempting the new outgoing emergency call. 4987 if (canHold(liveCall)) { 4988 Log.i(this, "makeRoomForOutgoingEmergencyCall: holding live call."); 4989 emergencyCall.getAnalytics().setCallIsAdditional(true); 4990 emergencyCall.increaseHeldByThisCallCount(); 4991 liveCall.getAnalytics().setCallIsInterrupted(true); 4992 liveCall.hold("calling " + emergencyCall.getId()); 4993 return true; 4994 } 4995 4996 // The live call cannot be held so we're out of luck here. There's no room. 4997 emergencyCall.setStartFailCause(CallFailureCause.CANNOT_HOLD_CALL); 4998 return false; 4999 } 5000 5001 @VisibleForTesting 5002 public boolean makeRoomForOutgoingCall(Call call) { 5003 // Already room! 5004 if (!hasMaximumLiveCalls(call)) return true; 5005 5006 // NOTE: If the amount of live calls changes beyond 1, this logic will probably 5007 // have to change. 5008 Call liveCall = getFirstCallWithState(LIVE_CALL_STATES); 5009 Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " + 5010 liveCall); 5011 5012 if (call == liveCall) { 5013 // If the call is already the foreground call, then we are golden. 5014 // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT 5015 // state since the call was already populated into the list. 5016 return true; 5017 } 5018 5019 // If the live call is stuck in a connecting state for longer than the transitory timeout, 5020 // then we should disconnect it in favor of the new outgoing call and prompt the user to 5021 // generate a bugreport. 5022 // TODO: In the future we should let the CallAnomalyWatchDog do this disconnection of the 5023 // live call stuck in the connecting state. Unfortunately that code will get tripped up by 5024 // calls that have a longer than expected new outgoing call broadcast response time. This 5025 // mitigation is intended to catch calls stuck in a CONNECTING state for a long time that 5026 // block outgoing calls. However, if the user dials two calls in quick succession it will 5027 // result in both calls getting disconnected, which is not optimal. 5028 if (liveCall.getState() == CallState.CONNECTING 5029 && ((mClockProxy.elapsedRealtime() - liveCall.getCreationElapsedRealtimeMillis()) 5030 > mTimeoutsAdapter.getNonVoipCallTransitoryStateTimeoutMillis())) { 5031 mAnomalyReporter.reportAnomaly(LIVE_CALL_STUCK_CONNECTING_ERROR_UUID, 5032 LIVE_CALL_STUCK_CONNECTING_ERROR_MSG); 5033 liveCall.disconnect("Force disconnect CONNECTING call."); 5034 return true; 5035 } 5036 5037 if (hasMaximumOutgoingCalls(call)) { 5038 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES); 5039 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) { 5040 // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT} 5041 // state, just disconnect it since the user has explicitly started a new call. 5042 call.getAnalytics().setCallIsAdditional(true); 5043 outgoingCall.getAnalytics().setCallIsInterrupted(true); 5044 outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor" 5045 + " of new outgoing call."); 5046 return true; 5047 } 5048 call.setStartFailCause(CallFailureCause.MAX_OUTGOING_CALLS); 5049 return false; 5050 } 5051 5052 // TODO: Remove once b/23035408 has been corrected. 5053 // If the live call is a conference, it will not have a target phone account set. This 5054 // means the check to see if the live call has the same target phone account as the new 5055 // call will not cause us to bail early. As a result, we'll end up holding the 5056 // ongoing conference call. However, the ConnectionService is already doing that. This 5057 // has caused problems with some carriers. As a workaround until b/23035408 is 5058 // corrected, we will try and get the target phone account for one of the conference's 5059 // children and use that instead. 5060 PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount(); 5061 if (liveCallPhoneAccount == null && liveCall.isConference() && 5062 !liveCall.getChildCalls().isEmpty()) { 5063 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall); 5064 Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " + 5065 liveCallPhoneAccount); 5066 } 5067 5068 // First thing, for managed calls, if we are trying to make a call with the same phone 5069 // account as the live call, then allow it so that the connection service can make its own 5070 // decision about how to handle the new call relative to the current one. 5071 // Note: This behavior is primarily in place because Telephony historically manages the 5072 // state of the calls it tracks by itself, holding and unholding as needed. Self-managed 5073 // calls, even though from the same package are normally held/unheld automatically by 5074 // Telecom. Calls within a single ConnectionService get held/unheld automatically during 5075 // "swap" operations by CallsManager#holdActiveCallForNewCall. There is, however, a quirk 5076 // in that if an app declares TWO different ConnectionServices, holdActiveCallForNewCall 5077 // would not work correctly because focus switches between ConnectionServices, yet we 5078 // tended to assume that if the calls are from the same package that the hold/unhold should 5079 // be done by the app. That was a bad assumption as it meant that we could have two active 5080 // calls. 5081 // TODO(b/280826075): We need to come back and revisit all this logic in a holistic manner. 5082 if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount, 5083 call.getTargetPhoneAccount()) 5084 && !call.isSelfManaged() 5085 && !liveCall.isSelfManaged()) { 5086 Log.i(this, "makeRoomForOutgoingCall: managed phoneAccount matches"); 5087 call.getAnalytics().setCallIsAdditional(true); 5088 liveCall.getAnalytics().setCallIsInterrupted(true); 5089 return true; 5090 } else if (call.getTargetPhoneAccount() == null) { 5091 // Without a phone account, we can't say reliably that the call will fail. 5092 // If the user chooses the same phone account as the live call, then it's 5093 // still possible that the call can be made (like with CDMA calls not supporting 5094 // hold but they still support adding a call by going immediately into conference 5095 // mode). Return true here and we'll run this code again after user chooses an 5096 // account. 5097 return true; 5098 } 5099 5100 // Try to hold the live call before attempting the new outgoing call. 5101 if (canHold(liveCall)) { 5102 Log.i(this, "makeRoomForOutgoingCall: holding live call."); 5103 call.getAnalytics().setCallIsAdditional(true); 5104 liveCall.getAnalytics().setCallIsInterrupted(true); 5105 liveCall.hold("calling " + call.getId()); 5106 return true; 5107 } 5108 5109 // The live call cannot be held so we're out of luck here. There's no room. 5110 call.setStartFailCause(CallFailureCause.CANNOT_HOLD_CALL); 5111 return false; 5112 } 5113 5114 /** 5115 * Given a call, find the first non-null phone account handle of its children. 5116 * 5117 * @param parentCall The parent call. 5118 * @return The first non-null phone account handle of the children, or {@code null} if none. 5119 */ 5120 private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) { 5121 for (Call childCall : parentCall.getChildCalls()) { 5122 PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount(); 5123 if (childPhoneAccount != null) { 5124 return childPhoneAccount; 5125 } 5126 } 5127 return null; 5128 } 5129 5130 /** 5131 * Checks to see if the call should be on speakerphone and if so, set it. 5132 */ 5133 private void maybeMoveToSpeakerPhone(Call call) { 5134 if (call.isHandoverInProgress() && call.getState() == CallState.DIALING) { 5135 // When a new outgoing call is initiated for the purpose of handing over, do not engage 5136 // speaker automatically until the call goes active. 5137 return; 5138 } 5139 if (call.getStartWithSpeakerphoneOn()) { 5140 setAudioRoute(CallAudioState.ROUTE_SPEAKER, null); 5141 call.setStartWithSpeakerphoneOn(false); 5142 } 5143 } 5144 5145 /** 5146 * Checks to see if the call is an emergency call and if so, turn off mute. 5147 */ 5148 private void maybeTurnOffMute(Call call) { 5149 if (call.isEmergencyCall()) { 5150 mute(false); 5151 } 5152 } 5153 5154 /** 5155 * Ensures that the call will be audible to the user by checking if the voice call stream is 5156 * audible, and if not increasing the volume to the default value. 5157 */ 5158 private void ensureCallAudible() { 5159 // Audio manager APIs can be somewhat slow. To prevent a potential ANR we will fire off 5160 // this opreation on the async task executor. Note that this operation does not have any 5161 // dependency on any Telecom state, so we can safely launch this on a different thread 5162 // without worrying that it is in the Telecom sync lock. 5163 mAsyncTaskExecutor.execute(() -> { 5164 AudioManager am = mContext.getSystemService(AudioManager.class); 5165 if (am == null) { 5166 Log.w(this, "ensureCallAudible: audio manager is null"); 5167 return; 5168 } 5169 if (am.getStreamVolume(AudioManager.STREAM_VOICE_CALL) == 0) { 5170 Log.i(this, 5171 "ensureCallAudible: voice call stream has volume 0. Adjusting to default."); 5172 am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 5173 AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL), 0); 5174 } 5175 }); 5176 } 5177 5178 /** 5179 * Asynchronously updates the emergency call notification. 5180 * @param context the context for the update. 5181 */ 5182 private void updateEmergencyCallNotificationAsync(Context context) { 5183 mAsyncTaskExecutor.execute(() -> { 5184 Log.startSession("CM.UEMCNA"); 5185 try { 5186 boolean shouldShow = mBlockedNumbersAdapter.shouldShowEmergencyCallNotification( 5187 context); 5188 Log.i(CallsManager.this, "updateEmergencyCallNotificationAsync; show=%b", 5189 shouldShow); 5190 mBlockedNumbersAdapter.updateEmergencyCallNotification(context, shouldShow); 5191 } finally { 5192 Log.endSession(); 5193 } 5194 }); 5195 } 5196 5197 /** 5198 * Creates a new call for an existing connection. 5199 * 5200 * @param callId The id of the new call. 5201 * @param connection The connection information. 5202 * @return The new call. 5203 */ 5204 Call createCallForExistingConnection(String callId, ParcelableConnection connection) { 5205 boolean isDowngradedConference = (connection.getConnectionProperties() 5206 & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0; 5207 5208 PhoneAccountHandle connectionMgr = 5209 mPhoneAccountRegistrar.getSimCallManagerFromHandle(connection.getPhoneAccount(), 5210 mCurrentUserHandle); 5211 Call call = new Call( 5212 callId, 5213 mContext, 5214 this, 5215 mLock, 5216 mConnectionServiceRepository, 5217 mPhoneNumberUtilsAdapter, 5218 connection.getHandle() /* handle */, 5219 null /* gatewayInfo */, 5220 connectionMgr, 5221 connection.getPhoneAccount(), /* targetPhoneAccountHandle */ 5222 Call.getRemappedCallDirection(connection.getCallDirection()) /* callDirection */, 5223 false /* forceAttachToExistingConnection */, 5224 isDowngradedConference /* isConference */, 5225 connection.getConnectTimeMillis() /* connectTimeMillis */, 5226 connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */ 5227 mClockProxy, 5228 mToastFactory); 5229 5230 call.initAnalytics(); 5231 call.getAnalytics().setCreatedFromExistingConnection(true); 5232 5233 setCallState(call, Call.getStateFromConnectionState(connection.getState()), 5234 "existing connection"); 5235 call.setVideoState(connection.getVideoState()); 5236 call.setConnectionCapabilities(connection.getConnectionCapabilities()); 5237 call.setConnectionProperties(connection.getConnectionProperties()); 5238 call.setHandle(connection.getHandle(), connection.getHandlePresentation()); 5239 call.setCallerDisplayName(connection.getCallerDisplayName(), 5240 connection.getCallerDisplayNamePresentation()); 5241 // For existing connections, use the phone account user handle to determine the user 5242 // association with the call. 5243 call.setAssociatedUser(connection.getPhoneAccount().getUserHandle()); 5244 call.addListener(this); 5245 call.putConnectionServiceExtras(connection.getExtras()); 5246 5247 Log.i(this, "createCallForExistingConnection: %s", connection); 5248 Call parentCall = null; 5249 if (!TextUtils.isEmpty(connection.getParentCallId())) { 5250 String parentId = connection.getParentCallId(); 5251 parentCall = mCalls 5252 .stream() 5253 .filter(c -> c.getId().equals(parentId)) 5254 .findFirst() 5255 .orElse(null); 5256 if (parentCall != null) { 5257 Log.i(this, "createCallForExistingConnection: %s added as child of %s.", 5258 call.getId(), 5259 parentCall.getId()); 5260 // Set JUST the parent property, which won't send an update to the Incall UI. 5261 call.setParentCall(parentCall); 5262 } 5263 } 5264 // Existing connections originate from a connection service, so they are completed creation 5265 // by the ConnectionService implicitly. 5266 call.setIsCreateConnectionComplete(true); 5267 addCall(call); 5268 if (parentCall != null) { 5269 // Now, set the call as a child of the parent since it has been added to Telecom. This 5270 // is where we will inform InCall. 5271 call.setChildOf(parentCall); 5272 call.notifyParentChanged(parentCall); 5273 } 5274 5275 return call; 5276 } 5277 5278 /** 5279 * Determines whether Telecom already knows about a Connection added via the 5280 * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle, 5281 * Connection)} API via a ConnectionManager. 5282 * 5283 * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}. 5284 * @param originalConnectionId The new connection ID to check. 5285 * @return {@code true} if this connection is already known by Telecom. 5286 */ 5287 Call getAlreadyAddedConnection(String originalConnectionId) { 5288 Optional<Call> existingCall = mCalls.stream() 5289 .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) || 5290 originalConnectionId.equals(call.getId())) 5291 .findFirst(); 5292 5293 if (existingCall.isPresent()) { 5294 Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s", 5295 originalConnectionId, existingCall.get().getId()); 5296 return existingCall.get(); 5297 } 5298 5299 return null; 5300 } 5301 5302 /** 5303 * @return A new unique telecom call Id. 5304 */ 5305 private String getNextCallId() { 5306 synchronized(mLock) { 5307 return TELECOM_CALL_ID_PREFIX + (++mCallId); 5308 } 5309 } 5310 5311 public int getNextRttRequestId() { 5312 synchronized (mLock) { 5313 return (++mRttRequestId); 5314 } 5315 } 5316 5317 /** 5318 * Callback when foreground user is switched. We will reload missed call in all profiles 5319 * including the user itself. There may be chances that profiles are not started yet. 5320 */ 5321 @VisibleForTesting 5322 public void onUserSwitch(UserHandle userHandle) { 5323 mCurrentUserHandle = userHandle; 5324 mMissedCallNotifier.setCurrentUserHandle(userHandle); 5325 mRoleManagerAdapter.setCurrentUserHandle(userHandle); 5326 final UserManager userManager = UserManager.get(mContext); 5327 List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier()); 5328 for (UserInfo profile : profiles) { 5329 reloadMissedCallsOfUser(profile.getUserHandle()); 5330 } 5331 } 5332 5333 /** 5334 * Because there may be chances that profiles are not started yet though its parent user is 5335 * switched, we reload missed calls of profile that are just started here. 5336 */ 5337 void onUserStarting(UserHandle userHandle) { 5338 if (UserUtil.isProfile(mContext, userHandle)) { 5339 reloadMissedCallsOfUser(userHandle); 5340 } 5341 } 5342 5343 public TelecomSystem.SyncRoot getLock() { 5344 return mLock; 5345 } 5346 5347 public Timeouts.Adapter getTimeoutsAdapter() { 5348 return mTimeoutsAdapter; 5349 } 5350 5351 public SystemStateHelper getSystemStateHelper() { 5352 return mSystemStateHelper; 5353 } 5354 5355 private void reloadMissedCallsOfUser(UserHandle userHandle) { 5356 mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper, 5357 new MissedCallNotifier.CallInfoFactory(), userHandle); 5358 } 5359 5360 public void onBootCompleted() { 5361 mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper, 5362 new MissedCallNotifier.CallInfoFactory()); 5363 } 5364 5365 public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 5366 return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle); 5367 } 5368 5369 public boolean isIncomingCallPermitted(Call excludeCall, 5370 PhoneAccountHandle phoneAccountHandle) { 5371 return checkIncomingCallPermitted(excludeCall, phoneAccountHandle).isSuccess(); 5372 } 5373 5374 private CallFailureCause checkIncomingCallPermitted( 5375 Call call, PhoneAccountHandle phoneAccountHandle) { 5376 if (phoneAccountHandle == null) { 5377 return CallFailureCause.INVALID_USE; 5378 } 5379 5380 PhoneAccount phoneAccount = 5381 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 5382 if (phoneAccount == null) { 5383 return CallFailureCause.INVALID_USE; 5384 } 5385 5386 if (isInEmergencyCall()) { 5387 return CallFailureCause.IN_EMERGENCY_CALL; 5388 } 5389 5390 if (phoneAccount.isSelfManaged()) { 5391 if (hasMaximumSelfManagedRingingCalls(call, phoneAccountHandle)) { 5392 return CallFailureCause.MAX_RINGING_CALLS; 5393 } 5394 if (hasMaximumSelfManagedCalls(call, phoneAccountHandle)) { 5395 return CallFailureCause.MAX_SELF_MANAGED_CALLS; 5396 } 5397 } else { 5398 if (hasMaximumManagedRingingCalls(call)) { 5399 return CallFailureCause.MAX_RINGING_CALLS; 5400 } 5401 if (hasMaximumManagedHoldingCalls(call)) { 5402 return CallFailureCause.MAX_HOLD_CALLS; 5403 } 5404 } 5405 5406 return CallFailureCause.NONE; 5407 } 5408 5409 public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) { 5410 return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle); 5411 } 5412 5413 public boolean isOutgoingCallPermitted(Call excludeCall, 5414 PhoneAccountHandle phoneAccountHandle) { 5415 if (phoneAccountHandle == null) { 5416 return false; 5417 } 5418 PhoneAccount phoneAccount = 5419 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); 5420 if (phoneAccount == null) { 5421 return false; 5422 } 5423 5424 if (!phoneAccount.isSelfManaged()) { 5425 return !hasMaximumManagedOutgoingCalls(excludeCall) && 5426 !hasMaximumManagedDialingCalls(excludeCall) && 5427 !hasMaximumManagedLiveCalls(excludeCall) && 5428 !hasMaximumManagedHoldingCalls(excludeCall); 5429 } else { 5430 // Only permit self-managed outgoing calls if 5431 // 1. there is no emergency ongoing call 5432 // 2. The outgoing call is an handover call or it not hit the self-managed call limit 5433 // and the current active call can be held. 5434 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 5435 return !isInEmergencyCall() && 5436 ((excludeCall != null && excludeCall.getHandoverSourceCall() != null) || 5437 (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) && 5438 (activeCall == null || canHold(activeCall)))); 5439 } 5440 } 5441 5442 public boolean isReplyWithSmsAllowed(int uid) { 5443 UserHandle callingUser = UserHandle.of(UserHandle.getUserId(uid)); 5444 UserManager userManager = mContext.getSystemService(UserManager.class); 5445 KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class); 5446 5447 boolean isUserRestricted = userManager != null 5448 && userManager.hasUserRestriction(UserManager.DISALLOW_SMS, callingUser); 5449 boolean isLockscreenRestricted = keyguardManager != null 5450 && keyguardManager.isDeviceLocked(); 5451 Log.d(this, "isReplyWithSmsAllowed: isUserRestricted: %s, isLockscreenRestricted: %s", 5452 isUserRestricted, isLockscreenRestricted); 5453 5454 // TODO(hallliu): actually check the lockscreen once b/77731473 is fixed 5455 return !isUserRestricted; 5456 } 5457 /** 5458 * Blocks execution until all Telecom handlers have completed their current work. 5459 */ 5460 public void waitOnHandlers() { 5461 CountDownLatch mainHandlerLatch = new CountDownLatch(3); 5462 mHandler.post(() -> { 5463 mainHandlerLatch.countDown(); 5464 }); 5465 mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> { 5466 mainHandlerLatch.countDown(); 5467 }); 5468 mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> { 5469 mainHandlerLatch.countDown(); 5470 }); 5471 5472 try { 5473 mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS); 5474 } catch (InterruptedException e) { 5475 Log.w(this, "waitOnHandlers: interrupted %s", e); 5476 } 5477 } 5478 5479 /** 5480 * Used to confirm creation of an outgoing call which was marked as pending confirmation in 5481 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)}. 5482 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 5483 * {@link ConfirmCallDialogActivity}. 5484 * @param callId The call ID of the call to confirm. 5485 */ 5486 public void confirmPendingCall(String callId) { 5487 Log.i(this, "confirmPendingCall: callId=%s", callId); 5488 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 5489 Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED); 5490 5491 // We are going to place the new outgoing call, so disconnect any ongoing self-managed 5492 // calls which are ongoing at this time. 5493 disconnectSelfManagedCalls("outgoing call " + callId); 5494 5495 mPendingCallConfirm.complete(mPendingCall); 5496 mPendingCallConfirm = null; 5497 mPendingCall = null; 5498 } 5499 } 5500 5501 /** 5502 * Used to cancel an outgoing call which was marked as pending confirmation in 5503 * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)}. 5504 * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via 5505 * {@link ConfirmCallDialogActivity}. 5506 * @param callId The call ID of the call to cancel. 5507 */ 5508 public void cancelPendingCall(String callId) { 5509 Log.i(this, "cancelPendingCall: callId=%s", callId); 5510 if (mPendingCall != null && mPendingCall.getId().equals(callId)) { 5511 Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED); 5512 markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED)); 5513 markCallAsRemoved(mPendingCall); 5514 mPendingCall = null; 5515 mPendingCallConfirm.complete(null); 5516 mPendingCallConfirm = null; 5517 } 5518 } 5519 5520 /** 5521 * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent, String)} when 5522 * a managed call is added while there are ongoing self-managed calls. Starts 5523 * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the 5524 * outgoing call or not. 5525 * @param call The call to confirm. 5526 */ 5527 private void startCallConfirmation(Call call, CompletableFuture<Call> confirmationFuture) { 5528 if (mPendingCall != null) { 5529 Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s", 5530 mPendingCall.getId(), call.getId()); 5531 markCallDisconnectedDueToSelfManagedCall(call); 5532 confirmationFuture.complete(null); 5533 return; 5534 } 5535 Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION); 5536 mPendingCall = call; 5537 mPendingCallConfirm = confirmationFuture; 5538 5539 // Figure out the name of the app in charge of the self-managed call(s). 5540 Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 5541 if (activeCall != null) { 5542 CharSequence ongoingAppName = activeCall.getTargetPhoneAccountLabel(); 5543 Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(), 5544 ongoingAppName); 5545 5546 Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class); 5547 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId()); 5548 confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName); 5549 confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5550 mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT); 5551 } 5552 } 5553 5554 /** 5555 * Disconnects all self-managed calls. 5556 */ 5557 private void disconnectSelfManagedCalls(String reason) { 5558 // Disconnect all self-managed calls to make priority for emergency call. 5559 // Use Call.disconnect() to command the ConnectionService to disconnect the calls. 5560 // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to 5561 // disconnect. 5562 mCalls.stream() 5563 .filter(c -> c.isSelfManaged()) 5564 .forEach(c -> c.disconnect(reason)); 5565 5566 // When disconnecting all self-managed calls, switch audio routing back to the baseline 5567 // route. This ensures if, for example, the self-managed ConnectionService was routed to 5568 // speakerphone that we'll switch back to earpiece for the managed call which necessitated 5569 // disconnecting the self-managed calls. 5570 mCallAudioManager.switchBaseline(); 5571 } 5572 5573 /** 5574 * Dumps the state of the {@link CallsManager}. 5575 * 5576 * @param pw The {@code IndentingPrintWriter} to write the state to. 5577 */ 5578 public void dump(IndentingPrintWriter pw, String[] args) { 5579 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 5580 if (mCalls != null) { 5581 pw.println("mCalls: "); 5582 pw.increaseIndent(); 5583 for (Call call : mCalls) { 5584 pw.println(call); 5585 } 5586 pw.decreaseIndent(); 5587 } 5588 5589 if (mPendingCall != null) { 5590 pw.print("mPendingCall:"); 5591 pw.println(mPendingCall.getId()); 5592 } 5593 5594 if (mPendingRedirectedOutgoingCallInfo.size() > 0) { 5595 pw.print("mPendingRedirectedOutgoingCallInfo:"); 5596 pw.println(mPendingRedirectedOutgoingCallInfo.keySet().stream().collect( 5597 Collectors.joining(", "))); 5598 } 5599 5600 if (mPendingUnredirectedOutgoingCallInfo.size() > 0) { 5601 pw.print("mPendingUnredirectedOutgoingCallInfo:"); 5602 pw.println(mPendingUnredirectedOutgoingCallInfo.keySet().stream().collect( 5603 Collectors.joining(", "))); 5604 } 5605 5606 if (mCallAudioManager != null) { 5607 pw.println("mCallAudioManager:"); 5608 pw.increaseIndent(); 5609 mCallAudioManager.dump(pw); 5610 pw.decreaseIndent(); 5611 } 5612 5613 if (mTtyManager != null) { 5614 pw.println("mTtyManager:"); 5615 pw.increaseIndent(); 5616 mTtyManager.dump(pw); 5617 pw.decreaseIndent(); 5618 } 5619 5620 if (mInCallController != null) { 5621 pw.println("mInCallController:"); 5622 pw.increaseIndent(); 5623 mInCallController.dump(pw); 5624 pw.decreaseIndent(); 5625 } 5626 5627 if (mCallDiagnosticServiceController != null) { 5628 pw.println("mCallDiagnosticServiceController:"); 5629 pw.increaseIndent(); 5630 mCallDiagnosticServiceController.dump(pw); 5631 pw.decreaseIndent(); 5632 } 5633 5634 if (mCallAnomalyWatchdog != null) { 5635 pw.println("mCallAnomalyWatchdog:"); 5636 pw.increaseIndent(); 5637 mCallAnomalyWatchdog.dump(pw); 5638 pw.decreaseIndent(); 5639 } 5640 5641 if (mEmergencyCallDiagnosticLogger != null) { 5642 pw.println("mEmergencyCallDiagnosticLogger:"); 5643 pw.increaseIndent(); 5644 mEmergencyCallDiagnosticLogger.dump(pw, args); 5645 pw.decreaseIndent(); 5646 } 5647 5648 if (mDefaultDialerCache != null) { 5649 pw.println("mDefaultDialerCache:"); 5650 pw.increaseIndent(); 5651 mDefaultDialerCache.dumpCache(pw); 5652 pw.decreaseIndent(); 5653 } 5654 5655 if (mConnectionServiceRepository != null) { 5656 pw.println("mConnectionServiceRepository:"); 5657 pw.increaseIndent(); 5658 mConnectionServiceRepository.dump(pw); 5659 pw.decreaseIndent(); 5660 } 5661 5662 if (mRoleManagerAdapter != null && mRoleManagerAdapter instanceof RoleManagerAdapterImpl) { 5663 RoleManagerAdapterImpl impl = (RoleManagerAdapterImpl) mRoleManagerAdapter; 5664 pw.println("mRoleManager:"); 5665 pw.increaseIndent(); 5666 impl.dump(pw); 5667 pw.decreaseIndent(); 5668 } 5669 5670 if (mConnectionSvrFocusMgr != null) { 5671 pw.println("mConnectionSvrFocusMgr:"); 5672 pw.increaseIndent(); 5673 mConnectionSvrFocusMgr.dump(pw); 5674 pw.decreaseIndent(); 5675 } 5676 } 5677 5678 /** 5679 * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code. 5680 * 5681 * @param call The call. 5682 */ 5683 private void maybeShowErrorDialogOnDisconnect(Call call) { 5684 if (call.getState() == CallState.DISCONNECTED && (mMmiUtils.isPotentialMMICode( 5685 call.getHandle()) 5686 || mMmiUtils.isPotentialInCallMMICode(call.getHandle())) && !mCalls.contains( 5687 call)) { 5688 DisconnectCause disconnectCause = call.getDisconnectCause(); 5689 if (!TextUtils.isEmpty(disconnectCause.getDescription()) && ((disconnectCause.getCode() 5690 == DisconnectCause.ERROR) || (disconnectCause.getCode() 5691 == DisconnectCause.RESTRICTED))) { 5692 Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 5693 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA, 5694 disconnectCause.getDescription()); 5695 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5696 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 5697 } 5698 } 5699 } 5700 5701 private void setIntentExtrasAndStartTime(Call call, Bundle extras) { 5702 if (extras != null) { 5703 // Create our own instance to modify (since extras may be Bundle.EMPTY) 5704 extras = new Bundle(extras); 5705 } else { 5706 extras = new Bundle(); 5707 } 5708 5709 // Specifies the time telecom began routing the call. This is used by the dialer for 5710 // analytics. 5711 extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, 5712 SystemClock.elapsedRealtime()); 5713 5714 if (call.visibleToInCallService()) { 5715 extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true); 5716 } 5717 call.setIntentExtras(extras); 5718 } 5719 5720 private void setCallSourceToAnalytics(Call call, Intent originalIntent) { 5721 if (originalIntent == null) { 5722 return; 5723 } 5724 5725 int callSource = originalIntent.getIntExtra(TelecomManager.EXTRA_CALL_SOURCE, 5726 Analytics.CALL_SOURCE_UNSPECIFIED); 5727 5728 // Call source is only used by metrics, so we simply set it to Analytics directly. 5729 call.getAnalytics().setCallSource(callSource); 5730 } 5731 5732 private boolean isVoicemail(Uri callHandle, PhoneAccount phoneAccount) { 5733 if (callHandle == null) { 5734 return false; 5735 } 5736 if (PhoneAccount.SCHEME_VOICEMAIL.equals(callHandle.getScheme())) { 5737 return true; 5738 } 5739 return phoneAccount != null && mPhoneAccountRegistrar.isVoiceMailNumber( 5740 phoneAccount.getAccountHandle(), 5741 callHandle.getSchemeSpecificPart()); 5742 } 5743 5744 /** 5745 * Notifies the {@link android.telecom.ConnectionService} associated with a 5746 * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. 5747 * 5748 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 5749 * @param call The {@link Call} which could not be added. 5750 */ 5751 private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) { 5752 if (phoneAccountHandle == null) { 5753 return; 5754 } 5755 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 5756 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); 5757 if (service == null) { 5758 Log.i(this, "Found no connection service."); 5759 return; 5760 } else { 5761 call.setConnectionService(service); 5762 service.createConnectionFailed(call); 5763 if (!mCalls.contains(call)){ 5764 mListeners.forEach(l -> l.onCreateConnectionFailed(call)); 5765 } 5766 } 5767 } 5768 5769 /** 5770 * Notifies the {@link android.telecom.ConnectionService} associated with a 5771 * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. 5772 * 5773 * @param phoneAccountHandle The {@link PhoneAccountHandle}. 5774 * @param call The {@link Call} which could not be added. 5775 */ 5776 private void notifyCreateConferenceFailed(PhoneAccountHandle phoneAccountHandle, Call call) { 5777 if (phoneAccountHandle == null) { 5778 return; 5779 } 5780 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 5781 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); 5782 if (service == null) { 5783 Log.i(this, "Found no connection service."); 5784 return; 5785 } else { 5786 call.setConnectionService(service); 5787 service.createConferenceFailed(call); 5788 if (!mCalls.contains(call)){ 5789 mListeners.forEach(l -> l.onCreateConnectionFailed(call)); 5790 } 5791 } 5792 } 5793 5794 /** 5795 * Notify interested parties that a new call is about to be handed off to a ConnectionService to 5796 * be created. 5797 * @param theCall the new call. 5798 */ 5799 private void notifyStartCreateConnection(final Call theCall) { 5800 mListeners.forEach(l -> l.onStartCreateConnection(theCall)); 5801 } 5802 5803 /** 5804 * Notifies the {@link android.telecom.ConnectionService} associated with a 5805 * {@link PhoneAccountHandle} that the attempt to handover a call has failed. 5806 * 5807 * @param call The handover call 5808 * @param reason The error reason code for handover failure 5809 */ 5810 private void notifyHandoverFailed(Call call, int reason) { 5811 ConnectionServiceWrapper service = call.getConnectionService(); 5812 service.handoverFailed(call, reason); 5813 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 5814 call.disconnect("handover failed"); 5815 } 5816 5817 /** 5818 * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)} 5819 * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the 5820 * {@link android.telecom.InCallService} has requested a handover to another 5821 * {@link android.telecom.ConnectionService}. 5822 * 5823 * We will explicitly disallow a handover when there is an emergency call present. 5824 * 5825 * @param handoverFromCall The {@link Call} to be handed over. 5826 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 5827 * @param videoState The desired video state of {@link Call} after handover. 5828 * @param initiatingExtras Extras associated with the handover, to be passed to the handover 5829 * {@link android.telecom.ConnectionService}. 5830 */ 5831 private void requestHandoverViaEvents(Call handoverFromCall, 5832 PhoneAccountHandle handoverToHandle, 5833 int videoState, Bundle initiatingExtras) { 5834 5835 handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null); 5836 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, "legacy request denied"); 5837 } 5838 5839 /** 5840 * Called in response to a {@link Call} receiving a {@link Call#handoverTo(PhoneAccountHandle, 5841 * int, Bundle)} indicating the {@link android.telecom.InCallService} has requested a 5842 * handover to another {@link android.telecom.ConnectionService}. 5843 * 5844 * We will explicitly disallow a handover when there is an emergency call present. 5845 * 5846 * @param handoverFromCall The {@link Call} to be handed over. 5847 * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to. 5848 * @param videoState The desired video state of {@link Call} after handover. 5849 * @param extras Extras associated with the handover, to be passed to the handover 5850 * {@link android.telecom.ConnectionService}. 5851 */ 5852 private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle, 5853 int videoState, Bundle extras) { 5854 5855 // Send an error back if there are any ongoing emergency calls. 5856 if (isInEmergencyCall()) { 5857 handoverFromCall.onHandoverFailed( 5858 android.telecom.Call.Callback.HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL); 5859 return; 5860 } 5861 5862 // If source and destination phone accounts don't support handover, send an error back. 5863 boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported( 5864 handoverFromCall.getTargetPhoneAccount()); 5865 boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle); 5866 if (!isHandoverFromSupported || !isHandoverToSupported) { 5867 handoverFromCall.onHandoverFailed( 5868 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 5869 return; 5870 } 5871 5872 Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle); 5873 5874 // Create a new instance of Call 5875 PhoneAccount account = 5876 mPhoneAccountRegistrar.getPhoneAccount(handoverToHandle, getCurrentUserHandle()); 5877 boolean isSelfManaged = account != null && account.isSelfManaged(); 5878 5879 Call call = new Call(getNextCallId(), mContext, 5880 this, mLock, mConnectionServiceRepository, 5881 mPhoneNumberUtilsAdapter, 5882 handoverFromCall.getHandle(), null, 5883 null, null, 5884 Call.CALL_DIRECTION_OUTGOING, false, 5885 false, mClockProxy, mToastFactory); 5886 call.initAnalytics(); 5887 5888 // Set self-managed and voipAudioMode if destination is self-managed CS 5889 call.setIsSelfManaged(isSelfManaged); 5890 if (isSelfManaged) { 5891 call.setIsVoipAudioMode(true); 5892 } 5893 // Set associated user based on the existing call as it doesn't make sense to handover calls 5894 // across user profiles. 5895 call.setAssociatedUser(handoverFromCall.getAssociatedUser()); 5896 5897 // Ensure we don't try to place an outgoing call with video if video is not 5898 // supported. 5899 if (VideoProfile.isVideo(videoState) && account != null && 5900 !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 5901 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 5902 } else { 5903 call.setVideoState(videoState); 5904 } 5905 5906 // Set target phone account to destAcct. 5907 call.setTargetPhoneAccount(handoverToHandle); 5908 5909 if (account != null && account.getExtras() != null && account.getExtras() 5910 .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { 5911 Log.d(this, "requestHandover: defaulting to voip mode for call %s", 5912 call.getId()); 5913 call.setIsVoipAudioMode(true); 5914 } 5915 5916 // Set call state to connecting 5917 call.setState( 5918 CallState.CONNECTING, 5919 handoverToHandle == null ? "no-handle" : handoverToHandle.toString()); 5920 5921 // Mark as handover so that the ConnectionService knows this is a handover request. 5922 if (extras == null) { 5923 extras = new Bundle(); 5924 } 5925 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 5926 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 5927 handoverFromCall.getTargetPhoneAccount()); 5928 setIntentExtrasAndStartTime(call, extras); 5929 5930 // Add call to call tracker 5931 if (!mCalls.contains(call)) { 5932 addCall(call); 5933 } 5934 5935 Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER, 5936 "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), call.getId()); 5937 5938 handoverFromCall.setHandoverDestinationCall(call); 5939 handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 5940 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 5941 call.setHandoverSourceCall(handoverFromCall); 5942 call.setNewOutgoingCallIntentBroadcastIsDone(); 5943 5944 // Auto-enable speakerphone if the originating intent specified to do so, if the call 5945 // is a video call, of if using speaker when docked 5946 final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( 5947 R.bool.use_speaker_when_docked); 5948 final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); 5949 final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); 5950 call.setStartWithSpeakerphoneOn(false || useSpeakerForVideoCall 5951 || (useSpeakerWhenDocked && useSpeakerForDock)); 5952 call.setVideoState(videoState); 5953 5954 final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call, 5955 call.getTargetPhoneAccount()); 5956 5957 // If the account has been set, proceed to place the outgoing call. 5958 if (call.isSelfManaged() && !isOutgoingCallPermitted) { 5959 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); 5960 } else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) { 5961 markCallDisconnectedDueToSelfManagedCall(call); 5962 } else { 5963 if (call.isEmergencyCall()) { 5964 // Disconnect all self-managed calls to make priority for emergency call. 5965 disconnectSelfManagedCalls("emergency call"); 5966 } 5967 notifyStartCreateConnection(call); 5968 call.startCreateConnection(mPhoneAccountRegistrar); 5969 } 5970 5971 } 5972 5973 /** 5974 * Determines if handover from the specified {@link PhoneAccountHandle} is supported. 5975 * 5976 * @param from The {@link PhoneAccountHandle} the handover originates from. 5977 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 5978 */ 5979 private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) { 5980 return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM); 5981 } 5982 5983 /** 5984 * Determines if handover to the specified {@link PhoneAccountHandle} is supported. 5985 * 5986 * @param to The {@link PhoneAccountHandle} the handover it to. 5987 * @return {@code true} if handover is currently allowed, {@code false} otherwise. 5988 */ 5989 private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) { 5990 return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO); 5991 } 5992 5993 /** 5994 * Retrieves a boolean phone account extra. 5995 * @param handle the {@link PhoneAccountHandle} to retrieve the extra for. 5996 * @param key The extras key. 5997 * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false} 5998 * otherwise. 5999 */ 6000 private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) { 6001 PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle); 6002 if (phoneAccount == null) { 6003 return false; 6004 } 6005 6006 Bundle fromExtras = phoneAccount.getExtras(); 6007 if (fromExtras == null) { 6008 return false; 6009 } 6010 return fromExtras.getBoolean(key); 6011 } 6012 6013 /** 6014 * Determines if there is an existing handover in process. 6015 * @return {@code true} if a call in the process of handover exists, {@code false} otherwise. 6016 */ 6017 private boolean isHandoverInProgress() { 6018 return mCalls.stream().filter(c -> c.getHandoverSourceCall() != null || 6019 c.getHandoverDestinationCall() != null).count() > 0; 6020 } 6021 6022 private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) { 6023 Intent intent = 6024 new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED); 6025 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 6026 intent.putExtra( 6027 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 6028 Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle); 6029 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 6030 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 6031 6032 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 6033 getCurrentUserHandle().getIdentifier()); 6034 if (!TextUtils.isEmpty(dialerPackage)) { 6035 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED) 6036 .setPackage(dialerPackage); 6037 directedIntent.putExtra( 6038 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 6039 Log.i(this, "Sending phone-account unregistered intent to default dialer"); 6040 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 6041 } 6042 return ; 6043 } 6044 6045 private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) { 6046 Intent intent = new Intent( 6047 TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED); 6048 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 6049 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 6050 accountHandle); 6051 Log.i(this, "Sending phone-account %s registered intent as user", accountHandle); 6052 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 6053 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION); 6054 6055 String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication( 6056 getCurrentUserHandle().getIdentifier()); 6057 if (!TextUtils.isEmpty(dialerPackage)) { 6058 Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED) 6059 .setPackage(dialerPackage); 6060 directedIntent.putExtra( 6061 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 6062 Log.i(this, "Sending phone-account registered intent to default dialer"); 6063 mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null); 6064 } 6065 return ; 6066 } 6067 6068 public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) { 6069 final String handleScheme = srcAddr.getSchemeSpecificPart(); 6070 Call fromCall = mCalls.stream() 6071 .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber( 6072 (c.getHandle() == null ? null : c.getHandle().getSchemeSpecificPart()), 6073 handleScheme)) 6074 .findFirst() 6075 .orElse(null); 6076 6077 Call call = new Call( 6078 getNextCallId(), 6079 mContext, 6080 this, 6081 mLock, 6082 mConnectionServiceRepository, 6083 mPhoneNumberUtilsAdapter, 6084 srcAddr, 6085 null /* gatewayInfo */, 6086 null /* connectionManagerPhoneAccount */, 6087 destAcct, 6088 Call.CALL_DIRECTION_INCOMING /* callDirection */, 6089 false /* forceAttachToExistingConnection */, 6090 false, /* isConference */ 6091 mClockProxy, 6092 mToastFactory); 6093 6094 if (fromCall == null || isHandoverInProgress() || 6095 !isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount()) || 6096 !isHandoverToPhoneAccountSupported(destAcct) || 6097 isInEmergencyCall()) { 6098 Log.w(this, "acceptHandover: Handover not supported"); 6099 notifyHandoverFailed(call, 6100 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 6101 return; 6102 } 6103 6104 PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(destAcct); 6105 if (phoneAccount == null) { 6106 Log.w(this, "acceptHandover: Handover not supported. phoneAccount = null"); 6107 notifyHandoverFailed(call, 6108 android.telecom.Call.Callback.HANDOVER_FAILURE_NOT_SUPPORTED); 6109 return; 6110 } 6111 call.setIsSelfManaged(phoneAccount.isSelfManaged()); 6112 if (call.isSelfManaged() || (phoneAccount.getExtras() != null && 6113 phoneAccount.getExtras().getBoolean( 6114 PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE))) { 6115 call.setIsVoipAudioMode(true); 6116 } 6117 if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { 6118 call.setVideoState(VideoProfile.STATE_AUDIO_ONLY); 6119 } else { 6120 call.setVideoState(videoState); 6121 } 6122 6123 call.initAnalytics(); 6124 call.addListener(this); 6125 6126 fromCall.setHandoverDestinationCall(call); 6127 call.setHandoverSourceCall(fromCall); 6128 call.setHandoverState(HandoverState.HANDOVER_TO_STARTED); 6129 // Set associated user based on the existing call as it doesn't make sense to handover calls 6130 // across user profiles. 6131 call.setAssociatedUser(fromCall.getAssociatedUser()); 6132 fromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED); 6133 6134 if (isSpeakerEnabledForVideoCalls() && VideoProfile.isVideo(videoState)) { 6135 // Ensure when the call goes active that it will go to speakerphone if the 6136 // handover to call is a video call. 6137 call.setStartWithSpeakerphoneOn(true); 6138 } 6139 6140 Bundle extras = call.getIntentExtras(); 6141 if (extras == null) { 6142 extras = new Bundle(); 6143 } 6144 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, true); 6145 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 6146 fromCall.getTargetPhoneAccount()); 6147 notifyStartCreateConnection(call); 6148 call.startCreateConnection(mPhoneAccountRegistrar); 6149 } 6150 6151 public ConnectionServiceFocusManager getConnectionServiceFocusManager() { 6152 return mConnectionSvrFocusMgr; 6153 } 6154 6155 @VisibleForTesting 6156 public boolean canHold(Call call) { 6157 return ((call.isTransactionalCall() && call.can(Connection.CAPABILITY_SUPPORT_HOLD)) || 6158 call.can(Connection.CAPABILITY_HOLD)) && call.getState() != CallState.DIALING; 6159 } 6160 6161 private boolean supportsHold(Call call) { 6162 return call.can(Connection.CAPABILITY_SUPPORT_HOLD); 6163 } 6164 6165 private final class ActionSetCallState implements PendingAction { 6166 6167 private final Call mCall; 6168 private final int mState; 6169 private final String mTag; 6170 6171 ActionSetCallState(Call call, int state, String tag) { 6172 mCall = call; 6173 mState = state; 6174 mTag = tag; 6175 } 6176 6177 @Override 6178 public void performAction() { 6179 synchronized (mLock) { 6180 Log.d(this, "performAction: current call state %s", mCall); 6181 if (mCall.getState() != CallState.DISCONNECTED 6182 && mCall.getState() != CallState.DISCONNECTING) { 6183 Log.d(this, "performAction: setting to new state = %s", mState); 6184 setCallState(mCall, mState, mTag); 6185 } 6186 } 6187 } 6188 } 6189 6190 private final class ActionUnHoldCall implements PendingAction { 6191 private final Call mCall; 6192 private final String mPreviouslyHeldCallId; 6193 6194 ActionUnHoldCall(Call call, String previouslyHeldCallId) { 6195 mCall = call; 6196 mPreviouslyHeldCallId = previouslyHeldCallId; 6197 } 6198 6199 @Override 6200 public void performAction() { 6201 synchronized (mLock) { 6202 Log.d(this, "perform unhold call for %s", mCall); 6203 mCall.unhold("held " + mPreviouslyHeldCallId); 6204 } 6205 } 6206 } 6207 6208 private final class ActionAnswerCall implements PendingAction { 6209 private final Call mCall; 6210 private final int mVideoState; 6211 6212 ActionAnswerCall(Call call, int videoState) { 6213 mCall = call; 6214 mVideoState = videoState; 6215 } 6216 6217 @Override 6218 public void performAction() { 6219 synchronized (mLock) { 6220 Log.d(this, "perform answer call for %s, videoState = %d", mCall, mVideoState); 6221 for (CallsManagerListener listener : mListeners) { 6222 listener.onIncomingCallAnswered(mCall); 6223 } 6224 6225 // We do not update the UI until we get confirmation of the answer() through 6226 // {@link #markCallAsActive}. 6227 if (mCall.getState() == CallState.RINGING) { 6228 mCall.answer(mVideoState); 6229 setCallState(mCall, CallState.ANSWERED, "answered"); 6230 } else if (mCall.getState() == CallState.SIMULATED_RINGING) { 6231 // If the call's in simulated ringing, we don't have to wait for the CS -- 6232 // we can just declare it active. 6233 setCallState(mCall, CallState.ACTIVE, "answering simulated ringing"); 6234 Log.addEvent(mCall, LogUtils.Events.REQUEST_SIMULATED_ACCEPT); 6235 } else if (mCall.getState() == CallState.ANSWERED) { 6236 // In certain circumstances, the connection service can lose track of a request 6237 // to answer a call. Therefore, if the user presses answer again, still send it 6238 // on down, but log a warning in the process and don't change the call state. 6239 mCall.answer(mVideoState); 6240 Log.w(this, "Duplicate answer request for call %s", mCall.getId()); 6241 } 6242 if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) { 6243 mCall.setStartWithSpeakerphoneOn(true); 6244 } 6245 } 6246 } 6247 } 6248 6249 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 6250 public static final class RequestCallback implements 6251 ConnectionServiceFocusManager.RequestFocusCallback { 6252 private PendingAction mPendingAction; 6253 6254 RequestCallback(PendingAction pendingAction) { 6255 mPendingAction = pendingAction; 6256 } 6257 6258 @Override 6259 public void onRequestFocusDone(ConnectionServiceFocusManager.CallFocus call) { 6260 if (mPendingAction != null) { 6261 mPendingAction.performAction(); 6262 } 6263 } 6264 } 6265 6266 /** 6267 * This helper mainly requests mConnectionSvrFocusMgr to update the call focus via a 6268 * {@link TransactionalFocusRequestCallback}. However, in the case of a held call, the 6269 * state must be set first and then a request must be made. 6270 * 6271 * @param newCallFocus to set active/answered 6272 * @param resultCallback that back propagates the focusManager result 6273 * 6274 * Note: This method should only be called if there are no active calls. 6275 */ 6276 public void requestNewCallFocusAndVerify(Call newCallFocus, 6277 OutcomeReceiver<Boolean, CallException> resultCallback) { 6278 int currentCallState = newCallFocus.getState(); 6279 PendingAction pendingAction = null; 6280 6281 // if the current call is in a state that can become the new call focus, we can set the 6282 // state afterwards... 6283 if (ConnectionServiceFocusManager.PRIORITY_FOCUS_CALL_STATE.contains(currentCallState)) { 6284 pendingAction = new ActionSetCallState(newCallFocus, CallState.ACTIVE, 6285 "vCFC: pending action set state"); 6286 } else { 6287 // However, HELD calls need to be set to ACTIVE before requesting call focus. 6288 setCallState(newCallFocus, CallState.ACTIVE, "vCFC: immediately set active"); 6289 } 6290 6291 mConnectionSvrFocusMgr 6292 .requestFocus(newCallFocus, 6293 new TransactionalFocusRequestCallback(pendingAction, currentCallState, 6294 newCallFocus, resultCallback)); 6295 } 6296 6297 /** 6298 * Request a new call focus and ensure the request was successful via an OutcomeReceiver. Also, 6299 * conditionally include a PendingAction that will execute if and only if the call focus change 6300 * is successful. 6301 */ 6302 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 6303 public class TransactionalFocusRequestCallback implements 6304 ConnectionServiceFocusManager.RequestFocusCallback { 6305 private PendingAction mPendingAction; 6306 private int mPreviousCallState; 6307 @NonNull private Call mTargetCallFocus; 6308 private OutcomeReceiver<Boolean, CallException> mCallback; 6309 6310 TransactionalFocusRequestCallback(PendingAction pendingAction, int previousState, 6311 @NonNull Call call, OutcomeReceiver<Boolean, CallException> callback) { 6312 mPendingAction = pendingAction; 6313 mPreviousCallState = previousState; 6314 mTargetCallFocus = call; 6315 mCallback = callback; 6316 } 6317 6318 @Override 6319 public void onRequestFocusDone(ConnectionServiceFocusManager.CallFocus call) { 6320 Call currentCallFocus = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall(); 6321 // verify the update was successful before updating the state 6322 Log.i(this, "tFRC: currentCallFocus=[%s], targetFocus=[%s]", 6323 mTargetCallFocus, currentCallFocus); 6324 if (currentCallFocus == null || 6325 !currentCallFocus.getId().equals(mTargetCallFocus.getId())) { 6326 // possibly reset the call state 6327 if (mTargetCallFocus.getState() != mPreviousCallState) { 6328 mTargetCallFocus.setState(mPreviousCallState, "resetting call state"); 6329 } 6330 mCallback.onError(new CallException("failed to switch focus to requested call", 6331 CallException.CODE_CALL_CANNOT_BE_SET_TO_ACTIVE)); 6332 return; 6333 } 6334 // at this point, we know the FocusManager is able to update successfully 6335 if (mPendingAction != null) { 6336 mPendingAction.performAction(); // set the call state 6337 } 6338 mCallback.onResult(true); // complete the transaction 6339 } 6340 } 6341 6342 public void resetConnectionTime(Call call) { 6343 call.setConnectTimeMillis(System.currentTimeMillis()); 6344 call.setConnectElapsedTimeMillis(SystemClock.elapsedRealtime()); 6345 if (mCalls.contains(call)) { 6346 for (CallsManagerListener listener : mListeners) { 6347 listener.onConnectionTimeChanged(call); 6348 } 6349 } 6350 } 6351 6352 public Context getContext() { 6353 return mContext; 6354 } 6355 6356 /** 6357 * Determines if there is an ongoing emergency call. This can be either an outgoing emergency 6358 * call, or a number which has been identified by the number as an emergency call. 6359 * @return {@code true} if there is an ongoing emergency call, {@code false} otherwise. 6360 */ 6361 public boolean 6362 isInEmergencyCall() { 6363 return mCalls.stream().filter(c -> (c.isEmergencyCall() 6364 || c.isNetworkIdentifiedEmergencyCall()) && !c.isDisconnected()).count() > 0; 6365 } 6366 6367 /** 6368 * Trigger a recalculation of support for CAPABILITY_CAN_PULL_CALL for external calls due to 6369 * a possible emergency call being added/removed. 6370 */ 6371 private void updateExternalCallCanPullSupport() { 6372 boolean isInEmergencyCall = isInEmergencyCall(); 6373 // Remove the capability to pull an external call in the case that we are in an emergency 6374 // call. 6375 mCalls.stream().filter(Call::isExternalCall).forEach( 6376 c->c.setIsPullExternalCallSupported(!isInEmergencyCall)); 6377 } 6378 6379 /** 6380 * Trigger display of an error message to the user; we do this outside of dialer for calls which 6381 * fail to be created and added to Dialer. 6382 * @param messageId The string resource id. 6383 */ 6384 private void showErrorMessage(int messageId) { 6385 final Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class); 6386 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, messageId); 6387 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 6388 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT); 6389 } 6390 6391 /** 6392 * Handles changes to a {@link PhoneAccount}. 6393 * 6394 * Checks for changes to video calling availability and updates whether calls for that phone 6395 * account are video capable. 6396 * 6397 * @param registrar The {@link PhoneAccountRegistrar} originating the change. 6398 * @param phoneAccount The {@link PhoneAccount} which changed. 6399 */ 6400 private void handlePhoneAccountChanged(PhoneAccountRegistrar registrar, 6401 PhoneAccount phoneAccount) { 6402 Log.i(this, "handlePhoneAccountChanged: phoneAccount=%s", phoneAccount); 6403 boolean isVideoNowSupported = phoneAccount.hasCapabilities( 6404 PhoneAccount.CAPABILITY_VIDEO_CALLING); 6405 mCalls.stream() 6406 .filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount())) 6407 .forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported)); 6408 } 6409 6410 /** 6411 * Determines if a {@link Call} is visible to the calling user. If the {@link PhoneAccount} has 6412 * CAPABILITY_MULTI_USER, or the user handle associated with the {@link PhoneAccount} is the 6413 * same as the calling user, the call is visible to the user. 6414 * @param call 6415 * @return {@code true} if call is visible to the calling user 6416 */ 6417 boolean isCallVisibleForUser(Call call, UserHandle userHandle) { 6418 return call.getAssociatedUser().equals(userHandle) 6419 || call.getPhoneAccountFromHandle() 6420 .hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER); 6421 } 6422 6423 /** 6424 * Determines if two {@link Call} instances originated from either the same target 6425 * {@link PhoneAccountHandle} or connection manager {@link PhoneAccountHandle}. 6426 * @param call1 The first call 6427 * @param call2 The second call 6428 * @return {@code true} if both calls are from the same target or connection manager 6429 * {@link PhoneAccountHandle}. 6430 */ 6431 public static boolean areFromSameSource(@NonNull Call call1, @NonNull Call call2) { 6432 PhoneAccountHandle call1ConnectionMgr = call1.getConnectionManagerPhoneAccount(); 6433 PhoneAccountHandle call2ConnectionMgr = call2.getConnectionManagerPhoneAccount(); 6434 6435 if (call1ConnectionMgr != null && call2ConnectionMgr != null 6436 && PhoneAccountHandle.areFromSamePackage(call1ConnectionMgr, call2ConnectionMgr)) { 6437 // Both calls share the same connection manager package, so they are from the same 6438 // source. 6439 return true; 6440 } 6441 6442 PhoneAccountHandle call1TargetAcct = call1.getTargetPhoneAccount(); 6443 PhoneAccountHandle call2TargetAcct = call2.getTargetPhoneAccount(); 6444 // Otherwise if the target phone account for both is the same package, they're the same 6445 // source. 6446 return PhoneAccountHandle.areFromSamePackage(call1TargetAcct, call2TargetAcct); 6447 } 6448 6449 public LinkedList<HandlerThread> getGraphHandlerThreads() { 6450 return mGraphHandlerThreads; 6451 } 6452 6453 private void maybeSendPostCallScreenIntent(Call call) { 6454 if (call.isEmergencyCall() || (call.isNetworkIdentifiedEmergencyCall()) || 6455 (call.getPostCallPackageName() == null)) { 6456 return; 6457 } 6458 6459 Intent intent = new Intent(ACTION_POST_CALL); 6460 intent.setPackage(call.getPostCallPackageName()); 6461 intent.putExtra(EXTRA_HANDLE, call.getHandle()); 6462 intent.putExtra(EXTRA_DISCONNECT_CAUSE, call.getDisconnectCause().getCode()); 6463 long duration = call.getAgeMillis(); 6464 int durationCode = DURATION_VERY_SHORT; 6465 if ((duration >= VERY_SHORT_CALL_TIME_MS) && (duration < SHORT_CALL_TIME_MS)) { 6466 durationCode = DURATION_SHORT; 6467 } else if ((duration >= SHORT_CALL_TIME_MS) && (duration < MEDIUM_CALL_TIME_MS)) { 6468 durationCode = DURATION_MEDIUM; 6469 } else if (duration >= MEDIUM_CALL_TIME_MS) { 6470 durationCode = DURATION_LONG; 6471 } 6472 intent.putExtra(EXTRA_CALL_DURATION, durationCode); 6473 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 6474 mContext.startActivityAsUser(intent, mCurrentUserHandle); 6475 } 6476 6477 @VisibleForTesting 6478 public void addToPendingCallsToDisconnect(Call call) { 6479 mPendingCallsToDisconnect.add(call); 6480 } 6481 6482 @VisibleForTesting 6483 public void addConnectionServiceRepositoryCache(ComponentName componentName, 6484 UserHandle userHandle, ConnectionServiceWrapper service) { 6485 mConnectionServiceRepository.setService(componentName, userHandle, service); 6486 } 6487 6488 /** 6489 * Generates a log "marking". This is a unique call event which contains a specified message. 6490 * A log mark is triggered by the command: adb shell telecom log-mark MESSAGE 6491 * A tester can use this when executing tests to make it very clear when a particular test step 6492 * was reached. 6493 * @param message the message to mark in the logs. 6494 */ 6495 public void requestLogMark(String message) { 6496 mCalls.forEach(c -> Log.addEvent(c, LogUtils.Events.USER_LOG_MARK, message)); 6497 Log.addEvent(null /* global */, LogUtils.Events.USER_LOG_MARK, message); 6498 } 6499 6500 @VisibleForTesting 6501 public Ringer getRinger() { 6502 return mRinger; 6503 } 6504 6505 @VisibleForTesting 6506 public VoipCallMonitor getVoipCallMonitor() { 6507 return mVoipCallMonitor; 6508 } 6509 6510 /** 6511 * This method should only be used for testing. 6512 */ 6513 @VisibleForTesting 6514 public void createActionSetCallStateAndPerformAction(Call call, int state, String tag) { 6515 ActionSetCallState actionSetCallState = new ActionSetCallState(call, state, tag); 6516 actionSetCallState.performAction(); 6517 } 6518 6519 public CallStreamingController getCallStreamingController() { 6520 return mCallStreamingController; 6521 } 6522 6523 /** 6524 * Given a call identified by call id, get the instance from the list of calls. 6525 * @param callId the call id. 6526 * @return the call, or null if not found. 6527 */ 6528 public @Nullable Call getCall(@NonNull String callId) { 6529 Optional<Call> foundCall = mCalls.stream().filter( 6530 c -> c.getId().equals(callId)).findFirst(); 6531 if (foundCall.isPresent()) { 6532 return foundCall.get(); 6533 } else { 6534 return null; 6535 } 6536 } 6537 6538 /** 6539 * Triggers stopping of call streaming for a call by launching a stop streaming transaction. 6540 * @param call the call. 6541 */ 6542 public void stopCallStreaming(@NonNull Call call) { 6543 if (call.getTransactionServiceWrapper() == null) { 6544 return; 6545 } 6546 call.getTransactionServiceWrapper().stopCallStreaming(call); 6547 } 6548 6549 @VisibleForTesting 6550 public Set<Call> getSelfManagedCallsBeingSetup() { 6551 return mSelfManagedCallsBeingSetup; 6552 } 6553 6554 @VisibleForTesting 6555 public void addCallBeingSetup(Call call) { 6556 mSelfManagedCallsBeingSetup.add(call); 6557 } 6558 } 6559