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