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