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