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