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