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