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