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