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