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