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