CallsManager.java revision 5b8facb5650b1f414353721697a2c85cf1d056c6
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
17package com.android.server.telecom;
18
19import android.app.ActivityManager;
20import android.content.Context;
21import android.content.pm.UserInfo;
22import android.content.Intent;
23import android.media.AudioManager;
24import android.net.Uri;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.Looper;
28import android.os.Process;
29import android.os.SystemClock;
30import android.os.SystemProperties;
31import android.os.SystemVibrator;
32import android.os.Trace;
33import android.os.UserHandle;
34import android.os.UserManager;
35import android.provider.CallLog.Calls;
36import android.provider.Settings;
37import android.telecom.CallAudioState;
38import android.telecom.Conference;
39import android.telecom.Connection;
40import android.telecom.DisconnectCause;
41import android.telecom.GatewayInfo;
42import android.telecom.Log;
43import android.telecom.ParcelableConference;
44import android.telecom.ParcelableConnection;
45import android.telecom.PhoneAccount;
46import android.telecom.PhoneAccountHandle;
47import android.telecom.Logging.Runnable;
48import android.telecom.TelecomManager;
49import android.telecom.VideoProfile;
50import android.telephony.PhoneNumberUtils;
51import android.telephony.TelephonyManager;
52import android.text.TextUtils;
53
54import com.android.internal.annotations.VisibleForTesting;
55import com.android.internal.telephony.AsyncEmergencyContactNotifier;
56import com.android.internal.telephony.PhoneConstants;
57import com.android.internal.telephony.TelephonyProperties;
58import com.android.internal.util.IndentingPrintWriter;
59import com.android.server.telecom.bluetooth.BluetoothRouteManager;
60import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
61import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
62import com.android.server.telecom.callfiltering.CallFilterResultCallback;
63import com.android.server.telecom.callfiltering.CallFilteringResult;
64import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
65import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
66import com.android.server.telecom.callfiltering.IncomingCallFilter;
67import com.android.server.telecom.components.ErrorDialogActivity;
68import com.android.server.telecom.ui.ConfirmCallDialogActivity;
69import com.android.server.telecom.ui.IncomingCallNotifier;
70
71import java.util.ArrayList;
72import java.util.Collection;
73import java.util.Collections;
74import java.util.HashMap;
75import java.util.HashSet;
76import java.util.Iterator;
77import java.util.List;
78import java.util.Map;
79import java.util.Objects;
80import java.util.Optional;
81import java.util.Set;
82import java.util.concurrent.ConcurrentHashMap;
83import java.util.concurrent.CountDownLatch;
84import java.util.concurrent.TimeUnit;
85import java.util.stream.Collectors;
86import java.util.stream.IntStream;
87import 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
97public class CallsManager extends Call.ListenerBase
98        implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy {
99
100    // TODO: Consider renaming this CallsManagerPlugin.
101    @VisibleForTesting
102    public interface CallsManagerListener {
103        void onCallAdded(Call call);
104        void onCallRemoved(Call call);
105        void onCallStateChanged(Call call, int oldState, int newState);
106        void onConnectionServiceChanged(
107                Call call,
108                ConnectionServiceWrapper oldService,
109                ConnectionServiceWrapper newService);
110        void onIncomingCallAnswered(Call call);
111        void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
112        void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
113        void onRingbackRequested(Call call, boolean ringback);
114        void onIsConferencedChanged(Call call);
115        void onIsVoipAudioModeChanged(Call call);
116        void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
117        void onCanAddCallChanged(boolean canAddCall);
118        void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
119        void onHoldToneRequested(Call call);
120        void onExternalCallChanged(Call call, boolean isExternalCall);
121    }
122
123    private static final String TAG = "CallsManager";
124
125    /**
126     * Call filter specifier used with
127     * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only
128     * self-managed calls should be included.
129     */
130    private static final int CALL_FILTER_SELF_MANAGED = 1;
131
132    /**
133     * Call filter specifier used with
134     * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate only
135     * managed calls should be included.
136     */
137    private static final int CALL_FILTER_MANAGED = 2;
138
139    /**
140     * Call filter specifier used with
141     * {@link #getNumCallsWithState(int, Call, PhoneAccountHandle, int...)} to indicate both managed
142     * and self-managed calls should be included.
143     */
144    private static final int CALL_FILTER_ALL = 3;
145
146    private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION =
147            "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION";
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);
192        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE);
193        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE);
194        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE);
195        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_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     */
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
391    public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) {
392        if (mIncomingCallNotifier != null) {
393            mListeners.remove(mIncomingCallNotifier);
394        }
395        mIncomingCallNotifier = incomingCallNotifier;
396        mListeners.add(mIncomingCallNotifier);
397    }
398
399    public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) {
400        if (mRespondViaSmsManager != null) {
401            mListeners.remove(mRespondViaSmsManager);
402        }
403        mRespondViaSmsManager = respondViaSmsManager;
404        mListeners.add(respondViaSmsManager);
405    }
406
407    public RespondViaSmsManager getRespondViaSmsManager() {
408        return mRespondViaSmsManager;
409    }
410
411    public CallerInfoLookupHelper getCallerInfoLookupHelper() {
412        return mCallerInfoLookupHelper;
413    }
414
415    @Override
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
435    public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) {
436        Log.v(this, "onFailedOutgoingCall, call: %s", call);
437
438        markCallAsRemoved(call);
439    }
440
441    @Override
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
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     */
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
541    public void onFailedIncomingCall(Call call) {
542        setCallState(call, CallState.DISCONNECTED, "failed incoming call");
543        call.removeListener(this);
544    }
545
546    @Override
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
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
561    public void onRingbackRequested(Call call, boolean ringback) {
562        for (CallsManagerListener listener : mListeners) {
563            listener.onRingbackRequested(call, ringback);
564        }
565    }
566
567    @Override
568    public void onPostDialWait(Call call, String remaining) {
569        mInCallController.onPostDialWait(call, remaining);
570    }
571
572    @Override
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
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
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
627    public void onIsVoipAudioModeChanged(Call call) {
628        for (CallsManagerListener listener : mListeners) {
629            listener.onIsVoipAudioModeChanged(call);
630        }
631    }
632
633    @Override
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
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
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
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
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
709    public void onHoldToneRequested(Call call) {
710        for (CallsManagerListener listener : mListeners) {
711            listener.onHoldToneRequested(call);
712        }
713    }
714
715    /**
716     * A {@link Call} managed by the {@link CallsManager} has requested a handover to another
717     * {@link PhoneAccount}.
718     * @param call The call.
719     * @param handoverTo The {@link PhoneAccountHandle} to handover the call to.
720     * @param videoState The desired video state of the call after handover.
721     * @param extras
722     */
723    @Override
724    public void onHandoverRequested(Call call, PhoneAccountHandle handoverTo, int videoState,
725                                    Bundle extras) {
726        requestHandover(call, handoverTo, videoState, extras);
727    }
728
729    @VisibleForTesting
730    public Call getForegroundCall() {
731        if (mCallAudioManager == null) {
732            // Happens when getForegroundCall is called before full initialization.
733            return null;
734        }
735        return mCallAudioManager.getForegroundCall();
736    }
737
738    @Override
739    public UserHandle getCurrentUserHandle() {
740        return mCurrentUserHandle;
741    }
742
743    public CallAudioManager getCallAudioManager() {
744        return mCallAudioManager;
745    }
746
747    InCallController getInCallController() {
748        return mInCallController;
749    }
750
751    EmergencyCallHelper getEmergencyCallHelper() {
752        return mEmergencyCallHelper;
753    }
754
755    @VisibleForTesting
756    public boolean hasEmergencyCall() {
757        for (Call call : mCalls) {
758            if (call.isEmergencyCall()) {
759                return true;
760            }
761        }
762        return false;
763    }
764
765    boolean hasOnlyDisconnectedCalls() {
766        for (Call call : mCalls) {
767            if (!call.isDisconnected()) {
768                return false;
769            }
770        }
771        return true;
772    }
773
774    public boolean hasVideoCall() {
775        for (Call call : mCalls) {
776            if (VideoProfile.isVideo(call.getVideoState())) {
777                return true;
778            }
779        }
780        return false;
781    }
782
783    @VisibleForTesting
784    public CallAudioState getAudioState() {
785        return mCallAudioManager.getCallAudioState();
786    }
787
788    boolean isTtySupported() {
789        return mTtyManager.isTtySupported();
790    }
791
792    int getCurrentTtyMode() {
793        return mTtyManager.getCurrentTtyMode();
794    }
795
796    @VisibleForTesting
797    public void addListener(CallsManagerListener listener) {
798        mListeners.add(listener);
799    }
800
801    void removeListener(CallsManagerListener listener) {
802        mListeners.remove(listener);
803    }
804
805    /**
806     * Starts the process to attach the call to a connection service.
807     *
808     * @param phoneAccountHandle The phone account which contains the component name of the
809     *        connection service to use for this call.
810     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
811     */
812    void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
813        Log.d(this, "processIncomingCallIntent");
814        boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER);
815        Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
816        if (handle == null) {
817            // Required for backwards compatibility
818            handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
819        }
820        Call call = new Call(
821                getNextCallId(),
822                mContext,
823                this,
824                mLock,
825                mConnectionServiceRepository,
826                mContactsAsyncHelper,
827                mCallerInfoAsyncQueryFactory,
828                mPhoneNumberUtilsAdapter,
829                handle,
830                null /* gatewayInfo */,
831                null /* connectionManagerPhoneAccount */,
832                phoneAccountHandle,
833                Call.CALL_DIRECTION_INCOMING /* callDirection */,
834                false /* forceAttachToExistingConnection */,
835                false /* isConference */
836        );
837
838        // Ensure new calls related to self-managed calls/connections are set as such.  This will
839        // be overridden when the actual connection is returned in startCreateConnection, however
840        // doing this now ensures the logs and any other logic will treat this call as self-managed
841        // from the moment it is created.
842        PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
843                phoneAccountHandle);
844        if (phoneAccount != null) {
845            call.setIsSelfManaged(phoneAccount.isSelfManaged());
846            if (call.isSelfManaged()) {
847                // Self managed calls will always be voip audio mode.
848                call.setIsVoipAudioMode(true);
849            } else {
850                // Incoming call is not self-managed, so we need to set extras on it to indicate
851                // whether answering will cause a background self-managed call to drop.
852                if (hasSelfManagedCalls()) {
853                    Bundle dropCallExtras = new Bundle();
854                    dropCallExtras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true);
855
856                    // Include the name of the app which will drop the call.
857                    Call foregroundCall = getForegroundCall();
858                    if (foregroundCall != null) {
859                        CharSequence droppedApp = foregroundCall.getTargetPhoneAccountLabel();
860                        dropCallExtras.putCharSequence(
861                                Connection.EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME, droppedApp);
862                        Log.i(this, "Incoming managed call will drop %s call.", droppedApp);
863                    }
864                    call.putExtras(Call.SOURCE_CONNECTION_SERVICE, dropCallExtras);
865                }
866            }
867
868            if (phoneAccount.getExtras()
869                    .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
870                Log.d(this, "processIncomingCallIntent: defaulting to voip mode for call %s",
871                        call.getId());
872                call.setIsVoipAudioMode(true);
873            }
874        }
875        if (extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
876            if (phoneAccount != null &&
877                    phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
878                call.setRttStreams(true);
879            }
880        }
881        // If the extras specifies a video state, set it on the call if the PhoneAccount supports
882        // video.
883        if (extras.containsKey(TelecomManager.EXTRA_INCOMING_VIDEO_STATE) &&
884                phoneAccount != null && phoneAccount.hasCapabilities(
885                        PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
886            call.setVideoState(extras.getInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE));
887        }
888
889        call.initAnalytics();
890        if (getForegroundCall() != null) {
891            getForegroundCall().getAnalytics().setCallIsInterrupted(true);
892            call.getAnalytics().setCallIsAdditional(true);
893        }
894
895        setIntentExtrasAndStartTime(call, extras);
896        // TODO: Move this to be a part of addCall()
897        call.addListener(this);
898
899        boolean isHandoverAllowed = true;
900        if (isHandover) {
901            if (!isHandoverInProgress() &&
902                    isHandoverToPhoneAccountSupported(phoneAccountHandle)) {
903                final String handleScheme = handle.getSchemeSpecificPart();
904                Call fromCall = mCalls.stream()
905                        .filter((c) -> mPhoneNumberUtilsAdapter.isSamePhoneNumber(
906                                c.getHandle().getSchemeSpecificPart(), handleScheme))
907                        .findFirst()
908                        .orElse(null);
909                if (fromCall != null) {
910                    if (!isHandoverFromPhoneAccountSupported(fromCall.getTargetPhoneAccount())) {
911                        Log.w(this, "processIncomingCallIntent: From account doesn't support " +
912                                        "handover.");
913                        isHandoverAllowed = false;
914                    }
915                } else {
916                    Log.w(this, "processIncomingCallIntent: handover fail; can't find from call.");
917                    isHandoverAllowed = false;
918                }
919
920                if (isHandoverAllowed) {
921                    // Link the calls so we know we're handing over.
922                    fromCall.setHandoverToCall(call);
923                    call.setHandoverFromCall(fromCall);
924                    Log.addEvent(fromCall, LogUtils.Events.START_HANDOVER,
925                            "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId());
926                    Log.addEvent(call, LogUtils.Events.START_HANDOVER,
927                            "handOverFrom=%s, handOverTo=%s", fromCall.getId(), call.getId());
928                }
929            } else {
930                Log.w(this, "processIncomingCallIntent: To account doesn't support handover.");
931                isHandoverAllowed = false;
932            }
933        }
934        if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
935                call.getTargetPhoneAccount()))) {
936            notifyCreateConnectionFailed(phoneAccountHandle, call);
937        } else {
938            call.startCreateConnection(mPhoneAccountRegistrar);
939        }
940    }
941
942    void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
943        Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE);
944        Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle));
945        Call call = new Call(
946                getNextCallId(),
947                mContext,
948                this,
949                mLock,
950                mConnectionServiceRepository,
951                mContactsAsyncHelper,
952                mCallerInfoAsyncQueryFactory,
953                mPhoneNumberUtilsAdapter,
954                handle,
955                null /* gatewayInfo */,
956                null /* connectionManagerPhoneAccount */,
957                phoneAccountHandle,
958                Call.CALL_DIRECTION_UNKNOWN /* callDirection */,
959                // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach
960                // to the existing connection instead of trying to create a new one.
961                true /* forceAttachToExistingConnection */,
962                false /* isConference */
963        );
964        call.initAnalytics();
965
966        setIntentExtrasAndStartTime(call, extras);
967        call.addListener(this);
968        call.startCreateConnection(mPhoneAccountRegistrar);
969    }
970
971    private boolean areHandlesEqual(Uri handle1, Uri handle2) {
972        if (handle1 == null || handle2 == null) {
973            return handle1 == handle2;
974        }
975
976        if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) {
977            return false;
978        }
979
980        final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart());
981        final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart());
982        return TextUtils.equals(number1, number2);
983    }
984
985    private Call reuseOutgoingCall(Uri handle) {
986        // Check to see if we can reuse any of the calls that are waiting to disconnect.
987        // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information.
988        Call reusedCall = null;
989        for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) {
990            Call pendingCall = callIter.next();
991            if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) {
992                callIter.remove();
993                Log.i(this, "Reusing disconnected call %s", pendingCall);
994                reusedCall = pendingCall;
995            } else {
996                Log.i(this, "Not reusing disconnected call %s", pendingCall);
997                callIter.remove();
998                pendingCall.disconnect();
999            }
1000        }
1001
1002        return reusedCall;
1003    }
1004
1005    /**
1006     * Kicks off the first steps to creating an outgoing call.
1007     *
1008     * For managed connections, this is the first step to launching the Incall UI.
1009     * For self-managed connections, we don't expect the Incall UI to launch, but this is still a
1010     * first step in getting the self-managed ConnectionService to create the connection.
1011     * @param handle Handle to connect the call with.
1012     * @param phoneAccountHandle The phone account which contains the component name of the
1013     *        connection service to use for this call.
1014     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
1015     * @param initiatingUser {@link UserHandle} of user that place the outgoing call.
1016     * @param originalIntent
1017     */
1018    Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
1019            UserHandle initiatingUser, Intent originalIntent) {
1020        boolean isReusedCall = true;
1021        Call call = reuseOutgoingCall(handle);
1022
1023        PhoneAccount account =
1024                mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
1025
1026        // Create a call with original handle. The handle may be changed when the call is attached
1027        // to a connection service, but in most cases will remain the same.
1028        if (call == null) {
1029            call = new Call(getNextCallId(), mContext,
1030                    this,
1031                    mLock,
1032                    mConnectionServiceRepository,
1033                    mContactsAsyncHelper,
1034                    mCallerInfoAsyncQueryFactory,
1035                    mPhoneNumberUtilsAdapter,
1036                    handle,
1037                    null /* gatewayInfo */,
1038                    null /* connectionManagerPhoneAccount */,
1039                    null /* phoneAccountHandle */,
1040                    Call.CALL_DIRECTION_OUTGOING /* callDirection */,
1041                    false /* forceAttachToExistingConnection */,
1042                    false /* isConference */
1043            );
1044            call.initAnalytics();
1045
1046            // Ensure new calls related to self-managed calls/connections are set as such.  This
1047            // will be overridden when the actual connection is returned in startCreateConnection,
1048            // however doing this now ensures the logs and any other logic will treat this call as
1049            // self-managed from the moment it is created.
1050            if (account != null) {
1051                call.setIsSelfManaged(account.isSelfManaged());
1052                if (call.isSelfManaged()) {
1053                    // Self-managed calls will ALWAYS use voip audio mode.
1054                    call.setIsVoipAudioMode(true);
1055                }
1056            }
1057
1058            call.setInitiatingUser(initiatingUser);
1059            isReusedCall = false;
1060        }
1061
1062        if (extras != null) {
1063            // Set the video state on the call early so that when it is added to the InCall UI the
1064            // UI knows to configure itself as a video call immediately.
1065            int videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
1066                    VideoProfile.STATE_AUDIO_ONLY);
1067
1068            // If this is an emergency video call, we need to check if the phone account supports
1069            // emergency video calling.
1070            // Also, ensure we don't try to place an outgoing call with video if video is not
1071            // supported.
1072            if (VideoProfile.isVideo(videoState)) {
1073                if (call.isEmergencyCall() && account != null &&
1074                        !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
1075                    // Phone account doesn't support emergency video calling, so fallback to
1076                    // audio-only now to prevent the InCall UI from setting up video surfaces
1077                    // needlessly.
1078                    Log.i(this, "startOutgoingCall - emergency video calls not supported; " +
1079                            "falling back to audio-only");
1080                    videoState = VideoProfile.STATE_AUDIO_ONLY;
1081                } else if (account != null &&
1082                        !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
1083                    // Phone account doesn't support video calling, so fallback to audio-only.
1084                    Log.i(this, "startOutgoingCall - video calls not supported; fallback to " +
1085                            "audio-only.");
1086                    videoState = VideoProfile.STATE_AUDIO_ONLY;
1087                }
1088            }
1089
1090            call.setVideoState(videoState);
1091        }
1092
1093        PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount(
1094                phoneAccountHandle, initiatingUser);
1095        boolean isSelfManaged = targetPhoneAccount != null && targetPhoneAccount.isSelfManaged();
1096
1097        List<PhoneAccountHandle> accounts;
1098        if (!isSelfManaged) {
1099            accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
1100            Log.v(this, "startOutgoingCall found accounts = " + accounts);
1101
1102            // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this
1103            // call as if a phoneAccount was not specified (does the default behavior instead).
1104            // Note: We will not attempt to dial with a requested phoneAccount if it is disabled.
1105            if (phoneAccountHandle != null) {
1106                if (!accounts.contains(phoneAccountHandle)) {
1107                    phoneAccountHandle = null;
1108                }
1109            }
1110
1111            if (phoneAccountHandle == null && accounts.size() > 0) {
1112                // No preset account, check if default exists that supports the URI scheme for the
1113                // handle and verify it can be used.
1114                if (accounts.size() > 1) {
1115                    PhoneAccountHandle defaultPhoneAccountHandle =
1116                            mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(
1117                                    handle.getScheme(), initiatingUser);
1118                    if (defaultPhoneAccountHandle != null &&
1119                            accounts.contains(defaultPhoneAccountHandle)) {
1120                        phoneAccountHandle = defaultPhoneAccountHandle;
1121                    }
1122                } else {
1123                    // Use the only PhoneAccount that is available
1124                    phoneAccountHandle = accounts.get(0);
1125                }
1126            }
1127        } else {
1128            accounts = Collections.EMPTY_LIST;
1129        }
1130
1131        call.setTargetPhoneAccount(phoneAccountHandle);
1132
1133        boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle) && !isSelfManaged;
1134
1135        // Do not support any more live calls.  Our options are to move a call to hold, disconnect
1136        // a call, or cancel this call altogether. If a call is being reused, then it has already
1137        // passed the makeRoomForOutgoingCall check once and will fail the second time due to the
1138        // call transitioning into the CONNECTING state.
1139        if (!isSelfManaged && !isPotentialInCallMMICode && (!isReusedCall &&
1140                !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) {
1141            // just cancel at this point.
1142            Log.i(this, "No remaining room for outgoing call: %s", call);
1143            if (mCalls.contains(call)) {
1144                // This call can already exist if it is a reused call,
1145                // See {@link #reuseOutgoingCall}.
1146                call.disconnect();
1147            }
1148            return null;
1149        }
1150
1151        boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
1152                !call.isEmergencyCall() && !isSelfManaged;
1153
1154        if (needsAccountSelection) {
1155            // This is the state where the user is expected to select an account
1156            call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
1157            // Create our own instance to modify (since extras may be Bundle.EMPTY)
1158            extras = new Bundle(extras);
1159            extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
1160        } else {
1161            PhoneAccount accountToUse =
1162                    mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
1163            if (accountToUse != null && accountToUse.getExtras() != null) {
1164                if (accountToUse.getExtras()
1165                        .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
1166                    Log.d(this, "startOutgoingCall: defaulting to voip mode for call %s",
1167                            call.getId());
1168                    call.setIsVoipAudioMode(true);
1169                }
1170            }
1171
1172            call.setState(
1173                    CallState.CONNECTING,
1174                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
1175            if (extras != null
1176                    && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
1177                if (accountToUse != null
1178                        && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1179                    call.setRttStreams(true);
1180                }
1181            }
1182        }
1183        setIntentExtrasAndStartTime(call, extras);
1184
1185        if ((isPotentialMMICode(handle) || isPotentialInCallMMICode)
1186                && !needsAccountSelection) {
1187            // Do not add the call if it is a potential MMI code.
1188            call.addListener(this);
1189        } else if (!isSelfManaged && hasSelfManagedCalls() && !call.isEmergencyCall()) {
1190            // Adding a managed call and there are ongoing self-managed call(s).
1191            call.setOriginalCallIntent(originalIntent);
1192            startCallConfirmation(call);
1193            return null;
1194        } else if (!mCalls.contains(call)) {
1195            // We check if mCalls already contains the call because we could potentially be reusing
1196            // a call which was previously added (See {@link #reuseOutgoingCall}).
1197            addCall(call);
1198        }
1199
1200        return call;
1201    }
1202
1203    /**
1204     * Attempts to issue/connect the specified call.
1205     *
1206     * @param handle Handle to connect the call with.
1207     * @param gatewayInfo Optional gateway information that can be used to route the call to the
1208     *        actual dialed handle via a gateway provider. May be null.
1209     * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects.
1210     * @param videoState The desired video state for the outgoing call.
1211     */
1212    @VisibleForTesting
1213    public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
1214            boolean speakerphoneOn, int videoState) {
1215        if (call == null) {
1216            // don't do anything if the call no longer exists
1217            Log.i(this, "Canceling unknown call.");
1218            return;
1219        }
1220
1221        final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();
1222
1223        if (gatewayInfo == null) {
1224            Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
1225        } else {
1226            Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
1227                    Log.pii(uriHandle), Log.pii(handle));
1228        }
1229
1230        call.setHandle(uriHandle);
1231        call.setGatewayInfo(gatewayInfo);
1232
1233        final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
1234                R.bool.use_speaker_when_docked);
1235        final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
1236        final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);
1237
1238        // Auto-enable speakerphone if the originating intent specified to do so, if the call
1239        // is a video call, of if using speaker when docked
1240        call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
1241                || (useSpeakerWhenDocked && useSpeakerForDock));
1242        call.setVideoState(videoState);
1243
1244        if (speakerphoneOn) {
1245            Log.i(this, "%s Starting with speakerphone as requested", call);
1246        } else if (useSpeakerWhenDocked && useSpeakerForDock) {
1247            Log.i(this, "%s Starting with speakerphone because car is docked.", call);
1248        } else if (useSpeakerForVideoCall) {
1249            Log.i(this, "%s Starting with speakerphone because its a video call.", call);
1250        }
1251
1252        if (call.isEmergencyCall()) {
1253            new AsyncEmergencyContactNotifier(mContext).execute();
1254        }
1255
1256        final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
1257                com.android.internal.R.bool.config_requireCallCapableAccountForHandle);
1258        final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call,
1259                call.getTargetPhoneAccount());
1260        if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
1261            // If the account has been set, proceed to place the outgoing call.
1262            // Otherwise the connection will be initiated when the account is set by the user.
1263            if (call.isSelfManaged() && !isOutgoingCallPermitted) {
1264                notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call);
1265            } else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) {
1266                markCallDisconnectedDueToSelfManagedCall(call);
1267            } else {
1268                if (call.isEmergencyCall()) {
1269                    // Disconnect all self-managed calls to make priority for emergency call.
1270                    disconnectSelfManagedCalls();
1271                }
1272
1273                call.startCreateConnection(mPhoneAccountRegistrar);
1274            }
1275        } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
1276                requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
1277                call.getInitiatingUser()).isEmpty()) {
1278            // If there are no call capable accounts, disconnect the call.
1279            markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
1280                    "No registered PhoneAccounts"));
1281            markCallAsRemoved(call);
1282        }
1283    }
1284
1285    /**
1286     * Attempts to start a conference call for the specified call.
1287     *
1288     * @param call The call to conference.
1289     * @param otherCall The other call to conference with.
1290     */
1291    @VisibleForTesting
1292    public void conference(Call call, Call otherCall) {
1293        call.conferenceWith(otherCall);
1294    }
1295
1296    /**
1297     * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call
1298     * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
1299     * the user opting to answer said call.
1300     *
1301     * @param call The call to answer.
1302     * @param videoState The video state in which to answer the call.
1303     */
1304    @VisibleForTesting
1305    public void answerCall(Call call, int videoState) {
1306        if (!mCalls.contains(call)) {
1307            Log.i(this, "Request to answer a non-existent call %s", call);
1308        } else {
1309            Call foregroundCall = getForegroundCall();
1310            // If the foreground call is not the ringing call and it is currently isActive() or
1311            // STATE_DIALING, put it on hold before answering the call.
1312            if (foregroundCall != null && foregroundCall != call &&
1313                    (foregroundCall.isActive() ||
1314                     foregroundCall.getState() == CallState.DIALING ||
1315                     foregroundCall.getState() == CallState.PULLING)) {
1316                if (!foregroundCall.getTargetPhoneAccount().equals(
1317                                call.getTargetPhoneAccount()) &&
1318                        ((call.isSelfManaged() != foregroundCall.isSelfManaged()) ||
1319                         call.isSelfManaged())) {
1320                    // The foreground call is from another connection service, and either:
1321                    // 1. FG call's managed state doesn't match that of the incoming call.
1322                    //    E.g. Incoming is self-managed and FG is managed, or incoming is managed
1323                    //    and foreground is self-managed.
1324                    // 2. The incoming call is self-managed.
1325                    //    E.g. The incoming call is
1326                    Log.i(this, "Answering call from %s CS; disconnecting calls from %s CS.",
1327                            foregroundCall.isSelfManaged() ? "selfMg" : "mg",
1328                            call.isSelfManaged() ? "selfMg" : "mg");
1329                    disconnectOtherCalls(call.getTargetPhoneAccount());
1330                } else if (0 == (foregroundCall.getConnectionCapabilities()
1331                        & Connection.CAPABILITY_HOLD)) {
1332                    // This call does not support hold.  If it is from a different connection
1333                    // service, then disconnect it, otherwise allow the connection service to
1334                    // figure out the right states.
1335                    if (foregroundCall.getConnectionService() != call.getConnectionService()) {
1336                        foregroundCall.disconnect();
1337                    }
1338                } else {
1339                    Call heldCall = getHeldCall();
1340                    if (heldCall != null) {
1341                        Log.i(this, "Disconnecting held call %s before holding active call.",
1342                                heldCall);
1343                        heldCall.disconnect();
1344                    }
1345
1346                    foregroundCall.hold();
1347                }
1348                // TODO: Wait until we get confirmation of the active call being
1349                // on-hold before answering the new call.
1350                // TODO: Import logic from CallManager.acceptCall()
1351            }
1352
1353            for (CallsManagerListener listener : mListeners) {
1354                listener.onIncomingCallAnswered(call);
1355            }
1356
1357            // We do not update the UI until we get confirmation of the answer() through
1358            // {@link #markCallAsActive}.
1359            call.answer(videoState);
1360            if (isSpeakerphoneAutoEnabledForVideoCalls(videoState)) {
1361                call.setStartWithSpeakerphoneOn(true);
1362            }
1363        }
1364    }
1365
1366    /**
1367     * Determines if the speakerphone should be automatically enabled for the call.  Speakerphone
1368     * should be enabled if the call is a video call and bluetooth or the wired headset are not in
1369     * use.
1370     *
1371     * @param videoState The video state of the call.
1372     * @return {@code true} if the speakerphone should be enabled.
1373     */
1374    public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) {
1375        return VideoProfile.isVideo(videoState) &&
1376            !mWiredHeadsetManager.isPluggedIn() &&
1377            !mBluetoothRouteManager.isBluetoothAvailable() &&
1378            isSpeakerEnabledForVideoCalls();
1379    }
1380
1381    /**
1382     * Determines if the speakerphone should be enabled for when docked.  Speakerphone
1383     * should be enabled if the device is docked and bluetooth or the wired headset are
1384     * not in use.
1385     *
1386     * @return {@code true} if the speakerphone should be enabled for the dock.
1387     */
1388    private boolean isSpeakerphoneEnabledForDock() {
1389        return mDockManager.isDocked() &&
1390            !mWiredHeadsetManager.isPluggedIn() &&
1391            !mBluetoothRouteManager.isBluetoothAvailable();
1392    }
1393
1394    /**
1395     * Determines if the speakerphone should be automatically enabled for video calls.
1396     *
1397     * @return {@code true} if the speakerphone should automatically be enabled.
1398     */
1399    private static boolean isSpeakerEnabledForVideoCalls() {
1400        return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT,
1401                PhoneConstants.AUDIO_OUTPUT_DEFAULT) ==
1402                PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER);
1403    }
1404
1405    /**
1406     * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call
1407     * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
1408     * the user opting to reject said call.
1409     */
1410    @VisibleForTesting
1411    public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) {
1412        if (!mCalls.contains(call)) {
1413            Log.i(this, "Request to reject a non-existent call %s", call);
1414        } else {
1415            for (CallsManagerListener listener : mListeners) {
1416                listener.onIncomingCallRejected(call, rejectWithMessage, textMessage);
1417            }
1418            call.reject(rejectWithMessage, textMessage);
1419        }
1420    }
1421
1422    /**
1423     * Instructs Telecom to play the specified DTMF tone within the specified call.
1424     *
1425     * @param digit The DTMF digit to play.
1426     */
1427    @VisibleForTesting
1428    public void playDtmfTone(Call call, char digit) {
1429        if (!mCalls.contains(call)) {
1430            Log.i(this, "Request to play DTMF in a non-existent call %s", call);
1431        } else {
1432            call.playDtmfTone(digit);
1433            mDtmfLocalTonePlayer.playTone(call, digit);
1434        }
1435    }
1436
1437    /**
1438     * Instructs Telecom to stop the currently playing DTMF tone, if any.
1439     */
1440    @VisibleForTesting
1441    public void stopDtmfTone(Call call) {
1442        if (!mCalls.contains(call)) {
1443            Log.i(this, "Request to stop DTMF in a non-existent call %s", call);
1444        } else {
1445            call.stopDtmfTone();
1446            mDtmfLocalTonePlayer.stopTone(call);
1447        }
1448    }
1449
1450    /**
1451     * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any.
1452     */
1453    void postDialContinue(Call call, boolean proceed) {
1454        if (!mCalls.contains(call)) {
1455            Log.i(this, "Request to continue post-dial string in a non-existent call %s", call);
1456        } else {
1457            call.postDialContinue(proceed);
1458        }
1459    }
1460
1461    /**
1462     * Instructs Telecom to disconnect the specified call. Intended to be invoked by the
1463     * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1464     * the user hitting the end-call button.
1465     */
1466    @VisibleForTesting
1467    public void disconnectCall(Call call) {
1468        Log.v(this, "disconnectCall %s", call);
1469
1470        if (!mCalls.contains(call)) {
1471            Log.w(this, "Unknown call (%s) asked to disconnect", call);
1472        } else {
1473            mLocallyDisconnectingCalls.add(call);
1474            call.disconnect();
1475        }
1476    }
1477
1478    /**
1479     * Instructs Telecom to disconnect all calls.
1480     */
1481    void disconnectAllCalls() {
1482        Log.v(this, "disconnectAllCalls");
1483
1484        for (Call call : mCalls) {
1485            disconnectCall(call);
1486        }
1487    }
1488
1489    /**
1490     * Disconnects calls for any other {@link PhoneAccountHandle} but the one specified.
1491     * Note: As a protective measure, will NEVER disconnect an emergency call.  Although that
1492     * situation should never arise, its a good safeguard.
1493     * @param phoneAccountHandle Calls owned by {@link PhoneAccountHandle}s other than this one will
1494     *                          be disconnected.
1495     */
1496    private void disconnectOtherCalls(PhoneAccountHandle phoneAccountHandle) {
1497        mCalls.stream()
1498                .filter(c -> !c.isEmergencyCall() &&
1499                        !c.getTargetPhoneAccount().equals(phoneAccountHandle))
1500                .forEach(c -> disconnectCall(c));
1501    }
1502
1503    /**
1504     * Instructs Telecom to put the specified call on hold. Intended to be invoked by the
1505     * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1506     * the user hitting the hold button during an active call.
1507     */
1508    @VisibleForTesting
1509    public void holdCall(Call call) {
1510        if (!mCalls.contains(call)) {
1511            Log.w(this, "Unknown call (%s) asked to be put on hold", call);
1512        } else {
1513            Log.d(this, "Putting call on hold: (%s)", call);
1514            call.hold();
1515        }
1516    }
1517
1518    /**
1519     * Instructs Telecom to release the specified call from hold. Intended to be invoked by
1520     * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered
1521     * by the user hitting the hold button during a held call.
1522     */
1523    @VisibleForTesting
1524    public void unholdCall(Call call) {
1525        if (!mCalls.contains(call)) {
1526            Log.w(this, "Unknown call (%s) asked to be removed from hold", call);
1527        } else {
1528            boolean otherCallHeld = false;
1529            Log.d(this, "unholding call: (%s)", call);
1530            for (Call c : mCalls) {
1531                // Only attempt to hold parent calls and not the individual children.
1532                if (c != null && c.isAlive() && c != call && c.getParentCall() == null) {
1533                    otherCallHeld = true;
1534                    Log.addEvent(c, LogUtils.Events.SWAP);
1535                    c.hold();
1536                }
1537            }
1538            if (otherCallHeld) {
1539                Log.addEvent(call, LogUtils.Events.SWAP);
1540            }
1541            call.unhold();
1542        }
1543    }
1544
1545    @Override
1546    public void onExtrasChanged(Call c, int source, Bundle extras) {
1547        if (source != Call.SOURCE_CONNECTION_SERVICE) {
1548            return;
1549        }
1550        handleCallTechnologyChange(c);
1551        handleChildAddressChange(c);
1552        updateCanAddCall();
1553    }
1554
1555    // Construct the list of possible PhoneAccounts that the outgoing call can use based on the
1556    // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount,
1557    // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP.
1558    private List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user) {
1559        if (handle == null) {
1560            return Collections.emptyList();
1561        }
1562        List<PhoneAccountHandle> allAccounts =
1563                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user);
1564        // First check the Radio SIM Technology
1565        if(mRadioSimVariants == null) {
1566            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
1567                    Context.TELEPHONY_SERVICE);
1568            // Cache Sim Variants
1569            mRadioSimVariants = tm.getMultiSimConfiguration();
1570        }
1571        // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount
1572        // Should be available if a call is already active on the SIM account.
1573        if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) {
1574            List<PhoneAccountHandle> simAccounts =
1575                    mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser();
1576            PhoneAccountHandle ongoingCallAccount = null;
1577            for (Call c : mCalls) {
1578                if (!c.isDisconnected() && !c.isNew() && simAccounts.contains(
1579                        c.getTargetPhoneAccount())) {
1580                    ongoingCallAccount = c.getTargetPhoneAccount();
1581                    break;
1582                }
1583            }
1584            if (ongoingCallAccount != null) {
1585                // Remove all SIM accounts that are not the active SIM from the list.
1586                simAccounts.remove(ongoingCallAccount);
1587                allAccounts.removeAll(simAccounts);
1588            }
1589        }
1590        return allAccounts;
1591    }
1592
1593    /**
1594     * Informs listeners (notably {@link CallAudioManager} of a change to the call's external
1595     * property.
1596     * .
1597     * @param call The call whose external property changed.
1598     * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise.
1599     */
1600    @Override
1601    public void onExternalCallChanged(Call call, boolean isExternalCall) {
1602        Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall);
1603        for (CallsManagerListener listener : mListeners) {
1604            listener.onExternalCallChanged(call, isExternalCall);
1605        }
1606    }
1607
1608    private void handleCallTechnologyChange(Call call) {
1609        if (call.getExtras() != null
1610                && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) {
1611
1612            Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get(
1613                    call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE));
1614            if (analyticsCallTechnology == null) {
1615                analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE;
1616            }
1617            call.getAnalytics().addCallTechnology(analyticsCallTechnology);
1618        }
1619    }
1620
1621    public void handleChildAddressChange(Call call) {
1622        if (call.getExtras() != null
1623                && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
1624
1625            String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS);
1626            call.setViaNumber(viaNumber);
1627        }
1628    }
1629
1630    /** Called by the in-call UI to change the mute state. */
1631    void mute(boolean shouldMute) {
1632        mCallAudioManager.mute(shouldMute);
1633    }
1634
1635    /**
1636      * Called by the in-call UI to change the audio route, for example to change from earpiece to
1637      * speaker phone.
1638      */
1639    void setAudioRoute(int route) {
1640        mCallAudioManager.setAudioRoute(route);
1641    }
1642
1643    /** Called by the in-call UI to turn the proximity sensor on. */
1644    void turnOnProximitySensor() {
1645        mProximitySensorManager.turnOn();
1646    }
1647
1648    /**
1649     * Called by the in-call UI to turn the proximity sensor off.
1650     * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise,
1651     *        the screen will be kept off until the proximity sensor goes negative.
1652     */
1653    void turnOffProximitySensor(boolean screenOnImmediately) {
1654        mProximitySensorManager.turnOff(screenOnImmediately);
1655    }
1656
1657    void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
1658        if (!mCalls.contains(call)) {
1659            Log.i(this, "Attempted to add account to unknown call %s", call);
1660        } else {
1661            call.setTargetPhoneAccount(account);
1662            PhoneAccount realPhoneAccount =
1663                    mPhoneAccountRegistrar.getPhoneAccountUnchecked(account);
1664            if (realPhoneAccount != null && realPhoneAccount.getExtras() != null
1665                    && realPhoneAccount.getExtras()
1666                    .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
1667                Log.d("phoneAccountSelected: default to voip mode for call %s", call.getId());
1668                call.setIsVoipAudioMode(true);
1669            }
1670            if (call.getIntentExtras()
1671                    .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
1672                if (realPhoneAccount != null
1673                        && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1674                    call.setRttStreams(true);
1675                }
1676            }
1677
1678            if (!call.isNewOutgoingCallIntentBroadcastDone()) {
1679                return;
1680            }
1681
1682            // Note: emergency calls never go through account selection dialog so they never
1683            // arrive here.
1684            if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) {
1685                call.startCreateConnection(mPhoneAccountRegistrar);
1686            } else {
1687                call.disconnect();
1688            }
1689
1690            if (setDefault) {
1691                mPhoneAccountRegistrar
1692                        .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser());
1693            }
1694        }
1695    }
1696
1697    /** Called when the audio state changes. */
1698    @VisibleForTesting
1699    public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState
1700            newAudioState) {
1701        Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState);
1702        for (CallsManagerListener listener : mListeners) {
1703            listener.onCallAudioStateChanged(oldAudioState, newAudioState);
1704        }
1705    }
1706
1707    void markCallAsRinging(Call call) {
1708        setCallState(call, CallState.RINGING, "ringing set explicitly");
1709    }
1710
1711    void markCallAsDialing(Call call) {
1712        setCallState(call, CallState.DIALING, "dialing set explicitly");
1713        maybeMoveToSpeakerPhone(call);
1714    }
1715
1716    void markCallAsPulling(Call call) {
1717        setCallState(call, CallState.PULLING, "pulling set explicitly");
1718        maybeMoveToSpeakerPhone(call);
1719    }
1720
1721    void markCallAsActive(Call call) {
1722        setCallState(call, CallState.ACTIVE, "active set explicitly");
1723        maybeMoveToSpeakerPhone(call);
1724    }
1725
1726    void markCallAsOnHold(Call call) {
1727        setCallState(call, CallState.ON_HOLD, "on-hold set explicitly");
1728    }
1729
1730    /**
1731     * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the
1732     * last live call, then also disconnect from the in-call controller.
1733     *
1734     * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
1735     */
1736    void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
1737        call.setDisconnectCause(disconnectCause);
1738        setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
1739    }
1740
1741    /**
1742     * Removes an existing disconnected call, and notifies the in-call app.
1743     */
1744    void markCallAsRemoved(Call call) {
1745        call.markHandoverFailed();
1746
1747        removeCall(call);
1748        Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
1749        if (mLocallyDisconnectingCalls.contains(call)) {
1750            boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
1751            Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = "
1752                + isDisconnectingChildCall + "call -> %s", call);
1753            mLocallyDisconnectingCalls.remove(call);
1754            // Auto-unhold the foreground call due to a locally disconnected call, except if the
1755            // call which was disconnected is a member of a conference (don't want to auto un-hold
1756            // the conference if we remove a member of the conference).
1757            if (!isDisconnectingChildCall && foregroundCall != null
1758                    && foregroundCall.getState() == CallState.ON_HOLD) {
1759                foregroundCall.unhold();
1760            }
1761        } else if (foregroundCall != null &&
1762                !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD)  &&
1763                foregroundCall.getState() == CallState.ON_HOLD) {
1764
1765            // The new foreground call is on hold, however the carrier does not display the hold
1766            // button in the UI.  Therefore, we need to auto unhold the held call since the user has
1767            // no means of unholding it themselves.
1768            Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)");
1769            foregroundCall.unhold();
1770        }
1771    }
1772
1773    /**
1774     * Given a call, marks the call as disconnected and removes it.  Set the error message to
1775     * indicate to the user that the call cannot me placed due to an ongoing call in another app.
1776     *
1777     * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed
1778     * call.  Called by {@link #startCallConfirmation(Call)} when the user is already confirming an
1779     * outgoing call.  Realistically this should almost never be called since in practice the user
1780     * won't make multiple outgoing calls at the same time.
1781     *
1782     * @param call The call to mark as disconnected.
1783     */
1784    void markCallDisconnectedDueToSelfManagedCall(Call call) {
1785        Call activeCall = getActiveCall();
1786        CharSequence errorMessage;
1787        if (activeCall == null) {
1788            // Realistically this shouldn't happen, but best to handle gracefully
1789            errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call);
1790        } else {
1791            errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call,
1792                    activeCall.getTargetPhoneAccountLabel());
1793        }
1794        // Call is managed and there are ongoing self-managed calls.
1795        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
1796                errorMessage, errorMessage, "Ongoing call in another app."));
1797        markCallAsRemoved(call);
1798    }
1799
1800    /**
1801     * Cleans up any calls currently associated with the specified connection service when the
1802     * service binder disconnects unexpectedly.
1803     *
1804     * @param service The connection service that disconnected.
1805     */
1806    void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
1807        if (service != null) {
1808            for (Call call : mCalls) {
1809                if (call.getConnectionService() == service) {
1810                    if (call.getState() != CallState.DISCONNECTED) {
1811                        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR));
1812                    }
1813                    markCallAsRemoved(call);
1814                }
1815            }
1816        }
1817    }
1818
1819    /**
1820     * Determines if the {@link CallsManager} has any non-external calls.
1821     *
1822     * @return {@code True} if there are any non-external calls, {@code false} otherwise.
1823     */
1824    boolean hasAnyCalls() {
1825        if (mCalls.isEmpty()) {
1826            return false;
1827        }
1828
1829        for (Call call : mCalls) {
1830            if (!call.isExternalCall()) {
1831                return true;
1832            }
1833        }
1834        return false;
1835    }
1836
1837    boolean hasActiveOrHoldingCall() {
1838        return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null;
1839    }
1840
1841    boolean hasRingingCall() {
1842        return getFirstCallWithState(CallState.RINGING) != null;
1843    }
1844
1845    boolean onMediaButton(int type) {
1846        if (hasAnyCalls()) {
1847            Call ringingCall = getFirstCallWithState(CallState.RINGING);
1848            if (HeadsetMediaButton.SHORT_PRESS == type) {
1849                if (ringingCall == null) {
1850                    Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING,
1851                            CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD);
1852                    Log.addEvent(callToHangup, LogUtils.Events.INFO,
1853                            "media btn short press - end call.");
1854                    if (callToHangup != null) {
1855                        callToHangup.disconnect();
1856                        return true;
1857                    }
1858                } else {
1859                    ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
1860                    return true;
1861                }
1862            } else if (HeadsetMediaButton.LONG_PRESS == type) {
1863                if (ringingCall != null) {
1864                    Log.addEvent(getForegroundCall(),
1865                            LogUtils.Events.INFO, "media btn long press - reject");
1866                    ringingCall.reject(false, null);
1867                } else {
1868                    Log.addEvent(getForegroundCall(), LogUtils.Events.INFO,
1869                            "media btn long press - mute");
1870                    mCallAudioManager.toggleMute();
1871                }
1872                return true;
1873            }
1874        }
1875        return false;
1876    }
1877
1878    /**
1879     * Returns true if telecom supports adding another top-level call.
1880     */
1881    @VisibleForTesting
1882    public boolean canAddCall() {
1883        boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
1884                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
1885        if (!isDeviceProvisioned) {
1886            Log.d(TAG, "Device not provisioned, canAddCall is false.");
1887            return false;
1888        }
1889
1890        if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) {
1891            return false;
1892        }
1893
1894        int count = 0;
1895        for (Call call : mCalls) {
1896            if (call.isEmergencyCall()) {
1897                // We never support add call if one of the calls is an emergency call.
1898                return false;
1899            } else if (call.isExternalCall()) {
1900                // External calls don't count.
1901                continue;
1902            } else if (call.getParentCall() == null) {
1903                count++;
1904            }
1905            Bundle extras = call.getExtras();
1906            if (extras != null) {
1907                if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) {
1908                    return false;
1909                }
1910            }
1911
1912            // We do not check states for canAddCall. We treat disconnected calls the same
1913            // and wait until they are removed instead. If we didn't count disconnected calls,
1914            // we could put InCallServices into a state where they are showing two calls but
1915            // also support add-call. Technically it's right, but overall looks better (UI-wise)
1916            // and acts better if we wait until the call is removed.
1917            if (count >= MAXIMUM_TOP_LEVEL_CALLS) {
1918                return false;
1919            }
1920        }
1921
1922        return true;
1923    }
1924
1925    @VisibleForTesting
1926    public Call getRingingCall() {
1927        return getFirstCallWithState(CallState.RINGING);
1928    }
1929
1930    public Call getActiveCall() {
1931        return getFirstCallWithState(CallState.ACTIVE);
1932    }
1933
1934    Call getDialingCall() {
1935        return getFirstCallWithState(CallState.DIALING);
1936    }
1937
1938    @VisibleForTesting
1939    public Call getHeldCall() {
1940        return getFirstCallWithState(CallState.ON_HOLD);
1941    }
1942
1943    @VisibleForTesting
1944    public int getNumHeldCalls() {
1945        int count = 0;
1946        for (Call call : mCalls) {
1947            if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) {
1948                count++;
1949            }
1950        }
1951        return count;
1952    }
1953
1954    @VisibleForTesting
1955    public Call getOutgoingCall() {
1956        return getFirstCallWithState(OUTGOING_CALL_STATES);
1957    }
1958
1959    @VisibleForTesting
1960    public Call getFirstCallWithState(int... states) {
1961        return getFirstCallWithState(null, states);
1962    }
1963
1964    @VisibleForTesting
1965    public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() {
1966        return mPhoneNumberUtilsAdapter;
1967    }
1968
1969    /**
1970     * Returns the first call that it finds with the given states. The states are treated as having
1971     * priority order so that any call with the first state will be returned before any call with
1972     * states listed later in the parameter list.
1973     *
1974     * @param callToSkip Call that this method should skip while searching
1975     */
1976    Call getFirstCallWithState(Call callToSkip, int... states) {
1977        for (int currentState : states) {
1978            // check the foreground first
1979            Call foregroundCall = getForegroundCall();
1980            if (foregroundCall != null && foregroundCall.getState() == currentState) {
1981                return foregroundCall;
1982            }
1983
1984            for (Call call : mCalls) {
1985                if (Objects.equals(callToSkip, call)) {
1986                    continue;
1987                }
1988
1989                // Only operate on top-level calls
1990                if (call.getParentCall() != null) {
1991                    continue;
1992                }
1993
1994                if (call.isExternalCall()) {
1995                    continue;
1996                }
1997
1998                if (currentState == call.getState()) {
1999                    return call;
2000                }
2001            }
2002        }
2003        return null;
2004    }
2005
2006    Call createConferenceCall(
2007            String callId,
2008            PhoneAccountHandle phoneAccount,
2009            ParcelableConference parcelableConference) {
2010
2011        // If the parceled conference specifies a connect time, use it; otherwise default to 0,
2012        // which is the default value for new Calls.
2013        long connectTime =
2014                parcelableConference.getConnectTimeMillis() ==
2015                        Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
2016                        parcelableConference.getConnectTimeMillis();
2017
2018        Call call = new Call(
2019                callId,
2020                mContext,
2021                this,
2022                mLock,
2023                mConnectionServiceRepository,
2024                mContactsAsyncHelper,
2025                mCallerInfoAsyncQueryFactory,
2026                mPhoneNumberUtilsAdapter,
2027                null /* handle */,
2028                null /* gatewayInfo */,
2029                null /* connectionManagerPhoneAccount */,
2030                phoneAccount,
2031                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
2032                false /* forceAttachToExistingConnection */,
2033                true /* isConference */,
2034                connectTime);
2035
2036        setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
2037                "new conference call");
2038        call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities());
2039        call.setConnectionProperties(parcelableConference.getConnectionProperties());
2040        call.setVideoState(parcelableConference.getVideoState());
2041        call.setVideoProvider(parcelableConference.getVideoProvider());
2042        call.setStatusHints(parcelableConference.getStatusHints());
2043        call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
2044        // In case this Conference was added via a ConnectionManager, keep track of the original
2045        // Connection ID as created by the originating ConnectionService.
2046        Bundle extras = parcelableConference.getExtras();
2047        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
2048            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
2049        }
2050
2051        // TODO: Move this to be a part of addCall()
2052        call.addListener(this);
2053        addCall(call);
2054        return call;
2055    }
2056
2057    /**
2058     * @return the call state currently tracked by {@link PhoneStateBroadcaster}
2059     */
2060    int getCallState() {
2061        return mPhoneStateBroadcaster.getCallState();
2062    }
2063
2064    /**
2065     * Retrieves the {@link PhoneAccountRegistrar}.
2066     *
2067     * @return The {@link PhoneAccountRegistrar}.
2068     */
2069    PhoneAccountRegistrar getPhoneAccountRegistrar() {
2070        return mPhoneAccountRegistrar;
2071    }
2072
2073    /**
2074     * Retrieves the {@link MissedCallNotifier}
2075     * @return The {@link MissedCallNotifier}.
2076     */
2077    MissedCallNotifier getMissedCallNotifier() {
2078        return mMissedCallNotifier;
2079    }
2080
2081    /**
2082     * Retrieves the {@link IncomingCallNotifier}.
2083     * @return The {@link IncomingCallNotifier}.
2084     */
2085    IncomingCallNotifier getIncomingCallNotifier() {
2086        return mIncomingCallNotifier;
2087    }
2088
2089    /**
2090     * Reject an incoming call and manually add it to the Call Log.
2091     * @param incomingCall Incoming call that has been rejected
2092     */
2093    private void rejectCallAndLog(Call incomingCall) {
2094        if (incomingCall.getConnectionService() != null) {
2095            // Only reject the call if it has not already been destroyed.  If a call ends while
2096            // incoming call filtering is taking place, it is possible that the call has already
2097            // been destroyed, and as such it will be impossible to send the reject to the
2098            // associated ConnectionService.
2099            incomingCall.reject(false, null);
2100        } else {
2101            Log.i(this, "rejectCallAndLog - call already destroyed.");
2102        }
2103
2104        // Since the call was not added to the list of calls, we have to call the missed
2105        // call notifier and the call logger manually.
2106        // Do we need missed call notification for direct to Voicemail calls?
2107        mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
2108                true /*showNotificationForMissedCall*/);
2109    }
2110
2111    /**
2112     * Adds the specified call to the main list of live calls.
2113     *
2114     * @param call The call to add.
2115     */
2116    private void addCall(Call call) {
2117        Trace.beginSection("addCall");
2118        Log.v(this, "addCall(%s)", call);
2119        call.addListener(this);
2120        mCalls.add(call);
2121
2122        // Specifies the time telecom finished routing the call. This is used by the dialer for
2123        // analytics.
2124        Bundle extras = call.getIntentExtras();
2125        extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
2126                SystemClock.elapsedRealtime());
2127
2128        updateCanAddCall();
2129        // onCallAdded for calls which immediately take the foreground (like the first call).
2130        for (CallsManagerListener listener : mListeners) {
2131            if (LogUtils.SYSTRACE_DEBUG) {
2132                Trace.beginSection(listener.getClass().toString() + " addCall");
2133            }
2134            listener.onCallAdded(call);
2135            if (LogUtils.SYSTRACE_DEBUG) {
2136                Trace.endSection();
2137            }
2138        }
2139        Trace.endSection();
2140    }
2141
2142    private void removeCall(Call call) {
2143        Trace.beginSection("removeCall");
2144        Log.v(this, "removeCall(%s)", call);
2145
2146        call.setParentAndChildCall(null);  // clean up parent relationship before destroying.
2147        call.removeListener(this);
2148        call.clearConnectionService();
2149        // TODO: clean up RTT pipes
2150
2151        boolean shouldNotify = false;
2152        if (mCalls.contains(call)) {
2153            mCalls.remove(call);
2154            shouldNotify = true;
2155        }
2156
2157        call.destroy();
2158
2159        // Only broadcast changes for calls that are being tracked.
2160        if (shouldNotify) {
2161            updateCanAddCall();
2162            for (CallsManagerListener listener : mListeners) {
2163                if (LogUtils.SYSTRACE_DEBUG) {
2164                    Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
2165                }
2166                listener.onCallRemoved(call);
2167                if (LogUtils.SYSTRACE_DEBUG) {
2168                    Trace.endSection();
2169                }
2170            }
2171        }
2172        Trace.endSection();
2173    }
2174
2175    /**
2176     * Sets the specified state on the specified call.
2177     *
2178     * @param call The call.
2179     * @param newState The new state of the call.
2180     */
2181    private void setCallState(Call call, int newState, String tag) {
2182        if (call == null) {
2183            return;
2184        }
2185        int oldState = call.getState();
2186        Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
2187                CallState.toString(newState), call);
2188        if (newState != oldState) {
2189            // Unfortunately, in the telephony world the radio is king. So if the call notifies
2190            // us that the call is in a particular state, we allow it even if it doesn't make
2191            // sense (e.g., STATE_ACTIVE -> STATE_RINGING).
2192            // TODO: Consider putting a stop to the above and turning CallState
2193            // into a well-defined state machine.
2194            // TODO: Define expected state transitions here, and log when an
2195            // unexpected transition occurs.
2196            call.setState(newState, tag);
2197            maybeShowErrorDialogOnDisconnect(call);
2198
2199            Trace.beginSection("onCallStateChanged");
2200
2201            // If this call became active because it is being handed over from another Call, the
2202            // call which was being handed over from can be disconnected at this point.
2203            if (call.getHandoverFromCall() != null) {
2204                if (newState == CallState.ACTIVE) {
2205                    Call handoverFrom = call.getHandoverFromCall();
2206                    Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2207                            handoverFrom.getId(), call.getId());
2208                    Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2209                            handoverFrom.getId(), call.getId());
2210                    handoverFrom.onConnectionEvent(
2211                            android.telecom.Connection.EVENT_HANDOVER_COMPLETE, null);
2212                    markCallAsDisconnected(handoverFrom,
2213                            new DisconnectCause(DisconnectCause.LOCAL));
2214                    call.markHandoverSuccess();
2215                    markCallAsRemoved(handoverFrom);
2216                    call.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
2217                } else if (newState == CallState.DISCONNECTED) {
2218                    Call handoverFrom = call.getHandoverFromCall();
2219                    Log.i(this, "Call %s failed to handover from %s.",
2220                            call.getId(), handoverFrom.getId());
2221                    Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s",
2222                            call.getId(), handoverFrom.getId());
2223                    // Inform the "from" Call (ie the source call) that the handover from it has
2224                    // failed; this allows the InCallService to be notified that a handover it
2225                    // initiated failed.
2226                    handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null);
2227                    // Inform the "to" ConnectionService that handover to it has failed.  This
2228                    // allows the ConnectionService the call was being handed over
2229                    if (call.getConnectionService() != null) {
2230                        // Only attempt if the call has a bound ConnectionService if handover failed
2231                        // early on in the handover process, the CS will be unbound and we won't be
2232                        // able to send the call event.
2233                        call.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null);
2234                    }
2235                    call.markHandoverFailed();
2236                }
2237            // If this call was disconnected because it was handed over TO another call, report the
2238            // handover as complete.
2239            } else if (call.getHandoverToCall() != null && newState == CallState.DISCONNECTED) {
2240                Call handoverTo = call.getHandoverToCall();
2241                Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2242                        call.getId(), handoverTo.getId());
2243                Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2244                        call.getId(), handoverTo.getId());
2245
2246                // Inform the "from" Call (ie the source call) that the handover from it has
2247                // completed; this allows the InCallService to be notified that a handover it
2248                // initiated completed.
2249                call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null);
2250                // Inform the "to" ConnectionService that handover to it has completed.
2251                handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
2252                answerCall(handoverTo, handoverTo.getVideoState());
2253                call.markHandoverSuccess();
2254            }
2255
2256            // Only broadcast state change for calls that are being tracked.
2257            if (mCalls.contains(call)) {
2258                updateCanAddCall();
2259                for (CallsManagerListener listener : mListeners) {
2260                    if (LogUtils.SYSTRACE_DEBUG) {
2261                        Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
2262                    }
2263                    listener.onCallStateChanged(call, oldState, newState);
2264                    if (LogUtils.SYSTRACE_DEBUG) {
2265                        Trace.endSection();
2266                    }
2267                }
2268            }
2269            Trace.endSection();
2270        }
2271    }
2272
2273    private void updateCanAddCall() {
2274        boolean newCanAddCall = canAddCall();
2275        if (newCanAddCall != mCanAddCall) {
2276            mCanAddCall = newCanAddCall;
2277            for (CallsManagerListener listener : mListeners) {
2278                if (LogUtils.SYSTRACE_DEBUG) {
2279                    Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
2280                }
2281                listener.onCanAddCallChanged(mCanAddCall);
2282                if (LogUtils.SYSTRACE_DEBUG) {
2283                    Trace.endSection();
2284                }
2285            }
2286        }
2287    }
2288
2289    private boolean isPotentialMMICode(Uri handle) {
2290        return (handle != null && handle.getSchemeSpecificPart() != null
2291                && handle.getSchemeSpecificPart().contains("#"));
2292    }
2293
2294    /**
2295     * Determines if a dialed number is potentially an In-Call MMI code.  In-Call MMI codes are
2296     * MMI codes which can be dialed when one or more calls are in progress.
2297     * <P>
2298     * Checks for numbers formatted similar to the MMI codes defined in:
2299     * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)}
2300     *
2301     * @param handle The URI to call.
2302     * @return {@code True} if the URI represents a number which could be an in-call MMI code.
2303     */
2304    private boolean isPotentialInCallMMICode(Uri handle) {
2305        if (handle != null && handle.getSchemeSpecificPart() != null &&
2306                handle.getScheme() != null &&
2307                handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) {
2308
2309            String dialedNumber = handle.getSchemeSpecificPart();
2310            return (dialedNumber.equals("0") ||
2311                    (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) ||
2312                    (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) ||
2313                    dialedNumber.equals("3") ||
2314                    dialedNumber.equals("4") ||
2315                    dialedNumber.equals("5"));
2316        }
2317        return false;
2318    }
2319
2320    @VisibleForTesting
2321    public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
2322                                    PhoneAccountHandle phoneAccountHandle, int... states) {
2323        return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED,
2324                excludeCall, phoneAccountHandle, states);
2325    }
2326
2327    /**
2328     * Determines the number of calls matching the specified criteria.
2329     * @param callFilter indicates whether to include just managed calls
2330     *                   ({@link #CALL_FILTER_MANAGED}), self-managed calls
2331     *                   ({@link #CALL_FILTER_SELF_MANAGED}), or all calls
2332     *                   ({@link #CALL_FILTER_ALL}).
2333     * @param excludeCall Where {@code non-null}, this call is excluded from the count.
2334     * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle}
2335     *                           are excluded from the count.
2336     * @param states The list of {@link CallState}s to include in the count.
2337     * @return Count of calls matching criteria.
2338     */
2339    @VisibleForTesting
2340    public int getNumCallsWithState(final int callFilter, Call excludeCall,
2341                                    PhoneAccountHandle phoneAccountHandle, int... states) {
2342
2343        Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet());
2344
2345        Stream<Call> callsStream = mCalls.stream()
2346                .filter(call -> desiredStates.contains(call.getState()) &&
2347                        call.getParentCall() == null && !call.isExternalCall());
2348
2349        if (callFilter == CALL_FILTER_MANAGED) {
2350            callsStream = callsStream.filter(call -> !call.isSelfManaged());
2351        } else if (callFilter == CALL_FILTER_SELF_MANAGED) {
2352            callsStream = callsStream.filter(call -> call.isSelfManaged());
2353        }
2354
2355        // If a call to exclude was specified, filter it out.
2356        if (excludeCall != null) {
2357            callsStream = callsStream.filter(call -> call != excludeCall);
2358        }
2359
2360        // If a phone account handle was specified, only consider calls for that phone account.
2361        if (phoneAccountHandle != null) {
2362            callsStream = callsStream.filter(
2363                    call -> phoneAccountHandle.equals(call.getTargetPhoneAccount()));
2364        }
2365
2366        return (int) callsStream.count();
2367    }
2368
2369    private boolean hasMaximumManagedLiveCalls(Call exceptCall) {
2370        return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */,
2371                exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES);
2372    }
2373
2374    private boolean hasMaximumSelfManagedCalls(Call exceptCall,
2375                                                   PhoneAccountHandle phoneAccountHandle) {
2376        return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */,
2377                exceptCall, phoneAccountHandle, ANY_CALL_STATE);
2378    }
2379
2380    private boolean hasMaximumManagedHoldingCalls(Call exceptCall) {
2381        return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2382                null /* phoneAccountHandle */, CallState.ON_HOLD);
2383    }
2384
2385    private boolean hasMaximumManagedRingingCalls(Call exceptCall) {
2386        return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2387                null /* phoneAccountHandle */, CallState.RINGING);
2388    }
2389
2390    private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall,
2391                                                      PhoneAccountHandle phoneAccountHandle) {
2392        return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall,
2393                phoneAccountHandle, CallState.RINGING);
2394    }
2395
2396    private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) {
2397        return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2398                null /* phoneAccountHandle */, OUTGOING_CALL_STATES);
2399    }
2400
2401    private boolean hasMaximumManagedDialingCalls(Call exceptCall) {
2402        return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2403                null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING);
2404    }
2405
2406    /**
2407     * Given a {@link PhoneAccountHandle} determines if there are calls owned by any other
2408     * {@link PhoneAccountHandle}.
2409     * @param phoneAccountHandle The {@link PhoneAccountHandle} to check.
2410     * @return {@code true} if there are other calls, {@code false} otherwise.
2411     */
2412    public boolean hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2413        return getNumCallsForOtherPhoneAccount(phoneAccountHandle) > 0;
2414    }
2415
2416    /**
2417     * Determines the number of calls present for PhoneAccounts other than the one specified.
2418     * @param phoneAccountHandle The handle of the PhoneAccount.
2419     * @return Number of calls owned by other PhoneAccounts.
2420     */
2421    public int getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2422        return (int) mCalls.stream().filter(call ->
2423                !phoneAccountHandle.equals(call.getTargetPhoneAccount()) &&
2424                        call.getParentCall() == null &&
2425                        !call.isExternalCall()).count();
2426    }
2427
2428    /**
2429     * Determines if there are any managed calls.
2430     * @return {@code true} if there are managed calls, {@code false} otherwise.
2431     */
2432    public boolean hasManagedCalls() {
2433        return mCalls.stream().filter(call -> !call.isSelfManaged() &&
2434                !call.isExternalCall()).count() > 0;
2435    }
2436
2437    /**
2438     * Determines if there are any self-managed calls.
2439     * @return {@code true} if there are self-managed calls, {@code false} otherwise.
2440     */
2441    public boolean hasSelfManagedCalls() {
2442        return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0;
2443    }
2444
2445    /**
2446     * Determines if there are any ongoing managed or self-managed calls.
2447     * Note: The {@link #ONGOING_CALL_STATES} are
2448     * @return {@code true} if there are ongoing managed or self-managed calls, {@code false}
2449     *      otherwise.
2450     */
2451    public boolean hasOngoingCalls() {
2452        return getNumCallsWithState(
2453                CALL_FILTER_ALL, null /* excludeCall */,
2454                null /* phoneAccountHandle */,
2455                ONGOING_CALL_STATES) > 0;
2456    }
2457
2458    /**
2459     * Determines if there are any ongoing managed calls.
2460     * @return {@code true} if there are ongoing managed calls, {@code false} otherwise.
2461     */
2462    public boolean hasOngoingManagedCalls() {
2463        return getNumCallsWithState(
2464                CALL_FILTER_MANAGED, null /* excludeCall */,
2465                null /* phoneAccountHandle */,
2466                ONGOING_CALL_STATES) > 0;
2467    }
2468
2469    /**
2470     * Determines if the system incoming call UI should be shown.
2471     * The system incoming call UI will be shown if the new incoming call is self-managed, and there
2472     * are ongoing calls for another PhoneAccount.
2473     * @param incomingCall The incoming call.
2474     * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise.
2475     */
2476    public boolean shouldShowSystemIncomingCallUi(Call incomingCall) {
2477        return incomingCall.isIncoming() && incomingCall.isSelfManaged() &&
2478                hasCallsForOtherPhoneAccount(incomingCall.getTargetPhoneAccount()) &&
2479                incomingCall.getHandoverFromCall() == null;
2480    }
2481
2482    private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) {
2483        if (hasMaximumManagedLiveCalls(call)) {
2484            // NOTE: If the amount of live calls changes beyond 1, this logic will probably
2485            // have to change.
2486            Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
2487            Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
2488                   liveCall);
2489
2490            if (call == liveCall) {
2491                // If the call is already the foreground call, then we are golden.
2492                // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
2493                // state since the call was already populated into the list.
2494                return true;
2495            }
2496
2497            if (hasMaximumManagedOutgoingCalls(call)) {
2498                Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
2499                if (isEmergency && !outgoingCall.isEmergencyCall()) {
2500                    // Disconnect the current outgoing call if it's not an emergency call. If the
2501                    // user tries to make two outgoing calls to different emergency call numbers,
2502                    // we will try to connect the first outgoing call.
2503                    call.getAnalytics().setCallIsAdditional(true);
2504                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
2505                    outgoingCall.disconnect();
2506                    return true;
2507                }
2508                if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
2509                    // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
2510                    // state, just disconnect it since the user has explicitly started a new call.
2511                    call.getAnalytics().setCallIsAdditional(true);
2512                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
2513                    outgoingCall.disconnect();
2514                    return true;
2515                }
2516                return false;
2517            }
2518
2519            if (hasMaximumManagedHoldingCalls(call)) {
2520                // There is no more room for any more calls, unless it's an emergency.
2521                if (isEmergency) {
2522                    // Kill the current active call, this is easier then trying to disconnect a
2523                    // holding call and hold an active call.
2524                    call.getAnalytics().setCallIsAdditional(true);
2525                    liveCall.getAnalytics().setCallIsInterrupted(true);
2526                    liveCall.disconnect();
2527                    return true;
2528                }
2529                return false;  // No more room!
2530            }
2531
2532            // We have room for at least one more holding call at this point.
2533
2534            // TODO: Remove once b/23035408 has been corrected.
2535            // If the live call is a conference, it will not have a target phone account set.  This
2536            // means the check to see if the live call has the same target phone account as the new
2537            // call will not cause us to bail early.  As a result, we'll end up holding the
2538            // ongoing conference call.  However, the ConnectionService is already doing that.  This
2539            // has caused problems with some carriers.  As a workaround until b/23035408 is
2540            // corrected, we will try and get the target phone account for one of the conference's
2541            // children and use that instead.
2542            PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
2543            if (liveCallPhoneAccount == null && liveCall.isConference() &&
2544                    !liveCall.getChildCalls().isEmpty()) {
2545                liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
2546                Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
2547                        liveCallPhoneAccount);
2548            }
2549
2550            // First thing, if we are trying to make a call with the same phone account as the live
2551            // call, then allow it so that the connection service can make its own decision about
2552            // how to handle the new call relative to the current one.
2553            if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
2554                Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
2555                call.getAnalytics().setCallIsAdditional(true);
2556                liveCall.getAnalytics().setCallIsInterrupted(true);
2557                return true;
2558            } else if (call.getTargetPhoneAccount() == null) {
2559                // Without a phone account, we can't say reliably that the call will fail.
2560                // If the user chooses the same phone account as the live call, then it's
2561                // still possible that the call can be made (like with CDMA calls not supporting
2562                // hold but they still support adding a call by going immediately into conference
2563                // mode). Return true here and we'll run this code again after user chooses an
2564                // account.
2565                return true;
2566            }
2567
2568            // Try to hold the live call before attempting the new outgoing call.
2569            if (liveCall.can(Connection.CAPABILITY_HOLD)) {
2570                Log.i(this, "makeRoomForOutgoingCall: holding live call.");
2571                call.getAnalytics().setCallIsAdditional(true);
2572                liveCall.getAnalytics().setCallIsInterrupted(true);
2573                liveCall.hold();
2574                return true;
2575            }
2576
2577            // The live call cannot be held so we're out of luck here.  There's no room.
2578            return false;
2579        }
2580        return true;
2581    }
2582
2583    /**
2584     * Given a call, find the first non-null phone account handle of its children.
2585     *
2586     * @param parentCall The parent call.
2587     * @return The first non-null phone account handle of the children, or {@code null} if none.
2588     */
2589    private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
2590        for (Call childCall : parentCall.getChildCalls()) {
2591            PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
2592            if (childPhoneAccount != null) {
2593                return childPhoneAccount;
2594            }
2595        }
2596        return null;
2597    }
2598
2599    /**
2600     * Checks to see if the call should be on speakerphone and if so, set it.
2601     */
2602    private void maybeMoveToSpeakerPhone(Call call) {
2603        if (call.getStartWithSpeakerphoneOn()) {
2604            setAudioRoute(CallAudioState.ROUTE_SPEAKER);
2605            call.setStartWithSpeakerphoneOn(false);
2606        }
2607    }
2608
2609    /**
2610     * Creates a new call for an existing connection.
2611     *
2612     * @param callId The id of the new call.
2613     * @param connection The connection information.
2614     * @return The new call.
2615     */
2616    Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
2617        boolean isDowngradedConference = (connection.getConnectionProperties()
2618                & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
2619        Call call = new Call(
2620                callId,
2621                mContext,
2622                this,
2623                mLock,
2624                mConnectionServiceRepository,
2625                mContactsAsyncHelper,
2626                mCallerInfoAsyncQueryFactory,
2627                mPhoneNumberUtilsAdapter,
2628                connection.getHandle() /* handle */,
2629                null /* gatewayInfo */,
2630                null /* connectionManagerPhoneAccount */,
2631                connection.getPhoneAccount(), /* targetPhoneAccountHandle */
2632                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
2633                false /* forceAttachToExistingConnection */,
2634                isDowngradedConference /* isConference */,
2635                connection.getConnectTimeMillis() /* connectTimeMillis */);
2636
2637        call.initAnalytics();
2638        call.getAnalytics().setCreatedFromExistingConnection(true);
2639
2640        setCallState(call, Call.getStateFromConnectionState(connection.getState()),
2641                "existing connection");
2642        call.setConnectionCapabilities(connection.getConnectionCapabilities());
2643        call.setConnectionProperties(connection.getConnectionProperties());
2644        call.setCallerDisplayName(connection.getCallerDisplayName(),
2645                connection.getCallerDisplayNamePresentation());
2646        call.addListener(this);
2647
2648        // In case this connection was added via a ConnectionManager, keep track of the original
2649        // Connection ID as created by the originating ConnectionService.
2650        Bundle extras = connection.getExtras();
2651        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
2652            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
2653        }
2654        Log.i(this, "createCallForExistingConnection: %s", connection);
2655        Call parentCall = null;
2656        if (!TextUtils.isEmpty(connection.getParentCallId())) {
2657            String parentId = connection.getParentCallId();
2658            parentCall = mCalls
2659                    .stream()
2660                    .filter(c -> c.getId().equals(parentId))
2661                    .findFirst()
2662                    .orElse(null);
2663            if (parentCall != null) {
2664                Log.i(this, "createCallForExistingConnection: %s added as child of %s.",
2665                        call.getId(),
2666                        parentCall.getId());
2667                // Set JUST the parent property, which won't send an update to the Incall UI.
2668                call.setParentCall(parentCall);
2669            }
2670        }
2671        addCall(call);
2672        if (parentCall != null) {
2673            // Now, set the call as a child of the parent since it has been added to Telecom.  This
2674            // is where we will inform InCall.
2675            call.setChildOf(parentCall);
2676            call.notifyParentChanged(parentCall);
2677        }
2678
2679        return call;
2680    }
2681
2682    /**
2683     * Determines whether Telecom already knows about a Connection added via the
2684     * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
2685     * Connection)} API via a ConnectionManager.
2686     *
2687     * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}.
2688     * @param originalConnectionId The new connection ID to check.
2689     * @return {@code true} if this connection is already known by Telecom.
2690     */
2691    Call getAlreadyAddedConnection(String originalConnectionId) {
2692        Optional<Call> existingCall = mCalls.stream()
2693                .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) ||
2694                            originalConnectionId.equals(call.getId()))
2695                .findFirst();
2696
2697        if (existingCall.isPresent()) {
2698            Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s",
2699                    originalConnectionId, existingCall.get().getId());
2700            return existingCall.get();
2701        }
2702
2703        return null;
2704    }
2705
2706    /**
2707     * @return A new unique telecom call Id.
2708     */
2709    private String getNextCallId() {
2710        synchronized(mLock) {
2711            return TELECOM_CALL_ID_PREFIX + (++mCallId);
2712        }
2713    }
2714
2715    public int getNextRttRequestId() {
2716        synchronized (mLock) {
2717            return (++mRttRequestId);
2718        }
2719    }
2720
2721    /**
2722     * Callback when foreground user is switched. We will reload missed call in all profiles
2723     * including the user itself. There may be chances that profiles are not started yet.
2724     */
2725    @VisibleForTesting
2726    public void onUserSwitch(UserHandle userHandle) {
2727        mCurrentUserHandle = userHandle;
2728        mMissedCallNotifier.setCurrentUserHandle(userHandle);
2729        final UserManager userManager = UserManager.get(mContext);
2730        List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier());
2731        for (UserInfo profile : profiles) {
2732            reloadMissedCallsOfUser(profile.getUserHandle());
2733        }
2734    }
2735
2736    /**
2737     * Because there may be chances that profiles are not started yet though its parent user is
2738     * switched, we reload missed calls of profile that are just started here.
2739     */
2740    void onUserStarting(UserHandle userHandle) {
2741        if (UserUtil.isProfile(mContext, userHandle)) {
2742            reloadMissedCallsOfUser(userHandle);
2743        }
2744    }
2745
2746    public TelecomSystem.SyncRoot getLock() {
2747        return mLock;
2748    }
2749
2750    private void reloadMissedCallsOfUser(UserHandle userHandle) {
2751        mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper,
2752                new MissedCallNotifier.CallInfoFactory(), userHandle);
2753    }
2754
2755    public void onBootCompleted() {
2756        mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper,
2757                new MissedCallNotifier.CallInfoFactory());
2758    }
2759
2760    public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2761        return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2762    }
2763
2764    public boolean isIncomingCallPermitted(Call excludeCall,
2765                                           PhoneAccountHandle phoneAccountHandle) {
2766        if (phoneAccountHandle == null) {
2767            return false;
2768        }
2769        PhoneAccount phoneAccount =
2770                mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2771        if (phoneAccount == null) {
2772            return false;
2773        }
2774
2775        if (!phoneAccount.isSelfManaged()) {
2776            return !hasMaximumManagedRingingCalls(excludeCall) &&
2777                    !hasMaximumManagedHoldingCalls(excludeCall);
2778        } else {
2779            return !hasEmergencyCall() &&
2780                    !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) &&
2781                    !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle);
2782        }
2783    }
2784
2785    public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2786        return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2787    }
2788
2789    public boolean isOutgoingCallPermitted(Call excludeCall,
2790                                           PhoneAccountHandle phoneAccountHandle) {
2791        if (phoneAccountHandle == null) {
2792            return false;
2793        }
2794        PhoneAccount phoneAccount =
2795                mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2796        if (phoneAccount == null) {
2797            return false;
2798        }
2799
2800        if (!phoneAccount.isSelfManaged()) {
2801            return !hasMaximumManagedOutgoingCalls(excludeCall) &&
2802                    !hasMaximumManagedDialingCalls(excludeCall) &&
2803                    !hasMaximumManagedLiveCalls(excludeCall) &&
2804                    !hasMaximumManagedHoldingCalls(excludeCall);
2805        } else {
2806            // Only permit outgoing calls if there is no ongoing emergency calls and all other calls
2807            // are associated with the current PhoneAccountHandle.
2808            return !hasEmergencyCall() && (
2809                    excludeCall.getHandoverFromCall() != null ||
2810                            (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) &&
2811                            !hasCallsForOtherPhoneAccount(phoneAccountHandle) &&
2812                            !hasManagedCalls()));
2813        }
2814    }
2815
2816    /**
2817     * Blocks execution until all Telecom handlers have completed their current work.
2818     */
2819    public void waitOnHandlers() {
2820        CountDownLatch mainHandlerLatch = new CountDownLatch(3);
2821        mHandler.post(() -> {
2822            mainHandlerLatch.countDown();
2823        });
2824        mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> {
2825            mainHandlerLatch.countDown();
2826        });
2827        mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> {
2828            mainHandlerLatch.countDown();
2829        });
2830
2831        try {
2832            mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);
2833        } catch (InterruptedException e) {
2834            Log.w(this, "waitOnHandlers: interrupted %s", e);
2835        }
2836    }
2837
2838    /**
2839     * Used to confirm creation of an outgoing call which was marked as pending confirmation in
2840     * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
2841     * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
2842     * {@link ConfirmCallDialogActivity}.
2843     * @param callId The call ID of the call to confirm.
2844     */
2845    public void confirmPendingCall(String callId) {
2846        Log.i(this, "confirmPendingCall: callId=%s", callId);
2847        if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
2848            Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED);
2849            addCall(mPendingCall);
2850
2851            // We are going to place the new outgoing call, so disconnect any ongoing self-managed
2852            // calls which are ongoing at this time.
2853            disconnectSelfManagedCalls();
2854
2855            // Kick of the new outgoing call intent from where it left off prior to confirming the
2856            // call.
2857            CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this,
2858                    mPendingCall.getOriginalCallIntent());
2859            mPendingCall = null;
2860        }
2861    }
2862
2863    /**
2864     * Used to cancel an outgoing call which was marked as pending confirmation in
2865     * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
2866     * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
2867     * {@link ConfirmCallDialogActivity}.
2868     * @param callId The call ID of the call to cancel.
2869     */
2870    public void cancelPendingCall(String callId) {
2871        Log.i(this, "cancelPendingCall: callId=%s", callId);
2872        if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
2873            Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED);
2874            markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED));
2875            markCallAsRemoved(mPendingCall);
2876            mPendingCall = null;
2877        }
2878    }
2879
2880    /**
2881     * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when
2882     * a managed call is added while there are ongoing self-managed calls.  Starts
2883     * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the
2884     * outgoing call or not.
2885     * @param call The call to confirm.
2886     */
2887    private void startCallConfirmation(Call call) {
2888        if (mPendingCall != null) {
2889            Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s",
2890                    mPendingCall.getId(), call.getId());
2891            markCallDisconnectedDueToSelfManagedCall(call);
2892            return;
2893        }
2894        Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION);
2895        mPendingCall = call;
2896
2897        // Figure out the name of the app in charge of the self-managed call(s).
2898        Call selfManagedCall = mCalls.stream()
2899                .filter(c -> c.isSelfManaged())
2900                .findFirst()
2901                .orElse(null);
2902        CharSequence ongoingAppName = "";
2903        if (selfManagedCall != null) {
2904            ongoingAppName = selfManagedCall.getTargetPhoneAccountLabel();
2905        }
2906        Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(),
2907                ongoingAppName);
2908
2909        Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class);
2910        confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId());
2911        confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName);
2912        confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2913        mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT);
2914    }
2915
2916    /**
2917     * Disconnects all self-managed calls.
2918     */
2919    private void disconnectSelfManagedCalls() {
2920        // Disconnect all self-managed calls to make priority for emergency call.
2921        // Use Call.disconnect() to command the ConnectionService to disconnect the calls.
2922        // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to
2923        // disconnect.
2924        mCalls.stream()
2925                .filter(c -> c.isSelfManaged())
2926                .forEach(c -> c.disconnect());
2927    }
2928
2929    /**
2930     * Dumps the state of the {@link CallsManager}.
2931     *
2932     * @param pw The {@code IndentingPrintWriter} to write the state to.
2933     */
2934    public void dump(IndentingPrintWriter pw) {
2935        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
2936        if (mCalls != null) {
2937            pw.println("mCalls: ");
2938            pw.increaseIndent();
2939            for (Call call : mCalls) {
2940                pw.println(call);
2941            }
2942            pw.decreaseIndent();
2943        }
2944
2945        if (mPendingCall != null) {
2946            pw.print("mPendingCall:");
2947            pw.println(mPendingCall.getId());
2948        }
2949
2950        if (mCallAudioManager != null) {
2951            pw.println("mCallAudioManager:");
2952            pw.increaseIndent();
2953            mCallAudioManager.dump(pw);
2954            pw.decreaseIndent();
2955        }
2956
2957        if (mTtyManager != null) {
2958            pw.println("mTtyManager:");
2959            pw.increaseIndent();
2960            mTtyManager.dump(pw);
2961            pw.decreaseIndent();
2962        }
2963
2964        if (mInCallController != null) {
2965            pw.println("mInCallController:");
2966            pw.increaseIndent();
2967            mInCallController.dump(pw);
2968            pw.decreaseIndent();
2969        }
2970
2971        if (mDefaultDialerCache != null) {
2972            pw.println("mDefaultDialerCache:");
2973            pw.increaseIndent();
2974            mDefaultDialerCache.dumpCache(pw);
2975            pw.decreaseIndent();
2976        }
2977
2978        if (mConnectionServiceRepository != null) {
2979            pw.println("mConnectionServiceRepository:");
2980            pw.increaseIndent();
2981            mConnectionServiceRepository.dump(pw);
2982            pw.decreaseIndent();
2983        }
2984    }
2985
2986    /**
2987    * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code.
2988    *
2989    * @param call The call.
2990    */
2991    private void maybeShowErrorDialogOnDisconnect(Call call) {
2992        if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle())
2993                || isPotentialInCallMMICode(call.getHandle()))) {
2994            DisconnectCause disconnectCause = call.getDisconnectCause();
2995            if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode()
2996                    == DisconnectCause.ERROR)) {
2997                Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class);
2998                errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA,
2999                        disconnectCause.getDescription());
3000                errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3001                mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
3002            }
3003        }
3004    }
3005
3006    private void setIntentExtrasAndStartTime(Call call, Bundle extras) {
3007      // Create our own instance to modify (since extras may be Bundle.EMPTY)
3008      extras = new Bundle(extras);
3009
3010      // Specifies the time telecom began routing the call. This is used by the dialer for
3011      // analytics.
3012      extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
3013              SystemClock.elapsedRealtime());
3014
3015      call.setIntentExtras(extras);
3016    }
3017
3018    /**
3019     * Notifies the {@link android.telecom.ConnectionService} associated with a
3020     * {@link PhoneAccountHandle} that the attempt to create a new connection has failed.
3021     *
3022     * @param phoneAccountHandle The {@link PhoneAccountHandle}.
3023     * @param call The {@link Call} which could not be added.
3024     */
3025    private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
3026        if (phoneAccountHandle == null) {
3027            return;
3028        }
3029        ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
3030                phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle());
3031        if (service == null) {
3032            Log.i(this, "Found no connection service.");
3033            return;
3034        } else {
3035            call.setConnectionService(service);
3036            service.createConnectionFailed(call);
3037        }
3038    }
3039
3040    /**
3041     * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)}
3042     * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the
3043     * {@link android.telecom.InCallService} has requested a handover to another
3044     * {@link android.telecom.ConnectionService}.
3045     *
3046     * We will explicitly disallow a handover when there is an emergency call present.
3047     *
3048     * @param handoverFromCall The {@link Call} to be handed over.
3049     * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to.
3050     * @param videoState The desired video state of {@link Call} after handover.
3051     * @param initiatingExtras Extras associated with the handover, to be passed to the handover
3052     *               {@link android.telecom.ConnectionService}.
3053     */
3054    private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle,
3055                                 int videoState, Bundle initiatingExtras) {
3056
3057        boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported(
3058                handoverFromCall.getTargetPhoneAccount());
3059        boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle);
3060
3061        if (!isHandoverFromSupported || !isHandoverToSupported || hasEmergencyCall()) {
3062            handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null);
3063            return;
3064        }
3065
3066        Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle);
3067
3068        Bundle extras = new Bundle();
3069        extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
3070        extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
3071        if (initiatingExtras != null) {
3072            extras.putAll(initiatingExtras);
3073        }
3074        extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE,
3075                mCallAudioManager.getCallAudioState());
3076        Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle,
3077                extras, getCurrentUserHandle(), null /* originalIntent */);
3078        Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER,
3079                "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), handoverToCall.getId());
3080        handoverFromCall.setHandoverToCall(handoverToCall);
3081        handoverToCall.setHandoverFromCall(handoverFromCall);
3082        handoverToCall.setNewOutgoingCallIntentBroadcastIsDone();
3083        placeOutgoingCall(handoverToCall, handoverToCall.getHandle(), null /* gatewayInfo */,
3084                false /* startwithSpeaker */,
3085                videoState);
3086    }
3087
3088    /**
3089     * Determines if handover from the specified {@link PhoneAccountHandle} is supported.
3090     *
3091     * @param from The {@link PhoneAccountHandle} the handover originates from.
3092     * @return {@code true} if handover is currently allowed, {@code false} otherwise.
3093     */
3094    private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) {
3095        return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM);
3096    }
3097
3098    /**
3099     * Determines if handover to the specified {@link PhoneAccountHandle} is supported.
3100     *
3101     * @param to The {@link PhoneAccountHandle} the handover it to.
3102     * @return {@code true} if handover is currently allowed, {@code false} otherwise.
3103     */
3104    private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) {
3105        return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO);
3106    }
3107
3108    /**
3109     * Retrieves a boolean phone account extra.
3110     * @param handle the {@link PhoneAccountHandle} to retrieve the extra for.
3111     * @param key The extras key.
3112     * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false}
3113     *      otherwise.
3114     */
3115    private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) {
3116        PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle);
3117        if (phoneAccount == null) {
3118            return false;
3119        }
3120
3121        Bundle fromExtras = phoneAccount.getExtras();
3122        if (fromExtras == null) {
3123            return false;
3124        }
3125        return fromExtras.getBoolean(key);
3126    }
3127
3128    /**
3129     * Determines if there is an existing handover in process.
3130     * @return {@code true} if a call in the process of handover exists, {@code false} otherwise.
3131     */
3132    private boolean isHandoverInProgress() {
3133        return mCalls.stream().filter(c -> c.getHandoverFromCall() != null ||
3134                c.getHandoverToCall() != null).count() > 0;
3135    }
3136
3137    private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) {
3138        Intent intent =
3139                new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED);
3140        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
3141        intent.putExtra(
3142                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3143        Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle);
3144        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
3145                PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
3146
3147        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
3148                getCurrentUserHandle().getIdentifier());
3149        if (!TextUtils.isEmpty(dialerPackage)) {
3150            Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED)
3151                    .setPackage(dialerPackage);
3152            directedIntent.putExtra(
3153                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3154            Log.i(this, "Sending phone-account unregistered intent to default dialer");
3155            mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
3156        }
3157        return ;
3158    }
3159
3160    private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) {
3161        Intent intent = new Intent(
3162                TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED);
3163        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
3164        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
3165                accountHandle);
3166        Log.i(this, "Sending phone-account %s registered intent as user", accountHandle);
3167        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
3168                PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
3169
3170        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
3171                getCurrentUserHandle().getIdentifier());
3172        if (!TextUtils.isEmpty(dialerPackage)) {
3173            Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED)
3174                    .setPackage(dialerPackage);
3175            directedIntent.putExtra(
3176                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3177            Log.i(this, "Sending phone-account registered intent to default dialer");
3178            mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
3179        }
3180        return ;
3181    }
3182}
3183