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