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