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