CallsManager.java revision 6d4b66df3d918e3f17263ff40ca3ba0ec5a46719
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.ParcelableConference;
43import android.telecom.ParcelableConnection;
44import android.telecom.PhoneAccount;
45import android.telecom.PhoneAccountHandle;
46import android.telecom.TelecomManager;
47import android.telecom.VideoProfile;
48import android.telephony.PhoneNumberUtils;
49import android.telephony.TelephonyManager;
50import android.text.TextUtils;
51
52import com.android.internal.annotations.VisibleForTesting;
53import com.android.internal.telephony.AsyncEmergencyContactNotifier;
54import com.android.internal.telephony.PhoneConstants;
55import com.android.internal.telephony.TelephonyProperties;
56import com.android.internal.util.IndentingPrintWriter;
57import com.android.server.telecom.TelecomServiceImpl.DefaultDialerManagerAdapter;
58import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
59import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
60import com.android.server.telecom.callfiltering.CallFilterResultCallback;
61import com.android.server.telecom.callfiltering.CallFilteringResult;
62import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
63import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
64import com.android.server.telecom.callfiltering.IncomingCallFilter;
65import com.android.server.telecom.components.ErrorDialogActivity;
66
67import java.util.ArrayList;
68import java.util.Collection;
69import java.util.Collections;
70import java.util.HashMap;
71import java.util.HashSet;
72import java.util.List;
73import java.util.Map;
74import java.util.Objects;
75import java.util.Set;
76import java.util.concurrent.ConcurrentHashMap;
77
78/**
79 * Singleton.
80 *
81 * NOTE: by design most APIs are package private, use the relevant adapter/s to allow
82 * access from other packages specifically refraining from passing the CallsManager instance
83 * beyond the com.android.server.telecom package boundary.
84 */
85@VisibleForTesting
86public class CallsManager extends Call.ListenerBase
87        implements VideoProviderProxy.Listener, CallFilterResultCallback {
88
89    // TODO: Consider renaming this CallsManagerPlugin.
90    @VisibleForTesting
91    public interface CallsManagerListener {
92        void onCallAdded(Call call);
93        void onCallRemoved(Call call);
94        void onCallStateChanged(Call call, int oldState, int newState);
95        void onConnectionServiceChanged(
96                Call call,
97                ConnectionServiceWrapper oldService,
98                ConnectionServiceWrapper newService);
99        void onIncomingCallAnswered(Call call);
100        void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
101        void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
102        void onRingbackRequested(Call call, boolean ringback);
103        void onIsConferencedChanged(Call call);
104        void onIsVoipAudioModeChanged(Call call);
105        void onVideoStateChanged(Call call);
106        void onCanAddCallChanged(boolean canAddCall);
107        void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
108        void onHoldToneRequested(Call call);
109        void onExternalCallChanged(Call call, boolean isExternalCall);
110    }
111
112    private static final String TAG = "CallsManager";
113
114    private static final int MAXIMUM_LIVE_CALLS = 1;
115    private static final int MAXIMUM_HOLD_CALLS = 1;
116    private static final int MAXIMUM_RINGING_CALLS = 1;
117    private static final int MAXIMUM_DIALING_CALLS = 1;
118    private static final int MAXIMUM_OUTGOING_CALLS = 1;
119    private static final int MAXIMUM_TOP_LEVEL_CALLS = 2;
120
121    private static final int[] OUTGOING_CALL_STATES =
122            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING};
123
124    private static final int[] LIVE_CALL_STATES =
125            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
126                CallState.ACTIVE};
127    public static final String TELECOM_CALL_ID_PREFIX = "TC@";
128
129    // Maps call technologies in PhoneConstants to those in Analytics.
130    private static final Map<Integer, Integer> sAnalyticsTechnologyMap;
131    static {
132        sAnalyticsTechnologyMap = new HashMap<>(5);
133        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_CDMA, Analytics.CDMA_PHONE);
134        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_GSM, Analytics.GSM_PHONE);
135        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_IMS, Analytics.IMS_PHONE);
136        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_SIP, Analytics.SIP_PHONE);
137        sAnalyticsTechnologyMap.put(PhoneConstants.PHONE_TYPE_THIRD_PARTY,
138                Analytics.THIRD_PARTY_PHONE);
139    }
140
141    /**
142     * The main call repository. Keeps an instance of all live calls. New incoming and outgoing
143     * calls are added to the map and removed when the calls move to the disconnected state.
144     *
145     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
146     * load factor before resizing, 1 means we only expect a single thread to
147     * access the map so make only a single shard
148     */
149    private final Set<Call> mCalls = Collections.newSetFromMap(
150            new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));
151
152    /**
153     * The current telecom call ID.  Used when creating new instances of {@link Call}.  Should
154     * only be accessed using the {@link #getNextCallId()} method which synchronizes on the
155     * {@link #mLock} sync root.
156     */
157    private int mCallId = 0;
158
159    /**
160     * Stores the current foreground user.
161     */
162    private UserHandle mCurrentUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
163
164    private final ConnectionServiceRepository mConnectionServiceRepository;
165    private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
166    private final InCallController mInCallController;
167    private final CallAudioManager mCallAudioManager;
168    private RespondViaSmsManager mRespondViaSmsManager;
169    private final Ringer mRinger;
170    private final InCallWakeLockController mInCallWakeLockController;
171    // For this set initial table size to 16 because we add 13 listeners in
172    // the CallsManager constructor.
173    private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(
174            new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));
175    private final HeadsetMediaButton mHeadsetMediaButton;
176    private final WiredHeadsetManager mWiredHeadsetManager;
177    private final BluetoothManager mBluetoothManager;
178    private final DockManager mDockManager;
179    private final TtyManager mTtyManager;
180    private final ProximitySensorManager mProximitySensorManager;
181    private final PhoneStateBroadcaster mPhoneStateBroadcaster;
182    private final CallLogManager mCallLogManager;
183    private final Context mContext;
184    private final TelecomSystem.SyncRoot mLock;
185    private final ContactsAsyncHelper mContactsAsyncHelper;
186    private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
187    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
188    private final MissedCallNotifier mMissedCallNotifier;
189    private final CallerInfoLookupHelper mCallerInfoLookupHelper;
190    private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
191    private final Timeouts.Adapter mTimeoutsAdapter;
192    private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
193    private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
194    /* Handler tied to thread in which CallManager was initialized. */
195    private final Handler mHandler = new Handler(Looper.getMainLooper());
196
197    private boolean mCanAddCall = true;
198
199    private TelephonyManager.MultiSimVariants mRadioSimVariants = null;
200
201    private Runnable mStopTone;
202
203    /**
204     * Initializes the required Telecom components.
205     */
206    CallsManager(
207            Context context,
208            TelecomSystem.SyncRoot lock,
209            ContactsAsyncHelper contactsAsyncHelper,
210            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
211            MissedCallNotifier missedCallNotifier,
212            PhoneAccountRegistrar phoneAccountRegistrar,
213            HeadsetMediaButtonFactory headsetMediaButtonFactory,
214            ProximitySensorManagerFactory proximitySensorManagerFactory,
215            InCallWakeLockControllerFactory inCallWakeLockControllerFactory,
216            CallAudioManager.AudioServiceFactory audioServiceFactory,
217            BluetoothManager bluetoothManager,
218            WiredHeadsetManager wiredHeadsetManager,
219            SystemStateProvider systemStateProvider,
220            DefaultDialerManagerAdapter defaultDialerAdapter,
221            Timeouts.Adapter timeoutsAdapter,
222            AsyncRingtonePlayer asyncRingtonePlayer) {
223        mContext = context;
224        mLock = lock;
225        mContactsAsyncHelper = contactsAsyncHelper;
226        mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
227        mPhoneAccountRegistrar = phoneAccountRegistrar;
228        mMissedCallNotifier = missedCallNotifier;
229        StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
230        mWiredHeadsetManager = wiredHeadsetManager;
231        mBluetoothManager = bluetoothManager;
232        mDefaultDialerManagerAdapter = defaultDialerAdapter;
233        mDockManager = new DockManager(context);
234        mTimeoutsAdapter = timeoutsAdapter;
235        mCallerInfoLookupHelper = new CallerInfoLookupHelper(context, mCallerInfoAsyncQueryFactory,
236                mContactsAsyncHelper, mLock);
237
238        mDtmfLocalTonePlayer = new DtmfLocalTonePlayer();
239        CallAudioRouteStateMachine callAudioRouteStateMachine = new CallAudioRouteStateMachine(
240                context,
241                this,
242                bluetoothManager,
243                wiredHeadsetManager,
244                statusBarNotifier,
245                audioServiceFactory,
246                CallAudioRouteStateMachine.doesDeviceSupportEarpieceRoute()
247        );
248        callAudioRouteStateMachine.initialize();
249
250        CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter =
251                new CallAudioRoutePeripheralAdapter(
252                        callAudioRouteStateMachine,
253                        bluetoothManager,
254                        wiredHeadsetManager,
255                        mDockManager);
256
257        InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(
258                callAudioRoutePeripheralAdapter, lock);
259
260        SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
261        RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
262        SystemVibrator systemVibrator = new SystemVibrator(context);
263        mInCallController = new InCallController(
264                context, mLock, this, systemStateProvider, defaultDialerAdapter);
265        mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
266                ringtoneFactory, systemVibrator, mInCallController);
267
268        mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
269                this,new CallAudioModeStateMachine((AudioManager)
270                        mContext.getSystemService(Context.AUDIO_SERVICE)),
271                playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer);
272
273        mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock);
274        mTtyManager = new TtyManager(context, mWiredHeadsetManager);
275        mProximitySensorManager = proximitySensorManagerFactory.create(context, this);
276        mPhoneStateBroadcaster = new PhoneStateBroadcaster(this);
277        mCallLogManager = new CallLogManager(context, phoneAccountRegistrar, mMissedCallNotifier);
278        mConnectionServiceRepository =
279                new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);
280        mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this);
281
282        mListeners.add(mInCallWakeLockController);
283        mListeners.add(statusBarNotifier);
284        mListeners.add(mCallLogManager);
285        mListeners.add(mPhoneStateBroadcaster);
286        mListeners.add(mInCallController);
287        mListeners.add(mCallAudioManager);
288        mListeners.add(missedCallNotifier);
289        mListeners.add(mHeadsetMediaButton);
290        mListeners.add(mProximitySensorManager);
291
292        // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
293        final UserManager userManager = UserManager.get(mContext);
294        // Don't load missed call if it is run in split user model.
295        if (userManager.isPrimaryUser()) {
296            onUserSwitch(Process.myUserHandle());
297        }
298    }
299
300    public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) {
301        if (mRespondViaSmsManager != null) {
302            mListeners.remove(mRespondViaSmsManager);
303        }
304        mRespondViaSmsManager = respondViaSmsManager;
305        mListeners.add(respondViaSmsManager);
306    }
307
308    public RespondViaSmsManager getRespondViaSmsManager() {
309        return mRespondViaSmsManager;
310    }
311
312    public CallerInfoLookupHelper getCallerInfoLookupHelper() {
313        return mCallerInfoLookupHelper;
314    }
315
316    @Override
317    public void onSuccessfulOutgoingCall(Call call, int callState) {
318        Log.v(this, "onSuccessfulOutgoingCall, %s", call);
319
320        setCallState(call, callState, "successful outgoing call");
321        if (!mCalls.contains(call)) {
322            // Call was not added previously in startOutgoingCall due to it being a potential MMI
323            // code, so add it now.
324            addCall(call);
325        }
326
327        // The call's ConnectionService has been updated.
328        for (CallsManagerListener listener : mListeners) {
329            listener.onConnectionServiceChanged(call, null, call.getConnectionService());
330        }
331
332        markCallAsDialing(call);
333    }
334
335    @Override
336    public void onFailedOutgoingCall(Call call, DisconnectCause disconnectCause) {
337        Log.v(this, "onFailedOutgoingCall, call: %s", call);
338
339        markCallAsRemoved(call);
340    }
341
342    @Override
343    public void onSuccessfulIncomingCall(Call incomingCall) {
344        Log.d(this, "onSuccessfulIncomingCall");
345        List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
346        filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
347        filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
348        filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
349                mDefaultDialerManagerAdapter,
350                new ParcelableCallUtils.Converter(), mLock));
351        new IncomingCallFilter(mContext, this, incomingCall, mLock,
352                mTimeoutsAdapter, filters).performFiltering();
353    }
354
355    @Override
356    public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
357        // Only set the incoming call as ringing if it isn't already disconnected. It is possible
358        // that the connection service disconnected the call before it was even added to Telecom, in
359        // which case it makes no sense to set it back to a ringing state.
360        if (incomingCall.getState() != CallState.DISCONNECTED &&
361                incomingCall.getState() != CallState.DISCONNECTING) {
362            setCallState(incomingCall, CallState.RINGING,
363                    result.shouldAllowCall ? "successful incoming call" : "blocking call");
364        } else {
365            Log.i(this, "onCallFilteringCompleted: call already disconnected.");
366        }
367
368        if (result.shouldAllowCall) {
369            if (hasMaximumRingingCalls()) {
370                Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
371                        "ringing calls.");
372                rejectCallAndLog(incomingCall);
373            } else if (hasMaximumDialingCalls()) {
374                Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
375                        "dialing calls.");
376                rejectCallAndLog(incomingCall);
377            } else {
378                addCall(incomingCall);
379            }
380        } else {
381            if (result.shouldReject) {
382                Log.i(this, "onCallFilteringCompleted: blocked call, rejecting.");
383                incomingCall.reject(false, null);
384            }
385            if (result.shouldAddToCallLog) {
386                Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log.");
387                if (result.shouldShowNotification) {
388                    Log.w(this, "onCallScreeningCompleted: blocked call, showing notification.");
389                }
390                mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
391                        result.shouldShowNotification);
392            } else if (result.shouldShowNotification) {
393                Log.i(this, "onCallScreeningCompleted: blocked call, showing notification.");
394                mMissedCallNotifier.showMissedCallNotification(incomingCall);
395            }
396        }
397    }
398
399    @Override
400    public void onFailedIncomingCall(Call call) {
401        setCallState(call, CallState.DISCONNECTED, "failed incoming call");
402        call.removeListener(this);
403    }
404
405    @Override
406    public void onSuccessfulUnknownCall(Call call, int callState) {
407        setCallState(call, callState, "successful unknown call");
408        Log.i(this, "onSuccessfulUnknownCall for call %s", call);
409        addCall(call);
410    }
411
412    @Override
413    public void onFailedUnknownCall(Call call) {
414        Log.i(this, "onFailedUnknownCall for call %s", call);
415        setCallState(call, CallState.DISCONNECTED, "failed unknown call");
416        call.removeListener(this);
417    }
418
419    @Override
420    public void onRingbackRequested(Call call, boolean ringback) {
421        for (CallsManagerListener listener : mListeners) {
422            listener.onRingbackRequested(call, ringback);
423        }
424    }
425
426    @Override
427    public void onPostDialWait(Call call, String remaining) {
428        mInCallController.onPostDialWait(call, remaining);
429    }
430
431    @Override
432    public void onPostDialChar(final Call call, char nextChar) {
433        if (PhoneNumberUtils.is12Key(nextChar)) {
434            // Play tone if it is one of the dialpad digits, canceling out the previously queued
435            // up stopTone runnable since playing a new tone automatically stops the previous tone.
436            if (mStopTone != null) {
437                mHandler.removeCallbacks(mStopTone.getRunnableToCancel());
438                mStopTone.cancel();
439            }
440
441            mDtmfLocalTonePlayer.playTone(call, nextChar);
442
443            // TODO: Create a LockedRunnable class that does the synchronization automatically.
444            mStopTone = new Runnable("CM.oPDC") {
445                @Override
446                public void loggedRun() {
447                    synchronized (mLock) {
448                        // Set a timeout to stop the tone in case there isn't another tone to
449                        // follow.
450                        mDtmfLocalTonePlayer.stopTone(call);
451                    }
452                }
453            };
454            mHandler.postDelayed(mStopTone.prepare(),
455                    Timeouts.getDelayBetweenDtmfTonesMillis(mContext.getContentResolver()));
456        } else if (nextChar == 0 || nextChar == TelecomManager.DTMF_CHARACTER_WAIT ||
457                nextChar == TelecomManager.DTMF_CHARACTER_PAUSE) {
458            // Stop the tone if a tone is playing, removing any other stopTone callbacks since
459            // the previous tone is being stopped anyway.
460            if (mStopTone != null) {
461                mHandler.removeCallbacks(mStopTone.getRunnableToCancel());
462                mStopTone.cancel();
463            }
464            mDtmfLocalTonePlayer.stopTone(call);
465        } else {
466            Log.w(this, "onPostDialChar: invalid value %d", nextChar);
467        }
468    }
469
470    @Override
471    public void onParentChanged(Call call) {
472        // parent-child relationship affects which call should be foreground, so do an update.
473        updateCallsManagerState();
474        for (CallsManagerListener listener : mListeners) {
475            listener.onIsConferencedChanged(call);
476        }
477    }
478
479    @Override
480    public void onChildrenChanged(Call call) {
481        // parent-child relationship affects which call should be foreground, so do an update.
482        updateCallsManagerState();
483        for (CallsManagerListener listener : mListeners) {
484            listener.onIsConferencedChanged(call);
485        }
486    }
487
488    @Override
489    public void onIsVoipAudioModeChanged(Call call) {
490        for (CallsManagerListener listener : mListeners) {
491            listener.onIsVoipAudioModeChanged(call);
492        }
493    }
494
495    @Override
496    public void onVideoStateChanged(Call call) {
497        for (CallsManagerListener listener : mListeners) {
498            listener.onVideoStateChanged(call);
499        }
500    }
501
502    @Override
503    public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call) {
504        mPendingCallsToDisconnect.add(call);
505        mHandler.postDelayed(new Runnable("CM.oCVNOCB") {
506            @Override
507            public void loggedRun() {
508                synchronized (mLock) {
509                    if (mPendingCallsToDisconnect.remove(call)) {
510                        Log.i(this, "Delayed disconnection of call: %s", call);
511                        call.disconnect();
512                    }
513                }
514            }
515        }.prepare(), Timeouts.getNewOutgoingCallCancelMillis(mContext.getContentResolver()));
516
517        return true;
518    }
519
520    /**
521     * Handles changes to the {@link Connection.VideoProvider} for a call.  Adds the
522     * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created
523     * in {@link Call#setVideoProvider(IVideoProvider)}.  This allows the {@link CallsManager} to
524     * respond to callbacks from the {@link VideoProviderProxy}.
525     *
526     * @param call The call.
527     */
528    @Override
529    public void onVideoCallProviderChanged(Call call) {
530        VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy();
531
532        if (videoProviderProxy == null) {
533            return;
534        }
535
536        videoProviderProxy.addListener(this);
537    }
538
539    /**
540     * Handles session modification requests received via the {@link TelecomVideoCallCallback} for
541     * a call.  Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session
542     * modification request.
543     *
544     * @param call The call.
545     * @param videoProfile The {@link VideoProfile}.
546     */
547    @Override
548    public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
549        int videoState = videoProfile != null ? videoProfile.getVideoState() :
550                VideoProfile.STATE_AUDIO_ONLY;
551        Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile
552                .videoStateToString(videoState));
553
554        for (CallsManagerListener listener : mListeners) {
555            listener.onSessionModifyRequestReceived(call, videoProfile);
556        }
557    }
558
559    public Collection<Call> getCalls() {
560        return Collections.unmodifiableCollection(mCalls);
561    }
562
563    /**
564     * Play or stop a call hold tone for a call.  Triggered via
565     * {@link Connection#sendConnectionEvent(String)} when the
566     * {@link Connection#EVENT_ON_HOLD_TONE_START} event or
567     * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the
568     *
569     * @param call The call which requested the hold tone.
570     */
571    @Override
572    public void onHoldToneRequested(Call call) {
573        for (CallsManagerListener listener : mListeners) {
574            listener.onHoldToneRequested(call);
575        }
576    }
577
578    @VisibleForTesting
579    public Call getForegroundCall() {
580        if (mCallAudioManager == null) {
581            // Happens when getForegroundCall is called before full initialization.
582            return null;
583        }
584        return mCallAudioManager.getForegroundCall();
585    }
586
587    public UserHandle getCurrentUserHandle() {
588        return mCurrentUserHandle;
589    }
590
591    public CallAudioManager getCallAudioManager() {
592        return mCallAudioManager;
593    }
594
595    InCallController getInCallController() {
596        return mInCallController;
597    }
598
599    @VisibleForTesting
600    public boolean hasEmergencyCall() {
601        for (Call call : mCalls) {
602            if (call.isEmergencyCall()) {
603                return true;
604            }
605        }
606        return false;
607    }
608
609    boolean hasOnlyDisconnectedCalls() {
610        for (Call call : mCalls) {
611            if (!call.isDisconnected()) {
612                return false;
613            }
614        }
615        return true;
616    }
617
618    boolean hasVideoCall() {
619        for (Call call : mCalls) {
620            if (VideoProfile.isVideo(call.getVideoState())) {
621                return true;
622            }
623        }
624        return false;
625    }
626
627    CallAudioState getAudioState() {
628        return mCallAudioManager.getCallAudioState();
629    }
630
631    boolean isTtySupported() {
632        return mTtyManager.isTtySupported();
633    }
634
635    int getCurrentTtyMode() {
636        return mTtyManager.getCurrentTtyMode();
637    }
638
639    @VisibleForTesting
640    public void addListener(CallsManagerListener listener) {
641        mListeners.add(listener);
642    }
643
644    void removeListener(CallsManagerListener listener) {
645        mListeners.remove(listener);
646    }
647
648    /**
649     * Starts the process to attach the call to a connection service.
650     *
651     * @param phoneAccountHandle The phone account which contains the component name of the
652     *        connection service to use for this call.
653     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
654     */
655    void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
656        Log.d(this, "processIncomingCallIntent");
657        Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
658        if (handle == null) {
659            // Required for backwards compatibility
660            handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
661        }
662        Call call = new Call(
663                getNextCallId(),
664                mContext,
665                this,
666                mLock,
667                mConnectionServiceRepository,
668                mContactsAsyncHelper,
669                mCallerInfoAsyncQueryFactory,
670                handle,
671                null /* gatewayInfo */,
672                null /* connectionManagerPhoneAccount */,
673                phoneAccountHandle,
674                Call.CALL_DIRECTION_INCOMING /* callDirection */,
675                false /* forceAttachToExistingConnection */,
676                false /* isConference */
677        );
678
679        call.initAnalytics();
680        if (getForegroundCall() != null) {
681            getForegroundCall().getAnalytics().setCallIsInterrupted(true);
682            call.getAnalytics().setCallIsAdditional(true);
683        }
684
685        setIntentExtrasAndStartTime(call, extras);
686        // TODO: Move this to be a part of addCall()
687        call.addListener(this);
688        call.startCreateConnection(mPhoneAccountRegistrar);
689    }
690
691    void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
692        Uri handle = extras.getParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE);
693        Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle));
694        Call call = new Call(
695                getNextCallId(),
696                mContext,
697                this,
698                mLock,
699                mConnectionServiceRepository,
700                mContactsAsyncHelper,
701                mCallerInfoAsyncQueryFactory,
702                handle,
703                null /* gatewayInfo */,
704                null /* connectionManagerPhoneAccount */,
705                phoneAccountHandle,
706                Call.CALL_DIRECTION_UNKNOWN /* callDirection */,
707                // Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach
708                // to the existing connection instead of trying to create a new one.
709                true /* forceAttachToExistingConnection */,
710                false /* isConference */
711        );
712        call.initAnalytics();
713
714        setIntentExtrasAndStartTime(call, extras);
715        call.addListener(this);
716        call.startCreateConnection(mPhoneAccountRegistrar);
717    }
718
719    private boolean areHandlesEqual(Uri handle1, Uri handle2) {
720        if (handle1 == null || handle2 == null) {
721            return handle1 == handle2;
722        }
723
724        if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) {
725            return false;
726        }
727
728        final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart());
729        final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart());
730        return TextUtils.equals(number1, number2);
731    }
732
733    private Call reuseOutgoingCall(Uri handle) {
734        // Check to see if we can reuse any of the calls that are waiting to disconnect.
735        // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information.
736        Call reusedCall = null;
737        for (Call pendingCall : mPendingCallsToDisconnect) {
738            if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) {
739                mPendingCallsToDisconnect.remove(pendingCall);
740                Log.i(this, "Reusing disconnected call %s", pendingCall);
741                reusedCall = pendingCall;
742            } else {
743                Log.i(this, "Not reusing disconnected call %s", pendingCall);
744                pendingCall.disconnect();
745            }
746        }
747
748        return reusedCall;
749    }
750
751    /**
752     * Kicks off the first steps to creating an outgoing call so that InCallUI can launch.
753     *
754     * @param handle Handle to connect the call with.
755     * @param phoneAccountHandle The phone account which contains the component name of the
756     *        connection service to use for this call.
757     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
758     * @param initiatingUser {@link UserHandle} of user that place the outgoing call.
759     */
760    Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
761            UserHandle initiatingUser) {
762        boolean isReusedCall = true;
763        Call call = reuseOutgoingCall(handle);
764
765        // Create a call with original handle. The handle may be changed when the call is attached
766        // to a connection service, but in most cases will remain the same.
767        if (call == null) {
768            call = new Call(getNextCallId(), mContext,
769                    this,
770                    mLock,
771                    mConnectionServiceRepository,
772                    mContactsAsyncHelper,
773                    mCallerInfoAsyncQueryFactory,
774                    handle,
775                    null /* gatewayInfo */,
776                    null /* connectionManagerPhoneAccount */,
777                    null /* phoneAccountHandle */,
778                    Call.CALL_DIRECTION_OUTGOING /* callDirection */,
779                    false /* forceAttachToExistingConnection */,
780                    false /* isConference */
781            );
782            call.setInitiatingUser(initiatingUser);
783
784            call.initAnalytics();
785
786            isReusedCall = false;
787        }
788
789        // Set the video state on the call early so that when it is added to the InCall UI the UI
790        // knows to configure itself as a video call immediately.
791        if (extras != null) {
792            int videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
793                    VideoProfile.STATE_AUDIO_ONLY);
794
795            // If this is an emergency video call, we need to check if the phone account supports
796            // emergency video calling.
797            if (call.isEmergencyCall() && VideoProfile.isVideo(videoState)) {
798                PhoneAccount account =
799                        mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
800
801                if (account != null &&
802                        !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
803                    // Phone account doesn't support emergency video calling, so fallback to
804                    // audio-only now to prevent the InCall UI from setting up video surfaces
805                    // needlessly.
806                    Log.i(this, "startOutgoingCall - emergency video calls not supported; " +
807                            "falling back to audio-only");
808                    videoState = VideoProfile.STATE_AUDIO_ONLY;
809                }
810            }
811
812            call.setVideoState(videoState);
813        }
814
815        List<PhoneAccountHandle> accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
816        Log.v(this, "startOutgoingCall found accounts = " + accounts);
817
818        // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this call
819        // as if a phoneAccount was not specified (does the default behavior instead).
820        // Note: We will not attempt to dial with a requested phoneAccount if it is disabled.
821        if (phoneAccountHandle != null) {
822            if (!accounts.contains(phoneAccountHandle)) {
823                phoneAccountHandle = null;
824            }
825        }
826
827        if (phoneAccountHandle == null && accounts.size() > 0 && !call.isEmergencyCall()) {
828            // No preset account, check if default exists that supports the URI scheme for the
829            // handle and verify it can be used.
830            if(accounts.size() > 1) {
831                PhoneAccountHandle defaultPhoneAccountHandle =
832                        mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme(),
833                                initiatingUser);
834                if (defaultPhoneAccountHandle != null &&
835                        accounts.contains(defaultPhoneAccountHandle)) {
836                    phoneAccountHandle = defaultPhoneAccountHandle;
837                }
838            } else {
839                // Use the only PhoneAccount that is available
840                phoneAccountHandle = accounts.get(0);
841            }
842
843        }
844
845        call.setTargetPhoneAccount(phoneAccountHandle);
846
847        boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle);
848
849        // Do not support any more live calls.  Our options are to move a call to hold, disconnect
850        // a call, or cancel this call altogether. If a call is being reused, then it has already
851        // passed the makeRoomForOutgoingCall check once and will fail the second time due to the
852        // call transitioning into the CONNECTING state.
853        if (!isPotentialInCallMMICode && (!isReusedCall &&
854                !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) {
855            // just cancel at this point.
856            Log.i(this, "No remaining room for outgoing call: %s", call);
857            if (mCalls.contains(call)) {
858                // This call can already exist if it is a reused call,
859                // See {@link #reuseOutgoingCall}.
860                call.disconnect();
861            }
862            return null;
863        }
864
865        boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
866                !call.isEmergencyCall();
867
868        if (needsAccountSelection) {
869            // This is the state where the user is expected to select an account
870            call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
871            // Create our own instance to modify (since extras may be Bundle.EMPTY)
872            extras = new Bundle(extras);
873            extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
874        } else {
875            call.setState(
876                    CallState.CONNECTING,
877                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
878        }
879
880        setIntentExtrasAndStartTime(call, extras);
881
882        // Do not add the call if it is a potential MMI code.
883        if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
884            call.addListener(this);
885        } else if (!mCalls.contains(call)) {
886            // We check if mCalls already contains the call because we could potentially be reusing
887            // a call which was previously added (See {@link #reuseOutgoingCall}).
888            addCall(call);
889        }
890
891        return call;
892    }
893
894    /**
895     * Attempts to issue/connect the specified call.
896     *
897     * @param handle Handle to connect the call with.
898     * @param gatewayInfo Optional gateway information that can be used to route the call to the
899     *        actual dialed handle via a gateway provider. May be null.
900     * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects.
901     * @param videoState The desired video state for the outgoing call.
902     */
903    @VisibleForTesting
904    public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
905            boolean speakerphoneOn, int videoState) {
906        if (call == null) {
907            // don't do anything if the call no longer exists
908            Log.i(this, "Canceling unknown call.");
909            return;
910        }
911
912        final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();
913
914        if (gatewayInfo == null) {
915            Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
916        } else {
917            Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
918                    Log.pii(uriHandle), Log.pii(handle));
919        }
920
921        call.setHandle(uriHandle);
922        call.setGatewayInfo(gatewayInfo);
923
924        final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
925                R.bool.use_speaker_when_docked);
926        final boolean isDocked = mDockManager.isDocked();
927        final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabled(videoState);
928
929        // Auto-enable speakerphone if the originating intent specified to do so, if the call
930        // is a video call, of if using speaker when docked
931        call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
932                || (useSpeakerWhenDocked && isDocked));
933        call.setVideoState(videoState);
934
935        if (speakerphoneOn) {
936            Log.i(this, "%s Starting with speakerphone as requested", call);
937        } else if (useSpeakerWhenDocked && useSpeakerWhenDocked) {
938            Log.i(this, "%s Starting with speakerphone because car is docked.", call);
939        } else if (useSpeakerForVideoCall) {
940            Log.i(this, "%s Starting with speakerphone because its a video call.", call);
941        }
942
943        if (call.isEmergencyCall()) {
944            // Emergency -- CreateConnectionProcessor will choose accounts automatically
945            call.setTargetPhoneAccount(null);
946            new AsyncEmergencyContactNotifier(mContext).execute();
947        }
948
949        final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
950                com.android.internal.R.bool.config_requireCallCapableAccountForHandle);
951
952        if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
953            // If the account has been set, proceed to place the outgoing call.
954            // Otherwise the connection will be initiated when the account is set by the user.
955            call.startCreateConnection(mPhoneAccountRegistrar);
956        } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
957                requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
958                call.getInitiatingUser()).isEmpty()) {
959            // If there are no call capable accounts, disconnect the call.
960            markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
961                    "No registered PhoneAccounts"));
962            markCallAsRemoved(call);
963        }
964    }
965
966    /**
967     * Attempts to start a conference call for the specified call.
968     *
969     * @param call The call to conference.
970     * @param otherCall The other call to conference with.
971     */
972    @VisibleForTesting
973    public void conference(Call call, Call otherCall) {
974        call.conferenceWith(otherCall);
975    }
976
977    /**
978     * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call
979     * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
980     * the user opting to answer said call.
981     *
982     * @param call The call to answer.
983     * @param videoState The video state in which to answer the call.
984     */
985    @VisibleForTesting
986    public void answerCall(Call call, int videoState) {
987        if (!mCalls.contains(call)) {
988            Log.i(this, "Request to answer a non-existent call %s", call);
989        } else {
990            Call foregroundCall = getForegroundCall();
991            // If the foreground call is not the ringing call and it is currently isActive() or
992            // STATE_DIALING, put it on hold before answering the call.
993            if (foregroundCall != null && foregroundCall != call &&
994                    (foregroundCall.isActive() ||
995                     foregroundCall.getState() == CallState.DIALING)) {
996                if (0 == (foregroundCall.getConnectionCapabilities()
997                        & Connection.CAPABILITY_HOLD)) {
998                    // This call does not support hold.  If it is from a different connection
999                    // service, then disconnect it, otherwise allow the connection service to
1000                    // figure out the right states.
1001                    if (foregroundCall.getConnectionService() != call.getConnectionService()) {
1002                        foregroundCall.disconnect();
1003                    }
1004                } else {
1005                    Call heldCall = getHeldCall();
1006                    if (heldCall != null) {
1007                        Log.v(this, "Disconnecting held call %s before holding active call.",
1008                                heldCall);
1009                        heldCall.disconnect();
1010                    }
1011
1012                    Log.v(this, "Holding active/dialing call %s before answering incoming call %s.",
1013                            foregroundCall, call);
1014                    foregroundCall.hold();
1015                }
1016                // TODO: Wait until we get confirmation of the active call being
1017                // on-hold before answering the new call.
1018                // TODO: Import logic from CallManager.acceptCall()
1019            }
1020
1021            for (CallsManagerListener listener : mListeners) {
1022                listener.onIncomingCallAnswered(call);
1023            }
1024
1025            // We do not update the UI until we get confirmation of the answer() through
1026            // {@link #markCallAsActive}.
1027            call.answer(videoState);
1028            if (isSpeakerphoneAutoEnabled(videoState)) {
1029                call.setStartWithSpeakerphoneOn(true);
1030            }
1031        }
1032    }
1033
1034    /**
1035     * Determines if the speakerphone should be automatically enabled for the call.  Speakerphone
1036     * should be enabled if the call is a video call and bluetooth or the wired headset are not in
1037     * use.
1038     *
1039     * @param videoState The video state of the call.
1040     * @return {@code true} if the speakerphone should be enabled.
1041     */
1042    private boolean isSpeakerphoneAutoEnabled(int videoState) {
1043        return VideoProfile.isVideo(videoState) &&
1044            !mWiredHeadsetManager.isPluggedIn() &&
1045            !mBluetoothManager.isBluetoothAvailable() &&
1046            isSpeakerEnabledForVideoCalls();
1047    }
1048
1049    /**
1050     * Determines if the speakerphone should be automatically enabled for video calls.
1051     *
1052     * @return {@code true} if the speakerphone should automatically be enabled.
1053     */
1054    private static boolean isSpeakerEnabledForVideoCalls() {
1055        return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT,
1056                PhoneConstants.AUDIO_OUTPUT_DEFAULT) ==
1057                PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER);
1058    }
1059
1060    /**
1061     * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call
1062     * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
1063     * the user opting to reject said call.
1064     */
1065    @VisibleForTesting
1066    public void rejectCall(Call call, boolean rejectWithMessage, String textMessage) {
1067        if (!mCalls.contains(call)) {
1068            Log.i(this, "Request to reject a non-existent call %s", call);
1069        } else {
1070            for (CallsManagerListener listener : mListeners) {
1071                listener.onIncomingCallRejected(call, rejectWithMessage, textMessage);
1072            }
1073            call.reject(rejectWithMessage, textMessage);
1074        }
1075    }
1076
1077    /**
1078     * Instructs Telecom to play the specified DTMF tone within the specified call.
1079     *
1080     * @param digit The DTMF digit to play.
1081     */
1082    @VisibleForTesting
1083    public void playDtmfTone(Call call, char digit) {
1084        if (!mCalls.contains(call)) {
1085            Log.i(this, "Request to play DTMF in a non-existent call %s", call);
1086        } else {
1087            call.playDtmfTone(digit);
1088            mDtmfLocalTonePlayer.playTone(call, digit);
1089        }
1090    }
1091
1092    /**
1093     * Instructs Telecom to stop the currently playing DTMF tone, if any.
1094     */
1095    @VisibleForTesting
1096    public void stopDtmfTone(Call call) {
1097        if (!mCalls.contains(call)) {
1098            Log.i(this, "Request to stop DTMF in a non-existent call %s", call);
1099        } else {
1100            call.stopDtmfTone();
1101            mDtmfLocalTonePlayer.stopTone(call);
1102        }
1103    }
1104
1105    /**
1106     * Instructs Telecom to continue (or not) the current post-dial DTMF string, if any.
1107     */
1108    void postDialContinue(Call call, boolean proceed) {
1109        if (!mCalls.contains(call)) {
1110            Log.i(this, "Request to continue post-dial string in a non-existent call %s", call);
1111        } else {
1112            call.postDialContinue(proceed);
1113        }
1114    }
1115
1116    /**
1117     * Instructs Telecom to disconnect the specified call. Intended to be invoked by the
1118     * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1119     * the user hitting the end-call button.
1120     */
1121    @VisibleForTesting
1122    public void disconnectCall(Call call) {
1123        Log.v(this, "disconnectCall %s", call);
1124
1125        if (!mCalls.contains(call)) {
1126            Log.w(this, "Unknown call (%s) asked to disconnect", call);
1127        } else {
1128            mLocallyDisconnectingCalls.add(call);
1129            call.disconnect();
1130        }
1131    }
1132
1133    /**
1134     * Instructs Telecom to disconnect all calls.
1135     */
1136    void disconnectAllCalls() {
1137        Log.v(this, "disconnectAllCalls");
1138
1139        for (Call call : mCalls) {
1140            disconnectCall(call);
1141        }
1142    }
1143
1144
1145    /**
1146     * Instructs Telecom to put the specified call on hold. Intended to be invoked by the
1147     * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
1148     * the user hitting the hold button during an active call.
1149     */
1150    @VisibleForTesting
1151    public void holdCall(Call call) {
1152        if (!mCalls.contains(call)) {
1153            Log.w(this, "Unknown call (%s) asked to be put on hold", call);
1154        } else {
1155            Log.d(this, "Putting call on hold: (%s)", call);
1156            call.hold();
1157        }
1158    }
1159
1160    /**
1161     * Instructs Telecom to release the specified call from hold. Intended to be invoked by
1162     * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered
1163     * by the user hitting the hold button during a held call.
1164     */
1165    @VisibleForTesting
1166    public void unholdCall(Call call) {
1167        if (!mCalls.contains(call)) {
1168            Log.w(this, "Unknown call (%s) asked to be removed from hold", call);
1169        } else {
1170            Log.d(this, "unholding call: (%s)", call);
1171            for (Call c : mCalls) {
1172                // Only attempt to hold parent calls and not the individual children.
1173                if (c != null && c.isAlive() && c != call && c.getParentCall() == null) {
1174                    c.hold();
1175                }
1176            }
1177            call.unhold();
1178        }
1179    }
1180
1181    @Override
1182    public void onExtrasChanged(Call c, int source, Bundle extras) {
1183        if (source != Call.SOURCE_CONNECTION_SERVICE) {
1184            return;
1185        }
1186        handleCallTechnologyChange(c);
1187        handleChildAddressChange(c);
1188    }
1189
1190    // Construct the list of possible PhoneAccounts that the outgoing call can use based on the
1191    // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount,
1192    // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP.
1193    private List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user) {
1194        if (handle == null) {
1195            return Collections.emptyList();
1196        }
1197        List<PhoneAccountHandle> allAccounts =
1198                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user);
1199        // First check the Radio SIM Technology
1200        if(mRadioSimVariants == null) {
1201            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
1202                    Context.TELEPHONY_SERVICE);
1203            // Cache Sim Variants
1204            mRadioSimVariants = tm.getMultiSimConfiguration();
1205        }
1206        // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount
1207        // Should be available if a call is already active on the SIM account.
1208        if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) {
1209            List<PhoneAccountHandle> simAccounts =
1210                    mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser();
1211            PhoneAccountHandle ongoingCallAccount = null;
1212            for (Call c : mCalls) {
1213                if (!c.isDisconnected() && !c.isNew() && simAccounts.contains(
1214                        c.getTargetPhoneAccount())) {
1215                    ongoingCallAccount = c.getTargetPhoneAccount();
1216                    break;
1217                }
1218            }
1219            if (ongoingCallAccount != null) {
1220                // Remove all SIM accounts that are not the active SIM from the list.
1221                simAccounts.remove(ongoingCallAccount);
1222                allAccounts.removeAll(simAccounts);
1223            }
1224        }
1225        return allAccounts;
1226    }
1227
1228    /**
1229     * Informs listeners (notably {@link CallAudioManager} of a change to the call's external
1230     * property.
1231     * .
1232     * @param call The call whose external property changed.
1233     * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise.
1234     */
1235    @Override
1236    public void onExternalCallChanged(Call call, boolean isExternalCall) {
1237        Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall);
1238        for (CallsManagerListener listener : mListeners) {
1239            listener.onExternalCallChanged(call, isExternalCall);
1240        }
1241    }
1242
1243    private void handleCallTechnologyChange(Call call) {
1244        if (call.getExtras() != null
1245                && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) {
1246
1247            Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get(
1248                    call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE));
1249            if (analyticsCallTechnology == null) {
1250                analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE;
1251            }
1252            call.getAnalytics().addCallTechnology(analyticsCallTechnology);
1253        }
1254    }
1255
1256    public void handleChildAddressChange(Call call) {
1257        if (call.getExtras() != null
1258                && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
1259
1260            String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS);
1261            call.setViaNumber(viaNumber);
1262        }
1263    }
1264
1265    /** Called by the in-call UI to change the mute state. */
1266    void mute(boolean shouldMute) {
1267        mCallAudioManager.mute(shouldMute);
1268    }
1269
1270    /**
1271      * Called by the in-call UI to change the audio route, for example to change from earpiece to
1272      * speaker phone.
1273      */
1274    void setAudioRoute(int route) {
1275        mCallAudioManager.setAudioRoute(route);
1276    }
1277
1278    /** Called by the in-call UI to turn the proximity sensor on. */
1279    void turnOnProximitySensor() {
1280        mProximitySensorManager.turnOn();
1281    }
1282
1283    /**
1284     * Called by the in-call UI to turn the proximity sensor off.
1285     * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise,
1286     *        the screen will be kept off until the proximity sensor goes negative.
1287     */
1288    void turnOffProximitySensor(boolean screenOnImmediately) {
1289        mProximitySensorManager.turnOff(screenOnImmediately);
1290    }
1291
1292    void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
1293        if (!mCalls.contains(call)) {
1294            Log.i(this, "Attempted to add account to unknown call %s", call);
1295        } else {
1296            call.setTargetPhoneAccount(account);
1297
1298            if (!call.isNewOutgoingCallIntentBroadcastDone()) {
1299                return;
1300            }
1301
1302            // Note: emergency calls never go through account selection dialog so they never
1303            // arrive here.
1304            if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) {
1305                call.startCreateConnection(mPhoneAccountRegistrar);
1306            } else {
1307                call.disconnect();
1308            }
1309
1310            if (setDefault) {
1311                mPhoneAccountRegistrar
1312                        .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser());
1313            }
1314        }
1315    }
1316
1317    /** Called when the audio state changes. */
1318    @VisibleForTesting
1319    public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState
1320            newAudioState) {
1321        Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState);
1322        for (CallsManagerListener listener : mListeners) {
1323            listener.onCallAudioStateChanged(oldAudioState, newAudioState);
1324        }
1325    }
1326
1327    void markCallAsRinging(Call call) {
1328        setCallState(call, CallState.RINGING, "ringing set explicitly");
1329    }
1330
1331    void markCallAsDialing(Call call) {
1332        setCallState(call, CallState.DIALING, "dialing set explicitly");
1333        maybeMoveToSpeakerPhone(call);
1334    }
1335
1336    void markCallAsActive(Call call) {
1337        setCallState(call, CallState.ACTIVE, "active set explicitly");
1338        maybeMoveToSpeakerPhone(call);
1339    }
1340
1341    void markCallAsOnHold(Call call) {
1342        setCallState(call, CallState.ON_HOLD, "on-hold set explicitly");
1343    }
1344
1345    /**
1346     * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the
1347     * last live call, then also disconnect from the in-call controller.
1348     *
1349     * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
1350     */
1351    void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
1352        call.setDisconnectCause(disconnectCause);
1353        setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
1354    }
1355
1356    /**
1357     * Removes an existing disconnected call, and notifies the in-call app.
1358     */
1359    void markCallAsRemoved(Call call) {
1360        removeCall(call);
1361        if (mLocallyDisconnectingCalls.contains(call)) {
1362            mLocallyDisconnectingCalls.remove(call);
1363            Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
1364            if (foregroundCall != null && foregroundCall.getState() == CallState.ON_HOLD) {
1365                foregroundCall.unhold();
1366            }
1367        }
1368    }
1369
1370    /**
1371     * Cleans up any calls currently associated with the specified connection service when the
1372     * service binder disconnects unexpectedly.
1373     *
1374     * @param service The connection service that disconnected.
1375     */
1376    void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
1377        if (service != null) {
1378            for (Call call : mCalls) {
1379                if (call.getConnectionService() == service) {
1380                    if (call.getState() != CallState.DISCONNECTED) {
1381                        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR));
1382                    }
1383                    markCallAsRemoved(call);
1384                }
1385            }
1386        }
1387    }
1388
1389    /**
1390     * Determines if the {@link CallsManager} has any non-external calls.
1391     *
1392     * @return {@code True} if there are any non-external calls, {@code false} otherwise.
1393     */
1394    boolean hasAnyCalls() {
1395        if (mCalls.isEmpty()) {
1396            return false;
1397        }
1398
1399        for (Call call : mCalls) {
1400            if (!call.isExternalCall()) {
1401                return true;
1402            }
1403        }
1404        return false;
1405    }
1406
1407    boolean hasActiveOrHoldingCall() {
1408        return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null;
1409    }
1410
1411    boolean hasRingingCall() {
1412        return getFirstCallWithState(CallState.RINGING) != null;
1413    }
1414
1415    boolean onMediaButton(int type) {
1416        if (hasAnyCalls()) {
1417            if (HeadsetMediaButton.SHORT_PRESS == type) {
1418                Call ringingCall = getFirstCallWithState(CallState.RINGING);
1419                if (ringingCall == null) {
1420                    mCallAudioManager.toggleMute();
1421                    return true;
1422                } else {
1423                    ringingCall.answer(ringingCall.getVideoState());
1424                    return true;
1425                }
1426            } else if (HeadsetMediaButton.LONG_PRESS == type) {
1427                Log.d(this, "handleHeadsetHook: longpress -> hangup");
1428                Call callToHangup = getFirstCallWithState(
1429                        CallState.RINGING, CallState.DIALING, CallState.ACTIVE, CallState.ON_HOLD);
1430                if (callToHangup != null) {
1431                    callToHangup.disconnect();
1432                    return true;
1433                }
1434            }
1435        }
1436        return false;
1437    }
1438
1439    /**
1440     * Returns true if telecom supports adding another top-level call.
1441     */
1442    boolean canAddCall() {
1443        boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
1444                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
1445        if (!isDeviceProvisioned) {
1446            Log.d(TAG, "Device not provisioned, canAddCall is false.");
1447            return false;
1448        }
1449
1450        if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) {
1451            return false;
1452        }
1453
1454        int count = 0;
1455        for (Call call : mCalls) {
1456            if (call.isEmergencyCall()) {
1457                // We never support add call if one of the calls is an emergency call.
1458                return false;
1459            } else if (call.getParentCall() == null) {
1460                count++;
1461            }
1462
1463            // We do not check states for canAddCall. We treat disconnected calls the same
1464            // and wait until they are removed instead. If we didn't count disconnected calls,
1465            // we could put InCallServices into a state where they are showing two calls but
1466            // also support add-call. Technically it's right, but overall looks better (UI-wise)
1467            // and acts better if we wait until the call is removed.
1468            if (count >= MAXIMUM_TOP_LEVEL_CALLS) {
1469                return false;
1470            }
1471        }
1472        return true;
1473    }
1474
1475    @VisibleForTesting
1476    public Call getRingingCall() {
1477        return getFirstCallWithState(CallState.RINGING);
1478    }
1479
1480    @VisibleForTesting
1481    public Call getActiveCall() {
1482        return getFirstCallWithState(CallState.ACTIVE);
1483    }
1484
1485    Call getDialingCall() {
1486        return getFirstCallWithState(CallState.DIALING);
1487    }
1488
1489    @VisibleForTesting
1490    public Call getHeldCall() {
1491        return getFirstCallWithState(CallState.ON_HOLD);
1492    }
1493
1494    @VisibleForTesting
1495    public int getNumHeldCalls() {
1496        int count = 0;
1497        for (Call call : mCalls) {
1498            if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) {
1499                count++;
1500            }
1501        }
1502        return count;
1503    }
1504
1505    @VisibleForTesting
1506    public Call getOutgoingCall() {
1507        return getFirstCallWithState(OUTGOING_CALL_STATES);
1508    }
1509
1510    @VisibleForTesting
1511    public Call getFirstCallWithState(int... states) {
1512        return getFirstCallWithState(null, states);
1513    }
1514
1515    /**
1516     * Returns the first call that it finds with the given states. The states are treated as having
1517     * priority order so that any call with the first state will be returned before any call with
1518     * states listed later in the parameter list.
1519     *
1520     * @param callToSkip Call that this method should skip while searching
1521     */
1522    Call getFirstCallWithState(Call callToSkip, int... states) {
1523        for (int currentState : states) {
1524            // check the foreground first
1525            Call foregroundCall = getForegroundCall();
1526            if (foregroundCall != null && foregroundCall.getState() == currentState) {
1527                return foregroundCall;
1528            }
1529
1530            for (Call call : mCalls) {
1531                if (Objects.equals(callToSkip, call)) {
1532                    continue;
1533                }
1534
1535                // Only operate on top-level calls
1536                if (call.getParentCall() != null) {
1537                    continue;
1538                }
1539
1540                if (currentState == call.getState()) {
1541                    return call;
1542                }
1543            }
1544        }
1545        return null;
1546    }
1547
1548    Call createConferenceCall(
1549            String callId,
1550            PhoneAccountHandle phoneAccount,
1551            ParcelableConference parcelableConference) {
1552
1553        // If the parceled conference specifies a connect time, use it; otherwise default to 0,
1554        // which is the default value for new Calls.
1555        long connectTime =
1556                parcelableConference.getConnectTimeMillis() ==
1557                        Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
1558                        parcelableConference.getConnectTimeMillis();
1559
1560        Call call = new Call(
1561                callId,
1562                mContext,
1563                this,
1564                mLock,
1565                mConnectionServiceRepository,
1566                mContactsAsyncHelper,
1567                mCallerInfoAsyncQueryFactory,
1568                null /* handle */,
1569                null /* gatewayInfo */,
1570                null /* connectionManagerPhoneAccount */,
1571                phoneAccount,
1572                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
1573                false /* forceAttachToExistingConnection */,
1574                true /* isConference */,
1575                connectTime);
1576
1577        setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
1578                "new conference call");
1579        call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities());
1580        call.setConnectionProperties(parcelableConference.getConnectionProperties());
1581        call.setVideoState(parcelableConference.getVideoState());
1582        call.setVideoProvider(parcelableConference.getVideoProvider());
1583        call.setStatusHints(parcelableConference.getStatusHints());
1584        call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
1585
1586        // TODO: Move this to be a part of addCall()
1587        call.addListener(this);
1588        addCall(call);
1589        return call;
1590    }
1591
1592    /**
1593     * @return the call state currently tracked by {@link PhoneStateBroadcaster}
1594     */
1595    int getCallState() {
1596        return mPhoneStateBroadcaster.getCallState();
1597    }
1598
1599    /**
1600     * Retrieves the {@link PhoneAccountRegistrar}.
1601     *
1602     * @return The {@link PhoneAccountRegistrar}.
1603     */
1604    PhoneAccountRegistrar getPhoneAccountRegistrar() {
1605        return mPhoneAccountRegistrar;
1606    }
1607
1608    /**
1609     * Retrieves the {@link MissedCallNotifier}
1610     * @return The {@link MissedCallNotifier}.
1611     */
1612    MissedCallNotifier getMissedCallNotifier() {
1613        return mMissedCallNotifier;
1614    }
1615
1616    /**
1617     * Reject an incoming call and manually add it to the Call Log.
1618     * @param incomingCall Incoming call that has been rejected
1619     */
1620    private void rejectCallAndLog(Call incomingCall) {
1621        incomingCall.reject(false, null);
1622        // Since the call was not added to the list of calls, we have to call the missed
1623        // call notifier and the call logger manually.
1624        // Do we need missed call notification for direct to Voicemail calls?
1625        mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
1626                true /*showNotificationForMissedCall*/);
1627    }
1628
1629    /**
1630     * Adds the specified call to the main list of live calls.
1631     *
1632     * @param call The call to add.
1633     */
1634    private void addCall(Call call) {
1635        Trace.beginSection("addCall");
1636        Log.v(this, "addCall(%s)", call);
1637        call.addListener(this);
1638        mCalls.add(call);
1639
1640        // Specifies the time telecom finished routing the call. This is used by the dialer for
1641        // analytics.
1642        Bundle extras = call.getIntentExtras();
1643        extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
1644                SystemClock.elapsedRealtime());
1645
1646        updateCallsManagerState();
1647        // onCallAdded for calls which immediately take the foreground (like the first call).
1648        for (CallsManagerListener listener : mListeners) {
1649            if (Log.SYSTRACE_DEBUG) {
1650                Trace.beginSection(listener.getClass().toString() + " addCall");
1651            }
1652            listener.onCallAdded(call);
1653            if (Log.SYSTRACE_DEBUG) {
1654                Trace.endSection();
1655            }
1656        }
1657        Trace.endSection();
1658    }
1659
1660    private void removeCall(Call call) {
1661        Trace.beginSection("removeCall");
1662        Log.v(this, "removeCall(%s)", call);
1663
1664        call.setParentCall(null);  // need to clean up parent relationship before destroying.
1665        call.removeListener(this);
1666        call.clearConnectionService();
1667
1668        boolean shouldNotify = false;
1669        if (mCalls.contains(call)) {
1670            mCalls.remove(call);
1671            shouldNotify = true;
1672        }
1673
1674        call.destroy();
1675
1676        // Only broadcast changes for calls that are being tracked.
1677        if (shouldNotify) {
1678            updateCallsManagerState();
1679            for (CallsManagerListener listener : mListeners) {
1680                if (Log.SYSTRACE_DEBUG) {
1681                    Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
1682                }
1683                listener.onCallRemoved(call);
1684                if (Log.SYSTRACE_DEBUG) {
1685                    Trace.endSection();
1686                }
1687            }
1688        }
1689        Trace.endSection();
1690    }
1691
1692    /**
1693     * Sets the specified state on the specified call.
1694     *
1695     * @param call The call.
1696     * @param newState The new state of the call.
1697     */
1698    private void setCallState(Call call, int newState, String tag) {
1699        if (call == null) {
1700            return;
1701        }
1702        int oldState = call.getState();
1703        Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
1704                CallState.toString(newState), call);
1705        if (newState != oldState) {
1706            // Unfortunately, in the telephony world the radio is king. So if the call notifies
1707            // us that the call is in a particular state, we allow it even if it doesn't make
1708            // sense (e.g., STATE_ACTIVE -> STATE_RINGING).
1709            // TODO: Consider putting a stop to the above and turning CallState
1710            // into a well-defined state machine.
1711            // TODO: Define expected state transitions here, and log when an
1712            // unexpected transition occurs.
1713            call.setState(newState, tag);
1714            maybeShowErrorDialogOnDisconnect(call);
1715
1716            Trace.beginSection("onCallStateChanged");
1717            // Only broadcast state change for calls that are being tracked.
1718            if (mCalls.contains(call)) {
1719                updateCallsManagerState();
1720                for (CallsManagerListener listener : mListeners) {
1721                    if (Log.SYSTRACE_DEBUG) {
1722                        Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
1723                    }
1724                    listener.onCallStateChanged(call, oldState, newState);
1725                    if (Log.SYSTRACE_DEBUG) {
1726                        Trace.endSection();
1727                    }
1728                }
1729            }
1730            Trace.endSection();
1731        }
1732    }
1733
1734    private void updateCanAddCall() {
1735        boolean newCanAddCall = canAddCall();
1736        if (newCanAddCall != mCanAddCall) {
1737            mCanAddCall = newCanAddCall;
1738            for (CallsManagerListener listener : mListeners) {
1739                if (Log.SYSTRACE_DEBUG) {
1740                    Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
1741                }
1742                listener.onCanAddCallChanged(mCanAddCall);
1743                if (Log.SYSTRACE_DEBUG) {
1744                    Trace.endSection();
1745                }
1746            }
1747        }
1748    }
1749
1750    private void updateCallsManagerState() {
1751        updateCanAddCall();
1752    }
1753
1754    private boolean isPotentialMMICode(Uri handle) {
1755        return (handle != null && handle.getSchemeSpecificPart() != null
1756                && handle.getSchemeSpecificPart().contains("#"));
1757    }
1758
1759    /**
1760     * Determines if a dialed number is potentially an In-Call MMI code.  In-Call MMI codes are
1761     * MMI codes which can be dialed when one or more calls are in progress.
1762     * <P>
1763     * Checks for numbers formatted similar to the MMI codes defined in:
1764     * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)}
1765     *
1766     * @param handle The URI to call.
1767     * @return {@code True} if the URI represents a number which could be an in-call MMI code.
1768     */
1769    private boolean isPotentialInCallMMICode(Uri handle) {
1770        if (handle != null && handle.getSchemeSpecificPart() != null &&
1771                handle.getScheme() != null &&
1772                handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) {
1773
1774            String dialedNumber = handle.getSchemeSpecificPart();
1775            return (dialedNumber.equals("0") ||
1776                    (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) ||
1777                    (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) ||
1778                    dialedNumber.equals("3") ||
1779                    dialedNumber.equals("4") ||
1780                    dialedNumber.equals("5"));
1781        }
1782        return false;
1783    }
1784
1785    private int getNumCallsWithState(int... states) {
1786        int count = 0;
1787        for (int state : states) {
1788            for (Call call : mCalls) {
1789                if (call.getParentCall() == null && call.getState() == state) {
1790                    count++;
1791                }
1792            }
1793        }
1794        return count;
1795    }
1796
1797    private boolean hasMaximumLiveCalls() {
1798        return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(LIVE_CALL_STATES);
1799    }
1800
1801    private boolean hasMaximumHoldingCalls() {
1802        return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(CallState.ON_HOLD);
1803    }
1804
1805    private boolean hasMaximumRingingCalls() {
1806        return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(CallState.RINGING);
1807    }
1808
1809    private boolean hasMaximumOutgoingCalls() {
1810        return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(OUTGOING_CALL_STATES);
1811    }
1812
1813    private boolean hasMaximumDialingCalls() {
1814        return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(CallState.DIALING);
1815    }
1816
1817    private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) {
1818        if (hasMaximumLiveCalls()) {
1819            // NOTE: If the amount of live calls changes beyond 1, this logic will probably
1820            // have to change.
1821            Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
1822            Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
1823                   liveCall);
1824
1825            if (call == liveCall) {
1826                // If the call is already the foreground call, then we are golden.
1827                // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
1828                // state since the call was already populated into the list.
1829                return true;
1830            }
1831
1832            if (hasMaximumOutgoingCalls()) {
1833                Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
1834                if (isEmergency && !outgoingCall.isEmergencyCall()) {
1835                    // Disconnect the current outgoing call if it's not an emergency call. If the
1836                    // user tries to make two outgoing calls to different emergency call numbers,
1837                    // we will try to connect the first outgoing call.
1838                    call.getAnalytics().setCallIsAdditional(true);
1839                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
1840                    outgoingCall.disconnect();
1841                    return true;
1842                }
1843                if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
1844                    // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
1845                    // state, just disconnect it since the user has explicitly started a new call.
1846                    call.getAnalytics().setCallIsAdditional(true);
1847                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
1848                    outgoingCall.disconnect();
1849                    return true;
1850                }
1851                return false;
1852            }
1853
1854            if (hasMaximumHoldingCalls()) {
1855                // There is no more room for any more calls, unless it's an emergency.
1856                if (isEmergency) {
1857                    // Kill the current active call, this is easier then trying to disconnect a
1858                    // holding call and hold an active call.
1859                    call.getAnalytics().setCallIsAdditional(true);
1860                    liveCall.getAnalytics().setCallIsInterrupted(true);
1861                    liveCall.disconnect();
1862                    return true;
1863                }
1864                return false;  // No more room!
1865            }
1866
1867            // We have room for at least one more holding call at this point.
1868
1869            // TODO: Remove once b/23035408 has been corrected.
1870            // If the live call is a conference, it will not have a target phone account set.  This
1871            // means the check to see if the live call has the same target phone account as the new
1872            // call will not cause us to bail early.  As a result, we'll end up holding the
1873            // ongoing conference call.  However, the ConnectionService is already doing that.  This
1874            // has caused problems with some carriers.  As a workaround until b/23035408 is
1875            // corrected, we will try and get the target phone account for one of the conference's
1876            // children and use that instead.
1877            PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
1878            if (liveCallPhoneAccount == null && liveCall.isConference() &&
1879                    !liveCall.getChildCalls().isEmpty()) {
1880                liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
1881                Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
1882                        liveCallPhoneAccount);
1883            }
1884
1885            // First thing, if we are trying to make a call with the same phone account as the live
1886            // call, then allow it so that the connection service can make its own decision about
1887            // how to handle the new call relative to the current one.
1888            if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
1889                Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
1890                call.getAnalytics().setCallIsAdditional(true);
1891                liveCall.getAnalytics().setCallIsInterrupted(true);
1892                return true;
1893            } else if (call.getTargetPhoneAccount() == null) {
1894                // Without a phone account, we can't say reliably that the call will fail.
1895                // If the user chooses the same phone account as the live call, then it's
1896                // still possible that the call can be made (like with CDMA calls not supporting
1897                // hold but they still support adding a call by going immediately into conference
1898                // mode). Return true here and we'll run this code again after user chooses an
1899                // account.
1900                return true;
1901            }
1902
1903            // Try to hold the live call before attempting the new outgoing call.
1904            if (liveCall.can(Connection.CAPABILITY_HOLD)) {
1905                Log.i(this, "makeRoomForOutgoingCall: holding live call.");
1906                call.getAnalytics().setCallIsAdditional(true);
1907                liveCall.getAnalytics().setCallIsInterrupted(true);
1908                liveCall.hold();
1909                return true;
1910            }
1911
1912            // The live call cannot be held so we're out of luck here.  There's no room.
1913            return false;
1914        }
1915        return true;
1916    }
1917
1918    /**
1919     * Given a call, find the first non-null phone account handle of its children.
1920     *
1921     * @param parentCall The parent call.
1922     * @return The first non-null phone account handle of the children, or {@code null} if none.
1923     */
1924    private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
1925        for (Call childCall : parentCall.getChildCalls()) {
1926            PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
1927            if (childPhoneAccount != null) {
1928                return childPhoneAccount;
1929            }
1930        }
1931        return null;
1932    }
1933
1934    /**
1935     * Checks to see if the call should be on speakerphone and if so, set it.
1936     */
1937    private void maybeMoveToSpeakerPhone(Call call) {
1938        if (call.getStartWithSpeakerphoneOn()) {
1939            setAudioRoute(CallAudioState.ROUTE_SPEAKER);
1940            call.setStartWithSpeakerphoneOn(false);
1941        }
1942    }
1943
1944    /**
1945     * Creates a new call for an existing connection.
1946     *
1947     * @param callId The id of the new call.
1948     * @param connection The connection information.
1949     * @return The new call.
1950     */
1951    Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
1952        Call call = new Call(
1953                callId,
1954                mContext,
1955                this,
1956                mLock,
1957                mConnectionServiceRepository,
1958                mContactsAsyncHelper,
1959                mCallerInfoAsyncQueryFactory,
1960                connection.getHandle() /* handle */,
1961                null /* gatewayInfo */,
1962                null /* connectionManagerPhoneAccount */,
1963                connection.getPhoneAccount(), /* targetPhoneAccountHandle */
1964                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
1965                false /* forceAttachToExistingConnection */,
1966                false /* isConference */,
1967                connection.getConnectTimeMillis() /* connectTimeMillis */);
1968
1969        call.initAnalytics();
1970        call.getAnalytics().setCreatedFromExistingConnection(true);
1971
1972        setCallState(call, Call.getStateFromConnectionState(connection.getState()),
1973                "existing connection");
1974        call.setConnectionCapabilities(connection.getConnectionCapabilities());
1975        call.setConnectionProperties(connection.getConnectionProperties());
1976        call.setCallerDisplayName(connection.getCallerDisplayName(),
1977                connection.getCallerDisplayNamePresentation());
1978
1979        call.addListener(this);
1980        addCall(call);
1981
1982        return call;
1983    }
1984
1985    /**
1986     * @return A new unique telecom call Id.
1987     */
1988    private String getNextCallId() {
1989        synchronized(mLock) {
1990            return TELECOM_CALL_ID_PREFIX + (++mCallId);
1991        }
1992    }
1993
1994    /**
1995     * Callback when foreground user is switched. We will reload missed call in all profiles
1996     * including the user itself. There may be chances that profiles are not started yet.
1997     */
1998    void onUserSwitch(UserHandle userHandle) {
1999        mCurrentUserHandle = userHandle;
2000        mMissedCallNotifier.setCurrentUserHandle(userHandle);
2001        final UserManager userManager = UserManager.get(mContext);
2002        List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier());
2003        for (UserInfo profile : profiles) {
2004            reloadMissedCallsOfUser(profile.getUserHandle());
2005        }
2006    }
2007
2008    /**
2009     * Because there may be chances that profiles are not started yet though its parent user is
2010     * switched, we reload missed calls of profile that are just started here.
2011     */
2012    void onUserStarting(UserHandle userHandle) {
2013        if (UserUtil.isProfile(mContext, userHandle)) {
2014            reloadMissedCallsOfUser(userHandle);
2015        }
2016    }
2017
2018    private void reloadMissedCallsOfUser(UserHandle userHandle) {
2019        mMissedCallNotifier.reloadFromDatabase(
2020                mLock, this, mContactsAsyncHelper, mCallerInfoAsyncQueryFactory, userHandle);
2021    }
2022
2023    /**
2024     * Dumps the state of the {@link CallsManager}.
2025     *
2026     * @param pw The {@code IndentingPrintWriter} to write the state to.
2027     */
2028    public void dump(IndentingPrintWriter pw) {
2029        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
2030        if (mCalls != null) {
2031            pw.println("mCalls: ");
2032            pw.increaseIndent();
2033            for (Call call : mCalls) {
2034                pw.println(call);
2035            }
2036            pw.decreaseIndent();
2037        }
2038
2039        if (mCallAudioManager != null) {
2040            pw.println("mCallAudioManager:");
2041            pw.increaseIndent();
2042            mCallAudioManager.dump(pw);
2043            pw.decreaseIndent();
2044        }
2045
2046        if (mTtyManager != null) {
2047            pw.println("mTtyManager:");
2048            pw.increaseIndent();
2049            mTtyManager.dump(pw);
2050            pw.decreaseIndent();
2051        }
2052
2053        if (mInCallController != null) {
2054            pw.println("mInCallController:");
2055            pw.increaseIndent();
2056            mInCallController.dump(pw);
2057            pw.decreaseIndent();
2058        }
2059
2060        if (mConnectionServiceRepository != null) {
2061            pw.println("mConnectionServiceRepository:");
2062            pw.increaseIndent();
2063            mConnectionServiceRepository.dump(pw);
2064            pw.decreaseIndent();
2065        }
2066    }
2067
2068    /**
2069    * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code.
2070    *
2071    * @param call The call.
2072    */
2073    private void maybeShowErrorDialogOnDisconnect(Call call) {
2074        if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle())
2075                || isPotentialInCallMMICode(call.getHandle()))) {
2076            DisconnectCause disconnectCause = call.getDisconnectCause();
2077            if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode()
2078                    == DisconnectCause.ERROR)) {
2079                Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class);
2080                errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA,
2081                        disconnectCause.getDescription());
2082                errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2083                mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
2084            }
2085        }
2086    }
2087
2088    private void setIntentExtrasAndStartTime(Call call, Bundle extras) {
2089      // Create our own instance to modify (since extras may be Bundle.EMPTY)
2090      extras = new Bundle(extras);
2091
2092      // Specifies the time telecom began routing the call. This is used by the dialer for
2093      // analytics.
2094      extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
2095              SystemClock.elapsedRealtime());
2096
2097      call.setIntentExtras(extras);
2098    }
2099}
2100