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