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