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