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