CallsManager.java revision ad97242cf1565c31ce82cc4b8c144729b1e539d9
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 onExtrasChanged(Call c, int source, Bundle extras) {
1614        if (source != Call.SOURCE_CONNECTION_SERVICE) {
1615            return;
1616        }
1617        handleCallTechnologyChange(c);
1618        handleChildAddressChange(c);
1619        updateCanAddCall();
1620    }
1621
1622    // Construct the list of possible PhoneAccounts that the outgoing call can use based on the
1623    // active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount,
1624    // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP.
1625    @VisibleForTesting
1626    public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user,
1627            boolean isVideo) {
1628        if (handle == null) {
1629            return Collections.emptyList();
1630        }
1631        // If we're specifically looking for video capable accounts, then include that capability,
1632        // otherwise specify no additional capability constraints.
1633        List<PhoneAccountHandle> allAccounts =
1634                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user,
1635                        isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0 /* any */);
1636        // First check the Radio SIM Technology
1637        if(mRadioSimVariants == null) {
1638            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
1639                    Context.TELEPHONY_SERVICE);
1640            // Cache Sim Variants
1641            mRadioSimVariants = tm.getMultiSimConfiguration();
1642        }
1643        // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount
1644        // Should be available if a call is already active on the SIM account.
1645        if(mRadioSimVariants != TelephonyManager.MultiSimVariants.DSDA) {
1646            List<PhoneAccountHandle> simAccounts =
1647                    mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser();
1648            PhoneAccountHandle ongoingCallAccount = null;
1649            for (Call c : mCalls) {
1650                if (!c.isDisconnected() && !c.isNew() && simAccounts.contains(
1651                        c.getTargetPhoneAccount())) {
1652                    ongoingCallAccount = c.getTargetPhoneAccount();
1653                    break;
1654                }
1655            }
1656            if (ongoingCallAccount != null) {
1657                // Remove all SIM accounts that are not the active SIM from the list.
1658                simAccounts.remove(ongoingCallAccount);
1659                allAccounts.removeAll(simAccounts);
1660            }
1661        }
1662        return allAccounts;
1663    }
1664
1665    /**
1666     * Informs listeners (notably {@link CallAudioManager} of a change to the call's external
1667     * property.
1668     * .
1669     * @param call The call whose external property changed.
1670     * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise.
1671     */
1672    @Override
1673    public void onExternalCallChanged(Call call, boolean isExternalCall) {
1674        Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall);
1675        for (CallsManagerListener listener : mListeners) {
1676            listener.onExternalCallChanged(call, isExternalCall);
1677        }
1678    }
1679
1680    private void handleCallTechnologyChange(Call call) {
1681        if (call.getExtras() != null
1682                && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) {
1683
1684            Integer analyticsCallTechnology = sAnalyticsTechnologyMap.get(
1685                    call.getExtras().getInt(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE));
1686            if (analyticsCallTechnology == null) {
1687                analyticsCallTechnology = Analytics.THIRD_PARTY_PHONE;
1688            }
1689            call.getAnalytics().addCallTechnology(analyticsCallTechnology);
1690        }
1691    }
1692
1693    public void handleChildAddressChange(Call call) {
1694        if (call.getExtras() != null
1695                && call.getExtras().containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
1696
1697            String viaNumber = call.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS);
1698            call.setViaNumber(viaNumber);
1699        }
1700    }
1701
1702    /** Called by the in-call UI to change the mute state. */
1703    void mute(boolean shouldMute) {
1704        mCallAudioManager.mute(shouldMute);
1705    }
1706
1707    /**
1708      * Called by the in-call UI to change the audio route, for example to change from earpiece to
1709      * speaker phone.
1710      */
1711    void setAudioRoute(int route, String bluetoothAddress) {
1712        mCallAudioManager.setAudioRoute(route, bluetoothAddress);
1713    }
1714
1715    /** Called by the in-call UI to turn the proximity sensor on. */
1716    void turnOnProximitySensor() {
1717        mProximitySensorManager.turnOn();
1718    }
1719
1720    /**
1721     * Called by the in-call UI to turn the proximity sensor off.
1722     * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise,
1723     *        the screen will be kept off until the proximity sensor goes negative.
1724     */
1725    void turnOffProximitySensor(boolean screenOnImmediately) {
1726        mProximitySensorManager.turnOff(screenOnImmediately);
1727    }
1728
1729    void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
1730        if (!mCalls.contains(call)) {
1731            Log.i(this, "Attempted to add account to unknown call %s", call);
1732        } else {
1733            call.setTargetPhoneAccount(account);
1734            PhoneAccount realPhoneAccount =
1735                    mPhoneAccountRegistrar.getPhoneAccountUnchecked(account);
1736            if (realPhoneAccount != null && realPhoneAccount.getExtras() != null
1737                    && realPhoneAccount.getExtras()
1738                    .getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
1739                Log.d("phoneAccountSelected: default to voip mode for call %s", call.getId());
1740                call.setIsVoipAudioMode(true);
1741            }
1742            if (call.getIntentExtras()
1743                    .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
1744                if (realPhoneAccount != null
1745                        && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1746                    call.setRttStreams(true);
1747                }
1748            }
1749
1750            if (!call.isNewOutgoingCallIntentBroadcastDone()) {
1751                return;
1752            }
1753
1754            // Note: emergency calls never go through account selection dialog so they never
1755            // arrive here.
1756            if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) {
1757                call.startCreateConnection(mPhoneAccountRegistrar);
1758            } else {
1759                call.disconnect();
1760            }
1761
1762            if (setDefault) {
1763                mPhoneAccountRegistrar
1764                        .setUserSelectedOutgoingPhoneAccount(account, call.getInitiatingUser());
1765            }
1766        }
1767    }
1768
1769    /** Called when the audio state changes. */
1770    @VisibleForTesting
1771    public void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState
1772            newAudioState) {
1773        Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState);
1774        for (CallsManagerListener listener : mListeners) {
1775            listener.onCallAudioStateChanged(oldAudioState, newAudioState);
1776        }
1777    }
1778
1779    void markCallAsRinging(Call call) {
1780        setCallState(call, CallState.RINGING, "ringing set explicitly");
1781    }
1782
1783    void markCallAsDialing(Call call) {
1784        setCallState(call, CallState.DIALING, "dialing set explicitly");
1785        maybeMoveToSpeakerPhone(call);
1786    }
1787
1788    void markCallAsPulling(Call call) {
1789        setCallState(call, CallState.PULLING, "pulling set explicitly");
1790        maybeMoveToSpeakerPhone(call);
1791    }
1792
1793    void markCallAsActive(Call call) {
1794        setCallState(call, CallState.ACTIVE, "active set explicitly");
1795        maybeMoveToSpeakerPhone(call);
1796    }
1797
1798    @VisibleForTesting
1799    public void markCallAsOnHold(Call call) {
1800        setCallState(call, CallState.ON_HOLD, "on-hold set explicitly");
1801    }
1802
1803    /**
1804     * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the
1805     * last live call, then also disconnect from the in-call controller.
1806     *
1807     * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
1808     */
1809    void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
1810        call.setDisconnectCause(disconnectCause);
1811        setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
1812    }
1813
1814    /**
1815     * Removes an existing disconnected call, and notifies the in-call app.
1816     */
1817    void markCallAsRemoved(Call call) {
1818        call.maybeCleanupHandover();
1819        removeCall(call);
1820        Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
1821        if (mLocallyDisconnectingCalls.contains(call)) {
1822            boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
1823            Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = "
1824                + isDisconnectingChildCall + "call -> %s", call);
1825            mLocallyDisconnectingCalls.remove(call);
1826            // Auto-unhold the foreground call due to a locally disconnected call, except if the
1827            // call which was disconnected is a member of a conference (don't want to auto un-hold
1828            // the conference if we remove a member of the conference).
1829            if (!isDisconnectingChildCall && foregroundCall != null
1830                    && foregroundCall.getState() == CallState.ON_HOLD) {
1831                foregroundCall.unhold();
1832            }
1833        } else if (foregroundCall != null &&
1834                !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD)  &&
1835                foregroundCall.getState() == CallState.ON_HOLD) {
1836
1837            // The new foreground call is on hold, however the carrier does not display the hold
1838            // button in the UI.  Therefore, we need to auto unhold the held call since the user has
1839            // no means of unholding it themselves.
1840            Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)");
1841            foregroundCall.unhold();
1842        }
1843    }
1844
1845    /**
1846     * Given a call, marks the call as disconnected and removes it.  Set the error message to
1847     * indicate to the user that the call cannot me placed due to an ongoing call in another app.
1848     *
1849     * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed
1850     * call.  Called by {@link #startCallConfirmation(Call)} when the user is already confirming an
1851     * outgoing call.  Realistically this should almost never be called since in practice the user
1852     * won't make multiple outgoing calls at the same time.
1853     *
1854     * @param call The call to mark as disconnected.
1855     */
1856    void markCallDisconnectedDueToSelfManagedCall(Call call) {
1857        Call activeCall = getActiveCall();
1858        CharSequence errorMessage;
1859        if (activeCall == null) {
1860            // Realistically this shouldn't happen, but best to handle gracefully
1861            errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call);
1862        } else {
1863            errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call,
1864                    activeCall.getTargetPhoneAccountLabel());
1865        }
1866        // Call is managed and there are ongoing self-managed calls.
1867        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
1868                errorMessage, errorMessage, "Ongoing call in another app."));
1869        markCallAsRemoved(call);
1870    }
1871
1872    /**
1873     * Cleans up any calls currently associated with the specified connection service when the
1874     * service binder disconnects unexpectedly.
1875     *
1876     * @param service The connection service that disconnected.
1877     */
1878    void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
1879        if (service != null) {
1880            Log.i(this, "handleConnectionServiceDeath: service %s died", service);
1881            for (Call call : mCalls) {
1882                if (call.getConnectionService() == service) {
1883                    if (call.getState() != CallState.DISCONNECTED) {
1884                        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
1885                                "CS_DEATH"));
1886                    }
1887                    markCallAsRemoved(call);
1888                }
1889            }
1890        }
1891    }
1892
1893    /**
1894     * Determines if the {@link CallsManager} has any non-external calls.
1895     *
1896     * @return {@code True} if there are any non-external calls, {@code false} otherwise.
1897     */
1898    boolean hasAnyCalls() {
1899        if (mCalls.isEmpty()) {
1900            return false;
1901        }
1902
1903        for (Call call : mCalls) {
1904            if (!call.isExternalCall()) {
1905                return true;
1906            }
1907        }
1908        return false;
1909    }
1910
1911    boolean hasActiveOrHoldingCall() {
1912        return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null;
1913    }
1914
1915    boolean hasRingingCall() {
1916        return getFirstCallWithState(CallState.RINGING) != null;
1917    }
1918
1919    boolean onMediaButton(int type) {
1920        if (hasAnyCalls()) {
1921            Call ringingCall = getFirstCallWithState(CallState.RINGING);
1922            if (HeadsetMediaButton.SHORT_PRESS == type) {
1923                if (ringingCall == null) {
1924                    Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING,
1925                            CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD);
1926                    Log.addEvent(callToHangup, LogUtils.Events.INFO,
1927                            "media btn short press - end call.");
1928                    if (callToHangup != null) {
1929                        disconnectCall(callToHangup);
1930                        return true;
1931                    }
1932                } else {
1933                    ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
1934                    return true;
1935                }
1936            } else if (HeadsetMediaButton.LONG_PRESS == type) {
1937                if (ringingCall != null) {
1938                    Log.addEvent(getForegroundCall(),
1939                            LogUtils.Events.INFO, "media btn long press - reject");
1940                    ringingCall.reject(false, null);
1941                } else {
1942                    Log.addEvent(getForegroundCall(), LogUtils.Events.INFO,
1943                            "media btn long press - mute");
1944                    mCallAudioManager.toggleMute();
1945                }
1946                return true;
1947            }
1948        }
1949        return false;
1950    }
1951
1952    /**
1953     * Returns true if telecom supports adding another top-level call.
1954     */
1955    @VisibleForTesting
1956    public boolean canAddCall() {
1957        boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
1958                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
1959        if (!isDeviceProvisioned) {
1960            Log.d(TAG, "Device not provisioned, canAddCall is false.");
1961            return false;
1962        }
1963
1964        if (getFirstCallWithState(OUTGOING_CALL_STATES) != null) {
1965            return false;
1966        }
1967
1968        int count = 0;
1969        for (Call call : mCalls) {
1970            if (call.isEmergencyCall()) {
1971                // We never support add call if one of the calls is an emergency call.
1972                return false;
1973            } else if (call.isExternalCall()) {
1974                // External calls don't count.
1975                continue;
1976            } else if (call.getParentCall() == null) {
1977                count++;
1978            }
1979            Bundle extras = call.getExtras();
1980            if (extras != null) {
1981                if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) {
1982                    return false;
1983                }
1984            }
1985
1986            // We do not check states for canAddCall. We treat disconnected calls the same
1987            // and wait until they are removed instead. If we didn't count disconnected calls,
1988            // we could put InCallServices into a state where they are showing two calls but
1989            // also support add-call. Technically it's right, but overall looks better (UI-wise)
1990            // and acts better if we wait until the call is removed.
1991            if (count >= MAXIMUM_TOP_LEVEL_CALLS) {
1992                return false;
1993            }
1994        }
1995
1996        return true;
1997    }
1998
1999    @VisibleForTesting
2000    public Call getRingingCall() {
2001        return getFirstCallWithState(CallState.RINGING);
2002    }
2003
2004    public Call getActiveCall() {
2005        return getFirstCallWithState(CallState.ACTIVE);
2006    }
2007
2008    Call getDialingCall() {
2009        return getFirstCallWithState(CallState.DIALING);
2010    }
2011
2012    @VisibleForTesting
2013    public Call getHeldCall() {
2014        return getFirstCallWithState(CallState.ON_HOLD);
2015    }
2016
2017    @VisibleForTesting
2018    public int getNumHeldCalls() {
2019        int count = 0;
2020        for (Call call : mCalls) {
2021            if (call.getParentCall() == null && call.getState() == CallState.ON_HOLD) {
2022                count++;
2023            }
2024        }
2025        return count;
2026    }
2027
2028    @VisibleForTesting
2029    public Call getOutgoingCall() {
2030        return getFirstCallWithState(OUTGOING_CALL_STATES);
2031    }
2032
2033    @VisibleForTesting
2034    public Call getFirstCallWithState(int... states) {
2035        return getFirstCallWithState(null, states);
2036    }
2037
2038    @VisibleForTesting
2039    public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() {
2040        return mPhoneNumberUtilsAdapter;
2041    }
2042
2043    /**
2044     * Returns the first call that it finds with the given states. The states are treated as having
2045     * priority order so that any call with the first state will be returned before any call with
2046     * states listed later in the parameter list.
2047     *
2048     * @param callToSkip Call that this method should skip while searching
2049     */
2050    Call getFirstCallWithState(Call callToSkip, int... states) {
2051        for (int currentState : states) {
2052            // check the foreground first
2053            Call foregroundCall = getForegroundCall();
2054            if (foregroundCall != null && foregroundCall.getState() == currentState) {
2055                return foregroundCall;
2056            }
2057
2058            for (Call call : mCalls) {
2059                if (Objects.equals(callToSkip, call)) {
2060                    continue;
2061                }
2062
2063                // Only operate on top-level calls
2064                if (call.getParentCall() != null) {
2065                    continue;
2066                }
2067
2068                if (call.isExternalCall()) {
2069                    continue;
2070                }
2071
2072                if (currentState == call.getState()) {
2073                    return call;
2074                }
2075            }
2076        }
2077        return null;
2078    }
2079
2080    Call createConferenceCall(
2081            String callId,
2082            PhoneAccountHandle phoneAccount,
2083            ParcelableConference parcelableConference) {
2084
2085        // If the parceled conference specifies a connect time, use it; otherwise default to 0,
2086        // which is the default value for new Calls.
2087        long connectTime =
2088                parcelableConference.getConnectTimeMillis() ==
2089                        Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
2090                        parcelableConference.getConnectTimeMillis();
2091        long connectElapsedTime =
2092                parcelableConference.getConnectElapsedTimeMillis() ==
2093                        Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
2094                        parcelableConference.getConnectElapsedTimeMillis();
2095
2096        Call call = new Call(
2097                callId,
2098                mContext,
2099                this,
2100                mLock,
2101                mConnectionServiceRepository,
2102                mContactsAsyncHelper,
2103                mCallerInfoAsyncQueryFactory,
2104                mPhoneNumberUtilsAdapter,
2105                null /* handle */,
2106                null /* gatewayInfo */,
2107                null /* connectionManagerPhoneAccount */,
2108                phoneAccount,
2109                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
2110                false /* forceAttachToExistingConnection */,
2111                true /* isConference */,
2112                connectTime,
2113                connectElapsedTime,
2114                mClockProxy);
2115
2116        setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
2117                "new conference call");
2118        call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities());
2119        call.setConnectionProperties(parcelableConference.getConnectionProperties());
2120        call.setVideoState(parcelableConference.getVideoState());
2121        call.setVideoProvider(parcelableConference.getVideoProvider());
2122        call.setStatusHints(parcelableConference.getStatusHints());
2123        call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
2124        // In case this Conference was added via a ConnectionManager, keep track of the original
2125        // Connection ID as created by the originating ConnectionService.
2126        Bundle extras = parcelableConference.getExtras();
2127        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
2128            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
2129        }
2130
2131        // TODO: Move this to be a part of addCall()
2132        call.addListener(this);
2133        addCall(call);
2134        return call;
2135    }
2136
2137    /**
2138     * @return the call state currently tracked by {@link PhoneStateBroadcaster}
2139     */
2140    int getCallState() {
2141        return mPhoneStateBroadcaster.getCallState();
2142    }
2143
2144    /**
2145     * Retrieves the {@link PhoneAccountRegistrar}.
2146     *
2147     * @return The {@link PhoneAccountRegistrar}.
2148     */
2149    PhoneAccountRegistrar getPhoneAccountRegistrar() {
2150        return mPhoneAccountRegistrar;
2151    }
2152
2153    /**
2154     * Retrieves the {@link MissedCallNotifier}
2155     * @return The {@link MissedCallNotifier}.
2156     */
2157    MissedCallNotifier getMissedCallNotifier() {
2158        return mMissedCallNotifier;
2159    }
2160
2161    /**
2162     * Retrieves the {@link IncomingCallNotifier}.
2163     * @return The {@link IncomingCallNotifier}.
2164     */
2165    IncomingCallNotifier getIncomingCallNotifier() {
2166        return mIncomingCallNotifier;
2167    }
2168
2169    /**
2170     * Reject an incoming call and manually add it to the Call Log.
2171     * @param incomingCall Incoming call that has been rejected
2172     */
2173    private void rejectCallAndLog(Call incomingCall) {
2174        if (incomingCall.getConnectionService() != null) {
2175            // Only reject the call if it has not already been destroyed.  If a call ends while
2176            // incoming call filtering is taking place, it is possible that the call has already
2177            // been destroyed, and as such it will be impossible to send the reject to the
2178            // associated ConnectionService.
2179            incomingCall.reject(false, null);
2180        } else {
2181            Log.i(this, "rejectCallAndLog - call already destroyed.");
2182        }
2183
2184        // Since the call was not added to the list of calls, we have to call the missed
2185        // call notifier and the call logger manually.
2186        // Do we need missed call notification for direct to Voicemail calls?
2187        mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
2188                true /*showNotificationForMissedCall*/);
2189    }
2190
2191    /**
2192     * Adds the specified call to the main list of live calls.
2193     *
2194     * @param call The call to add.
2195     */
2196    @VisibleForTesting
2197    public void addCall(Call call) {
2198        Trace.beginSection("addCall");
2199        Log.v(this, "addCall(%s)", call);
2200        call.addListener(this);
2201        mCalls.add(call);
2202
2203        // Specifies the time telecom finished routing the call. This is used by the dialer for
2204        // analytics.
2205        Bundle extras = call.getIntentExtras();
2206        extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
2207                SystemClock.elapsedRealtime());
2208
2209        updateCanAddCall();
2210        // onCallAdded for calls which immediately take the foreground (like the first call).
2211        for (CallsManagerListener listener : mListeners) {
2212            if (LogUtils.SYSTRACE_DEBUG) {
2213                Trace.beginSection(listener.getClass().toString() + " addCall");
2214            }
2215            listener.onCallAdded(call);
2216            if (LogUtils.SYSTRACE_DEBUG) {
2217                Trace.endSection();
2218            }
2219        }
2220        Trace.endSection();
2221    }
2222
2223    private void removeCall(Call call) {
2224        Trace.beginSection("removeCall");
2225        Log.v(this, "removeCall(%s)", call);
2226
2227        call.setParentAndChildCall(null);  // clean up parent relationship before destroying.
2228        call.removeListener(this);
2229        call.clearConnectionService();
2230        // TODO: clean up RTT pipes
2231
2232        boolean shouldNotify = false;
2233        if (mCalls.contains(call)) {
2234            mCalls.remove(call);
2235            shouldNotify = true;
2236        }
2237
2238        call.destroy();
2239
2240        // Only broadcast changes for calls that are being tracked.
2241        if (shouldNotify) {
2242            updateCanAddCall();
2243            for (CallsManagerListener listener : mListeners) {
2244                if (LogUtils.SYSTRACE_DEBUG) {
2245                    Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
2246                }
2247                listener.onCallRemoved(call);
2248                if (LogUtils.SYSTRACE_DEBUG) {
2249                    Trace.endSection();
2250                }
2251            }
2252        }
2253        Trace.endSection();
2254    }
2255
2256    /**
2257     * Sets the specified state on the specified call.
2258     *
2259     * @param call The call.
2260     * @param newState The new state of the call.
2261     */
2262    private void setCallState(Call call, int newState, String tag) {
2263        if (call == null) {
2264            return;
2265        }
2266        int oldState = call.getState();
2267        Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
2268                CallState.toString(newState), call);
2269        if (newState != oldState) {
2270            // If the call switches to held state while a DTMF tone is playing, stop the tone to
2271            // ensure that the tone generator stops playing the tone.
2272            if (newState == CallState.ON_HOLD && call.isDtmfTonePlaying()) {
2273                stopDtmfTone(call);
2274            }
2275
2276            // Unfortunately, in the telephony world the radio is king. So if the call notifies
2277            // us that the call is in a particular state, we allow it even if it doesn't make
2278            // sense (e.g., STATE_ACTIVE -> STATE_RINGING).
2279            // TODO: Consider putting a stop to the above and turning CallState
2280            // into a well-defined state machine.
2281            // TODO: Define expected state transitions here, and log when an
2282            // unexpected transition occurs.
2283            call.setState(newState, tag);
2284            maybeShowErrorDialogOnDisconnect(call);
2285
2286            Trace.beginSection("onCallStateChanged");
2287
2288            maybeHandleHandover(call, newState);
2289
2290            // Only broadcast state change for calls that are being tracked.
2291            if (mCalls.contains(call)) {
2292                updateCanAddCall();
2293                for (CallsManagerListener listener : mListeners) {
2294                    if (LogUtils.SYSTRACE_DEBUG) {
2295                        Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
2296                    }
2297                    listener.onCallStateChanged(call, oldState, newState);
2298                    if (LogUtils.SYSTRACE_DEBUG) {
2299                        Trace.endSection();
2300                    }
2301                }
2302            }
2303            Trace.endSection();
2304        }
2305    }
2306
2307    /**
2308     * Identifies call state transitions for a call which trigger handover events.
2309     * - If this call has a handover to it which just started and this call goes active, treat
2310     * this as if the user accepted the handover.
2311     * - If this call has a handover to it which just started and this call is disconnected, treat
2312     * this as if the user rejected the handover.
2313     * - If this call has a handover from it which just started and this call is disconnected, do
2314     * nothing as the call prematurely disconnected before the user accepted the handover.
2315     * - If this call has a handover from it which was already accepted by the user and this call is
2316     * disconnected, mark the handover as complete.
2317     *
2318     * @param call A call whose state is changing.
2319     * @param newState The new state of the call.
2320     */
2321    private void maybeHandleHandover(Call call, int newState) {
2322        if (call.getHandoverSourceCall() != null) {
2323            // We are handing over another call to this one.
2324            if (call.getHandoverState() == HandoverState.HANDOVER_TO_STARTED) {
2325                // A handover to this call has just been initiated.
2326                if (newState == CallState.ACTIVE) {
2327                    // This call went active, so the user has accepted the handover.
2328                    Log.i(this, "setCallState: handover to accepted");
2329                    acceptHandoverTo(call);
2330                } else if (newState == CallState.DISCONNECTED) {
2331                    // The call was disconnected, so the user has rejected the handover.
2332                    Log.i(this, "setCallState: handover to rejected");
2333                    rejectHandoverTo(call);
2334                }
2335            }
2336        // If this call was disconnected because it was handed over TO another call, report the
2337        // handover as complete.
2338        } else if (call.getHandoverDestinationCall() != null
2339                && newState == CallState.DISCONNECTED) {
2340            int handoverState = call.getHandoverState();
2341            if (handoverState == HandoverState.HANDOVER_FROM_STARTED) {
2342                // Disconnect before handover was accepted.
2343                Log.i(this, "setCallState: disconnect before handover accepted");
2344                // Let the handover destination know that the source has disconnected prior to
2345                // completion of the handover.
2346                call.getHandoverDestinationCall().sendCallEvent(
2347                        android.telecom.Call.EVENT_HANDOVER_SOURCE_DISCONNECTED, null);
2348            } else if (handoverState == HandoverState.HANDOVER_ACCEPTED) {
2349                Log.i(this, "setCallState: handover from complete");
2350                completeHandoverFrom(call);
2351            }
2352        }
2353    }
2354
2355    private void completeHandoverFrom(Call call) {
2356        Call handoverTo = call.getHandoverDestinationCall();
2357        Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2358                call.getId(), handoverTo.getId());
2359        Log.addEvent(call, LogUtils.Events.HANDOVER_COMPLETE, "from=%s, to=%s",
2360                call.getId(), handoverTo.getId());
2361
2362        // Inform the "from" Call (ie the source call) that the handover from it has
2363        // completed; this allows the InCallService to be notified that a handover it
2364        // initiated completed.
2365        call.onConnectionEvent(Connection.EVENT_HANDOVER_COMPLETE, null);
2366        // Inform the "to" ConnectionService that handover to it has completed.
2367        handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
2368        answerCall(handoverTo, handoverTo.getVideoState());
2369        call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE);
2370
2371        // If the call we handed over to is self-managed, we need to disconnect the calls for other
2372        // ConnectionServices.
2373        if (handoverTo.isSelfManaged()) {
2374            disconnectOtherCalls(handoverTo.getTargetPhoneAccount());
2375        }
2376    }
2377
2378    private void rejectHandoverTo(Call handoverTo) {
2379        Call handoverFrom = handoverTo.getHandoverSourceCall();
2380        Log.i(this, "rejectHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId());
2381        Log.addEvent(handoverFrom, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s",
2382                handoverTo.getId(), handoverFrom.getId());
2383        Log.addEvent(handoverTo, LogUtils.Events.HANDOVER_FAILED, "from=%s, to=%s",
2384                handoverTo.getId(), handoverFrom.getId());
2385
2386        // Inform the "from" Call (ie the source call) that the handover from it has
2387        // failed; this allows the InCallService to be notified that a handover it
2388        // initiated failed.
2389        handoverFrom.onConnectionEvent(Connection.EVENT_HANDOVER_FAILED, null);
2390        // Inform the "to" ConnectionService that handover to it has failed.  This
2391        // allows the ConnectionService the call was being handed over
2392        if (handoverTo.getConnectionService() != null) {
2393            // Only attempt if the call has a bound ConnectionService if handover failed
2394            // early on in the handover process, the CS will be unbound and we won't be
2395            // able to send the call event.
2396            handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null);
2397        }
2398        handoverTo.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_FAILED);
2399    }
2400
2401    private void acceptHandoverTo(Call handoverTo) {
2402        Call handoverFrom = handoverTo.getHandoverSourceCall();
2403        Log.i(this, "acceptHandoverTo: from=%s, to=%s", handoverFrom.getId(), handoverTo.getId());
2404        handoverTo.setHandoverState(HandoverState.HANDOVER_ACCEPTED);
2405        handoverFrom.setHandoverState(HandoverState.HANDOVER_ACCEPTED);
2406
2407        Log.addEvent(handoverTo, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s",
2408                handoverFrom.getId(), handoverTo.getId());
2409        Log.addEvent(handoverFrom, LogUtils.Events.ACCEPT_HANDOVER, "from=%s, to=%s",
2410                handoverFrom.getId(), handoverTo.getId());
2411
2412        // Disconnect the call we handed over from.
2413        disconnectCall(handoverFrom);
2414        // If we handed over to a self-managed ConnectionService, we need to disconnect calls for
2415        // other ConnectionServices.
2416        if (handoverTo.isSelfManaged()) {
2417            disconnectOtherCalls(handoverTo.getTargetPhoneAccount());
2418        }
2419    }
2420
2421    private void updateCanAddCall() {
2422        boolean newCanAddCall = canAddCall();
2423        if (newCanAddCall != mCanAddCall) {
2424            mCanAddCall = newCanAddCall;
2425            for (CallsManagerListener listener : mListeners) {
2426                if (LogUtils.SYSTRACE_DEBUG) {
2427                    Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
2428                }
2429                listener.onCanAddCallChanged(mCanAddCall);
2430                if (LogUtils.SYSTRACE_DEBUG) {
2431                    Trace.endSection();
2432                }
2433            }
2434        }
2435    }
2436
2437    private boolean isPotentialMMICode(Uri handle) {
2438        return (handle != null && handle.getSchemeSpecificPart() != null
2439                && handle.getSchemeSpecificPart().contains("#"));
2440    }
2441
2442    /**
2443     * Determines if a dialed number is potentially an In-Call MMI code.  In-Call MMI codes are
2444     * MMI codes which can be dialed when one or more calls are in progress.
2445     * <P>
2446     * Checks for numbers formatted similar to the MMI codes defined in:
2447     * {@link com.android.internal.telephony.Phone#handleInCallMmiCommands(String)}
2448     *
2449     * @param handle The URI to call.
2450     * @return {@code True} if the URI represents a number which could be an in-call MMI code.
2451     */
2452    private boolean isPotentialInCallMMICode(Uri handle) {
2453        if (handle != null && handle.getSchemeSpecificPart() != null &&
2454                handle.getScheme() != null &&
2455                handle.getScheme().equals(PhoneAccount.SCHEME_TEL)) {
2456
2457            String dialedNumber = handle.getSchemeSpecificPart();
2458            return (dialedNumber.equals("0") ||
2459                    (dialedNumber.startsWith("1") && dialedNumber.length() <= 2) ||
2460                    (dialedNumber.startsWith("2") && dialedNumber.length() <= 2) ||
2461                    dialedNumber.equals("3") ||
2462                    dialedNumber.equals("4") ||
2463                    dialedNumber.equals("5"));
2464        }
2465        return false;
2466    }
2467
2468    @VisibleForTesting
2469    public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
2470                                    PhoneAccountHandle phoneAccountHandle, int... states) {
2471        return getNumCallsWithState(isSelfManaged ? CALL_FILTER_SELF_MANAGED : CALL_FILTER_MANAGED,
2472                excludeCall, phoneAccountHandle, states);
2473    }
2474
2475    /**
2476     * Determines the number of calls matching the specified criteria.
2477     * @param callFilter indicates whether to include just managed calls
2478     *                   ({@link #CALL_FILTER_MANAGED}), self-managed calls
2479     *                   ({@link #CALL_FILTER_SELF_MANAGED}), or all calls
2480     *                   ({@link #CALL_FILTER_ALL}).
2481     * @param excludeCall Where {@code non-null}, this call is excluded from the count.
2482     * @param phoneAccountHandle Where {@code non-null}, calls for this {@link PhoneAccountHandle}
2483     *                           are excluded from the count.
2484     * @param states The list of {@link CallState}s to include in the count.
2485     * @return Count of calls matching criteria.
2486     */
2487    @VisibleForTesting
2488    public int getNumCallsWithState(final int callFilter, Call excludeCall,
2489                                    PhoneAccountHandle phoneAccountHandle, int... states) {
2490
2491        Set<Integer> desiredStates = IntStream.of(states).boxed().collect(Collectors.toSet());
2492
2493        Stream<Call> callsStream = mCalls.stream()
2494                .filter(call -> desiredStates.contains(call.getState()) &&
2495                        call.getParentCall() == null && !call.isExternalCall());
2496
2497        if (callFilter == CALL_FILTER_MANAGED) {
2498            callsStream = callsStream.filter(call -> !call.isSelfManaged());
2499        } else if (callFilter == CALL_FILTER_SELF_MANAGED) {
2500            callsStream = callsStream.filter(call -> call.isSelfManaged());
2501        }
2502
2503        // If a call to exclude was specified, filter it out.
2504        if (excludeCall != null) {
2505            callsStream = callsStream.filter(call -> call != excludeCall);
2506        }
2507
2508        // If a phone account handle was specified, only consider calls for that phone account.
2509        if (phoneAccountHandle != null) {
2510            callsStream = callsStream.filter(
2511                    call -> phoneAccountHandle.equals(call.getTargetPhoneAccount()));
2512        }
2513
2514        return (int) callsStream.count();
2515    }
2516
2517    private boolean hasMaximumManagedLiveCalls(Call exceptCall) {
2518        return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(false /* isSelfManaged */,
2519                exceptCall, null /* phoneAccountHandle */, LIVE_CALL_STATES);
2520    }
2521
2522    private boolean hasMaximumSelfManagedCalls(Call exceptCall,
2523                                                   PhoneAccountHandle phoneAccountHandle) {
2524        return MAXIMUM_SELF_MANAGED_CALLS <= getNumCallsWithState(true /* isSelfManaged */,
2525                exceptCall, phoneAccountHandle, ANY_CALL_STATE);
2526    }
2527
2528    private boolean hasMaximumManagedHoldingCalls(Call exceptCall) {
2529        return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2530                null /* phoneAccountHandle */, CallState.ON_HOLD);
2531    }
2532
2533    private boolean hasMaximumManagedRingingCalls(Call exceptCall) {
2534        return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2535                null /* phoneAccountHandle */, CallState.RINGING);
2536    }
2537
2538    private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall,
2539                                                      PhoneAccountHandle phoneAccountHandle) {
2540        return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall,
2541                phoneAccountHandle, CallState.RINGING);
2542    }
2543
2544    private boolean hasMaximumManagedOutgoingCalls(Call exceptCall) {
2545        return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2546                null /* phoneAccountHandle */, OUTGOING_CALL_STATES);
2547    }
2548
2549    private boolean hasMaximumManagedDialingCalls(Call exceptCall) {
2550        return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
2551                null /* phoneAccountHandle */, CallState.DIALING, CallState.PULLING);
2552    }
2553
2554    /**
2555     * Given a {@link PhoneAccountHandle} determines if there are calls owned by any other
2556     * {@link PhoneAccountHandle}.
2557     * @param phoneAccountHandle The {@link PhoneAccountHandle} to check.
2558     * @return {@code true} if there are other calls, {@code false} otherwise.
2559     */
2560    public boolean hasCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2561        return getNumCallsForOtherPhoneAccount(phoneAccountHandle) > 0;
2562    }
2563
2564    /**
2565     * Determines the number of calls present for PhoneAccounts other than the one specified.
2566     * @param phoneAccountHandle The handle of the PhoneAccount.
2567     * @return Number of calls owned by other PhoneAccounts.
2568     */
2569    public int getNumCallsForOtherPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
2570        return (int) mCalls.stream().filter(call ->
2571                !phoneAccountHandle.equals(call.getTargetPhoneAccount()) &&
2572                        call.getParentCall() == null &&
2573                        !call.isExternalCall()).count();
2574    }
2575
2576    /**
2577     * Determines if there are any managed calls.
2578     * @return {@code true} if there are managed calls, {@code false} otherwise.
2579     */
2580    public boolean hasManagedCalls() {
2581        return mCalls.stream().filter(call -> !call.isSelfManaged() &&
2582                !call.isExternalCall()).count() > 0;
2583    }
2584
2585    /**
2586     * Determines if there are any self-managed calls.
2587     * @return {@code true} if there are self-managed calls, {@code false} otherwise.
2588     */
2589    public boolean hasSelfManagedCalls() {
2590        return mCalls.stream().filter(call -> call.isSelfManaged()).count() > 0;
2591    }
2592
2593    /**
2594     * Determines if there are any ongoing managed or self-managed calls.
2595     * Note: The {@link #ONGOING_CALL_STATES} are
2596     * @return {@code true} if there are ongoing managed or self-managed calls, {@code false}
2597     *      otherwise.
2598     */
2599    public boolean hasOngoingCalls() {
2600        return getNumCallsWithState(
2601                CALL_FILTER_ALL, null /* excludeCall */,
2602                null /* phoneAccountHandle */,
2603                ONGOING_CALL_STATES) > 0;
2604    }
2605
2606    /**
2607     * Determines if there are any ongoing managed calls.
2608     * @return {@code true} if there are ongoing managed calls, {@code false} otherwise.
2609     */
2610    public boolean hasOngoingManagedCalls() {
2611        return getNumCallsWithState(
2612                CALL_FILTER_MANAGED, null /* excludeCall */,
2613                null /* phoneAccountHandle */,
2614                ONGOING_CALL_STATES) > 0;
2615    }
2616
2617    /**
2618     * Determines if the system incoming call UI should be shown.
2619     * The system incoming call UI will be shown if the new incoming call is self-managed, and there
2620     * are ongoing calls for another PhoneAccount.
2621     * @param incomingCall The incoming call.
2622     * @return {@code true} if the system incoming call UI should be shown, {@code false} otherwise.
2623     */
2624    public boolean shouldShowSystemIncomingCallUi(Call incomingCall) {
2625        return incomingCall.isIncoming() && incomingCall.isSelfManaged() &&
2626                hasCallsForOtherPhoneAccount(incomingCall.getTargetPhoneAccount()) &&
2627                incomingCall.getHandoverSourceCall() == null;
2628    }
2629
2630    private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) {
2631        if (hasMaximumManagedLiveCalls(call)) {
2632            // NOTE: If the amount of live calls changes beyond 1, this logic will probably
2633            // have to change.
2634            Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
2635            Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
2636                   liveCall);
2637
2638            if (call == liveCall) {
2639                // If the call is already the foreground call, then we are golden.
2640                // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
2641                // state since the call was already populated into the list.
2642                return true;
2643            }
2644
2645            if (hasMaximumManagedOutgoingCalls(call)) {
2646                Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
2647                if (isEmergency && !outgoingCall.isEmergencyCall()) {
2648                    // Disconnect the current outgoing call if it's not an emergency call. If the
2649                    // user tries to make two outgoing calls to different emergency call numbers,
2650                    // we will try to connect the first outgoing call.
2651                    call.getAnalytics().setCallIsAdditional(true);
2652                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
2653                    outgoingCall.disconnect();
2654                    return true;
2655                }
2656                if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
2657                    // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
2658                    // state, just disconnect it since the user has explicitly started a new call.
2659                    call.getAnalytics().setCallIsAdditional(true);
2660                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
2661                    outgoingCall.disconnect();
2662                    return true;
2663                }
2664                return false;
2665            }
2666
2667            if (hasMaximumManagedHoldingCalls(call)) {
2668                // There is no more room for any more calls, unless it's an emergency.
2669                if (isEmergency) {
2670                    // Kill the current active call, this is easier then trying to disconnect a
2671                    // holding call and hold an active call.
2672                    call.getAnalytics().setCallIsAdditional(true);
2673                    liveCall.getAnalytics().setCallIsInterrupted(true);
2674                    liveCall.disconnect();
2675                    return true;
2676                }
2677                return false;  // No more room!
2678            }
2679
2680            // We have room for at least one more holding call at this point.
2681
2682            // TODO: Remove once b/23035408 has been corrected.
2683            // If the live call is a conference, it will not have a target phone account set.  This
2684            // means the check to see if the live call has the same target phone account as the new
2685            // call will not cause us to bail early.  As a result, we'll end up holding the
2686            // ongoing conference call.  However, the ConnectionService is already doing that.  This
2687            // has caused problems with some carriers.  As a workaround until b/23035408 is
2688            // corrected, we will try and get the target phone account for one of the conference's
2689            // children and use that instead.
2690            PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
2691            if (liveCallPhoneAccount == null && liveCall.isConference() &&
2692                    !liveCall.getChildCalls().isEmpty()) {
2693                liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
2694                Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
2695                        liveCallPhoneAccount);
2696            }
2697
2698            // First thing, if we are trying to make a call with the same phone account as the live
2699            // call, then allow it so that the connection service can make its own decision about
2700            // how to handle the new call relative to the current one.
2701            if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
2702                Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
2703                call.getAnalytics().setCallIsAdditional(true);
2704                liveCall.getAnalytics().setCallIsInterrupted(true);
2705                return true;
2706            } else if (call.getTargetPhoneAccount() == null) {
2707                // Without a phone account, we can't say reliably that the call will fail.
2708                // If the user chooses the same phone account as the live call, then it's
2709                // still possible that the call can be made (like with CDMA calls not supporting
2710                // hold but they still support adding a call by going immediately into conference
2711                // mode). Return true here and we'll run this code again after user chooses an
2712                // account.
2713                return true;
2714            }
2715
2716            // Try to hold the live call before attempting the new outgoing call.
2717            if (liveCall.can(Connection.CAPABILITY_HOLD)) {
2718                Log.i(this, "makeRoomForOutgoingCall: holding live call.");
2719                call.getAnalytics().setCallIsAdditional(true);
2720                liveCall.getAnalytics().setCallIsInterrupted(true);
2721                liveCall.hold();
2722                return true;
2723            }
2724
2725            // The live call cannot be held so we're out of luck here.  There's no room.
2726            return false;
2727        }
2728        return true;
2729    }
2730
2731    /**
2732     * Given a call, find the first non-null phone account handle of its children.
2733     *
2734     * @param parentCall The parent call.
2735     * @return The first non-null phone account handle of the children, or {@code null} if none.
2736     */
2737    private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
2738        for (Call childCall : parentCall.getChildCalls()) {
2739            PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
2740            if (childPhoneAccount != null) {
2741                return childPhoneAccount;
2742            }
2743        }
2744        return null;
2745    }
2746
2747    /**
2748     * Checks to see if the call should be on speakerphone and if so, set it.
2749     */
2750    private void maybeMoveToSpeakerPhone(Call call) {
2751        if (call.isHandoverInProgress() && call.getState() == CallState.DIALING) {
2752            // When a new outgoing call is initiated for the purpose of handing over, do not engage
2753            // speaker automatically until the call goes active.
2754            return;
2755        }
2756        if (call.getStartWithSpeakerphoneOn()) {
2757            setAudioRoute(CallAudioState.ROUTE_SPEAKER, null);
2758            call.setStartWithSpeakerphoneOn(false);
2759        }
2760    }
2761
2762    /**
2763     * Creates a new call for an existing connection.
2764     *
2765     * @param callId The id of the new call.
2766     * @param connection The connection information.
2767     * @return The new call.
2768     */
2769    Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
2770        boolean isDowngradedConference = (connection.getConnectionProperties()
2771                & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
2772        Call call = new Call(
2773                callId,
2774                mContext,
2775                this,
2776                mLock,
2777                mConnectionServiceRepository,
2778                mContactsAsyncHelper,
2779                mCallerInfoAsyncQueryFactory,
2780                mPhoneNumberUtilsAdapter,
2781                connection.getHandle() /* handle */,
2782                null /* gatewayInfo */,
2783                null /* connectionManagerPhoneAccount */,
2784                connection.getPhoneAccount(), /* targetPhoneAccountHandle */
2785                Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
2786                false /* forceAttachToExistingConnection */,
2787                isDowngradedConference /* isConference */,
2788                connection.getConnectTimeMillis() /* connectTimeMillis */,
2789                connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */
2790                mClockProxy);
2791
2792        call.initAnalytics();
2793        call.getAnalytics().setCreatedFromExistingConnection(true);
2794
2795        setCallState(call, Call.getStateFromConnectionState(connection.getState()),
2796                "existing connection");
2797        call.setConnectionCapabilities(connection.getConnectionCapabilities());
2798        call.setConnectionProperties(connection.getConnectionProperties());
2799        call.setHandle(connection.getHandle(), connection.getHandlePresentation());
2800        call.setCallerDisplayName(connection.getCallerDisplayName(),
2801                connection.getCallerDisplayNamePresentation());
2802        call.addListener(this);
2803
2804        // In case this connection was added via a ConnectionManager, keep track of the original
2805        // Connection ID as created by the originating ConnectionService.
2806        Bundle extras = connection.getExtras();
2807        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
2808            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
2809        }
2810        Log.i(this, "createCallForExistingConnection: %s", connection);
2811        Call parentCall = null;
2812        if (!TextUtils.isEmpty(connection.getParentCallId())) {
2813            String parentId = connection.getParentCallId();
2814            parentCall = mCalls
2815                    .stream()
2816                    .filter(c -> c.getId().equals(parentId))
2817                    .findFirst()
2818                    .orElse(null);
2819            if (parentCall != null) {
2820                Log.i(this, "createCallForExistingConnection: %s added as child of %s.",
2821                        call.getId(),
2822                        parentCall.getId());
2823                // Set JUST the parent property, which won't send an update to the Incall UI.
2824                call.setParentCall(parentCall);
2825            }
2826        }
2827        addCall(call);
2828        if (parentCall != null) {
2829            // Now, set the call as a child of the parent since it has been added to Telecom.  This
2830            // is where we will inform InCall.
2831            call.setChildOf(parentCall);
2832            call.notifyParentChanged(parentCall);
2833        }
2834
2835        return call;
2836    }
2837
2838    /**
2839     * Determines whether Telecom already knows about a Connection added via the
2840     * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
2841     * Connection)} API via a ConnectionManager.
2842     *
2843     * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}.
2844     * @param originalConnectionId The new connection ID to check.
2845     * @return {@code true} if this connection is already known by Telecom.
2846     */
2847    Call getAlreadyAddedConnection(String originalConnectionId) {
2848        Optional<Call> existingCall = mCalls.stream()
2849                .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) ||
2850                            originalConnectionId.equals(call.getId()))
2851                .findFirst();
2852
2853        if (existingCall.isPresent()) {
2854            Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s",
2855                    originalConnectionId, existingCall.get().getId());
2856            return existingCall.get();
2857        }
2858
2859        return null;
2860    }
2861
2862    /**
2863     * @return A new unique telecom call Id.
2864     */
2865    private String getNextCallId() {
2866        synchronized(mLock) {
2867            return TELECOM_CALL_ID_PREFIX + (++mCallId);
2868        }
2869    }
2870
2871    public int getNextRttRequestId() {
2872        synchronized (mLock) {
2873            return (++mRttRequestId);
2874        }
2875    }
2876
2877    /**
2878     * Callback when foreground user is switched. We will reload missed call in all profiles
2879     * including the user itself. There may be chances that profiles are not started yet.
2880     */
2881    @VisibleForTesting
2882    public void onUserSwitch(UserHandle userHandle) {
2883        mCurrentUserHandle = userHandle;
2884        mMissedCallNotifier.setCurrentUserHandle(userHandle);
2885        final UserManager userManager = UserManager.get(mContext);
2886        List<UserInfo> profiles = userManager.getEnabledProfiles(userHandle.getIdentifier());
2887        for (UserInfo profile : profiles) {
2888            reloadMissedCallsOfUser(profile.getUserHandle());
2889        }
2890    }
2891
2892    /**
2893     * Because there may be chances that profiles are not started yet though its parent user is
2894     * switched, we reload missed calls of profile that are just started here.
2895     */
2896    void onUserStarting(UserHandle userHandle) {
2897        if (UserUtil.isProfile(mContext, userHandle)) {
2898            reloadMissedCallsOfUser(userHandle);
2899        }
2900    }
2901
2902    public TelecomSystem.SyncRoot getLock() {
2903        return mLock;
2904    }
2905
2906    private void reloadMissedCallsOfUser(UserHandle userHandle) {
2907        mMissedCallNotifier.reloadFromDatabase(mCallerInfoLookupHelper,
2908                new MissedCallNotifier.CallInfoFactory(), userHandle);
2909    }
2910
2911    public void onBootCompleted() {
2912        mMissedCallNotifier.reloadAfterBootComplete(mCallerInfoLookupHelper,
2913                new MissedCallNotifier.CallInfoFactory());
2914    }
2915
2916    public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2917        return isIncomingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2918    }
2919
2920    public boolean isIncomingCallPermitted(Call excludeCall,
2921                                           PhoneAccountHandle phoneAccountHandle) {
2922        if (phoneAccountHandle == null) {
2923            return false;
2924        }
2925        PhoneAccount phoneAccount =
2926                mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2927        if (phoneAccount == null) {
2928            return false;
2929        }
2930
2931        if (!phoneAccount.isSelfManaged()) {
2932            return !hasMaximumManagedRingingCalls(excludeCall) &&
2933                    !hasMaximumManagedHoldingCalls(excludeCall);
2934        } else {
2935            return !hasEmergencyCall() &&
2936                    !hasMaximumSelfManagedRingingCalls(excludeCall, phoneAccountHandle) &&
2937                    !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle);
2938        }
2939    }
2940
2941    public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
2942        return isOutgoingCallPermitted(null /* excludeCall */, phoneAccountHandle);
2943    }
2944
2945    public boolean isOutgoingCallPermitted(Call excludeCall,
2946                                           PhoneAccountHandle phoneAccountHandle) {
2947        if (phoneAccountHandle == null) {
2948            return false;
2949        }
2950        PhoneAccount phoneAccount =
2951                mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle);
2952        if (phoneAccount == null) {
2953            return false;
2954        }
2955
2956        if (!phoneAccount.isSelfManaged()) {
2957            return !hasMaximumManagedOutgoingCalls(excludeCall) &&
2958                    !hasMaximumManagedDialingCalls(excludeCall) &&
2959                    !hasMaximumManagedLiveCalls(excludeCall) &&
2960                    !hasMaximumManagedHoldingCalls(excludeCall);
2961        } else {
2962            // Only permit outgoing calls if there is no ongoing emergency calls and all other calls
2963            // are associated with the current PhoneAccountHandle.
2964            return !hasEmergencyCall() && (
2965                    (excludeCall != null && excludeCall.getHandoverSourceCall() != null) || (
2966                            !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle)
2967                                    && !hasCallsForOtherPhoneAccount(phoneAccountHandle)
2968                                    && !hasManagedCalls()));
2969        }
2970    }
2971
2972    /**
2973     * Blocks execution until all Telecom handlers have completed their current work.
2974     */
2975    public void waitOnHandlers() {
2976        CountDownLatch mainHandlerLatch = new CountDownLatch(3);
2977        mHandler.post(() -> {
2978            mainHandlerLatch.countDown();
2979        });
2980        mCallAudioManager.getCallAudioModeStateMachine().getHandler().post(() -> {
2981            mainHandlerLatch.countDown();
2982        });
2983        mCallAudioManager.getCallAudioRouteStateMachine().getHandler().post(() -> {
2984            mainHandlerLatch.countDown();
2985        });
2986
2987        try {
2988            mainHandlerLatch.await(HANDLER_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);
2989        } catch (InterruptedException e) {
2990            Log.w(this, "waitOnHandlers: interrupted %s", e);
2991        }
2992    }
2993
2994    /**
2995     * Used to confirm creation of an outgoing call which was marked as pending confirmation in
2996     * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
2997     * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
2998     * {@link ConfirmCallDialogActivity}.
2999     * @param callId The call ID of the call to confirm.
3000     */
3001    public void confirmPendingCall(String callId) {
3002        Log.i(this, "confirmPendingCall: callId=%s", callId);
3003        if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
3004            Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED);
3005            addCall(mPendingCall);
3006
3007            // We are going to place the new outgoing call, so disconnect any ongoing self-managed
3008            // calls which are ongoing at this time.
3009            disconnectSelfManagedCalls();
3010
3011            // Kick of the new outgoing call intent from where it left off prior to confirming the
3012            // call.
3013            CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this,
3014                    mPendingCall.getOriginalCallIntent());
3015            mPendingCall = null;
3016        }
3017    }
3018
3019    /**
3020     * Used to cancel an outgoing call which was marked as pending confirmation in
3021     * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
3022     * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
3023     * {@link ConfirmCallDialogActivity}.
3024     * @param callId The call ID of the call to cancel.
3025     */
3026    public void cancelPendingCall(String callId) {
3027        Log.i(this, "cancelPendingCall: callId=%s", callId);
3028        if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
3029            Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED);
3030            markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED));
3031            markCallAsRemoved(mPendingCall);
3032            mPendingCall = null;
3033        }
3034    }
3035
3036    /**
3037     * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when
3038     * a managed call is added while there are ongoing self-managed calls.  Starts
3039     * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the
3040     * outgoing call or not.
3041     * @param call The call to confirm.
3042     */
3043    private void startCallConfirmation(Call call) {
3044        if (mPendingCall != null) {
3045            Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s",
3046                    mPendingCall.getId(), call.getId());
3047            markCallDisconnectedDueToSelfManagedCall(call);
3048            return;
3049        }
3050        Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION);
3051        mPendingCall = call;
3052
3053        // Figure out the name of the app in charge of the self-managed call(s).
3054        Call selfManagedCall = mCalls.stream()
3055                .filter(c -> c.isSelfManaged())
3056                .findFirst()
3057                .orElse(null);
3058        CharSequence ongoingAppName = "";
3059        if (selfManagedCall != null) {
3060            ongoingAppName = selfManagedCall.getTargetPhoneAccountLabel();
3061        }
3062        Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(),
3063                ongoingAppName);
3064
3065        Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class);
3066        confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId());
3067        confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName);
3068        confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3069        mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT);
3070    }
3071
3072    /**
3073     * Disconnects all self-managed calls.
3074     */
3075    private void disconnectSelfManagedCalls() {
3076        // Disconnect all self-managed calls to make priority for emergency call.
3077        // Use Call.disconnect() to command the ConnectionService to disconnect the calls.
3078        // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to
3079        // disconnect.
3080        mCalls.stream()
3081                .filter(c -> c.isSelfManaged())
3082                .forEach(c -> c.disconnect());
3083    }
3084
3085    /**
3086     * Dumps the state of the {@link CallsManager}.
3087     *
3088     * @param pw The {@code IndentingPrintWriter} to write the state to.
3089     */
3090    public void dump(IndentingPrintWriter pw) {
3091        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3092        if (mCalls != null) {
3093            pw.println("mCalls: ");
3094            pw.increaseIndent();
3095            for (Call call : mCalls) {
3096                pw.println(call);
3097            }
3098            pw.decreaseIndent();
3099        }
3100
3101        if (mPendingCall != null) {
3102            pw.print("mPendingCall:");
3103            pw.println(mPendingCall.getId());
3104        }
3105
3106        if (mCallAudioManager != null) {
3107            pw.println("mCallAudioManager:");
3108            pw.increaseIndent();
3109            mCallAudioManager.dump(pw);
3110            pw.decreaseIndent();
3111        }
3112
3113        if (mTtyManager != null) {
3114            pw.println("mTtyManager:");
3115            pw.increaseIndent();
3116            mTtyManager.dump(pw);
3117            pw.decreaseIndent();
3118        }
3119
3120        if (mInCallController != null) {
3121            pw.println("mInCallController:");
3122            pw.increaseIndent();
3123            mInCallController.dump(pw);
3124            pw.decreaseIndent();
3125        }
3126
3127        if (mDefaultDialerCache != null) {
3128            pw.println("mDefaultDialerCache:");
3129            pw.increaseIndent();
3130            mDefaultDialerCache.dumpCache(pw);
3131            pw.decreaseIndent();
3132        }
3133
3134        if (mConnectionServiceRepository != null) {
3135            pw.println("mConnectionServiceRepository:");
3136            pw.increaseIndent();
3137            mConnectionServiceRepository.dump(pw);
3138            pw.decreaseIndent();
3139        }
3140    }
3141
3142    /**
3143    * For some disconnected causes, we show a dialog when it's a mmi code or potential mmi code.
3144    *
3145    * @param call The call.
3146    */
3147    private void maybeShowErrorDialogOnDisconnect(Call call) {
3148        if (call.getState() == CallState.DISCONNECTED && (isPotentialMMICode(call.getHandle())
3149                || isPotentialInCallMMICode(call.getHandle())) && !mCalls.contains(call)) {
3150            DisconnectCause disconnectCause = call.getDisconnectCause();
3151            if (!TextUtils.isEmpty(disconnectCause.getDescription()) && (disconnectCause.getCode()
3152                    == DisconnectCause.ERROR)) {
3153                Intent errorIntent = new Intent(mContext, ErrorDialogActivity.class);
3154                errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_STRING_EXTRA,
3155                        disconnectCause.getDescription());
3156                errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3157                mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
3158            }
3159        }
3160    }
3161
3162    private void setIntentExtrasAndStartTime(Call call, Bundle extras) {
3163      // Create our own instance to modify (since extras may be Bundle.EMPTY)
3164      extras = new Bundle(extras);
3165
3166      // Specifies the time telecom began routing the call. This is used by the dialer for
3167      // analytics.
3168      extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
3169              SystemClock.elapsedRealtime());
3170
3171      call.setIntentExtras(extras);
3172    }
3173
3174    /**
3175     * Notifies the {@link android.telecom.ConnectionService} associated with a
3176     * {@link PhoneAccountHandle} that the attempt to create a new connection has failed.
3177     *
3178     * @param phoneAccountHandle The {@link PhoneAccountHandle}.
3179     * @param call The {@link Call} which could not be added.
3180     */
3181    private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
3182        if (phoneAccountHandle == null) {
3183            return;
3184        }
3185        ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
3186                phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle());
3187        if (service == null) {
3188            Log.i(this, "Found no connection service.");
3189            return;
3190        } else {
3191            call.setConnectionService(service);
3192            service.createConnectionFailed(call);
3193        }
3194    }
3195
3196    /**
3197     * Called in response to a {@link Call} receiving a {@link Call#sendCallEvent(String, Bundle)}
3198     * of type {@link android.telecom.Call#EVENT_REQUEST_HANDOVER} indicating the
3199     * {@link android.telecom.InCallService} has requested a handover to another
3200     * {@link android.telecom.ConnectionService}.
3201     *
3202     * We will explicitly disallow a handover when there is an emergency call present.
3203     *
3204     * @param handoverFromCall The {@link Call} to be handed over.
3205     * @param handoverToHandle The {@link PhoneAccountHandle} to hand over the call to.
3206     * @param videoState The desired video state of {@link Call} after handover.
3207     * @param initiatingExtras Extras associated with the handover, to be passed to the handover
3208     *               {@link android.telecom.ConnectionService}.
3209     */
3210    private void requestHandover(Call handoverFromCall, PhoneAccountHandle handoverToHandle,
3211                                 int videoState, Bundle initiatingExtras) {
3212
3213        boolean isHandoverFromSupported = isHandoverFromPhoneAccountSupported(
3214                handoverFromCall.getTargetPhoneAccount());
3215        boolean isHandoverToSupported = isHandoverToPhoneAccountSupported(handoverToHandle);
3216
3217        if (!isHandoverFromSupported || !isHandoverToSupported || hasEmergencyCall()) {
3218            handoverFromCall.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_FAILED, null);
3219            return;
3220        }
3221
3222        Log.addEvent(handoverFromCall, LogUtils.Events.HANDOVER_REQUEST, handoverToHandle);
3223
3224        Bundle extras = new Bundle();
3225        extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
3226        extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT,
3227                handoverFromCall.getTargetPhoneAccount());
3228        extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
3229        if (initiatingExtras != null) {
3230            extras.putAll(initiatingExtras);
3231        }
3232        extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE,
3233                mCallAudioManager.getCallAudioState());
3234        Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle,
3235                extras, getCurrentUserHandle(), null /* originalIntent */);
3236        Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER,
3237                "handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), handoverToCall.getId());
3238        handoverFromCall.setHandoverDestinationCall(handoverToCall);
3239        handoverFromCall.setHandoverState(HandoverState.HANDOVER_FROM_STARTED);
3240        handoverToCall.setHandoverState(HandoverState.HANDOVER_TO_STARTED);
3241        handoverToCall.setHandoverSourceCall(handoverFromCall);
3242        handoverToCall.setNewOutgoingCallIntentBroadcastIsDone();
3243        placeOutgoingCall(handoverToCall, handoverToCall.getHandle(), null /* gatewayInfo */,
3244                false /* startwithSpeaker */,
3245                videoState);
3246    }
3247
3248    /**
3249     * Determines if handover from the specified {@link PhoneAccountHandle} is supported.
3250     *
3251     * @param from The {@link PhoneAccountHandle} the handover originates from.
3252     * @return {@code true} if handover is currently allowed, {@code false} otherwise.
3253     */
3254    private boolean isHandoverFromPhoneAccountSupported(PhoneAccountHandle from) {
3255        return getBooleanPhoneAccountExtra(from, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM);
3256    }
3257
3258    /**
3259     * Determines if handover to the specified {@link PhoneAccountHandle} is supported.
3260     *
3261     * @param to The {@link PhoneAccountHandle} the handover it to.
3262     * @return {@code true} if handover is currently allowed, {@code false} otherwise.
3263     */
3264    private boolean isHandoverToPhoneAccountSupported(PhoneAccountHandle to) {
3265        return getBooleanPhoneAccountExtra(to, PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO);
3266    }
3267
3268    /**
3269     * Retrieves a boolean phone account extra.
3270     * @param handle the {@link PhoneAccountHandle} to retrieve the extra for.
3271     * @param key The extras key.
3272     * @return {@code true} if the extra {@link PhoneAccount} extra is true, {@code false}
3273     *      otherwise.
3274     */
3275    private boolean getBooleanPhoneAccountExtra(PhoneAccountHandle handle, String key) {
3276        PhoneAccount phoneAccount = getPhoneAccountRegistrar().getPhoneAccountUnchecked(handle);
3277        if (phoneAccount == null) {
3278            return false;
3279        }
3280
3281        Bundle fromExtras = phoneAccount.getExtras();
3282        if (fromExtras == null) {
3283            return false;
3284        }
3285        return fromExtras.getBoolean(key);
3286    }
3287
3288    /**
3289     * Determines if there is an existing handover in process.
3290     * @return {@code true} if a call in the process of handover exists, {@code false} otherwise.
3291     */
3292    private boolean isHandoverInProgress() {
3293        return mCalls.stream().filter(c -> c.getHandoverSourceCall() != null ||
3294                c.getHandoverDestinationCall() != null).count() > 0;
3295    }
3296
3297    private void broadcastUnregisterIntent(PhoneAccountHandle accountHandle) {
3298        Intent intent =
3299                new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED);
3300        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
3301        intent.putExtra(
3302                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3303        Log.i(this, "Sending phone-account %s unregistered intent as user", accountHandle);
3304        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
3305                PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
3306
3307        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
3308                getCurrentUserHandle().getIdentifier());
3309        if (!TextUtils.isEmpty(dialerPackage)) {
3310            Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED)
3311                    .setPackage(dialerPackage);
3312            directedIntent.putExtra(
3313                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3314            Log.i(this, "Sending phone-account unregistered intent to default dialer");
3315            mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
3316        }
3317        return ;
3318    }
3319
3320    private void broadcastRegisterIntent(PhoneAccountHandle accountHandle) {
3321        Intent intent = new Intent(
3322                TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED);
3323        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
3324        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
3325                accountHandle);
3326        Log.i(this, "Sending phone-account %s registered intent as user", accountHandle);
3327        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
3328                PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
3329
3330        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
3331                getCurrentUserHandle().getIdentifier());
3332        if (!TextUtils.isEmpty(dialerPackage)) {
3333            Intent directedIntent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED)
3334                    .setPackage(dialerPackage);
3335            directedIntent.putExtra(
3336                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
3337            Log.i(this, "Sending phone-account registered intent to default dialer");
3338            mContext.sendBroadcastAsUser(directedIntent, UserHandle.ALL, null);
3339        }
3340        return ;
3341    }
3342
3343    public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
3344        // TODO:
3345    }
3346}
3347