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