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