1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.telecom;
18 
19 import android.app.ActivityManager;
20 import android.content.Context;
21 import android.content.pm.UserInfo;
22 import android.content.Intent;
23 import android.media.AudioManager;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Process;
29 import android.os.SystemClock;
30 import android.os.SystemProperties;
31 import android.os.SystemVibrator;
32 import android.os.Trace;
33 import android.os.UserHandle;
34 import android.os.UserManager;
35 import android.provider.CallLog.Calls;
36 import android.provider.Settings;
37 import android.telecom.CallAudioState;
38 import android.telecom.Conference;
39 import android.telecom.Connection;
40 import android.telecom.DisconnectCause;
41 import android.telecom.GatewayInfo;
42 import android.telecom.Log;
43 import android.telecom.ParcelableConference;
44 import android.telecom.ParcelableConnection;
45 import android.telecom.PhoneAccount;
46 import android.telecom.PhoneAccountHandle;
47 import android.telecom.Logging.Runnable;
48 import android.telecom.TelecomManager;
49 import android.telecom.VideoProfile;
50 import android.telephony.PhoneNumberUtils;
51 import android.telephony.TelephonyManager;
52 import android.text.TextUtils;
53 
54 import com.android.internal.annotations.VisibleForTesting;
55 import com.android.internal.telephony.AsyncEmergencyContactNotifier;
56 import com.android.internal.telephony.PhoneConstants;
57 import com.android.internal.telephony.TelephonyProperties;
58 import com.android.internal.util.IndentingPrintWriter;
59 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
60 import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
61 import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
62 import com.android.server.telecom.callfiltering.CallFilterResultCallback;
63 import com.android.server.telecom.callfiltering.CallFilteringResult;
64 import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
65 import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
66 import com.android.server.telecom.callfiltering.IncomingCallFilter;
67 import com.android.server.telecom.components.ErrorDialogActivity;
68 import com.android.server.telecom.ui.ConfirmCallDialogActivity;
69 import com.android.server.telecom.ui.IncomingCallNotifier;
70 
71 import java.util.ArrayList;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.HashMap;
75 import java.util.HashSet;
76 import java.util.Iterator;
77 import java.util.List;
78 import java.util.Map;
79 import java.util.Objects;
80 import java.util.Optional;
81 import java.util.Set;
82 import java.util.concurrent.ConcurrentHashMap;
83 import java.util.concurrent.CountDownLatch;
84 import java.util.concurrent.TimeUnit;
85 import java.util.stream.Collectors;
86 import java.util.stream.IntStream;
87 import java.util.stream.Stream;
88 
89 /**
90  * Singleton.
91  *
92  * NOTE: by design most APIs are package private, use the relevant adapter/s to allow
93  * access from other packages specifically refraining from passing the CallsManager instance
94  * beyond the com.android.server.telecom package boundary.
95  */
96 @VisibleForTesting
97 public class CallsManager extends Call.ListenerBase
98         implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy {
99 
100     // TODO: Consider renaming this CallsManagerPlugin.
101     @VisibleForTesting
102     public interface CallsManagerListener {
onCallAdded(Call call)103         void onCallAdded(Call call);
onCallRemoved(Call call)104         void onCallRemoved(Call call);
onCallStateChanged(Call call, int oldState, int newState)105         void onCallStateChanged(Call call, int oldState, int newState);
onConnectionServiceChanged( Call call, ConnectionServiceWrapper oldService, ConnectionServiceWrapper newService)106         void onConnectionServiceChanged(
107                 Call call,
108                 ConnectionServiceWrapper oldService,
109                 ConnectionServiceWrapper newService);
onIncomingCallAnswered(Call call)110         void onIncomingCallAnswered(Call call);
onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage)111         void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState)112         void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
onRingbackRequested(Call call, boolean ringback)113         void onRingbackRequested(Call call, boolean ringback);
onIsConferencedChanged(Call call)114         void onIsConferencedChanged(Call call);
onIsVoipAudioModeChanged(Call call)115         void onIsVoipAudioModeChanged(Call call);
onVideoStateChanged(Call call, int previousVideoState, int newVideoState)116         void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
onCanAddCallChanged(boolean canAddCall)117         void onCanAddCallChanged(boolean canAddCall);
onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)118         void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
onHoldToneRequested(Call call)119         void onHoldToneRequested(Call call);
onExternalCallChanged(Call call, boolean isExternalCall)120         void onExternalCallChanged(Call call, boolean isExternalCall);
121     }
122 
123     private static final String TAG = "CallsManager";
124 
125     private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION =
126             "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION";
127 
128     /**
129      * Call filter specifier used with
130      * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only
131      * self-managed calls should be included.
132      */
133     private static final int CALL_FILTER_SELF_MANAGED = 1;
134 
135     /**
136      * Call filter specifier used with
137      * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only
138      * managed calls should be included.
139      */
140     private static final int CALL_FILTER_MANAGED = 2;
141 
142     /**
143      * Call filter specifier used with
144      * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed
145      * and self-managed calls should be included.
146      */
147     private static final int CALL_FILTER_ALL = 3;
148 
149     private static final int HANDLER_WAIT_TIMEOUT = 10000;
150     private static final int MAXIMUM_LIVE_CALLS = 1;
151     private static final int MAXIMUM_HOLD_CALLS = 1;
152     private static final int MAXIMUM_RINGING_CALLS = 1;
153     private static final int MAXIMUM_DIALING_CALLS = 1;
154     private static final int MAXIMUM_OUTGOING_CALLS = 1;
155     private static final int MAXIMUM_TOP_LEVEL_CALLS = 2;
156     private static final int MAXIMUM_SELF_MANAGED_CALLS = 10;
157 
158     private static final int[] OUTGOING_CALL_STATES =
159             {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
160                     CallState.PULLING};
161 
162     /**
163      * These states are used by {@link #makeRoomForOutgoingCall(Call, boolean)} to determine which
164      * call should be ended first to make room for a new outgoing call.
165      */
166     private static final int[] LIVE_CALL_STATES =
167             {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
168                     CallState.PULLING, CallState.ACTIVE};
169 
170     /**
171      * These states determine which calls will cause {@link TelecomManager#isInCall()} or
172      * {@link TelecomManager#isInManagedCall()} to return true.
173      *
174      * See also {@link PhoneStateBroadcaster}, which considers a similar set of states as being
175      * off-hook.
176      */
177     public static final int[] ONGOING_CALL_STATES =
178             {CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.PULLING, CallState.ACTIVE,
179                     CallState.ON_HOLD, CallState.RINGING};
180 
181     private static final int[] ANY_CALL_STATE =
182             {CallState.NEW, CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
183                     CallState.RINGING, CallState.ACTIVE, CallState.ON_HOLD, CallState.DISCONNECTED,
184                     CallState.ABORTED, CallState.DISCONNECTING, CallState.PULLING};
185 
186     public static final String TELECOM_CALL_ID_PREFIX = "TC@";
187 
188     // Maps call technologies in PhoneConstants to those in Analytics.
189     private static final Map<Integer, Integer> sAnalyticsTechnologyMap;
190     static {
191         sAnalyticsTechnologyMap = new HashMap<>(5);
sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE)192         sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE);
sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE)193         sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE);
sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE)194         sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE);
sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE)195         sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE);
sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY, Analytics.THIRD_PARTY_PHONE)196         sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY,
197                 Analytics.THIRD_PARTY_PHONE);
198     }
199 
200     /**
201      * The main call repository. Keeps an instance of all live calls. New incoming and outgoing
202      * calls are added to the map and removed when the calls move to the disconnected state.
203      *
204      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
205      * load factor before resizing, 1 means we only expect a single thread to
206      * access the map so make only a single shard
207      */
208     private final Set<Call> mCalls = Collections.newSetFromMap(
209             new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));
210 
211     /**
212      * A pending call is one which requires user-intervention in order to be placed.
213      * Used by {@link #startCallConfirmation(Call)}.
214      */
215     private Call mPendingCall;
216 
217     /**
218      * The current telecom call ID.  Used when creating new instances of {@link Call}.  Should
219      * only be accessed using the {@link #getNextCallId()} method which synchronizes on the
220      * {@link #mLock} sync root.
221      */
222     private int mCallId = 0;
223 
224     private int mRttRequestId = 0;
225     /**
226      * Stores the current foreground user.
227      */
228     private UserHandle mCurrentUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
229 
230     private final ConnectionServiceRepository mConnectionServiceRepository;
231     private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
232     private final InCallController mInCallController;
233     private final CallAudioManager mCallAudioManager;
234     private RespondViaSmsManager mRespondViaSmsManager;
235     private final Ringer mRinger;
236     private final InCallWakeLockController mInCallWakeLockController;
237     // For this set initial table size to 16 because we add 13 listeners in
238     // the CallsManager constructor.
239     private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(
240             new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));
241     private final HeadsetMediaButton mHeadsetMediaButton;
242     private final WiredHeadsetManager mWiredHeadsetManager;
243     private final BluetoothRouteManager mBluetoothRouteManager;
244     private final DockManager mDockManager;
245     private final TtyManager mTtyManager;
246     private final ProximitySensorManager mProximitySensorManager;
247     private final PhoneStateBroadcaster mPhoneStateBroadcaster;
248     private final CallLogManager mCallLogManager;
249     private final Context mContext;
250     private final TelecomSystem.SyncRoot mLock;
251     private final ContactsAsyncHelper mContactsAsyncHelper;
252     private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
253     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
254     private final MissedCallNotifier mMissedCallNotifier;
255     private IncomingCallNotifier mIncomingCallNotifier;
256     private final CallerInfoLookupHelper mCallerInfoLookupHelper;
257     private final DefaultDialerCache mDefaultDialerCache;
258     private final Timeouts.Adapter mTimeoutsAdapter;
259     private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
260     private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
261     private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
262     /* Handler tied to thread in which CallManager was initialized. */
263     private final Handler mHandler = new Handler(Looper.getMainLooper());
264     private final EmergencyCallHelper mEmergencyCallHelper;
265 
266     private boolean mCanAddCall = true;
267 
268     private TelephonyManager.MultiSimVariants mRadioSimVariants = null;
269 
270     private Runnable mStopTone;
271 
272     /**
273      * Listener to PhoneAccountRegistrar events.
274      */
275     private PhoneAccountRegistrar.Listener mPhoneAccountListener =
276             new PhoneAccountRegistrar.Listener() {
277         public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar,
278                                              PhoneAccountHandle handle) {
279             broadcastRegisterIntent(handle);
280         }
281         public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar,
282                                                PhoneAccountHandle handle) {
283             broadcastUnregisterIntent(handle);
284         }
285     };
286 
287     /**
288      * Initializes the required Telecom components.
289      */
CallsManager( Context context, TelecomSystem.SyncRoot lock, ContactsAsyncHelper contactsAsyncHelper, CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory, MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar, HeadsetMediaButtonFactory headsetMediaButtonFactory, ProximitySensorManagerFactory proximitySensorManagerFactory, InCallWakeLockControllerFactory inCallWakeLockControllerFactory, CallAudioManager.AudioServiceFactory audioServiceFactory, BluetoothRouteManager bluetoothManager, WiredHeadsetManager wiredHeadsetManager, SystemStateProvider systemStateProvider, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, AsyncRingtonePlayer asyncRingtonePlayer, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, EmergencyCallHelper emergencyCallHelper)290     CallsManager(
291             Context context,
292             TelecomSystem.SyncRoot lock,
293             ContactsAsyncHelper contactsAsyncHelper,
294             CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
295             MissedCallNotifier missedCallNotifier,
296             PhoneAccountRegistrar phoneAccountRegistrar,
297             HeadsetMediaButtonFactory headsetMediaButtonFactory,
298             ProximitySensorManagerFactory proximitySensorManagerFactory,
299             InCallWakeLockControllerFactory inCallWakeLockControllerFactory,
300             CallAudioManager.AudioServiceFactory audioServiceFactory,
301             BluetoothRouteManager bluetoothManager,
302             WiredHeadsetManager wiredHeadsetManager,
303             SystemStateProvider systemStateProvider,
304             DefaultDialerCache defaultDialerCache,
305             Timeouts.Adapter timeoutsAdapter,
306             AsyncRingtonePlayer asyncRingtonePlayer,
307             PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
308             EmergencyCallHelper emergencyCallHelper) {
309         mContext = context;
310         mLock = lock;
311         mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
312         mContactsAsyncHelper = contactsAsyncHelper;
313         mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
314         mPhoneAccountRegistrar = phoneAccountRegistrar;
315         mPhoneAccountRegistrar.addListener(mPhoneAccountListener);
316         mMissedCallNotifier = missedCallNotifier;
317         StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
318         mWiredHeadsetManager = wiredHeadsetManager;
319         mDefaultDialerCache = defaultDialerCache;
320         mBluetoothRouteManager = bluetoothManager;
321         mDockManager = new DockManager(context);
322         mTimeoutsAdapter = timeoutsAdapter;
323         mEmergencyCallHelper = emergencyCallHelper;
324         mCallerInfoLookupHelper = new CallerInfoLookupHelper(context, mCallerInfoAsyncQueryFactory,
325                 mContactsAsyncHelper, mLock);
326 
327         mDtmfLocalTonePlayer =
328                 new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy());
329         CallAudioRouteStateMachine callAudioRouteStateMachine = new CallAudioRouteStateMachine(
330                 context,
331                 this,
332                 bluetoothManager,
333                 wiredHeadsetManager,
334                 statusBarNotifier,
335                 audioServiceFactory,
336                 CallAudioRouteStateMachine.doesDeviceSupportEarpieceRoute()
337         );
338         callAudioRouteStateMachine.initialize();
339 
340         CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter =
341                 new CallAudioRoutePeripheralAdapter(
342                         callAudioRouteStateMachine,
343                         bluetoothManager,
344                         wiredHeadsetManager,
345                         mDockManager);
346 
347         InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(
348                 callAudioRoutePeripheralAdapter, lock);
349 
350         SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
351         RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
352         SystemVibrator systemVibrator = new SystemVibrator(context);
353         mInCallController = new InCallController(
354                 context, mLock, this, systemStateProvider, defaultDialerCache, mTimeoutsAdapter,
355                 emergencyCallHelper);
356         mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
357                 ringtoneFactory, systemVibrator, mInCallController);
358 
359         mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
360                 this,new CallAudioModeStateMachine((AudioManager)
361                         mContext.getSystemService(Context.AUDIO_SERVICE)),
362                 playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer);
363 
364         mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock);
365         mTtyManager = new TtyManager(context, mWiredHeadsetManager);
366         mProximitySensorManager = proximitySensorManagerFactory.create(context, this);
367         mPhoneStateBroadcaster = new PhoneStateBroadcaster(this);
368         mCallLogManager = new CallLogManager(context, phoneAccountRegistrar, mMissedCallNotifier);
369         mConnectionServiceRepository =
370                 new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);
371         mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this);
372 
373         mListeners.add(mInCallWakeLockController);
374         mListeners.add(statusBarNotifier);
375         mListeners.add(mCallLogManager);
376         mListeners.add(mPhoneStateBroadcaster);
377         mListeners.add(mInCallController);
378         mListeners.add(mCallAudioManager);
379         mListeners.add(missedCallNotifier);
380         mListeners.add(mHeadsetMediaButton);
381         mListeners.add(mProximitySensorManager);
382 
383         // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
384         final UserManager userManager = UserManager.get(mContext);
385         // Don't load missed call if it is run in split user model.
386         if (userManager.isPrimaryUser()) {
387             onUserSwitch(Process.myUserHandle());
388         }
389     }
390 
setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier)391     public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) {
392         if (mIncomingCallNotifier != null) {
393             mListeners.remove(mIncomingCallNotifier);
394         }
395         mIncomingCallNotifier = incomingCallNotifier;
396         mListeners.add(mIncomingCallNotifier);
397     }
398 
setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager)399     public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) {
400         if (mRespondViaSmsManager != null) {
401             mListeners.remove(mRespondViaSmsManager);
402         }
403         mRespondViaSmsManager = respondViaSmsManager;
404         mListeners.add(respondViaSmsManager);
405     }
406 
getRespondViaSmsManager()407     public RespondViaSmsManager getRespondViaSmsManager() {
408         return mRespondViaSmsManager;
409     }
410 
getCallerInfoLookupHelper()411     public CallerInfoLookupHelper getCallerInfoLookupHelper() {
412         return mCallerInfoLookupHelper;
413     }
414 
415     @Override
onSuccessfulOutgoingCall(Call call, int callState)416     public void onSuccessfulOutgoingCall(Call call, int callState) {
417         Log.v(this, "onSuccessfulOutgoingCall, %s", call);
418 
419         setCallState(call, callState, "successful outgoing call");
420         if (!mCalls.contains(call)) {
421             // Call was not added previously in startOutgoingCall due to it being a potential MMI
422             // code, so add it now.
423             addCall(call);
424         }
425 
426         // The call's ConnectionService has been updated.
427         for (CallsManagerListener listener : mListeners) {
428             listener.onConnectionServiceChanged(call, null, call.getConnectionService());
429         }
430 
431         markCallAsDialing(call);
432     }
433 
434     @Override
onFailedOutgoingCall(Call call, DisconnectCause disconnectCause)435     public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) {
436         Log.v(this, "onFailedOutgoingCall, call: %s", call);
437 
438         markCallAsRemoved(call);
439     }
440 
441     @Override
onSuccessfulIncomingCall(Call incomingCall)442     public void onSuccessfulIncomingCall(Call incomingCall) {
443         Log.d(this, "onSuccessfulIncomingCall");
444         if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
445             Log.i(this, "Skipping call filtering due to ECBM");
446             onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));
447             return;
448         }
449 
450         List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
451         filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
452         filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
453         filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
454                 mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock));
455         new IncomingCallFilter(mContext, this, incomingCall, mLock,
456                 mTimeoutsAdapter, filters).performFiltering();
457     }
458 
459     @Override
onCallFilteringComplete(Call incomingCall, CallFilteringResult result)460     public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
461         // Only set the incoming call as ringing if it isn't already disconnected. It is possible
462         // that the connection service disconnected the call before it was even added to Telecom, in
463         // which case it makes no sense to set it back to a ringing state.
464         if (incomingCall.getState() != CallState.DISCONNECTED &&
465                 incomingCall.getState() != CallState.DISCONNECTING) {
466             setCallState(incomingCall, CallState.RINGING,
467                     result.shouldAllowCall ? "successful incoming call" : "blocking call");
468         } else {
469             Log.i(this, "onCallFilteringCompleted: call already disconnected.");
470             return;
471         }
472 
473         if (result.shouldAllowCall) {
474             if (hasMaximumManagedRingingCalls(incomingCall)) {
475                 if (shouldSilenceInsteadOfReject(incomingCall)) {
476                     incomingCall.silence();
477                 } else {
478                     Log.i(this, "onCallFilteringCompleted: Call rejected! " +
479                             "Exceeds maximum number of ringing calls.");
480                     rejectCallAndLog(incomingCall);
481                 }
482             } else if (hasMaximumManagedDialingCalls(incomingCall)) {
483                 Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
484                         "dialing calls.");
485                 rejectCallAndLog(incomingCall);
486             } else {
487                 addCall(incomingCall);
488             }
489         } else {
490             if (result.shouldReject) {
491                 Log.i(this, "onCallFilteringCompleted: blocked call, rejecting.");
492                 incomingCall.reject(false, null);
493             }
494             if (result.shouldAddToCallLog) {
495                 Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log.");
496                 if (result.shouldShowNotification) {
497                     Log.w(this, "onCallScreeningCompleted: blocked call, showing notification.");
498                 }
499                 mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
500                         result.shouldShowNotification);
501             } else if (result.shouldShowNotification) {
502                 Log.i(this, "onCallScreeningCompleted: blocked call, showing notification.");
503                 mMissedCallNotifier.showMissedCallNotification(
504                         new MissedCallNotifier.CallInfo(incomingCall));
505             }
506         }
507     }
508 
509     /**
510      * Whether allow (silence rather than reject) the incoming call if it has a different source
511      * (connection service) from the existing ringing call when reaching maximum ringing calls.
512      */
shouldSilenceInsteadOfReject(Call incomingCall)513     private boolean shouldSilenceInsteadOfReject(Call incomingCall) {
514         if (!mContext.getResources().getBoolean(
515                 R.bool.silence_incoming_when_different_service_and_maximum_ringing)) {
516             return false;
517         }
518 
519         Call ringingCall = null;
520 
521         for (Call call : mCalls) {
522             // Only operate on top-level calls
523             if (call.getParentCall() != null) {
524                 continue;
525             }
526 
527             if (call.isExternalCall()) {
528                 continue;
529             }
530 
531             if (CallState.RINGING == call.getState() &&
532                     call.getConnectionService() == incomingCall.getConnectionService()) {
533                 return false;
534             }
535         }
536 
537         return true;
538     }
539 
540     @Override
onFailedIncomingCall(Call call)541     public void onFailedIncomingCall(Call call) {
542         setCallState(call, CallState.DISCONNECTED, "failed incoming call");
543         call.removeListener(this);
544     }
545 
546     @Override
onSuccessfulUnknownCall(Call call, int callState)547     public void onSuccessfulUnknownCall(Call call, int callState) {
548         setCallState(call, callState, "successful unknown call");
549         Log.i(this, "onSuccessfulUnknownCall for call %s", call);
550         addCall(call);
551     }
552 
553     @Override
onFailedUnknownCall(Call call)554     public void onFailedUnknownCall(Call call) {
555         Log.i(this, "onFailedUnknownCall for call %s", call);
556         setCallState(call, CallState.DISCONNECTED, "failed unknown call");
557         call.removeListener(this);
558     }
559 
560     @Override
onRingbackRequested(Call call, boolean ringback)561     public void onRingbackRequested(Call call, boolean ringback) {
562         for (CallsManagerListener listener : mListeners) {
563             listener.onRingbackRequested(call, ringback);
564         }
565     }
566 
567     @Override
onPostDialWait(Call call, String remaining)568     public void onPostDialWait(Call call, String remaining) {
569         mInCallController.onPostDialWait(call, remaining);
570     }
571 
572     @Override
onPostDialChar(final Call call, char nextChar)573     public void onPostDialChar(final Call call, char nextChar) {
574         if (PhoneNumberUtils.is12Key(nextChar)) {
575             // Play tone if it is one of the dialpad digits, canceling out the previously queued
576             // up stopTone runnable since playing a new tone automatically stops the previous tone.
577             if (mStopTone != null) {
578                 mHandler.removeCallbacks(mStopTone.getRunnableToCancel());
579                 mStopTone.cancel();
580             }
581 
582             mDtmfLocalTonePlayer.playTone(call, nextChar);
583 
584             mStopTone = new Runnable("CM.oPDC", mLock) {
585                 @Override
586                 public void loggedRun() {
587                     // Set a timeout to stop the tone in case there isn't another tone to
588                     // follow.
589                     mDtmfLocalTonePlayer.stopTone(call);
590                 }
591             };
592             mHandler.postDelayed(mStopTone.prepare(),
593                     Timeouts.getDelayBetweenDtmfTonesMillis(mContext.getContentResolver()));
594         } else if (nextChar == 0 || nextChar == TelecomManager.DTMF_CHARACTER_WAIT ||
595                 nextChar == TelecomManager.DTMF_CHARACTER_PAUSE) {
596             // Stop the tone if a tone is playing, removing any other stopTone callbacks since
597             // the previous tone is being stopped anyway.
598             if (mStopTone != null) {
599                 mHandler.removeCallbacks(mStopTone.getRunnableToCancel());
600                 mStopTone.cancel();
601             }
602             mDtmfLocalTonePlayer.stopTone(call);
603         } else {
604             Log.w(this, "onPostDialChar: invalid value %d", nextChar);
605         }
606     }
607 
608     @Override
onParentChanged(Call call)609     public void onParentChanged(Call call) {
610         // parent-child relationship affects which call should be foreground, so do an update.
611         updateCanAddCall();
612         for (CallsManagerListener listener : mListeners) {
613             listener.onIsConferencedChanged(call);
614         }
615     }
616 
617     @Override
onChildrenChanged(Call call)618     public void onChildrenChanged(Call call) {
619         // parent-child relationship affects which call should be foreground, so do an update.
620         updateCanAddCall();
621         for (CallsManagerListener listener : mListeners) {
622             listener.onIsConferencedChanged(call);
623         }
624     }
625 
626     @Override
onIsVoipAudioModeChanged(Call call)627     public void onIsVoipAudioModeChanged(Call call) {
628         for (CallsManagerListener listener : mListeners) {
629             listener.onIsVoipAudioModeChanged(call);
630         }
631     }
632 
633     @Override
onVideoStateChanged(Call call, int previousVideoState, int newVideoState)634     public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
635         for (CallsManagerListener listener : mListeners) {
636             listener.onVideoStateChanged(call, previousVideoState, newVideoState);
637         }
638     }
639 
640     @Override
onCanceledViaNewOutgoingCallBroadcast(final Call call, long disconnectionTimeout)641     public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call,
642             long disconnectionTimeout) {
643         mPendingCallsToDisconnect.add(call);
644         mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) {
645             @Override
646             public void loggedRun() {
647                 if (mPendingCallsToDisconnect.remove(call)) {
648                     Log.i(this, "Delayed disconnection of call: %s", call);
649                     call.disconnect();
650                 }
651             }
652         }.prepare(), disconnectionTimeout);
653 
654         return true;
655     }
656 
657     /**
658      * Handles changes to the {@link Connection.VideoProvider} for a call.  Adds the
659      * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created
660      * in {@link Call#setVideoProvider(IVideoProvider)}.  This allows the {@link CallsManager} to
661      * respond to callbacks from the {@link VideoProviderProxy}.
662      *
663      * @param call The call.
664      */
665     @Override
onVideoCallProviderChanged(Call call)666     public void onVideoCallProviderChanged(Call call) {
667         VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy();
668 
669         if (videoProviderProxy == null) {
670             return;
671         }
672 
673         videoProviderProxy.addListener(this);
674     }
675 
676     /**
677      * Handles session modification requests received via the {@link TelecomVideoCallCallback} for
678      * a call.  Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session
679      * modification request.
680      *
681      * @param call The call.
682      * @param videoProfile The {@link VideoProfile}.
683      */
684     @Override
onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)685     public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
686         int videoState = videoProfile != null ? videoProfile.getVideoState() :
687                 VideoProfile.STATE_AUDIO_ONLY;
688         Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile
689                 .videoStateToString(videoState));
690 
691         for (CallsManagerListener listener : mListeners) {
692             listener.onSessionModifyRequestReceived(call, videoProfile);
693         }
694     }
695 
getCalls()696     public Collection<Call> getCalls() {
697         return Collections.unmodifiableCollection(mCalls);
698     }
699 
700     /**
701      * Play or stop a call hold tone for a call.  Triggered via
702      * {@link Connection#sendConnectionEvent(String)} when the
703      * {@link Connection#EVENT_ON_HOLD_TONE_START} event or
704      * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the
705      *
706      * @param call The call which requested the hold tone.
707      */
708     @Override
onHoldToneRequested(Call call)709     public void onHoldToneRequested(Call call) {
710         for (CallsManagerListener listener : mListeners) {
711             listener.onHoldToneRequested(call);
712         }
713     }
714 
715     @VisibleForTesting
getForegroundCall()716     public Call getForegroundCall() {
717         if (mCallAudioManager == null) {
718             // Happens when getForegroundCall is called before full initialization.
719             return null;
720         }
721         return mCallAudioManager.getForegroundCall();
722     }
723 
724     @Override
getCurrentUserHandle()725     public UserHandle getCurrentUserHandle() {
726         return mCurrentUserHandle;
727     }
728 
getCallAudioManager()729     public CallAudioManager getCallAudioManager() {
730         return mCallAudioManager;
731     }
732 
getInCallController()733     InCallController getInCallController() {
734         return mInCallController;
735     }
736 
getEmergencyCallHelper()737     EmergencyCallHelper getEmergencyCallHelper() {
738         return mEmergencyCallHelper;
739     }
740 
741     @VisibleForTesting
hasEmergencyCall()742     public boolean hasEmergencyCall() {
743         for (Call call : mCalls) {
744             if (call.isEmergencyCall()) {
745                 return true;
746             }
747         }
748         return false;
749     }
750 
hasOnlyDisconnectedCalls()751     boolean hasOnlyDisconnectedCalls() {
752         for (Call call : mCalls) {
753             if (!call.isDisconnected()) {
754                 return false;
755             }
756         }
757         return true;
758     }
759 
hasVideoCall()760     public boolean hasVideoCall() {
761         for (Call call : mCalls) {
762             if (VideoProfile.isVideo(call.getVideoState())) {
763                 return true;
764             }
765         }
766         return false;
767     }
768 
769     @VisibleForTesting
getAudioState()770     public CallAudioState getAudioState() {
771         return mCallAudioManager.getCallAudioState();
772     }
773 
isTtySupported()774     boolean isTtySupported() {
775         return mTtyManager.isTtySupported();
776     }
777 
getCurrentTtyMode()778     int getCurrentTtyMode() {
779         return mTtyManager.getCurrentTtyMode();
780     }
781 
782     @VisibleForTesting
addListener(CallsManagerListener listener)783     public void addListener(CallsManagerListener listener) {
784         mListeners.add(listener);
785     }
786 
removeListener(CallsManagerListener listener)787     void removeListener(CallsManagerListener listener) {
788         mListeners.remove(listener);
789     }
790 
791     /**
792      * Starts the process to attach the call to a connection service.
793      *
794      * @param phoneAccountHandle The phone account which contains the component name of the
795      *        connection service to use for this call.
796      * @param extras The optional extras Bundle passed with the intent used for the incoming call.
797      */
processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras)798     void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
799         Log.d(this, "processIncomingCallIntent");
800         Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
801         if (handle == null) {
802             // Required for backwards compatibility
803             handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
804         }
805         Call call = new Call(
806                 getNextCallId(),
807                 mContext,
808                 this,
809                 mLock,
810                 mConnectionServiceRepository,
811                 mContactsAsyncHelper,
812                 mCallerInfoAsyncQueryFactory,
813                 mPhoneNumberUtilsAdapter,
814                 handle,
815                 null /* gatewayInfo */,
816                 null /* connectionManagerPhoneAccount */,
817                 phoneAccountHandle,
818                 Call.CALL_DIRECTION_INCOMING /* callDirection */,
819                 false /* forceAttachToExistingConnection */,
820                 false /* isConference */
821         );
822 
823         // Ensure new calls related to self-managed calls/connections are set as such.  This will
824         // be overridden when the actual connection is returned in startCreateConnection, however
825         // doing this now ensures the logs and any other logic will treat this call as self-managed
826         // from the moment it is created.
827         PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
828                 phoneAccountHandle);
829         if (phoneAccount != null) {
830             call.setIsSelfManaged(phoneAccount.isSelfManaged());
831             if (call.isSelfManaged()) {
832                 // Self managed calls will always be voip audio mode.
833                 call.setIsVoipAudioMode(true);
834             } else {
835                 // Incoming call is not self-managed, so we need to set extras on it to indicate
836                 // whether answering will cause a background self-managed call to drop.
837                 if (hasSelfManagedCalls()) {
838                     Bundle dropCallExtras = new Bundle();
839                     dropCallExtras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true);
840 
841                     // Include the name of the app which will drop the call.
842                     Call foregroundCall = getForegroundCall();
843                     if (foregroundCall != null) {
844                         CharSequence droppedApp = foregroundCall.getTargetPhoneAccountLabel();
845                         dropCallExtras.putCharSequence(
846                                 Connection.EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME, droppedApp);
847                         Log.i(this, "Incoming managed call will drop %s call.", droppedApp);
848                     }
849                     call.putExtras(Call.SOURCE_CONNECTION_SERVICE, dropCallExtras);
850                 }
851             }
852         }
853         if (extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
854             if (phoneAccount != null &&
855                     phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
856                 call.setRttStreams(true);
857             }
858         }
859         // If the extras specifies a video state, set it on the call if the PhoneAccount supports
860         // video.
861         if (extras.containsKey(TelecomManager.EXTRA_INCOMING_VIDEO_STATE) &&
862                 phoneAccount != null && phoneAccount.hasCapabilities(
863                         PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
864             call.setVideoState(extras.getInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE));
865         }
866 
867         call.initAnalytics();
868         if (getForegroundCall() != null) {
869             getForegroundCall().getAnalytics().setCallIsInterrupted(true);
870             call.getAnalytics().setCallIsAdditional(true);
871         }
872 
873         setIntentExtrasAndStartTime(call, extras);
874         // TODO: Move this to be a part of addCall()
875         call.addListener(this);
876 
877         if (call.isSelfManaged() && !isIncomingCallPermitted(call, call.getTargetPhoneAccount())) {
878             notifyCreateConnectionFailed(phoneAccountHandle, call);
879         } else {
880             call.startCreateConnection(mPhoneAccountRegistrar);
881         }
882     }
883 
addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras)884     void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
885         Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE);
886         Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle));
887         Call call = new Call(
888                 getNextCallId(),
889                 mContext,
890                 this,
891                 mLock,
892                 mConnectionServiceRepository,
893                 mContactsAsyncHelper,
894                 mCallerInfoAsyncQueryFactory,
895                 mPhoneNumberUtilsAdapter,
896                 handle,
897                 null /* gatewayInfo */,
898                 null /* connectionManagerPhoneAccount */,
899                 phoneAccountHandle,
900                 Call.CALL_DIRECTION_UNKNOWN /* callDirection */,
901                 // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach
902                 // to the existing connection instead of trying to create a new one.
903                 true /* forceAttachToExistingConnection */,
904                 false /* isConference */
905         );
906         call.initAnalytics();
907 
908         setIntentExtrasAndStartTime(call, extras);
909         call.addListener(this);
910         call.startCreateConnection(mPhoneAccountRegistrar);
911     }
912 
areHandlesEqual(Uri handle1, Uri handle2)913     private boolean areHandlesEqual(Uri handle1, Uri handle2) {
914         if (handle1 == null || handle2 == null) {
915             return handle1 == handle2;
916         }
917 
918         if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) {
919             return false;
920         }
921 
922         final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart());
923         final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart());
924         return TextUtils.equals(number1, number2);
925     }
926 
reuseOutgoingCall(Uri handle)927     private Call reuseOutgoingCall(Uri handle) {
928         // Check to see if we can reuse any of the calls that are waiting to disconnect.
929         // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information.
930         Call reusedCall = null;
931         for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) {
932             Call pendingCall = callIter.next();
933             if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) {
934                 callIter.remove();
935                 Log.i(this, "Reusing disconnected call %s", pendingCall);
936                 reusedCall = pendingCall;
937             } else {
938                 Log.i(this, "Not reusing disconnected call %s", pendingCall);
939                 callIter.remove();
940                 pendingCall.disconnect();
941             }
942         }
943 
944         return reusedCall;
945     }
946 
947     /**
948      * Kicks off the first steps to creating an outgoing call.
949      *
950      * For managed connections, this is the first step to launching the Incall UI.
951      * For self-managed connections, we don't expect the Incall UI to launch, but this is still a
952      * first step in getting the self-managed ConnectionService to create the connection.
953      * @param handle Handle to connect the call with.
954      * @param phoneAccountHandle The phone account which contains the component name of the
955      *        connection service to use for this call.
956      * @param extras The optional extras Bundle passed with the intent used for the incoming call.
957      * @param initiatingUser {@link UserHandle} of user that place the outgoing call.
958      * @param originalIntent
959      */
startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent)960     Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
961             UserHandle initiatingUser, Intent originalIntent) {
962         boolean isReusedCall = true;
963         Call call = reuseOutgoingCall(handle);
964 
965         PhoneAccount account =
966                 mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
967 
968         // Create a call with original handle. The handle may be changed when the call is attached
969         // to a connection service, but in most cases will remain the same.
970         if (call == null) {
971             call = new Call(getNextCallId(), mContext,
972                     this,
973                     mLock,
974                     mConnectionServiceRepository,
975                     mContactsAsyncHelper,
976                     mCallerInfoAsyncQueryFactory,
977                     mPhoneNumberUtilsAdapter,
978                     handle,
979                     null /* gatewayInfo */,
980                     null /* connectionManagerPhoneAccount */,
981                     null /* phoneAccountHandle */,
982                     Call.CALL_DIRECTION_OUTGOING /* callDirection */,
983                     false /* forceAttachToExistingConnection */,
984                     false /* isConference */
985             );
986             call.initAnalytics();
987 
988             // Ensure new calls related to self-managed calls/connections are set as such.  This
989             // will be overridden when the actual connection is returned in startCreateConnection,
990             // however doing this now ensures the logs and any other logic will treat this call as
991             // self-managed from the moment it is created.
992             if (account != null) {
993                 call.setIsSelfManaged(account.isSelfManaged());
994                 if (call.isSelfManaged()) {
995                     // Self-managed calls will ALWAYS use voip audio mode.
996                     call.setIsVoipAudioMode(true);
997                 }
998             }
999 
1000             call.setInitiatingUser(initiatingUser);
1001             isReusedCall = false;
1002         }
1003 
1004         if (extras != null) {
1005             // Set the video state on the call early so that when it is added to the InCall UI the
1006             // UI knows to configure itself as a video call immediately.
1007             int videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
1008                     VideoProfile.STATE_AUDIO_ONLY);
1009 
1010             // If this is an emergency video call, we need to check if the phone account supports
1011             // emergency video calling.
1012             // Also, ensure we don't try to place an outgoing call with video if video is not
1013             // supported.
1014             if (VideoProfile.isVideo(videoState)) {
1015                 if (call.isEmergencyCall() && account != null &&
1016                         !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
1017                     // Phone account doesn't support emergency video calling, so fallback to
1018                     // audio-only now to prevent the InCall UI from setting up video surfaces
1019                     // needlessly.
1020                     Log.i(this, "startOutgoingCall - emergency video calls not supported; " +
1021                             "falling back to audio-only");
1022                     videoState = VideoProfile.STATE_AUDIO_ONLY;
1023                 } else if (account != null &&
1024                         !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
1025                     // Phone account doesn't support video calling, so fallback to audio-only.
1026                     Log.i(this, "startOutgoingCall - video calls not supported; fallback to " +
1027                             "audio-only.");
1028                     videoState = VideoProfile.STATE_AUDIO_ONLY;
1029                 }
1030             }
1031 
1032             call.setVideoState(videoState);
1033         }
1034 
1035         PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount(
1036                 phoneAccountHandle, initiatingUser);
1037         boolean isSelfManaged = targetPhoneAccount != null && targetPhoneAccount.isSelfManaged();
1038 
1039         List<PhoneAccountHandle> accounts;
1040         if (!isSelfManaged) {
1041             accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
1042             Log.v(this, "startOutgoingCall found accounts = " + accounts);
1043 
1044             // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this
1045             // call as if a phoneAccount was not specified (does the default behavior instead).
1046             // Note: We will not attempt to dial with a requested phoneAccount if it is disabled.
1047             if (phoneAccountHandle != null) {
1048                 if (!accounts.contains(phoneAccountHandle)) {
1049                     phoneAccountHandle = null;
1050                 }
1051             }
1052 
1053             if (phoneAccountHandle == null && accounts.size() > 0) {
1054                 // No preset account, check if default exists that supports the URI scheme for the
1055                 // handle and verify it can be used.
1056                 if (accounts.size() > 1) {
1057                     PhoneAccountHandle defaultPhoneAccountHandle =
1058                             mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(
1059                                     handle.getScheme(), initiatingUser);
1060                     if (defaultPhoneAccountHandle != null &&
1061                             accounts.contains(defaultPhoneAccountHandle)) {
1062                         phoneAccountHandle = defaultPhoneAccountHandle;
1063                     }
1064                 } else {
1065                     // Use the only PhoneAccount that is available
1066                     phoneAccountHandle = accounts.get(0);
1067                 }
1068             }
1069         } else {
1070             accounts = Collections.EMPTY_LIST;
1071         }
1072 
1073         call.setTargetPhoneAccount(phoneAccountHandle);
1074 
1075         boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle) && !isSelfManaged;
1076 
1077         // Do not support any more live calls.  Our options are to move a call to hold, disconnect
1078         // a call, or cancel this call altogether. If a call is being reused, then it has already
1079         // passed the makeRoomForOutgoingCall check once and will fail the second time due to the
1080         // call transitioning into the CONNECTING state.
1081         if (!isSelfManaged && !isPotentialInCallMMICode && (!isReusedCall &&
1082                 !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) {
1083             // just cancel at this point.
1084             Log.i(this, "No remaining room for outgoing call: %s", call);
1085             if (mCalls.contains(call)) {
1086                 // This call can already exist if it is a reused call,
1087                 // See {@link #reuseOutgoingCall}.
1088                 call.disconnect();
1089             }
1090             return null;
1091         }
1092 
1093         boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
1094                 !call.isEmergencyCall() && !isSelfManaged;
1095 
1096         if (needsAccountSelection) {
1097             // This is the state where the user is expected to select an account
1098             call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
1099             // Create our own instance to modify (since extras may be Bundle.EMPTY)
1100             extras = new Bundle(extras);
1101             extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
1102         } else {
1103             call.setState(
1104                     CallState.CONNECTING,
1105                     phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
1106             PhoneAccount accountToUse =
1107                     mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
1108             if (extras != null
1109                     && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
1110                 if (accountToUse != null
1111                         && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1112                     call.setRttStreams(true);
1113                 }
1114             }
1115         }
1116         setIntentExtrasAndStartTime(call, extras);
1117 
1118         if ((isPotentialMMICode(handle) || isPotentialInCallMMICode)
1119                 && !needsAccountSelection) {
1120             // Do not add the call if it is a potential MMI code.
1121             call.addListener(this);
1122         } else if (!isSelfManaged && hasSelfManagedCalls() && !call.isEmergencyCall()) {
1123             // Adding a managed call and there are ongoing self-managed call(s).
1124             call.setOriginalCallIntent(originalIntent);
1125             startCallConfirmation(call);
1126             return null;
1127         } else if (!mCalls.contains(call)) {
1128             // We check if mCalls already contains the call because we could potentially be reusing
1129             // a call which was previously added (See {@link #reuseOutgoingCall}).
1130             addCall(call);
1131         }
1132 
1133         return call;
1134     }
1135 
1136     /**
1137      * Attempts to issue/connect the specified call.
1138      *
1139      * @param handle Handle to connect the call with.
1140      * @param gatewayInfo Optional gateway information that can be used to route the call to the
1141      *        actual dialed handle via a gateway provider. May be null.
1142      * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects.
1143      * @param videoState The desired video state for the outgoing call.
1144      */
1145     @VisibleForTesting
placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn, int videoState)1146     public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
1147             boolean speakerphoneOn, int videoState) {
1148         if (call == null) {
1149             // don't do anything if the call no longer exists
1150             Log.i(this, "Canceling unknown call.");
1151             return;
1152         }
1153 
1154         final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();
1155 
1156         if (gatewayInfo == null) {
1157             Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
1158         } else {
1159             Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
1160                     Log.pii(uriHandle), Log.pii(handle));
1161         }
1162 
1163         call.setHandle(uriHandle);
1164         call.setGatewayInfo(gatewayInfo);
1165 
1166         final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
1167                 R.bool.use_speaker_when_docked);
1168         final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
1169         final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);
1170 
1171         // Auto-enable speakerphone if the originating intent specified to do so, if the call
1172         // is a video call, of if using speaker when docked
1173         call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
1174                 || (useSpeakerWhenDocked && useSpeakerForDock));
1175         call.setVideoState(videoState);
1176 
1177         if (speakerphoneOn) {
1178             Log.i(this, "%s Starting with speakerphone as requested", call);
1179         } else if (useSpeakerWhenDocked && useSpeakerForDock) {
1180             Log.i(this, "%s Starting with speakerphone because car is docked.", call);
1181         } else if (useSpeakerForVideoCall) {
1182             Log.i(this, "%s Starting with speakerphone because its a video call.", call);
1183         }
1184 
1185         if (call.isEmergencyCall()) {
1186             new AsyncEmergencyContactNotifier(mContext).execute();
1187         }
1188 
1189         final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
1190                 com.android.internal.R.bool.config_requireCallCapableAccountForHandle);
1191         final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call,
1192                 call.getTargetPhoneAccount());
1193         if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
1194             // If the account has been set, proceed to place the outgoing call.
1195             // Otherwise the connection will be initiated when the account is set by the user.
1196             if (call.isSelfManaged() && !isOutgoingCallPermitted) {
1197                 notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call);
1198             } else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) {
1199                 markCallDisconnectedDueToSelfManagedCall(call);
1200             } else {
1201                 if (call.isEmergencyCall()) {
1202                     // Disconnect all self-managed calls to make priority for emergency call.
1203                     disconnectSelfManagedCalls();
1204                 }
1205 
1206                 call.startCreateConnection(mPhoneAccountRegistrar);
1207             }
1208         } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
1209                 requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
1210                 call.getInitiatingUser()).isEmpty()) {
1211             // If there are no call capable accounts, disconnect the call.
1212             markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
1213                     "No registered PhoneAccounts"));
1214             markCallAsRemoved(call);
1215         }
1216     }
1217 
1218     /**
1219      * Attempts to start a conference call for the specified call.
1220      *
1221      * @param call The call to conference.
1222      * @param otherCall The other call to conference with.
1223      */
1224     @VisibleForTesting
conference(Call call, Call otherCall)1225     public void conference(Call call, Call otherCall) {
1226         call.conferenceWith(otherCall);
1227     }
1228 
1229     /**
1230      * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call
1231      * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
1232      * the user opting to answer said call.
1233      *
1234      * @param call The call to answer.
1235      * @param videoState The video state in which to answer the call.
1236      */
1237     @VisibleForTesting
answerCall(Call call, int videoState)1238     public void answerCall(Call call, int videoState) {
1239         if (!mCalls.contains(call)) {
1240             Log.i(this, "Request to answer a non-existent call %s", call);
1241         } else {
1242             Call foregroundCall = getForegroundCall();
1243             // If the foreground call is not the ringing call and it is currently isActive() or
1244             // STATE_DIALING, put it on hold before answering the call.
1245             if (foregroundCall != null && foregroundCall != call &&
1246                     (foregroundCall.isActive() ||
1247                      foregroundCall.getState() == CallState.DIALING ||
1248                      foregroundCall.getState() == CallState.PULLING)) {
1249                 if (!foregroundCall.getTargetPhoneAccount().equals(
1250                                 call.getTargetPhoneAccount()) &&
1251                         ((call.isSelfManaged() != foregroundCall.isSelfManaged()) ||
1252                          call.isSelfManaged())) {
1253                     // The foreground call is from another connection service, and either:
1254                     // 1. FG call's managed state doesn't match that of the incoming call.
1255                     //    E.g. Incoming is self-managed and FG is managed, or incoming is managed
1256                     //    and foreground is self-managed.
1257                     // 2. The incoming call is self-managed.
1258                     //    E.g. The incoming call is
1259                     Log.i(this, "Answering call from %s CS; disconnecting calls from %s CS.",
1260                             foregroundCall.isSelfManaged() ? "selfMg" : "mg",
1261                             call.isSelfManaged() ? "selfMg" : "mg");
1262                     disconnectOtherCalls(call.getTargetPhoneAccount());
1263                 } else if (0 == (foregroundCall.getConnectionCapabilities()
1264                         & Connection.CAPABILITY_HOLD)) {
1265                     // This call does not support hold.  If it is from a different connection
1266                     // service, then disconnect it, otherwise allow the connection service to
1267                     // figure out the right states.
1268                     if (foregroundCall.getConnectionService() != call.getConnectionService()) {
1269                         foregroundCall.disconnect();
1270                     }
1271                 } else {
1272                     Call heldCall = getHeldCall();
1273                     if (heldCall != null) {
1274                         Log.i(this, "Disconnecting held call %s before holding active call.",
1275                                 heldCall);
1276                         heldCall.disconnect();
1277                     }
1278 
1279                     foregroundCall.hold();
1280                 }
1281                 // TODO: Wait until we get confirmation of the active call being
1282                 // on-hold before answering the new call.
1283                 // TODO: Import logic from CallManager.acceptCall()
1284             }
1285 
1286             for (CallsManagerListener listener : mListeners) {
1287                 listener.onIncomingCallAnswered(call);
1288             }
1289 
1290             // We do not update the UI until we get confirmation of the answer() through
1291             // {@link #markCallAsActive}.
1292             call.answer(videoState);
1293             if (isSpeakerphoneAutoEnabledForVideoCalls(videoState)) {
1294                 call.setStartWithSpeakerphoneOn(true);
1295             }
1296         }
1297     }
1298 
1299     /**
1300      * Determines if the speakerphone should be automatically enabled for the call.  Speakerphone
1301      * should be enabled if the call is a video call and bluetooth or the wired headset are not in
1302      * use.
1303      *
1304      * @param videoState The video state of the call.
1305      * @return {@code true} if the speakerphone should be enabled.
1306      */
isSpeakerphoneAutoEnabledForVideoCalls(int videoState)1307     public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) {
1308         return VideoProfile.isVideo(videoState) &&
1309             !mWiredHeadsetManager.isPluggedIn() &&
1310             !mBluetoothRouteManager.isBluetoothAvailable() &&
1311             isSpeakerEnabledForVideoCalls();
1312     }
1313 
1314     /**
1315      * Determines if the speakerphone should be enabled for when docked.  Speakerphone
1316      * should be enabled if the device is docked and bluetooth or the wired headset are
1317      * not in use.
1318      *
1319      * @return {@code true} if the speakerphone should be enabled for the dock.
1320      */
isSpeakerphoneEnabledForDock()1321     private boolean isSpeakerphoneEnabledForDock() {
1322         return mDockManager.isDocked() &&
1323             !mWiredHeadsetManager.isPluggedIn() &&
1324             !mBluetoothRouteManager.isBluetoothAvailable();
1325     }
1326 
1327     /**
1328      * Determines if the speakerphone should be automatically enabled for video calls.
1329      *
1330      * @return {@code true} if the speakerphone should automatically be enabled.
1331      */
isSpeakerEnabledForVideoCalls()1332     private static boolean isSpeakerEnabledForVideoCalls() {
1333         return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT,
1334                 PhoneConstants.AUDIO_OUTPUT_DEFAULT) ==
1335                 PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER);
1336     }
1337 
1338     /**
1339      * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call
1340      * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
1341      * the user opting to reject said call.
1342      */
1343     @VisibleForTesting
rejectCall(Call call, boolean rejectWithMessage, String textMessage)1344     public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) {
1345         if (!mCalls.contains(call)) {
1346             Log.i(this, "Request to reject a non-existent call %s", call);
1347         } else {
1348             for (CallsManagerListener listener : mListeners) {
1349                 listener.onIncomingCallRejected(call, rejectWithMessage, textMessage);
1350             }
1351             call.reject(rejectWithMessage, textMessage);
1352         }
1353     }
1354 
1355     /**
1356      * Instructs Telecom to play the specified DTMF tone within the specified call.
1357      *
1358      * @param digit The DTMF digit to play.
1359      */
1360     @VisibleForTesting
playDtmfTone(Call call, char digit)1361     public void playDtmfTone(Call call, char digit) {
1362         if (!mCalls.contains(call)) {
1363             Log.i(this, "Request to play DTMF in a non-existent call %s", call);
1364         } else {
1365             call.playDtmfTone(digit);
1366             mDtmfLocalTonePlayer.playTone(call, digit);
1367         }
1368     }
1369 
1370     /**
1371      * Instructs Telecom to stop the currently playing DTMF tone, if any.
1372      */
1373     @VisibleForTesting
stopDtmfTone(Call call)1374     public void stopDtmfTone(Call call) {
1375         if (!mCalls.contains(call)) {
1376             Log.i(this, "Request to stop DTMF in a non-existent call %s", call);
1377         } else {
1378             call.stopDtmfTone();
1379             mDtmfLocalTonePlayer.stopTone(call);
1380         }
1381     }
1382 
1383     /**
1384      * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any.
1385      */
postDialContinue(Call call, boolean proceed)1386     void postDialContinue(Call call, boolean proceed) {
1387         if (!mCalls.contains(call)) {
1388             Log.i(this, "Request to continue post-dial string in a non-existent call %s", call);
1389         } else {
1390             call.postDialContinue(proceed);
1391         }
1392     }
1393 
1394     /**
1395      * Instructs Telecom to disconnect the specified call. Intended to be invoked by the
1396      * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1397      * the user hitting the end-call button.
1398      */
1399     @VisibleForTesting
disconnectCall(Call call)1400     public void disconnectCall(Call call) {
1401         Log.v(this, "disconnectCall %s", call);
1402 
1403         if (!mCalls.contains(call)) {
1404             Log.w(this, "Unknown call (%s) asked to disconnect", call);
1405         } else {
1406             mLocallyDisconnectingCalls.add(call);
1407             call.disconnect();
1408         }
1409     }
1410 
1411     /**
1412      * Instructs Telecom to disconnect all calls.
1413      */
disconnectAllCalls()1414     void disconnectAllCalls() {
1415         Log.v(this, "disconnectAllCalls");
1416 
1417         for (Call call : mCalls) {
1418             disconnectCall(call);
1419         }
1420     }
1421 
1422     /**
1423      * Disconnects calls for any other {@link PhoneAccountHandle} but the one specified.
1424      * Note: As a protective measure, will NEVER disconnect an emergency call.  Although that
1425      * situation should never arise, its a good safeguard.
1426      * @param phoneAccountHandle Calls owned by {@link PhoneAccountHandle}s other than this one will
1427      *                          be disconnected.
1428      */
disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle)1429     private void disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle) {
1430         mCalls.stream()
1431                 .filter(c -> !c.isEmergencyCall() &&
1432                         !c.getTargetPhoneAccount().equals(phoneAccountHandle))
1433                 .forEach(c -> disconnectCall(c));
1434     }
1435 
1436     /**
1437      * Instructs Telecom to put the specified call on hold. Intended to be invoked by the
1438      * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1439      * the user hitting the hold button during an active call.
1440      */
1441     @VisibleForTesting
holdCall(Call call)1442     public void holdCall(Call call) {
1443         if (!mCalls.contains(call)) {
1444             Log.w(this, "Unknown call (%s) asked to be put on hold", call);
1445         } else {
1446             Log.d(this, "Putting call on hold: (%s)", call);
1447             call.hold();
1448         }
1449     }
1450 
1451     /**
1452      * Instructs Telecom to release the specified call from hold. Intended to be invoked by
1453      * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered
1454      * by the user hitting the hold button during a held call.
1455      */
1456     @VisibleForTesting
unholdCall(Call call)1457     public void unholdCall(Call call) {
1458         if (!mCalls.contains(call)) {
1459             Log.w(this, "Unknown call (%s) asked to be removed from hold", call);
1460         } else {
1461             boolean otherCallHeld = false;
1462             Log.d(this, "unholding call: (%s)", call);
1463             for (Call c : mCalls) {
1464                 // Only attempt to hold parent calls and not the individual children.
1465                 if (c != null && c.isAlive() && c != call && c.getParentCall() == null) {
1466                     otherCallHeld = true;
1467                     Log.addEvent(c, LogUtils.Events.SWAP);
1468                     c.hold();
1469                 }
1470             }
1471             if (otherCallHeld) {
1472                 Log.addEvent(call, LogUtils.Events.SWAP);
1473             }
1474             call.unhold();
1475         }
1476     }
1477 
1478     @Override
onExtrasChanged(Call c, int source, Bundle extras)1479     public void onExtrasChanged(Call c, int source, Bundle extras) {
1480         if (source != Call.SOURCE_CONNECTION_SERVICE) {
1481             return;
1482         }
1483         handleCallTechnologyChange(c);
1484         handleChildAddressChange(c);
1485         updateCanAddCall();
1486     }
1487 
1488     // Construct the list of possible PhoneAccounts that the outgoing call can use based on the
1489     // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount,
1490     // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP.
constructPossiblePhoneAccounts(Uri handle, UserHandle user)1491     private List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user) {
1492         if (handle == null) {
1493             return Collections.emptyList();
1494         }
1495         List<PhoneAccountHandle> allAccounts =
1496                 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user);
1497         // First check the Radio SIM Technology
1498         if(mRadioSimVariants == null) {
1499             TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
1500                     Context.TELEPHONY_SERVICE);
1501             // Cache Sim Variants
1502             mRadioSimVariants = tm.getMultiSimConfiguration();
1503         }
1504         // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount
1505         // Should be available if a call is already active on the SIM account.
1506         if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) {
1507             List<PhoneAccountHandle> simAccounts =
1508                     mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser();
1509             PhoneAccountHandle ongoingCallAccount = null;
1510             for (Call c : mCalls) {
1511                 if (!c.isDisconnected() && !c.isNew() && simAccounts.contains(
1512                         c.getTargetPhoneAccount())) {
1513                     ongoingCallAccount = c.getTargetPhoneAccount();
1514                     break;
1515                 }
1516             }
1517             if (ongoingCallAccount != null) {
1518                 // Remove all SIM accounts that are not the active SIM from the list.
1519                 simAccounts.remove(ongoingCallAccount);
1520                 allAccounts.removeAll(simAccounts);
1521             }
1522         }
1523         return allAccounts;
1524     }
1525 
1526     /**
1527      * Informs listeners (notably {@link CallAudioManager} of a change to the call's external
1528      * property.
1529      * .
1530      * @param call The call whose external property changed.
1531      * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise.
1532      */
1533     @Override
onExternalCallChanged(Call call, boolean isExternalCall)1534     public void onExternalCallChanged(Call call, boolean isExternalCall) {
1535         Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall);
1536         for (CallsManagerListener listener : mListeners) {
1537             listener.onExternalCallChanged(call, isExternalCall);
1538         }
1539     }
1540 
handleCallTechnologyChange(Call call)1541     private void handleCallTechnologyChange(Call call) {
1542         if (call.getExtras() != null
1543                 && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) {
1544 
1545             Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get(
1546                     call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE));
1547             if (analyticsCallTechnology == null) {
1548                 analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE;
1549             }
1550             call.getAnalytics().addCallTechnology(analyticsCallTechnology);
1551         }
1552     }
1553 
handleChildAddressChange(Call call)1554     public void handleChildAddressChange(Call call) {
1555         if (call.getExtras() != null
1556                 && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
1557 
1558             String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS);
1559             call.setViaNumber(viaNumber);
1560         }
1561     }
1562 
1563     /** Called by the in-call UI to change the mute state. */
mute(boolean shouldMute)1564     void mute(boolean shouldMute) {
1565         mCallAudioManager.mute(shouldMute);
1566     }
1567 
1568     /**
1569       * Called by the in-call UI to change the audio route, for example to change from earpiece to
1570       * speaker phone.
1571       */
setAudioRoute(int route)1572     void setAudioRoute(int route) {
1573         mCallAudioManager.setAudioRoute(route);
1574     }
1575 
1576     /** Called by the in-call UI to turn the proximity sensor on. */
turnOnProximitySensor()1577     void turnOnProximitySensor() {
1578         mProximitySensorManager.turnOn();
1579     }
1580 
1581     /**
1582      * Called by the in-call UI to turn the proximity sensor off.
1583      * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise,
1584      *        the screen will be kept off until the proximity sensor goes negative.
1585      */
turnOffProximitySensor(boolean screenOnImmediately)1586     void turnOffProximitySensor(boolean screenOnImmediately) {
1587         mProximitySensorManager.turnOff(screenOnImmediately);
1588     }
1589 
phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault)1590     void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
1591         if (!mCalls.contains(call)) {
1592             Log.i(this, "Attempted to add account to unknown call %s", call);
1593         } else {
1594             call.setTargetPhoneAccount(account);
1595 
1596             if (call.getIntentExtras()
1597                     .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
1598                 PhoneAccount realPhoneAccount =
1599                         mPhoneAccountRegistrar.getPhoneAccountUnchecked(account);
1600                 if (realPhoneAccount != null
1601                         && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1602                     call.setRttStreams(true);
1603                 }
1604             }
1605 
1606             if (!call.isNewOutgoingCallIntentBroadcastDone()) {
1607                 return;
1608             }
1609 
1610             // Note: emergency calls never go through account selection dialog so they never
1611             // arrive here.
1612             if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) {
1613                 call.startCreateConnection(mPhoneAccountRegistrar);
1614             } else {
1615                 call.disconnect();
1616             }
1617 
1618             if (setDefault) {
1619                 mPhoneAccountRegistrar
1620                         .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser());
1621             }
1622         }
1623     }
1624 
1625     /** Called when the audio state changes. */
1626     @VisibleForTesting
onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState)1627     public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState
1628             newAudioState) {
1629         Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState);
1630         for (CallsManagerListener listener : mListeners) {
1631             listener.onCallAudioStateChanged(oldAudioState, newAudioState);
1632         }
1633     }
1634 
markCallAsRinging(Call call)1635     void markCallAsRinging(Call call) {
1636         setCallState(call, CallState.RINGING, "ringing set explicitly");
1637     }
1638 
markCallAsDialing(Call call)1639     void markCallAsDialing(Call call) {
1640         setCallState(call, CallState.DIALING, "dialing set explicitly");
1641         maybeMoveToSpeakerPhone(call);
1642     }
1643 
markCallAsPulling(Call call)1644     void markCallAsPulling(Call call) {
1645         setCallState(call, CallState.PULLING, "pulling set explicitly");
1646         maybeMoveToSpeakerPhone(call);
1647     }
1648 
markCallAsActive(Call call)1649     void markCallAsActive(Call call) {
1650         setCallState(call, CallState.ACTIVE, "active set explicitly");
1651         maybeMoveToSpeakerPhone(call);
1652     }
1653 
markCallAsOnHold(Call call)1654     void markCallAsOnHold(Call call) {
1655         setCallState(call, CallState.ON_HOLD, "on-hold set explicitly");
1656     }
1657 
1658     /**
1659      * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the
1660      * last live call, then also disconnect from the in-call controller.
1661      *
1662      * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
1663      */
markCallAsDisconnected(Call call, DisconnectCause disconnectCause)1664     void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
1665         call.setDisconnectCause(disconnectCause);
1666         setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
1667     }
1668 
1669     /**
1670      * Removes an existing disconnected call, and notifies the in-call app.
1671      */
markCallAsRemoved(Call call)1672     void markCallAsRemoved(Call call) {
1673         removeCall(call);
1674         Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
1675         if (mLocallyDisconnectingCalls.contains(call)) {
1676             boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
1677             Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = "
1678                 + isDisconnectingChildCall + "call -> %s", call);
1679             mLocallyDisconnectingCalls.remove(call);
1680             // Auto-unhold the foreground call due to a locally disconnected call, except if the
1681             // call which was disconnected is a member of a conference (don't want to auto un-hold
1682             // the conference if we remove a member of the conference).
1683             if (!isDisconnectingChildCall && foregroundCall != null
1684                     && foregroundCall.getState() == CallState.ON_HOLD) {
1685                 foregroundCall.unhold();
1686             }
1687         } else if (foregroundCall != null &&
1688                 !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD)  &&
1689                 foregroundCall.getState() == CallState.ON_HOLD) {
1690 
1691             // The new foreground call is on hold, however the carrier does not display the hold
1692             // button in the UI.  Therefore, we need to auto unhold the held call since the user has
1693             // no means of unholding it themselves.
1694             Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)");
1695             foregroundCall.unhold();
1696         }
1697     }
1698 
1699     /**
1700      * Given a call, marks the call as disconnected and removes it.  Set the error message to
1701      * indicate to the user that the call cannot me placed due to an ongoing call in another app.
1702      *
1703      * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed
1704      * call.  Called by {@link #startCallConfirmation(Call)} when the user is already confirming an
1705      * outgoing call.  Realistically this should almost never be called since in practice the user
1706      * won't make multiple outgoing calls at the same time.
1707      *
1708      * @param call The call to mark as disconnected.
1709      */
markCallDisconnectedDueToSelfManagedCall(Call call)1710     void markCallDisconnectedDueToSelfManagedCall(Call call) {
1711         Call activeCall = getActiveCall();
1712         CharSequence errorMessage;
1713         if (activeCall == null) {
1714             // Realistically this shouldn't happen, but best to handle gracefully
1715             errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call);
1716         } else {
1717             errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call,
1718                     activeCall.getTargetPhoneAccountLabel());
1719         }
1720         // Call is managed and there are ongoing self-managed calls.
1721         markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
1722                 errorMessage, errorMessage, "Ongoing call in another app."));
1723         markCallAsRemoved(call);
1724     }
1725 
1726     /**
1727      * Cleans up any calls currently associated with the specified connection service when the
1728      * service binder disconnects unexpectedly.
1729      *
1730      * @param service The connection service that disconnected.
1731      */
handleConnectionServiceDeath(ConnectionServiceWrapper service)1732     void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
1733         if (service != null) {
1734             for (Call call : mCalls) {
1735                 if (call.getConnectionService() == service) {
1736                     if (call.getState() != CallState.DISCONNECTED) {
1737                         markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR));
1738                     }
1739                     markCallAsRemoved(call);
1740                 }
1741             }
1742         }
1743     }
1744 
1745     /**
1746      * Determines if the {@link CallsManager} has any non-external calls.
1747      *
1748      * @return {@code True} if there are any non-external calls, {@code false} otherwise.
1749      */
hasAnyCalls()1750     boolean hasAnyCalls() {
1751         if (mCalls.isEmpty()) {
1752             return false;
1753         }
1754 
1755         for (Call call : mCalls) {
1756             if (!call.isExternalCall()) {
1757                 return true;
1758             }
1759         }
1760         return false;
1761     }
1762 
hasActiveOrHoldingCall()1763     boolean hasActiveOrHoldingCall() {
1764         return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null;
1765     }
1766 
hasRingingCall()1767     boolean hasRingingCall() {
1768         return getFirstCallWithState(CallState.RINGING) != null;
1769     }
1770 
onMediaButton(int type)1771     boolean onMediaButton(int type) {
1772         if (hasAnyCalls()) {
1773             Call ringingCall = getFirstCallWithState(CallState.RINGING);
1774             if (HeadsetMediaButton.SHORT_PRESS == type) {
1775                 if (ringingCall == null) {
1776                     Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING,
1777                             CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD);
1778                     Log.addEvent(callToHangup, LogUtils.Events.INFO,
1779                             "media btn short press - end call.");
1780                     if (callToHangup != null) {
1781                         callToHangup.disconnect();
1782                         return true;
1783                     }
1784                 } else {
1785                     ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
1786                     return true;
1787                 }
1788             } else if (HeadsetMediaButton.LONG_PRESS == type) {
1789                 if (ringingCall != null) {
1790                     Log.addEvent(getForegroundCall(),
1791                             LogUtils.Events.INFO, "media btn long press - reject");
1792                     ringingCall.reject(false, null);
1793                 } else {
1794                     Log.addEvent(getForegroundCall(), LogUtils.Events.INFO,
1795                             "media btn long press - mute");
1796                     mCallAudioManager.toggleMute();
1797                 }
1798                 return true;
1799             }
1800         }
1801         return false;
1802     }
1803 
1804     /**
1805      * Returns true if telecom supports adding another top-level call.
1806      */
1807     @VisibleForTesting
canAddCall()1808     public boolean canAddCall() {
1809         boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
1810                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
1811         if (!isDeviceProvisioned) {
1812             Log.d(TAG, "Device not provisioned, canAddCall is false.");
1813             return false;
1814         }
1815 
1816         if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) {
1817             return false;
1818         }
1819 
1820         int count = 0;
1821         for (Call call : mCalls) {
1822             if (call.isEmergencyCall()) {
1823                 // We never support add call if one of the calls is an emergency call.
1824                 return false;
1825             } else if (call.isExternalCall()) {
1826                 // External calls don't count.
1827                 continue;
1828             } else if (call.getParentCall() == null) {
1829                 count++;
1830             }
1831             Bundle extras = call.getExtras();
1832             if (extras != null) {
1833                 if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) {
1834                     return false;
1835                 }
1836             }
1837 
1838             // We do not check states for canAddCall. We treat disconnected calls the same
1839             // and wait until they are removed instead. If we didn't count disconnected calls,
1840             // we could put InCallServices into a state where they are showing two calls but
1841             // also support add-call. Technically it's right, but overall looks better (UI-wise)
1842             // and acts better if we wait until the call is removed.
1843             if (count >= MAXIMUM_TOP_LEVEL_CALLS) {
1844                 return false;
1845             }
1846         }
1847 
1848         return true;
1849     }
1850 
1851     @VisibleForTesting
getRingingCall()1852     public Call getRingingCall() {
1853         return getFirstCallWithState(CallState.RINGING);
1854     }
1855 
getActiveCall()1856     public Call getActiveCall() {
1857         return getFirstCallWithState(CallState.ACTIVE);
1858     }
1859 
getDialingCall()1860     Call getDialingCall() {
1861         return getFirstCallWithState(CallState.DIALING);
1862     }
1863 
1864     @VisibleForTesting
getHeldCall()1865     public Call getHeldCall() {
1866         return getFirstCallWithState(CallState.ON_HOLD);
1867     }
1868 
1869     @VisibleForTesting
getNumHeldCalls()1870     public int getNumHeldCalls() {
1871         int count = 0;
1872         for (Call call : mCalls) {
1873             if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) {
1874                 count++;
1875             }
1876         }
1877         return count;
1878     }
1879 
1880     @VisibleForTesting
getOutgoingCall()1881     public Call getOutgoingCall() {
1882         return getFirstCallWithState(OUTGOING_CALL_STATES);
1883     }
1884 
1885     @VisibleForTesting
getFirstCallWithState(int... states)1886     public Call getFirstCallWithState(int... states) {
1887         return getFirstCallWithState(null, states);
1888     }
1889 
1890     @VisibleForTesting
getPhoneNumberUtilsAdapter()1891     public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() {
1892         return mPhoneNumberUtilsAdapter;
1893     }
1894 
1895     /**
1896      * Returns the first call that it finds with the given states. The states are treated as having
1897      * priority order so that any call with the first state will be returned before any call with
1898      * states listed later in the parameter list.
1899      *
1900      * @param callToSkip Call that this method should skip while searching
1901      */
getFirstCallWithState(Call callToSkip, int... states)1902     Call getFirstCallWithState(Call callToSkip, int... states) {
1903         for (int currentState : states) {
1904             // check the foreground first
1905             Call foregroundCall = getForegroundCall();
1906             if (foregroundCall != null && foregroundCall.getState() == currentState) {
1907                 return foregroundCall;
1908             }
1909 
1910             for (Call call : mCalls) {
1911                 if (Objects.equals(callToSkip, call)) {
1912                     continue;
1913                 }
1914 
1915                 // Only operate on top-level calls
1916                 if (call.getParentCall() != null) {
1917                     continue;
1918                 }
1919 
1920                 if (call.isExternalCall()) {
1921                     continue;
1922                 }
1923 
1924                 if (currentState == call.getState()) {
1925                     return call;
1926                 }
1927             }
1928         }
1929         return null;
1930     }
1931 
createConferenceCall( String callId, PhoneAccountHandle phoneAccount, ParcelableConference parcelableConference)1932     Call createConferenceCall(
1933             String callId,
1934             PhoneAccountHandle phoneAccount,
1935             ParcelableConference parcelableConference) {
1936 
1937         // If the parceled conference specifies a connect time, use it; otherwise default to 0,
1938         // which is the default value for new Calls.
1939         long connectTime =
1940                 parcelableConference.getConnectTimeMillis() ==
1941                         Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
1942                         parcelableConference.getConnectTimeMillis();
1943 
1944         Call call = new Call(
1945                 callId,
1946                 mContext,
1947                 this,
1948                 mLock,
1949                 mConnectionServiceRepository,
1950                 mContactsAsyncHelper,
1951                 mCallerInfoAsyncQueryFactory,
1952                 mPhoneNumberUtilsAdapter,
1953                 null /* handle */,
1954                 null /* gatewayInfo */,
1955                 null /* connectionManagerPhoneAccount */,
1956                 phoneAccount,
1957                 Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
1958                 false /* forceAttachToExistingConnection */,
1959                 true /* isConference */,
1960                 connectTime);
1961 
1962         setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
1963                 "new conference call");
1964         call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities());
1965         call.setConnectionProperties(parcelableConference.getConnectionProperties());
1966         call.setVideoState(parcelableConference.getVideoState());
1967         call.setVideoProvider(parcelableConference.getVideoProvider());
1968         call.setStatusHints(parcelableConference.getStatusHints());
1969         call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
1970         // In case this Conference was added via a ConnectionManager, keep track of the original
1971         // Connection ID as created by the originating ConnectionService.
1972         Bundle extras = parcelableConference.getExtras();
1973         if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
1974             call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
1975         }
1976 
1977         // TODO: Move this to be a part of addCall()
1978         call.addListener(this);
1979         addCall(call);
1980         return call;
1981     }
1982 
1983     /**
1984      * @return the call state currently tracked by {@link PhoneStateBroadcaster}
1985      */
getCallState()1986     int getCallState() {
1987         return mPhoneStateBroadcaster.getCallState();
1988     }
1989 
1990     /**
1991      * Retrieves the {@link PhoneAccountRegistrar}.
1992      *
1993      * @return The {@link PhoneAccountRegistrar}.
1994      */
getPhoneAccountRegistrar()1995     PhoneAccountRegistrar getPhoneAccountRegistrar() {
1996         return mPhoneAccountRegistrar;
1997     }
1998 
1999     /**
2000      * Retrieves the {@link MissedCallNotifier}
2001      * @return The {@link MissedCallNotifier}.
2002      */
getMissedCallNotifier()2003     MissedCallNotifier getMissedCallNotifier() {
2004         return mMissedCallNotifier;
2005     }
2006 
2007     /**
2008      * Retrieves the {@link IncomingCallNotifier}.
2009      * @return The {@link IncomingCallNotifier}.
2010      */
getIncomingCallNotifier()2011     IncomingCallNotifier getIncomingCallNotifier() {
2012         return mIncomingCallNotifier;
2013     }
2014 
2015     /**
2016      * Reject an incoming call and manually add it to the Call Log.
2017      * @param incomingCall Incoming call that has been rejected
2018      */
rejectCallAndLog(Call incomingCall)2019     private void rejectCallAndLog(Call incomingCall) {
2020         if (incomingCall.getConnectionService() != null) {
2021             // Only reject the call if it has not already been destroyed.  If a call ends while
2022             // incoming call filtering is taking place, it is possible that the call has already
2023             // been destroyed, and as such it will be impossible to send the reject to the
2024             // associated ConnectionService.
2025             incomingCall.reject(false, null);
2026         } else {
2027             Log.i(this, "rejectCallAndLog - call already destroyed.");
2028         }
2029 
2030         // Since the call was not added to the list of calls, we have to call the missed
2031         // call notifier and the call logger manually.
2032         // Do we need missed call notification for direct to Voicemail calls?
2033         mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
2034                 true /*showNotificationForMissedCall*/);
2035     }
2036 
2037     /**
2038      * Adds the specified call to the main list of live calls.
2039      *
2040      * @param call The call to add.
2041      */
addCall(Call call)2042     private void addCall(Call call) {
2043         Trace.beginSection("addCall");
2044         Log.v(this, "addCall(%s)", call);
2045         call.addListener(this);
2046         mCalls.add(call);
2047 
2048         // Specifies the time telecom finished routing the call. This is used by the dialer for
2049         // analytics.
2050         Bundle extras = call.getIntentExtras();
2051         extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
2052                 SystemClock.elapsedRealtime());
2053 
2054         updateCanAddCall();
2055         // onCallAdded for calls which immediately take the foreground (like the first call).
2056         for (CallsManagerListener listener : mListeners) {
2057             if (LogUtils.SYSTRACE_DEBUG) {
2058                 Trace.beginSection(listener.getClass().toString() + " addCall");
2059             }
2060             listener.onCallAdded(call);
2061             if (LogUtils.SYSTRACE_DEBUG) {
2062                 Trace.endSection();
2063             }
2064         }
2065         Trace.endSection();
2066     }
2067 
removeCall(Call call)2068     private void removeCall(Call call) {
2069         Trace.beginSection("removeCall");
2070         Log.v(this, "removeCall(%s)", call);
2071 
2072         call.setParentAndChildCall(null);  // clean up parent relationship before destroying.
2073         call.removeListener(this);
2074         call.clearConnectionService();
2075         // TODO: clean up RTT pipes
2076 
2077         boolean shouldNotify = false;
2078         if (mCalls.contains(call)) {
2079             mCalls.remove(call);
2080             shouldNotify = true;
2081         }
2082 
2083         call.destroy();
2084 
2085         // Only broadcast changes for calls that are being tracked.
2086         if (shouldNotify) {
2087             updateCanAddCall();
2088             for (CallsManagerListener listener : mListeners) {
2089                 if (LogUtils.SYSTRACE_DEBUG) {
2090                     Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
2091                 }
2092                 listener.onCallRemoved(call);
2093                 if (LogUtils.SYSTRACE_DEBUG) {
2094                     Trace.endSection();
2095                 }
2096             }
2097         }
2098         Trace.endSection();
2099     }
2100 
2101     /**
2102      * Sets the specified state on the specified call.
2103      *
2104      * @param call The call.
2105      * @param newState The new state of the call.
2106      */
setCallState(Call call, int newState, String tag)2107     private void setCallState(Call call, int newState, String tag) {
2108         if (call == null) {
2109             return;
2110         }
2111         int oldState = call.getState();
2112         Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
2113                 CallState.toString(newState), call);
2114         if (newState != oldState) {
2115             // Unfortunately, in the telephony world the radio is king. So if the call notifies
2116             // us that the call is in a particular state, we allow it even if it doesn't make
2117             // sense (e.g., STATE_ACTIVE -> STATE_RINGING).
2118             // TODO: Consider putting a stop to the above and turning CallState
2119             // into a well-defined state machine.
2120             // TODO: Define expected state transitions here, and log when an
2121             // unexpected transition occurs.
2122             call.setState(newState, tag);
2123             maybeShowErrorDialogOnDisconnect(call);
2124 
2125             Trace.beginSection("onCallStateChanged");
2126             // Only broadcast state change for calls that are being tracked.
2127             if (mCalls.contains(call)) {
2128                 updateCanAddCall();
2129                 for (CallsManagerListener listener : mListeners) {
2130                     if (LogUtils.SYSTRACE_DEBUG) {
2131                         Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
2132                     }
2133                     listener.onCallStateChanged(call, oldState, newState);
2134                     if (LogUtils.SYSTRACE_DEBUG) {
2135                         Trace.endSection();
2136                     }
2137                 }
2138             }
2139             Trace.endSection();
2140         }
2141     }
2142 
updateCanAddCall()2143     private void updateCanAddCall() {
2144         boolean newCanAddCall = canAddCall();
2145         if (newCanAddCall != mCanAddCall) {
2146             mCanAddCall = newCanAddCall;
2147             for (CallsManagerListener listener : mListeners) {
2148                 if (LogUtils.SYSTRACE_DEBUG) {
2149                     Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
2150                 }
2151                 listener.onCanAddCallChanged(mCanAddCall);
2152                 if (LogUtils.SYSTRACE_DEBUG) {
2153                     Trace.endSection();
2154                 }
2155             }
2156         }
2157     }
2158 
isPotentialMMICode(Uri handle)2159     private boolean isPotentialMMICode(Uri handle) {
2160         return (handle != null && handle.getSchemeSpecificPart() != null
2161                 && handle.getSchemeSpecificPart().contains("#"));
2162     }
2163 
2164     /**
2165      * Determines if a dialed number is potentially an In-Call MMI code.  In-Call MMI codes are
2166      * MMI codes which can be dialed when one or more calls are in progress.
2167      * <P>
2168      * Checks for numbers formatted similar to the MMI codes defined in:
2169      * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)}
2170      *
2171      * @param handle The URI to call.
2172      * @return {@code True} if the URI represents a number which could be an in-call MMI code.
2173      */
isPotentialInCallMMICode(Uri handle)2174     private boolean isPotentialInCallMMICode(Uri handle) {
2175         if (handle != null && handle.getSchemeSpecificPart() != null &&
2176                 handle.getScheme() != null &&
2177                 handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) {
2178 
2179             String dialedNumber = handle.getSchemeSpecificPart();
2180             return (dialedNumber.equals("0") ||
2181                     (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) ||
2182                     (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) ||
2183                     dialedNumber.equals("3") ||
2184                     dialedNumber.equals("4") ||
2185                     dialedNumber.equals("5"));
2186         }
2187         return false;
2188     }
2189 
2190     @VisibleForTesting
getNumCallsWithState(final boolean isSelfManaged, Call excludeCall, PhoneAccountHandle phoneAccountHandle, int... states)2191     public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
2192                                     PhoneAccountHandle phoneAccountHandle, int... states) {
2193         return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED,
2194                 excludeCall, phoneAccountHandle, states);
2195     }
2196 
2197     /**
2198      * Determines the number of calls matching the specified criteria.
2199      * @param callFilter indicates whether to include just managed calls
2200      *                   ({@link #CALL_FILTER_MANAGED}), self-managed calls
2201      *                   ({@link #CALL_FILTER_SELF_MANAGED}), or all calls
2202      *                   ({@link #CALL_FILTER_ALL}).
2203      * @param excludeCall Where {@code non-null}, this call is excluded from the count.
2204      * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle}
2205      *                           are excluded from the count.
2206      * @param states The list of {@link CallState}s to include in the count.
2207      * @return Count of calls matching criteria.
2208      */
2209     @VisibleForTesting
getNumCallsWithState(final int callFilter, Call excludeCall, PhoneAccountHandle phoneAccountHandle, int... states)2210     public int getNumCallsWithState(final int callFilter, Call excludeCall,
2211                                     PhoneAccountHandle phoneAccountHandle, int... states) {
2212 
2213         Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet());
2214 
2215         Stream<Call> callsStream = mCalls.stream()
2216                 .filter(call -> desiredStates.contains(call.getState()) &&
2217                         call.getParentCall() == null && !call.isExternalCall());
2218 
2219         if (callFilter == CALL_FILTER_MANAGED) {
2220             callsStream = callsStream.filter(call -> !call.isSelfManaged());
2221         } else if (callFilter == CALL_FILTER_SELF_MANAGED) {
2222             callsStream = callsStream.filter(call -> call.isSelfManaged());
2223         }
2224 
2225         // If a call to exclude was specified, filter it out.
2226         if (excludeCall != null) {
2227             callsStream = callsStream.filter(call -> call != excludeCall);
2228         }
2229 
2230         // If a phone account handle was specified, only consider calls for that phone account.
2231         if (phoneAccountHandle != null) {
2232             callsStream = callsStream.filter(
2233                     call -> phoneAccountHandle.equals(call.getTargetPhoneAccount()));
2234         }
2235 
2236         return (int) callsStream.count();
2237     }
2238 
hasMaximumManagedLiveCalls(Call exceptCall)2239     private boolean hasMaximumManagedLiveCalls(Call exceptCall) {
2240         return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */,
2241                 exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES);
2242     }
2243 
hasMaximumSelfManagedCalls(Call exceptCall, PhoneAccountHandle phoneAccountHandle)2244     private boolean hasMaximumSelfManagedCalls(Call exceptCall,
2245                                                    PhoneAccountHandle phoneAccountHandle) {
2246         return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */,
2247                 exceptCall, phoneAccountHandle, ANY_CALL_STATE);
2248     }
2249 
hasMaximumManagedHoldingCalls(Call exceptCall)2250     private boolean hasMaximumManagedHoldingCalls(Call exceptCall) {
2251         return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2252                 null /* phoneAccountHandle */, CallState.ON_HOLD);
2253     }
2254 
hasMaximumManagedRingingCalls(Call exceptCall)2255     private boolean hasMaximumManagedRingingCalls(Call exceptCall) {
2256         return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2257                 null /* phoneAccountHandle */, CallState.RINGING);
2258     }
2259 
hasMaximumSelfManagedRingingCalls(Call exceptCall, PhoneAccountHandle phoneAccountHandle)2260     private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall,
2261                                                       PhoneAccountHandle phoneAccountHandle) {
2262         return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall,
2263                 phoneAccountHandle, CallState.RINGING);
2264     }
2265 
hasMaximumManagedOutgoingCalls(Call exceptCall)2266     private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) {
2267         return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2268                 null /* phoneAccountHandle */, OUTGOING_CALL_STATES);
2269     }
2270 
hasMaximumManagedDialingCalls(Call exceptCall)2271     private boolean hasMaximumManagedDialingCalls(Call exceptCall) {
2272         return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2273                 null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING);
2274     }
2275 
2276     /**
2277      * Given a {@link PhoneAccountHandle} determines if there are calls owned by any other
2278      * {@link PhoneAccountHandle}.
2279      * @param phoneAccountHandle The {@link PhoneAccountHandle} to check.
2280      * @return {@code true} if there are other calls, {@code false} otherwise.
2281      */
hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle)2282     public boolean hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2283         return getNumCallsForOtherPhoneAccount(phoneAccountHandle) > 0;
2284     }
2285 
2286     /**
2287      * Determines the number of calls present for PhoneAccounts other than the one specified.
2288      * @param phoneAccountHandle The handle of the PhoneAccount.
2289      * @return Number of calls owned by other PhoneAccounts.
2290      */
getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle)2291     public int getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2292         return (int) mCalls.stream().filter(call ->
2293                 !phoneAccountHandle.equals(call.getTargetPhoneAccount()) &&
2294                         call.getParentCall() == null &&
2295                         !call.isExternalCall()).count();
2296     }
2297 
2298     /**
2299      * Determines if there are any managed calls.
2300      * @return {@code true} if there are managed calls, {@code false} otherwise.
2301      */
hasManagedCalls()2302     public boolean hasManagedCalls() {
2303         return mCalls.stream().filter(call -> !call.isSelfManaged() &&
2304                 !call.isExternalCall()).count() > 0;
2305     }
2306 
2307     /**
2308      * Determines if there are any self-managed calls.
2309      * @return {@code true} if there are self-managed calls, {@code false} otherwise.
2310      */
hasSelfManagedCalls()2311     public boolean hasSelfManagedCalls() {
2312         return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0;
2313     }
2314 
2315     /**
2316      * Determines if there are any ongoing managed or self-managed calls.
2317      * Note: The {@link #ONGOING_CALL_STATES} are
2318      * @return {@code true} if there are ongoing managed or self-managed calls, {@code false}
2319      *      otherwise.
2320      */
hasOngoingCalls()2321     public boolean hasOngoingCalls() {
2322         return getNumCallsWithState(
2323                 CALL_FILTER_ALL, null /* excludeCall */,
2324                 null /* phoneAccountHandle */,
2325                 ONGOING_CALL_STATES) > 0;
2326     }
2327 
2328     /**
2329      * Determines if there are any ongoing managed calls.
2330      * @return {@code true} if there are ongoing managed calls, {@code false} otherwise.
2331      */
hasOngoingManagedCalls()2332     public boolean hasOngoingManagedCalls() {
2333         return getNumCallsWithState(
2334                 CALL_FILTER_MANAGED, null /* excludeCall */,
2335                 null /* phoneAccountHandle */,
2336                 ONGOING_CALL_STATES) > 0;
2337     }
2338 
2339     /**
2340      * Determines if the system incoming call UI should be shown.
2341      * The system incoming call UI will be shown if the new incoming call is self-managed, and there
2342      * are ongoing calls for another PhoneAccount.
2343      * @param incomingCall The incoming call.
2344      * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise.
2345      */
shouldShowSystemIncomingCallUi(Call incomingCall)2346     public boolean shouldShowSystemIncomingCallUi(Call incomingCall) {
2347         return incomingCall.isIncoming() && incomingCall.isSelfManaged() &&
2348                 hasCallsForOtherPhoneAccount(incomingCall.getTargetPhoneAccount());
2349     }
2350 
makeRoomForOutgoingCall(Call call, boolean isEmergency)2351     private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) {
2352         if (hasMaximumManagedLiveCalls(call)) {
2353             // NOTE: If the amount of live calls changes beyond 1, this logic will probably
2354             // have to change.
2355             Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
2356             Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
2357                    liveCall);
2358 
2359             if (call == liveCall) {
2360                 // If the call is already the foreground call, then we are golden.
2361                 // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
2362                 // state since the call was already populated into the list.
2363                 return true;
2364             }
2365 
2366             if (hasMaximumManagedOutgoingCalls(call)) {
2367                 Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
2368                 if (isEmergency && !outgoingCall.isEmergencyCall()) {
2369                     // Disconnect the current outgoing call if it's not an emergency call. If the
2370                     // user tries to make two outgoing calls to different emergency call numbers,
2371                     // we will try to connect the first outgoing call.
2372                     call.getAnalytics().setCallIsAdditional(true);
2373                     outgoingCall.getAnalytics().setCallIsInterrupted(true);
2374                     outgoingCall.disconnect();
2375                     return true;
2376                 }
2377                 if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
2378                     // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
2379                     // state, just disconnect it since the user has explicitly started a new call.
2380                     call.getAnalytics().setCallIsAdditional(true);
2381                     outgoingCall.getAnalytics().setCallIsInterrupted(true);
2382                     outgoingCall.disconnect();
2383                     return true;
2384                 }
2385                 return false;
2386             }
2387 
2388             if (hasMaximumManagedHoldingCalls(call)) {
2389                 // There is no more room for any more calls, unless it's an emergency.
2390                 if (isEmergency) {
2391                     // Kill the current active call, this is easier then trying to disconnect a
2392                     // holding call and hold an active call.
2393                     call.getAnalytics().setCallIsAdditional(true);
2394                     liveCall.getAnalytics().setCallIsInterrupted(true);
2395                     liveCall.disconnect();
2396                     return true;
2397                 }
2398                 return false;  // No more room!
2399             }
2400 
2401             // We have room for at least one more holding call at this point.
2402 
2403             // TODO: Remove once b/23035408 has been corrected.
2404             // If the live call is a conference, it will not have a target phone account set.  This
2405             // means the check to see if the live call has the same target phone account as the new
2406             // call will not cause us to bail early.  As a result, we'll end up holding the
2407             // ongoing conference call.  However, the ConnectionService is already doing that.  This
2408             // has caused problems with some carriers.  As a workaround until b/23035408 is
2409             // corrected, we will try and get the target phone account for one of the conference's
2410             // children and use that instead.
2411             PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
2412             if (liveCallPhoneAccount == null && liveCall.isConference() &&
2413                     !liveCall.getChildCalls().isEmpty()) {
2414                 liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
2415                 Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
2416                         liveCallPhoneAccount);
2417             }
2418 
2419             // First thing, if we are trying to make a call with the same phone account as the live
2420             // call, then allow it so that the connection service can make its own decision about
2421             // how to handle the new call relative to the current one.
2422             if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
2423                 Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
2424                 call.getAnalytics().setCallIsAdditional(true);
2425                 liveCall.getAnalytics().setCallIsInterrupted(true);
2426                 return true;
2427             } else if (call.getTargetPhoneAccount() == null) {
2428                 // Without a phone account, we can't say reliably that the call will fail.
2429                 // If the user chooses the same phone account as the live call, then it's
2430                 // still possible that the call can be made (like with CDMA calls not supporting
2431                 // hold but they still support adding a call by going immediately into conference
2432                 // mode). Return true here and we'll run this code again after user chooses an
2433                 // account.
2434                 return true;
2435             }
2436 
2437             // Try to hold the live call before attempting the new outgoing call.
2438             if (liveCall.can(Connection.CAPABILITY_HOLD)) {
2439                 Log.i(this, "makeRoomForOutgoingCall: holding live call.");
2440                 call.getAnalytics().setCallIsAdditional(true);
2441                 liveCall.getAnalytics().setCallIsInterrupted(true);
2442                 liveCall.hold();
2443                 return true;
2444             }
2445 
2446             // The live call cannot be held so we're out of luck here.  There's no room.
2447             return false;
2448         }
2449         return true;
2450     }
2451 
2452     /**
2453      * Given a call, find the first non-null phone account handle of its children.
2454      *
2455      * @param parentCall The parent call.
2456      * @return The first non-null phone account handle of the children, or {@code null} if none.
2457      */
getFirstChildPhoneAccount(Call parentCall)2458     private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
2459         for (Call childCall : parentCall.getChildCalls()) {
2460             PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
2461             if (childPhoneAccount != null) {
2462                 return childPhoneAccount;
2463             }
2464         }
2465         return null;
2466     }
2467 
2468     /**
2469      * Checks to see if the call should be on speakerphone and if so, set it.
2470      */
maybeMoveToSpeakerPhone(Call call)2471     private void maybeMoveToSpeakerPhone(Call call) {
2472         if (call.getStartWithSpeakerphoneOn()) {
2473             setAudioRoute(CallAudioState.ROUTE_SPEAKER);
2474             call.setStartWithSpeakerphoneOn(false);
2475         }
2476     }
2477 
2478     /**
2479      * Creates a new call for an existing connection.
2480      *
2481      * @param callId The id of the new call.
2482      * @param connection The connection information.
2483      * @return The new call.
2484      */
createCallForExistingConnection(String callId, ParcelableConnection connection)2485     Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
2486         boolean isDowngradedConference = (connection.getConnectionProperties()
2487                 & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
2488         Call call = new Call(
2489                 callId,
2490                 mContext,
2491                 this,
2492                 mLock,
2493                 mConnectionServiceRepository,
2494                 mContactsAsyncHelper,
2495                 mCallerInfoAsyncQueryFactory,
2496                 mPhoneNumberUtilsAdapter,
2497                 connection.getHandle() /* handle */,
2498                 null /* gatewayInfo */,
2499                 null /* connectionManagerPhoneAccount */,
2500                 connection.getPhoneAccount(), /* targetPhoneAccountHandle */
2501                 Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
2502                 false /* forceAttachToExistingConnection */,
2503                 isDowngradedConference /* isConference */,
2504                 connection.getConnectTimeMillis() /* connectTimeMillis */);
2505 
2506         call.initAnalytics();
2507         call.getAnalytics().setCreatedFromExistingConnection(true);
2508 
2509         setCallState(call, Call.getStateFromConnectionState(connection.getState()),
2510                 "existing connection");
2511         call.setConnectionCapabilities(connection.getConnectionCapabilities());
2512         call.setConnectionProperties(connection.getConnectionProperties());
2513         call.setCallerDisplayName(connection.getCallerDisplayName(),
2514                 connection.getCallerDisplayNamePresentation());
2515         call.addListener(this);
2516 
2517         // In case this connection was added via a ConnectionManager, keep track of the original
2518         // Connection ID as created by the originating ConnectionService.
2519         Bundle extras = connection.getExtras();
2520         if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
2521             call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
2522         }
2523         Log.i(this, "createCallForExistingConnection: %s", connection);
2524         Call parentCall = null;
2525         if (!TextUtils.isEmpty(connection.getParentCallId())) {
2526             String parentId = connection.getParentCallId();
2527             parentCall = mCalls
2528                     .stream()
2529                     .filter(c -> c.getId().equals(parentId))
2530                     .findFirst()
2531                     .orElse(null);
2532             if (parentCall != null) {
2533                 Log.i(this, "createCallForExistingConnection: %s added as child of %s.",
2534                         call.getId(),
2535                         parentCall.getId());
2536                 // Set JUST the parent property, which won't send an update to the Incall UI.
2537                 call.setParentCall(parentCall);
2538             }
2539         }
2540         addCall(call);
2541         if (parentCall != null) {
2542             // Now, set the call as a child of the parent since it has been added to Telecom.  This
2543             // is where we will inform InCall.
2544             call.setChildOf(parentCall);
2545             call.notifyParentChanged(parentCall);
2546         }
2547 
2548         return call;
2549     }
2550 
2551     /**
2552      * Determines whether Telecom already knows about a Connection added via the
2553      * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
2554      * Connection)} API via a ConnectionManager.
2555      *
2556      * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}.
2557      * @param originalConnectionId The new connection ID to check.
2558      * @return {@code true} if this connection is already known by Telecom.
2559      */
getAlreadyAddedConnection(String originalConnectionId)2560     Call getAlreadyAddedConnection(String originalConnectionId) {
2561         Optional<Call> existingCall = mCalls.stream()
2562                 .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) ||
2563                             originalConnectionId.equals(call.getId()))
2564                 .findFirst();
2565 
2566         if (existingCall.isPresent()) {
2567             Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s",
2568                     originalConnectionId, existingCall.get().getId());
2569             return existingCall.get();
2570         }
2571 
2572         return null;
2573     }
2574 
2575     /**
2576      * @return A new unique telecom call Id.
2577      */
getNextCallId()2578     private String getNextCallId() {
2579         synchronized(mLock) {
2580             return TELECOM_CALL_ID_PREFIX + (++mCallId);
2581         }
2582     }
2583 
getNextRttRequestId()2584     public int getNextRttRequestId() {
2585         synchronized (mLock) {
2586             return (++mRttRequestId);
2587         }
2588     }
2589 
2590     /**
2591      * Callback when foreground user is switched. We will reload missed call in all profiles
2592      * including the user itself. There may be chances that profiles are not started yet.
2593      */
2594     @VisibleForTesting
onUserSwitch(UserHandle userHandle)2595     public void onUserSwitch(UserHandle userHandle) {
2596         mCurrentUserHandle = userHandle;
2597         mMissedCallNotifier.setCurrentUserHandle(userHandle);
2598         final UserManager userManager = UserManager.get(mContext);
2599         List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier());
2600         for (UserInfo profile : profiles) {
2601             reloadMissedCallsOfUser(profile.getUserHandle());
2602         }
2603     }
2604 
2605     /**
2606      * Because there may be chances that profiles are not started yet though its parent user is
2607      * switched, we reload missed calls of profile that are just started here.
2608      */
onUserStarting(UserHandle userHandle)2609     void onUserStarting(UserHandle userHandle) {
2610         if (UserUtil.isProfile(mContext, userHandle)) {
2611             reloadMissedCallsOfUser(userHandle);
2612         }
2613     }
2614 
getLock()2615     public TelecomSystem.SyncRoot getLock() {
2616         return mLock;
2617     }
2618 
reloadMissedCallsOfUser(UserHandle userHandle)2619     private void reloadMissedCallsOfUser(UserHandle userHandle) {
2620         mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper,
2621                 new MissedCallNotifier.CallInfoFactory(), userHandle);
2622     }
2623 
onBootCompleted()2624     public void onBootCompleted() {
2625         mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper,
2626                 new MissedCallNotifier.CallInfoFactory());
2627     }
2628 
isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle)2629     public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2630         return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2631     }
2632 
isIncomingCallPermitted(Call excludeCall, PhoneAccountHandle phoneAccountHandle)2633     public boolean isIncomingCallPermitted(Call excludeCall,
2634                                            PhoneAccountHandle phoneAccountHandle) {
2635         if (phoneAccountHandle == null) {
2636             return false;
2637         }
2638         PhoneAccount phoneAccount =
2639                 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2640         if (phoneAccount == null) {
2641             return false;
2642         }
2643 
2644         if (!phoneAccount.isSelfManaged()) {
2645             return !hasMaximumManagedRingingCalls(excludeCall) &&
2646                     !hasMaximumManagedHoldingCalls(excludeCall);
2647         } else {
2648             return !hasEmergencyCall() &&
2649                     !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) &&
2650                     !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle);
2651         }
2652     }
2653 
isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle)2654     public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2655         return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2656     }
2657 
isOutgoingCallPermitted(Call excludeCall, PhoneAccountHandle phoneAccountHandle)2658     public boolean isOutgoingCallPermitted(Call excludeCall,
2659                                            PhoneAccountHandle phoneAccountHandle) {
2660         if (phoneAccountHandle == null) {
2661             return false;
2662         }
2663         PhoneAccount phoneAccount =
2664                 mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2665         if (phoneAccount == null) {
2666             return false;
2667         }
2668 
2669         if (!phoneAccount.isSelfManaged()) {
2670             return !hasMaximumManagedOutgoingCalls(excludeCall) &&
2671                     !hasMaximumManagedDialingCalls(excludeCall) &&
2672                     !hasMaximumManagedLiveCalls(excludeCall) &&
2673                     !hasMaximumManagedHoldingCalls(excludeCall);
2674         } else {
2675             // Only permit outgoing calls if there is no ongoing emergency calls and all other calls
2676             // are associated with the current PhoneAccountHandle.
2677             return !hasEmergencyCall() &&
2678                     !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) &&
2679                     !hasCallsForOtherPhoneAccount(phoneAccountHandle) &&
2680                     !hasManagedCalls();
2681         }
2682     }
2683 
2684     /**
2685      * Blocks execution until all Telecom handlers have completed their current work.
2686      */
waitOnHandlers()2687     public void waitOnHandlers() {
2688         CountDownLatch mainHandlerLatch = new CountDownLatch(3);
2689         mHandler.post(() -> {
2690             mainHandlerLatch.countDown();
2691         });
2692         mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> {
2693             mainHandlerLatch.countDown();
2694         });
2695         mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> {
2696             mainHandlerLatch.countDown();
2697         });
2698 
2699         try {
2700             mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);
2701         } catch (InterruptedException e) {
2702             Log.w(this, "waitOnHandlers: interrupted %s", e);
2703         }
2704     }
2705 
2706     /**
2707      * Used to confirm creation of an outgoing call which was marked as pending confirmation in
2708      * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
2709      * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
2710      * {@link ConfirmCallDialogActivity}.
2711      * @param callId The call ID of the call to confirm.
2712      */
confirmPendingCall(String callId)2713     public void confirmPendingCall(String callId) {
2714         Log.i(this, "confirmPendingCall: callId=%s", callId);
2715         if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
2716             Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED);
2717             addCall(mPendingCall);
2718 
2719             // We are going to place the new outgoing call, so disconnect any ongoing self-managed
2720             // calls which are ongoing at this time.
2721             disconnectSelfManagedCalls();
2722 
2723             // Kick of the new outgoing call intent from where it left off prior to confirming the
2724             // call.
2725             CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this,
2726                     mPendingCall.getOriginalCallIntent());
2727             mPendingCall = null;
2728         }
2729     }
2730 
2731     /**
2732      * Used to cancel an outgoing call which was marked as pending confirmation in
2733      * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
2734      * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
2735      * {@link ConfirmCallDialogActivity}.
2736      * @param callId The call ID of the call to cancel.
2737      */
cancelPendingCall(String callId)2738     public void cancelPendingCall(String callId) {
2739         Log.i(this, "cancelPendingCall: callId=%s", callId);
2740         if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
2741             Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED);
2742             markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED));
2743             markCallAsRemoved(mPendingCall);
2744             mPendingCall = null;
2745         }
2746     }
2747 
2748     /**
2749      * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when
2750      * a managed call is added while there are ongoing self-managed calls.  Starts
2751      * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the
2752      * outgoing call or not.
2753      * @param call The call to confirm.
2754      */
startCallConfirmation(Call call)2755     private void startCallConfirmation(Call call) {
2756         if (mPendingCall != null) {
2757             Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s",
2758                     mPendingCall.getId(), call.getId());
2759             markCallDisconnectedDueToSelfManagedCall(call);
2760             return;
2761         }
2762         Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION);
2763         mPendingCall = call;
2764 
2765         // Figure out the name of the app in charge of the self-managed call(s).
2766         Call selfManagedCall = mCalls.stream()
2767                 .filter(c -> c.isSelfManaged())
2768                 .findFirst()
2769                 .orElse(null);
2770         CharSequence ongoingAppName = "";
2771         if (selfManagedCall != null) {
2772             ongoingAppName = selfManagedCall.getTargetPhoneAccountLabel();
2773         }
2774         Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(),
2775                 ongoingAppName);
2776 
2777         Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class);
2778         confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId());
2779         confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName);
2780         confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2781         mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT);
2782     }
2783 
2784     /**
2785      * Disconnects all self-managed calls.
2786      */
disconnectSelfManagedCalls()2787     private void disconnectSelfManagedCalls() {
2788         // Disconnect all self-managed calls to make priority for emergency call.
2789         // Use Call.disconnect() to command the ConnectionService to disconnect the calls.
2790         // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to
2791         // disconnect.
2792         mCalls.stream()
2793                 .filter(c -> c.isSelfManaged())
2794                 .forEach(c -> c.disconnect());
2795     }
2796 
2797     /**
2798      * Dumps the state of the {@link CallsManager}.
2799      *
2800      * @param pw The {@code IndentingPrintWriter} to write the state to.
2801      */
dump(IndentingPrintWriter pw)2802     public void dump(IndentingPrintWriter pw) {
2803         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
2804         if (mCalls != null) {
2805             pw.println("mCalls: ");
2806             pw.increaseIndent();
2807             for (Call call : mCalls) {
2808                 pw.println(call);
2809             }
2810             pw.decreaseIndent();
2811         }
2812 
2813         if (mPendingCall != null) {
2814             pw.print("mPendingCall:");
2815             pw.println(mPendingCall.getId());
2816         }
2817 
2818         if (mCallAudioManager != null) {
2819             pw.println("mCallAudioManager:");
2820             pw.increaseIndent();
2821             mCallAudioManager.dump(pw);
2822             pw.decreaseIndent();
2823         }
2824 
2825         if (mTtyManager != null) {
2826             pw.println("mTtyManager:");
2827             pw.increaseIndent();
2828             mTtyManager.dump(pw);
2829             pw.decreaseIndent();
2830         }
2831 
2832         if (mInCallController != null) {
2833             pw.println("mInCallController:");
2834             pw.increaseIndent();
2835             mInCallController.dump(pw);
2836             pw.decreaseIndent();
2837         }
2838 
2839         if (mDefaultDialerCache != null) {
2840             pw.println("mDefaultDialerCache:");
2841             pw.increaseIndent();
2842             mDefaultDialerCache.dumpCache(pw);
2843             pw.decreaseIndent();
2844         }
2845 
2846         if (mConnectionServiceRepository != null) {
2847             pw.println("mConnectionServiceRepository:");
2848             pw.increaseIndent();
2849             mConnectionServiceRepository.dump(pw);
2850             pw.decreaseIndent();
2851         }
2852     }
2853 
2854     /**
2855     * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code.
2856     *
2857     * @param call The call.
2858     */
maybeShowErrorDialogOnDisconnect(Call call)2859     private void maybeShowErrorDialogOnDisconnect(Call call) {
2860         if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle())
2861                 || isPotentialInCallMMICode(call.getHandle()))) {
2862             DisconnectCause disconnectCause = call.getDisconnectCause();
2863             if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode()
2864                     == DisconnectCause.ERROR)) {
2865                 Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class);
2866                 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA,
2867                         disconnectCause.getDescription());
2868                 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2869                 mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
2870             }
2871         }
2872     }
2873 
setIntentExtrasAndStartTime(Call call, Bundle extras)2874     private void setIntentExtrasAndStartTime(Call call, Bundle extras) {
2875       // Create our own instance to modify (since extras may be Bundle.EMPTY)
2876       extras = new Bundle(extras);
2877 
2878       // Specifies the time telecom began routing the call. This is used by the dialer for
2879       // analytics.
2880       extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
2881               SystemClock.elapsedRealtime());
2882 
2883       call.setIntentExtras(extras);
2884     }
2885 
2886     /**
2887      * Notifies the {@link android.telecom.ConnectionService} associated with a
2888      * {@link PhoneAccountHandle} that the attempt to create a new connection has failed.
2889      *
2890      * @param phoneAccountHandle The {@link PhoneAccountHandle}.
2891      * @param call The {@link Call} which could not be added.
2892      */
notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call)2893     private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
2894         if (phoneAccountHandle == null) {
2895             return;
2896         }
2897         ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
2898                 phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle());
2899         if (service == null) {
2900             Log.i(this, "Found no connection service.");
2901             return;
2902         } else {
2903             call.setConnectionService(service);
2904             service.createConnectionFailed(call);
2905         }
2906     }
2907 
broadcastUnregisterIntent(PhoneAccountHandle accountHandle)2908     private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) {
2909         Intent intent =
2910                 new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED);
2911         intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
2912         intent.putExtra(
2913                 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
2914         Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle);
2915         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
2916                 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
2917 
2918         String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
2919                 getCurrentUserHandle().getIdentifier());
2920         if (!TextUtils.isEmpty(dialerPackage)) {
2921             Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED)
2922                     .setPackage(dialerPackage);
2923             directedIntent.putExtra(
2924                     TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
2925             Log.i(this, "Sending phone-account unregistered intent to default dialer");
2926             mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
2927         }
2928         return ;
2929     }
2930 
broadcastRegisterIntent(PhoneAccountHandle accountHandle)2931     private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) {
2932         Intent intent = new Intent(
2933                 TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED);
2934         intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
2935         intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
2936                 accountHandle);
2937         Log.i(this, "Sending phone-account %s registered intent as user", accountHandle);
2938         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
2939                 PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
2940 
2941         String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
2942                 getCurrentUserHandle().getIdentifier());
2943         if (!TextUtils.isEmpty(dialerPackage)) {
2944             Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED)
2945                     .setPackage(dialerPackage);
2946             directedIntent.putExtra(
2947                     TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
2948             Log.i(this, "Sending phone-account registered intent to default dialer");
2949             mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
2950         }
2951         return ;
2952     }
2953 }
2954