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