1 /*
2  * Copyright (C) 2022 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.internal.telephony.emergency;
18 
19 import static android.telecom.Connection.STATE_ACTIVE;
20 import static android.telecom.Connection.STATE_DISCONNECTED;
21 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL;
22 import static android.telephony.CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL;
23 
24 import static com.android.internal.telephony.TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED;
25 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK;
26 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE;
27 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN;
28 
29 import android.annotation.IntDef;
30 import android.annotation.NonNull;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.SharedPreferences;
36 import android.os.AsyncResult;
37 import android.os.Handler;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.os.PersistableBundle;
41 import android.os.PowerManager;
42 import android.os.SystemClock;
43 import android.os.UserHandle;
44 import android.preference.PreferenceManager;
45 import android.provider.Settings;
46 import android.sysprop.TelephonyProperties;
47 import android.telephony.AccessNetworkConstants;
48 import android.telephony.Annotation.DisconnectCauses;
49 import android.telephony.CarrierConfigManager;
50 import android.telephony.DisconnectCause;
51 import android.telephony.EmergencyRegistrationResult;
52 import android.telephony.NetworkRegistrationInfo;
53 import android.telephony.ServiceState;
54 import android.telephony.SubscriptionManager;
55 import android.telephony.TelephonyManager;
56 import android.util.ArraySet;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.telephony.Call;
60 import com.android.internal.telephony.CallStateException;
61 import com.android.internal.telephony.Connection;
62 import com.android.internal.telephony.GsmCdmaPhone;
63 import com.android.internal.telephony.Phone;
64 import com.android.internal.telephony.PhoneConstants;
65 import com.android.internal.telephony.PhoneFactory;
66 import com.android.internal.telephony.TelephonyIntents;
67 import com.android.internal.telephony.data.PhoneSwitcher;
68 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
69 import com.android.internal.telephony.satellite.SatelliteController;
70 import com.android.telephony.Rlog;
71 
72 import java.lang.annotation.Retention;
73 import java.lang.annotation.RetentionPolicy;
74 import java.util.Arrays;
75 import java.util.Objects;
76 import java.util.Set;
77 import java.util.concurrent.CompletableFuture;
78 import java.util.function.Consumer;
79 
80 /**
81  * Tracks the emergency call state and notifies listeners of changes to the emergency mode.
82  */
83 public class EmergencyStateTracker {
84 
85     private static final String TAG = "EmergencyStateTracker";
86 
87     private static class OnDisconnectListener extends Connection.ListenerBase {
88         private final CompletableFuture<Boolean> mFuture;
89 
OnDisconnectListener(CompletableFuture<Boolean> future)90         OnDisconnectListener(CompletableFuture<Boolean> future) {
91             mFuture = future;
92         }
93 
94         @Override
onDisconnect(int cause)95         public void onDisconnect(int cause) {
96             mFuture.complete(true);
97         }
98     };
99 
100     /**
101      * Timeout before we continue with the emergency call without waiting for DDS switch response
102      * from the modem.
103      */
104     private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1 * 1000;
105     @VisibleForTesting
106     public static final int DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS = 3 * 1000;
107     /** Default value for if Emergency Callback Mode is supported. */
108     private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true;
109     /** Default Emergency Callback Mode exit timeout value. */
110     private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000;
111 
112     private static final int DEFAULT_TRANSPORT_CHANGE_TIMEOUT_MS = 1 * 1000;
113 
114     // Timeout to wait for the termination of incoming call before continue with the emergency call.
115     private static final int DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS = 3 * 1000; // 3 seconds.
116 
117     /** The emergency types used when setting the emergency mode on modem. */
118     @Retention(RetentionPolicy.SOURCE)
119     @IntDef(prefix = "EMERGENCY_TYPE_",
120             value = {
121                     EMERGENCY_TYPE_CALL,
122                     EMERGENCY_TYPE_SMS})
123     public @interface EmergencyType {}
124 
125     /** Indicates the emergency type is call. */
126     public static final int EMERGENCY_TYPE_CALL = 1;
127     /** Indicates the emergency type is SMS. */
128     public static final int EMERGENCY_TYPE_SMS = 2;
129 
130     private static final String KEY_NO_SIM_ECBM_SUPPORT = "no_sim_ecbm_support";
131 
132     private static EmergencyStateTracker INSTANCE = null;
133 
134     private final Context mContext;
135     private final CarrierConfigManager mConfigManager;
136     private final Handler mHandler;
137     private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall;
138     private final PowerManager.WakeLock mWakeLock;
139     private RadioOnHelper mRadioOnHelper;
140     @EmergencyConstants.EmergencyMode
141     private int mEmergencyMode = MODE_EMERGENCY_NONE;
142     private boolean mWasEmergencyModeSetOnModem;
143     private EmergencyRegistrationResult mLastEmergencyRegistrationResult;
144     private boolean mIsEmergencyModeInProgress;
145     private boolean mIsEmergencyCallStartedDuringEmergencySms;
146     private boolean mIsWaitingForRadioOff;
147 
148     /** For emergency calls */
149     private final long mEcmExitTimeoutMs;
150     // A runnable which is used to automatically exit from Ecm after a period of time.
151     private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode;
152     // Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}.
153     private final Set<android.telecom.Connection> mActiveEmergencyCalls = new ArraySet<>();
154     private Phone mPhone;
155     // Tracks ongoing emergency connection to handle a second emergency call
156     private android.telecom.Connection mOngoingConnection;
157     // Domain of the active emergency call. Assuming here that there will only be one domain active.
158     private int mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN;
159     private CompletableFuture<Integer> mCallEmergencyModeFuture;
160     private boolean mIsInEmergencyCall;
161     private boolean mIsInEcm;
162     private boolean mIsTestEmergencyNumber;
163     private Runnable mOnEcmExitCompleteRunnable;
164     private int mOngoingCallProperties;
165     private boolean mSentEmergencyCallState;
166     private android.telecom.Connection mNormalRoutingEmergencyConnection;
167 
168     /** For emergency SMS */
169     private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>();
170     private Phone mSmsPhone;
171     private CompletableFuture<Integer> mSmsEmergencyModeFuture;
172     private boolean mIsTestEmergencyNumberForSms;
173     // For tracking the emergency SMS callback mode.
174     private boolean mIsInScbm;
175     private boolean mIsEmergencySmsStartedDuringScbm;
176 
177     private CompletableFuture<Boolean> mEmergencyTransportChangedFuture;
178     private final Object mRegistrantidentifier = new Object();
179 
180     private final android.util.ArrayMap<Integer, Boolean> mNoSimEcbmSupported =
181             new android.util.ArrayMap<>();
182     private final android.util.ArrayMap<Integer, Boolean> mBroadcastEmergencyCallStateChanges =
183             new android.util.ArrayMap<>();
184     private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
185             (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged(
186                     slotIndex, subId);
187 
188     /**
189      * Listens for Emergency Callback Mode state change intents
190      */
191     private final BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() {
192         @Override
193         public void onReceive(Context context, Intent intent) {
194             if (intent.getAction().equals(
195                     TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
196 
197                 boolean isInEcm = intent.getBooleanExtra(
198                         TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false);
199                 Rlog.d(TAG, "Received ACTION_EMERGENCY_CALLBACK_MODE_CHANGED isInEcm = " + isInEcm);
200 
201                 // If we exit ECM mode, notify all connections.
202                 if (!isInEcm) {
203                     exitEmergencyCallbackMode();
204                 }
205             }
206         }
207     };
208 
209     /** PhoneFactory Dependencies for testing. */
210     @VisibleForTesting
211     public interface PhoneFactoryProxy {
getPhones()212         Phone[] getPhones();
213     }
214 
215     private PhoneFactoryProxy mPhoneFactoryProxy = PhoneFactory::getPhones;
216 
217     /** PhoneSwitcher dependencies for testing. */
218     @VisibleForTesting
219     public interface PhoneSwitcherProxy {
220 
getPhoneSwitcher()221         PhoneSwitcher getPhoneSwitcher();
222     }
223 
224     private PhoneSwitcherProxy mPhoneSwitcherProxy = PhoneSwitcher::getInstance;
225 
226     /**
227      * TelephonyManager dependencies for testing.
228      */
229     @VisibleForTesting
230     public interface TelephonyManagerProxy {
getPhoneCount()231         int getPhoneCount();
getSimState(int slotIndex)232         int getSimState(int slotIndex);
233     }
234 
235     private final TelephonyManagerProxy mTelephonyManagerProxy;
236 
237     private static class TelephonyManagerProxyImpl implements TelephonyManagerProxy {
238         private final TelephonyManager mTelephonyManager;
239 
TelephonyManagerProxyImpl(Context context)240         TelephonyManagerProxyImpl(Context context) {
241             mTelephonyManager = new TelephonyManager(context);
242         }
243 
244         @Override
getPhoneCount()245         public int getPhoneCount() {
246             return mTelephonyManager.getActiveModemCount();
247         }
248 
249         @Override
getSimState(int slotIndex)250         public int getSimState(int slotIndex) {
251             return mTelephonyManager.getSimState(slotIndex);
252         }
253     }
254 
255     /**
256      * Return the handler for testing.
257      */
258     @VisibleForTesting
getHandler()259     public Handler getHandler() {
260         return mHandler;
261     }
262 
263     @VisibleForTesting
264     public static final int MSG_SET_EMERGENCY_MODE_DONE = 1;
265     @VisibleForTesting
266     public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 2;
267     @VisibleForTesting
268     public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 3;
269     /** A message which is used to automatically exit from SCBM after a period of time. */
270     private static final int MSG_EXIT_SCBM = 4;
271     @VisibleForTesting
272     public static final int MSG_NEW_RINGING_CONNECTION = 5;
273     @VisibleForTesting
274     public static final int MSG_VOICE_REG_STATE_CHANGED = 6;
275 
276     private class MyHandler extends Handler {
277 
MyHandler(Looper looper)278         MyHandler(Looper looper) {
279             super(looper);
280         }
281 
282         @Override
handleMessage(Message msg)283         public void handleMessage(Message msg) {
284             switch (msg.what) {
285                 case MSG_SET_EMERGENCY_MODE_DONE: {
286                     AsyncResult ar = (AsyncResult) msg.obj;
287                     Integer emergencyType = (Integer) ar.userObj;
288                     Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE_DONE for "
289                             + emergencyTypeToString(emergencyType));
290                     if (ar.exception == null) {
291                         mLastEmergencyRegistrationResult = (EmergencyRegistrationResult) ar.result;
292                     } else {
293                         mLastEmergencyRegistrationResult = null;
294                         Rlog.w(TAG,
295                                 "LastEmergencyRegistrationResult not set. AsyncResult.exception: "
296                                 + ar.exception);
297                     }
298                     setEmergencyModeInProgress(false);
299 
300                     // Transport changed from WLAN to WWAN or CALLBACK to WWAN
301                     maybeNotifyTransportChangeCompleted(emergencyType, false);
302 
303                     if (emergencyType == EMERGENCY_TYPE_CALL) {
304                         setIsInEmergencyCall(true);
305                         completeEmergencyMode(emergencyType);
306 
307                         // Case 1) When the emergency call is setting the emergency mode and
308                         // the emergency SMS is being sent, completes the SMS future also.
309                         // Case 2) When the emergency SMS is setting the emergency mode and
310                         // the emergency call is being started, the SMS request is cancelled and
311                         // the call request will be handled.
312                         if (mSmsPhone != null) {
313                             completeEmergencyMode(EMERGENCY_TYPE_SMS);
314                         }
315                     } else if (emergencyType == EMERGENCY_TYPE_SMS) {
316                         if (mPhone != null && mSmsPhone != null) {
317                             if (mIsEmergencyCallStartedDuringEmergencySms) {
318                                 if (!isSamePhone(mPhone, mSmsPhone) || !isInScbm()) {
319                                     // Clear call phone temporarily to exit the emergency mode
320                                     // if the emergency call is started.
321                                     Phone phone = mPhone;
322                                     mPhone = null;
323                                     exitEmergencyMode(mSmsPhone, emergencyType);
324                                     // Restore call phone for further use.
325                                     mPhone = phone;
326                                     if (!isSamePhone(mPhone, mSmsPhone)) {
327                                         completeEmergencyMode(emergencyType,
328                                                 DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED);
329                                         exitEmergencySmsCallbackMode();
330                                     }
331                                 } else {
332                                     completeEmergencyMode(emergencyType);
333                                     mIsEmergencyCallStartedDuringEmergencySms = false;
334                                     exitEmergencySmsCallbackMode();
335                                     turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
336                                             mIsTestEmergencyNumber);
337                                 }
338                             } else {
339                                 completeEmergencyMode(emergencyType);
340                             }
341                         } else {
342                             completeEmergencyMode(emergencyType);
343 
344                             if (mIsEmergencyCallStartedDuringEmergencySms) {
345                                 mIsEmergencyCallStartedDuringEmergencySms = false;
346                                 exitEmergencySmsCallbackMode();
347                                 turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
348                                         mIsTestEmergencyNumber);
349                             }
350                         }
351                     }
352                     break;
353                 }
354                 case MSG_EXIT_EMERGENCY_MODE_DONE: {
355                     AsyncResult ar = (AsyncResult) msg.obj;
356                     Integer emergencyType = (Integer) ar.userObj;
357                     Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE_DONE for "
358                             + emergencyTypeToString(emergencyType));
359                     setEmergencyModeInProgress(false);
360 
361                     if (emergencyType == EMERGENCY_TYPE_CALL) {
362                         setIsInEmergencyCall(false);
363                         if (mOnEcmExitCompleteRunnable != null) {
364                             mOnEcmExitCompleteRunnable.run();
365                             mOnEcmExitCompleteRunnable = null;
366                         }
367                         if (mPhone != null && mEmergencyMode == MODE_EMERGENCY_WWAN) {
368                             // In cross sim redialing.
369                             setEmergencyModeInProgress(true);
370                             mWasEmergencyModeSetOnModem = true;
371                             mPhone.setEmergencyMode(MODE_EMERGENCY_WWAN,
372                                     mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE,
373                                     Integer.valueOf(EMERGENCY_TYPE_CALL)));
374                         }
375                     } else if (emergencyType == EMERGENCY_TYPE_SMS) {
376                         if (mIsEmergencyCallStartedDuringEmergencySms) {
377                             mIsEmergencyCallStartedDuringEmergencySms = false;
378                             turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
379                                     mIsTestEmergencyNumber);
380                         } else if (mPhone != null && mEmergencyMode == MODE_EMERGENCY_WWAN) {
381                             // Starting emergency call while exiting emergency mode
382                             setEmergencyModeInProgress(true);
383                             mWasEmergencyModeSetOnModem = true;
384                             mPhone.setEmergencyMode(MODE_EMERGENCY_WWAN,
385                                     mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE,
386                                     Integer.valueOf(EMERGENCY_TYPE_CALL)));
387                         } else if (mIsEmergencySmsStartedDuringScbm) {
388                             mIsEmergencySmsStartedDuringScbm = false;
389                             setEmergencyMode(mSmsPhone, emergencyType,
390                                     MODE_EMERGENCY_WWAN, MSG_SET_EMERGENCY_MODE_DONE);
391                         }
392                     }
393                     break;
394                 }
395                 case MSG_SET_EMERGENCY_CALLBACK_MODE_DONE: {
396                     AsyncResult ar = (AsyncResult) msg.obj;
397                     Integer emergencyType = (Integer) ar.userObj;
398                     Rlog.v(TAG, "MSG_SET_EMERGENCY_CALLBACK_MODE_DONE for "
399                             + emergencyTypeToString(emergencyType));
400                     setEmergencyModeInProgress(false);
401                     // When the emergency callback mode is in progress and the emergency SMS is
402                     // started, it needs to be completed here for the emergency SMS.
403                     if (emergencyType == EMERGENCY_TYPE_CALL) {
404                         if (mSmsPhone != null) {
405                             completeEmergencyMode(EMERGENCY_TYPE_SMS);
406                         }
407                     } else if (emergencyType == EMERGENCY_TYPE_SMS) {
408                         // When the emergency SMS callback mode is in progress on other phone and
409                         // the emergency call was started, needs to exit the emergency mode first.
410                         if (mIsEmergencyCallStartedDuringEmergencySms) {
411                             final Phone smsPhone = mSmsPhone;
412                             exitEmergencySmsCallbackMode();
413 
414                             if (mPhone != null && smsPhone != null
415                                     && !isSamePhone(mPhone, smsPhone)) {
416                                 Phone phone = mPhone;
417                                 mPhone = null;
418                                 exitEmergencyMode(smsPhone, emergencyType);
419                                 // Restore call phone for further use.
420                                 mPhone = phone;
421                             } else {
422                                 mIsEmergencyCallStartedDuringEmergencySms = false;
423                                 turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
424                                         mIsTestEmergencyNumber);
425                             }
426                         }
427                     }
428                     break;
429                 }
430                 case MSG_EXIT_SCBM: {
431                     exitEmergencySmsCallbackModeAndEmergencyMode();
432                     break;
433                 }
434                 case MSG_NEW_RINGING_CONNECTION: {
435                     handleNewRingingConnection(msg);
436                     break;
437                 }
438                 case MSG_VOICE_REG_STATE_CHANGED: {
439                     if (mIsWaitingForRadioOff && isPowerOff()) {
440                         unregisterForVoiceRegStateOrRatChanged();
441                         if (mPhone != null) {
442                             turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
443                                     mIsTestEmergencyNumber);
444                         }
445                     }
446                     break;
447                 }
448                 default:
449                     break;
450             }
451         }
452     }
453 
454     /**
455      * Creates the EmergencyStateTracker singleton instance.
456      *
457      * @param context                                 The context of the application.
458      * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for
459      *                                                emergency call.
460      */
make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall)461     public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall) {
462         if (INSTANCE == null) {
463             INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(),
464                     isSuplDdsSwitchRequiredForEmergencyCall);
465         }
466     }
467 
468     /**
469      * Returns the singleton instance of EmergencyStateTracker.
470      *
471      * @return {@link EmergencyStateTracker} instance.
472      */
getInstance()473     public static EmergencyStateTracker getInstance() {
474         if (INSTANCE == null) {
475             throw new IllegalStateException("EmergencyStateTracker is not ready!");
476         }
477         return INSTANCE;
478     }
479 
480     /**
481      * Initializes EmergencyStateTracker.
482      */
EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall)483     private EmergencyStateTracker(Context context, Looper looper,
484             boolean isSuplDdsSwitchRequiredForEmergencyCall) {
485         mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS;
486         mContext = context;
487         mHandler = new MyHandler(looper);
488         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
489 
490         PowerManager pm = context.getSystemService(PowerManager.class);
491         mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
492                 "telephony:" + TAG) : null;
493         mConfigManager = context.getSystemService(CarrierConfigManager.class);
494         if (mConfigManager != null) {
495             // Carrier config changed callback should be executed in handler thread
496             mConfigManager.registerCarrierConfigChangeListener(mHandler::post,
497                     mCarrierConfigChangeListener);
498         } else {
499             Rlog.e(TAG, "CarrierConfigLoader is not available.");
500         }
501 
502         // Register receiver for ECM exit.
503         IntentFilter filter = new IntentFilter();
504         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
505         context.registerReceiver(mEcmExitReceiver, filter, null, mHandler);
506         mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context);
507 
508         registerForNewRingingConnection();
509 
510         // To recover the abnormal state after crash of com.android.phone process
511         maybeResetEmergencyCallStateChangedIntent();
512     }
513 
514     /**
515      * Initializes EmergencyStateTracker with injections for testing.
516      *
517      * @param context                                 The context of the application.
518      * @param looper                                  The {@link Looper} of the application.
519      * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for
520      *                                                emergency call.
521      * @param phoneFactoryProxy                       The {@link PhoneFactoryProxy} to be injected.
522      * @param phoneSwitcherProxy                      The {@link PhoneSwitcherProxy} to be injected.
523      * @param telephonyManagerProxy                   The {@link TelephonyManagerProxy} to be
524      *                                                injected.
525      * @param radioOnHelper                           The {@link RadioOnHelper} to be injected.
526      */
527     @VisibleForTesting
EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy, PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy, RadioOnHelper radioOnHelper, long ecmExitTimeoutMs)528     public EmergencyStateTracker(Context context, Looper looper,
529             boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy,
530             PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy,
531             RadioOnHelper radioOnHelper, long ecmExitTimeoutMs) {
532         mContext = context;
533         mHandler = new MyHandler(looper);
534         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
535         mPhoneFactoryProxy = phoneFactoryProxy;
536         mPhoneSwitcherProxy = phoneSwitcherProxy;
537         mTelephonyManagerProxy = telephonyManagerProxy;
538         mRadioOnHelper = radioOnHelper;
539         mEcmExitTimeoutMs = ecmExitTimeoutMs;
540         mWakeLock = null; // Don't declare a wakelock in tests
541         mConfigManager = context.getSystemService(CarrierConfigManager.class);
542         mConfigManager.registerCarrierConfigChangeListener(mHandler::post,
543                 mCarrierConfigChangeListener);
544         IntentFilter filter = new IntentFilter();
545         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
546         context.registerReceiver(mEcmExitReceiver, filter, null, mHandler);
547         registerForNewRingingConnection();
548     }
549 
550     /**
551      * Starts the process of an emergency call.
552      *
553      * <p>
554      * Handles turning on radio and switching DDS.
555      *
556      * @param phone                 the {@code Phone} on which to process the emergency call.
557      * @param c                     the {@code Connection} on which to process the emergency call.
558      * @param isTestEmergencyNumber whether this is a test emergency number.
559      * @return a {@code CompletableFuture} that results in {@code DisconnectCause.NOT_DISCONNECTED}
560      *         if emergency call successfully started.
561      */
startEmergencyCall(@onNull Phone phone, @NonNull android.telecom.Connection c, boolean isTestEmergencyNumber)562     public CompletableFuture<Integer> startEmergencyCall(@NonNull Phone phone,
563             @NonNull android.telecom.Connection c, boolean isTestEmergencyNumber) {
564         Rlog.i(TAG, "startEmergencyCall: phoneId=" + phone.getPhoneId()
565                 + ", callId=" + c.getTelecomCallId());
566 
567         if (needToSwitchPhone(phone)) {
568             Rlog.e(TAG, "startEmergencyCall failed. need to switch stacks.");
569             return CompletableFuture.completedFuture(DisconnectCause.EMERGENCY_PERM_FAILURE);
570         }
571 
572         if (mPhone != null) {
573             // Create new future to return as to not interfere with any uncompleted futures.
574             // Case1) When 2nd emergency call is initiated during an active call on the same phone.
575             // Case2) While the device is in ECBM, an emergency call is initiated on the same phone.
576             if (isSamePhone(mPhone, phone) && (!mActiveEmergencyCalls.isEmpty() || isInEcm())) {
577                 exitEmergencySmsCallbackMode();
578                 mOngoingConnection = c;
579                 mIsTestEmergencyNumber = isTestEmergencyNumber;
580                 if (isInEcm()) {
581                     // Remove pending exit ECM runnable.
582                     mHandler.removeCallbacks(mExitEcmRunnable);
583                     releaseWakeLock();
584                     ((GsmCdmaPhone) mPhone).notifyEcbmTimerReset(Boolean.TRUE);
585 
586                     mOngoingCallProperties = 0;
587                     mCallEmergencyModeFuture = new CompletableFuture<>();
588                     setEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WWAN,
589                             MSG_SET_EMERGENCY_MODE_DONE);
590                     return mCallEmergencyModeFuture;
591                 }
592                 // Ensure that domain selector requests scan.
593                 mLastEmergencyRegistrationResult = new EmergencyRegistrationResult(
594                         AccessNetworkConstants.AccessNetworkType.UNKNOWN,
595                         NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN,
596                         NetworkRegistrationInfo.DOMAIN_UNKNOWN, false, false, 0, 0, "", "", "");
597                 return CompletableFuture.completedFuture(DisconnectCause.NOT_DISCONNECTED);
598             }
599 
600             Rlog.e(TAG, "startEmergencyCall failed. Existing emergency call in progress.");
601             return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
602         }
603 
604         mOngoingCallProperties = 0;
605         mCallEmergencyModeFuture = new CompletableFuture<>();
606 
607         if (mSmsPhone != null) {
608             mIsEmergencyCallStartedDuringEmergencySms = true;
609             // Case1) While exiting the emergency mode on the other phone,
610             // the emergency mode for this call will be restarted after the exit complete.
611             // Case2) While entering the emergency mode on the other phone,
612             // exit the emergency mode when receiving the result of setting the emergency mode and
613             // the emergency mode for this call will be restarted after the exit complete.
614             if (isInEmergencyMode() && !isEmergencyModeInProgress()) {
615                 if (!isSamePhone(mSmsPhone, phone)) {
616                     exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS);
617                 } else {
618                     // If the device is already in the emergency mode on the same phone,
619                     // the general emergency call procedure can be immediately performed.
620                     // And, if the emergency PDN is already connected, then we need to keep
621                     // this PDN active while initating the emergency call.
622                     mIsEmergencyCallStartedDuringEmergencySms = false;
623                 }
624 
625                 exitEmergencySmsCallbackMode();
626             }
627 
628             if (mIsEmergencyCallStartedDuringEmergencySms) {
629                 mPhone = phone;
630                 mOngoingConnection = c;
631                 mIsTestEmergencyNumber = isTestEmergencyNumber;
632                 sendEmergencyCallStateChange(mPhone, true);
633                 maybeRejectIncomingCall(null);
634                 return mCallEmergencyModeFuture;
635             }
636         }
637 
638         mPhone = phone;
639         mOngoingConnection = c;
640         mIsTestEmergencyNumber = isTestEmergencyNumber;
641         sendEmergencyCallStateChange(mPhone, true);
642         final android.telecom.Connection expectedConnection = mOngoingConnection;
643         maybeRejectIncomingCall(result -> {
644             Rlog.i(TAG, "maybeRejectIncomingCall : result = " + result);
645             if (!Objects.equals(mOngoingConnection, expectedConnection)) {
646                 Rlog.i(TAG, "maybeRejectIncomingCall "
647                         + expectedConnection.getTelecomCallId() + " canceled.");
648                 return;
649             }
650             turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, mIsTestEmergencyNumber);
651         });
652         return mCallEmergencyModeFuture;
653     }
654 
655     /**
656      * Ends emergency call.
657      *
658      * <p>
659      * Enter ECM only once all active emergency calls have ended. If a call never reached
660      * {@link Call.State#ACTIVE}, then no need to enter ECM.
661      *
662      * @param c the emergency call disconnected.
663      */
endCall(@onNull android.telecom.Connection c)664     public void endCall(@NonNull android.telecom.Connection c) {
665         boolean wasActive = mActiveEmergencyCalls.remove(c);
666 
667         if (Objects.equals(mOngoingConnection, c)) {
668             mOngoingConnection = null;
669             mOngoingCallProperties = 0;
670             sendEmergencyCallStateChange(mPhone, false);
671             unregisterForVoiceRegStateOrRatChanged();
672         }
673 
674         if (wasActive && mActiveEmergencyCalls.isEmpty()
675                 && isEmergencyCallbackModeSupported(mPhone)) {
676             enterEmergencyCallbackMode();
677 
678             if (mOngoingConnection == null) {
679                 mIsEmergencyCallStartedDuringEmergencySms = false;
680                 mCallEmergencyModeFuture = null;
681             }
682         } else if (mOngoingConnection == null) {
683             if (isInEcm()) {
684                 mIsEmergencyCallStartedDuringEmergencySms = false;
685                 mCallEmergencyModeFuture = null;
686                 // If the emergency call was initiated during the emergency callback mode,
687                 // the emergency callback mode should be restored when the emergency call is ended.
688                 if (mActiveEmergencyCalls.isEmpty()) {
689                     enterEmergencyCallbackMode();
690                 }
691             } else {
692                 if (isInScbm()) {
693                     setIsInEmergencyCall(false);
694                     setEmergencyCallbackMode(mSmsPhone, EMERGENCY_TYPE_SMS);
695                 } else {
696                     exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL);
697                 }
698                 clearEmergencyCallInfo();
699             }
700         }
701 
702         // Release any blocked thread immediately
703         maybeNotifyTransportChangeCompleted(EMERGENCY_TYPE_CALL, true);
704     }
705 
clearEmergencyCallInfo()706     private void clearEmergencyCallInfo() {
707         mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN;
708         mIsTestEmergencyNumber = false;
709         mIsEmergencyCallStartedDuringEmergencySms = false;
710         mCallEmergencyModeFuture = null;
711         mOngoingConnection = null;
712         mOngoingCallProperties = 0;
713         mPhone = null;
714     }
715 
switchDdsAndSetEmergencyMode(Phone phone, @EmergencyType int emergencyType)716     private void switchDdsAndSetEmergencyMode(Phone phone, @EmergencyType int emergencyType) {
717         switchDdsDelayed(phone, result -> {
718             Rlog.i(TAG, "switchDdsDelayed: result = " + result);
719             if (!result) {
720                 // DDS Switch timed out/failed, but continue with call as it may still succeed.
721                 Rlog.e(TAG, "DDS Switch failed.");
722             }
723             // Once radio is on and DDS switched, must call setEmergencyMode() before selecting
724             // emergency domain. EmergencyRegistrationResult is required to determine domain and
725             // this is the only API that can receive it before starting domain selection.
726             // Once domain selection is finished, the actual emergency mode will be set when
727             // onEmergencyTransportChanged() is called.
728             if (mEmergencyMode != MODE_EMERGENCY_WWAN) {
729                 setEmergencyMode(phone, emergencyType, MODE_EMERGENCY_WWAN,
730                         MSG_SET_EMERGENCY_MODE_DONE);
731             } else {
732                 // Ensure that domain selector requests the network scan.
733                 mLastEmergencyRegistrationResult = new EmergencyRegistrationResult(
734                         AccessNetworkConstants.AccessNetworkType.UNKNOWN,
735                         NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN,
736                         NetworkRegistrationInfo.DOMAIN_UNKNOWN, false, false, 0, 0, "", "", "");
737                 if (emergencyType == EMERGENCY_TYPE_CALL) {
738                     setIsInEmergencyCall(true);
739                 }
740                 completeEmergencyMode(emergencyType);
741             }
742         });
743     }
744 
745     /**
746      * Triggers modem to set new emergency mode.
747      *
748      * @param phone the {@code Phone} to set the emergency mode on modem.
749      * @param emergencyType the emergency type to identify an emergency call or SMS.
750      * @param mode the new emergency mode.
751      * @param msg the message to be sent once mode has been set.
752      */
setEmergencyMode(Phone phone, @EmergencyType int emergencyType, @EmergencyConstants.EmergencyMode int mode, int msg)753     private void setEmergencyMode(Phone phone, @EmergencyType int emergencyType,
754             @EmergencyConstants.EmergencyMode int mode, int msg) {
755         Rlog.i(TAG, "setEmergencyMode from " + mEmergencyMode + " to " + mode + " for "
756                 + emergencyTypeToString(emergencyType));
757 
758         if (mEmergencyMode == mode) {
759             // Initial transport selection of DomainSelector
760             maybeNotifyTransportChangeCompleted(emergencyType, false);
761             return;
762         }
763 
764         if (emergencyType == EMERGENCY_TYPE_CALL
765                 && mode == MODE_EMERGENCY_WWAN
766                 && isEmergencyModeInProgress() && !isInEmergencyMode()) {
767             // In cross sim redialing or ending emergency SMS, exitEmergencyMode is not completed.
768             mEmergencyMode = mode;
769             Rlog.i(TAG, "setEmergencyMode wait for the completion of exitEmergencyMode");
770             return;
771         }
772 
773         mEmergencyMode = mode;
774         setEmergencyModeInProgress(true);
775 
776         Message m = mHandler.obtainMessage(msg, Integer.valueOf(emergencyType));
777         if (mIsTestEmergencyNumberForSms && emergencyType == EMERGENCY_TYPE_SMS) {
778             Rlog.d(TAG, "TestEmergencyNumber for " + emergencyTypeToString(emergencyType)
779                     + ": Skipping setting emergency mode on modem.");
780             // Send back a response for the command, but with null information
781             AsyncResult.forMessage(m, null, null);
782             // Ensure that we do not accidentally block indefinitely when trying to validate test
783             // emergency numbers
784             m.sendToTarget();
785             return;
786         }
787 
788         mWasEmergencyModeSetOnModem = true;
789         phone.setEmergencyMode(mode, m);
790     }
791 
792     /**
793      * Sets the emergency callback mode on modem.
794      *
795      * @param phone the {@code Phone} to set the emergency mode on modem.
796      * @param emergencyType the emergency type to identify an emergency call or SMS.
797      */
setEmergencyCallbackMode(Phone phone, @EmergencyType int emergencyType)798     private void setEmergencyCallbackMode(Phone phone, @EmergencyType int emergencyType) {
799         boolean needToSetCallbackMode = false;
800 
801         if (emergencyType == EMERGENCY_TYPE_CALL) {
802             needToSetCallbackMode = true;
803         } else if (emergencyType == EMERGENCY_TYPE_SMS) {
804             // Ensure that no emergency call is in progress.
805             if (mActiveEmergencyCalls.isEmpty() && mOngoingConnection == null
806                     && mOngoingEmergencySmsIds.isEmpty()) {
807                 needToSetCallbackMode = true;
808             }
809         }
810 
811         if (needToSetCallbackMode) {
812             // Set emergency mode on modem.
813             setEmergencyMode(phone, emergencyType, MODE_EMERGENCY_CALLBACK,
814                     MSG_SET_EMERGENCY_CALLBACK_MODE_DONE);
815         }
816     }
817 
completeEmergencyMode(@mergencyType int emergencyType)818     private void completeEmergencyMode(@EmergencyType int emergencyType) {
819         completeEmergencyMode(emergencyType, DisconnectCause.NOT_DISCONNECTED);
820     }
821 
completeEmergencyMode(@mergencyType int emergencyType, @DisconnectCauses int result)822     private void completeEmergencyMode(@EmergencyType int emergencyType,
823             @DisconnectCauses int result) {
824         if (emergencyType == EMERGENCY_TYPE_CALL) {
825             if (mCallEmergencyModeFuture != null && !mCallEmergencyModeFuture.isDone()) {
826                 mCallEmergencyModeFuture.complete(result);
827             }
828 
829             if (result != DisconnectCause.NOT_DISCONNECTED) {
830                 clearEmergencyCallInfo();
831             }
832         } else if (emergencyType == EMERGENCY_TYPE_SMS) {
833             if (mSmsEmergencyModeFuture != null && !mSmsEmergencyModeFuture.isDone()) {
834                 mSmsEmergencyModeFuture.complete(result);
835             }
836 
837             if (result != DisconnectCause.NOT_DISCONNECTED) {
838                 clearEmergencySmsInfo();
839             }
840         }
841     }
842 
843     /**
844      * Checks if the device is currently in the emergency mode or not.
845      */
846     @VisibleForTesting
isInEmergencyMode()847     public boolean isInEmergencyMode() {
848         return mEmergencyMode != MODE_EMERGENCY_NONE;
849     }
850 
851     /**
852      * Sets the flag to inidicate whether setting the emergency mode on modem is in progress or not.
853      */
setEmergencyModeInProgress(boolean isEmergencyModeInProgress)854     private void setEmergencyModeInProgress(boolean isEmergencyModeInProgress) {
855         mIsEmergencyModeInProgress = isEmergencyModeInProgress;
856     }
857 
858     /**
859      * Checks whether setting the emergency mode on modem is in progress or not.
860      */
isEmergencyModeInProgress()861     private boolean isEmergencyModeInProgress() {
862         return mIsEmergencyModeInProgress;
863     }
864 
865     /**
866      * Notifies external app listeners of emergency mode changes.
867      *
868      * @param isInEmergencyCall a flag to indicate whether there is an active emergency call.
869      */
setIsInEmergencyCall(boolean isInEmergencyCall)870     private void setIsInEmergencyCall(boolean isInEmergencyCall) {
871         mIsInEmergencyCall = isInEmergencyCall;
872     }
873 
874     /**
875      * Checks if there is an ongoing emergency call.
876      *
877      * @return true if in emergency call
878      */
isInEmergencyCall()879     public boolean isInEmergencyCall() {
880         return mIsInEmergencyCall;
881     }
882 
883     /**
884      * Triggers modem to exit emergency mode.
885      *
886      * @param phone the {@code Phone} to exit the emergency mode.
887      * @param emergencyType the emergency type to identify an emergency call or SMS.
888      */
exitEmergencyMode(Phone phone, @EmergencyType int emergencyType)889     private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType) {
890         Rlog.i(TAG, "exitEmergencyMode for " + emergencyTypeToString(emergencyType));
891 
892         if (emergencyType == EMERGENCY_TYPE_CALL) {
893             if (mSmsPhone != null && isSamePhone(phone, mSmsPhone)) {
894                 // Waits for exiting the emergency mode until the emergency SMS is ended.
895                 Rlog.i(TAG, "exitEmergencyMode: waits for emergency SMS end.");
896                 setIsInEmergencyCall(false);
897                 return;
898             }
899         } else if (emergencyType == EMERGENCY_TYPE_SMS) {
900             if (mPhone != null && isSamePhone(phone, mPhone)) {
901                 // Waits for exiting the emergency mode until the emergency call is ended.
902                 Rlog.i(TAG, "exitEmergencyMode: waits for emergency call end.");
903                 return;
904             }
905         }
906 
907         if (mEmergencyMode == MODE_EMERGENCY_NONE) {
908             return;
909         }
910         mEmergencyMode = MODE_EMERGENCY_NONE;
911         setEmergencyModeInProgress(true);
912 
913         Message m = mHandler.obtainMessage(
914                 MSG_EXIT_EMERGENCY_MODE_DONE, Integer.valueOf(emergencyType));
915         if (!mWasEmergencyModeSetOnModem) {
916             Rlog.d(TAG, "Emergency mode was not set on modem: Skipping exiting emergency mode.");
917             // Send back a response for the command, but with null information
918             AsyncResult.forMessage(m, null, null);
919             // Ensure that we do not accidentally block indefinitely when trying to validate
920             // the exit condition.
921             m.sendToTarget();
922             return;
923         }
924 
925         mWasEmergencyModeSetOnModem = false;
926         phone.exitEmergencyMode(m);
927     }
928 
929     /** Returns last {@link EmergencyRegistrationResult} as set by {@code setEmergencyMode()}. */
getEmergencyRegistrationResult()930     public EmergencyRegistrationResult getEmergencyRegistrationResult() {
931         return mLastEmergencyRegistrationResult;
932     }
933 
waitForTransportChangeCompleted(CompletableFuture<Boolean> future)934     private void waitForTransportChangeCompleted(CompletableFuture<Boolean> future) {
935         if (future != null) {
936             synchronized (future) {
937                 if ((mEmergencyMode == MODE_EMERGENCY_NONE)
938                         || mHandler.getLooper().isCurrentThread()) {
939                     // Do not block the Handler's thread
940                     return;
941                 }
942                 long now = SystemClock.elapsedRealtime();
943                 long deadline = now + DEFAULT_TRANSPORT_CHANGE_TIMEOUT_MS;
944                 // Guard with while loop to handle spurious wakeups
945                 while (!future.isDone() && now < deadline) {
946                     try {
947                         future.wait(deadline - now);
948                     } catch (Exception e) {
949                         Rlog.e(TAG, "waitForTransportChangeCompleted wait e=" + e);
950                     }
951                     now = SystemClock.elapsedRealtime();
952                 }
953             }
954         }
955     }
956 
maybeNotifyTransportChangeCompleted(@mergencyType int emergencyType, boolean enforced)957     private void maybeNotifyTransportChangeCompleted(@EmergencyType int emergencyType,
958             boolean enforced) {
959         if (emergencyType != EMERGENCY_TYPE_CALL) {
960             // It's not for the emergency call
961             return;
962         }
963         CompletableFuture<Boolean> future = mEmergencyTransportChangedFuture;
964         if (future != null) {
965             synchronized (future) {
966                 if (!future.isDone()
967                         && ((!isEmergencyModeInProgress() && mEmergencyMode == MODE_EMERGENCY_WWAN)
968                                 || enforced)) {
969                     future.complete(Boolean.TRUE);
970                     future.notifyAll();
971                 }
972             }
973         }
974     }
975 
976     /**
977      * Handles emergency transport change by setting new emergency mode.
978      *
979      * @param emergencyType the emergency type to identify an emergency call or SMS
980      * @param mode the new emergency mode
981      */
onEmergencyTransportChangedAndWait(@mergencyType int emergencyType, @EmergencyConstants.EmergencyMode int mode)982     public void onEmergencyTransportChangedAndWait(@EmergencyType int emergencyType,
983             @EmergencyConstants.EmergencyMode int mode) {
984         // Wait for the completion of setting MODE_EMERGENCY_WWAN only for emergency calls
985         if (emergencyType == EMERGENCY_TYPE_CALL && mode == MODE_EMERGENCY_WWAN) {
986             CompletableFuture<Boolean> future = new CompletableFuture<>();
987             synchronized (future) {
988                 mEmergencyTransportChangedFuture = future;
989                 onEmergencyTransportChanged(emergencyType, mode);
990                 waitForTransportChangeCompleted(future);
991             }
992             return;
993         }
994         onEmergencyTransportChanged(emergencyType, mode);
995     }
996 
997     /**
998      * Handles emergency transport change by setting new emergency mode.
999      *
1000      * @param emergencyType the emergency type to identify an emergency call or SMS
1001      * @param mode the new emergency mode
1002      */
onEmergencyTransportChanged(@mergencyType int emergencyType, @EmergencyConstants.EmergencyMode int mode)1003     public void onEmergencyTransportChanged(@EmergencyType int emergencyType,
1004             @EmergencyConstants.EmergencyMode int mode) {
1005         if (mHandler.getLooper().isCurrentThread()) {
1006             Phone phone = null;
1007             if (emergencyType == EMERGENCY_TYPE_CALL) {
1008                 phone = mPhone;
1009             } else if (emergencyType == EMERGENCY_TYPE_SMS) {
1010                 phone = mSmsPhone;
1011             }
1012 
1013             if (phone != null) {
1014                 setEmergencyMode(phone, emergencyType, mode, MSG_SET_EMERGENCY_MODE_DONE);
1015             }
1016         } else {
1017             mHandler.post(() -> {
1018                 onEmergencyTransportChanged(emergencyType, mode);
1019             });
1020         }
1021     }
1022 
1023     /**
1024      * Notify the tracker that the emergency call domain has been updated.
1025      * @param phoneType The new PHONE_TYPE_* of the call.
1026      * @param c The connection of the call
1027      */
onEmergencyCallDomainUpdated(int phoneType, android.telecom.Connection c)1028     public void onEmergencyCallDomainUpdated(int phoneType, android.telecom.Connection c) {
1029         Rlog.d(TAG, "domain update for callId: " + c.getTelecomCallId());
1030         int domain = -1;
1031         switch(phoneType) {
1032             case (PhoneConstants.PHONE_TYPE_CDMA_LTE):
1033                 //fallthrough
1034             case (PhoneConstants.PHONE_TYPE_GSM):
1035                 //fallthrough
1036             case (PhoneConstants.PHONE_TYPE_CDMA): {
1037                 domain = NetworkRegistrationInfo.DOMAIN_CS;
1038                 break;
1039             }
1040             case (PhoneConstants.PHONE_TYPE_IMS): {
1041                 domain = NetworkRegistrationInfo.DOMAIN_PS;
1042                 break;
1043             }
1044             default: {
1045                 Rlog.w(TAG, "domain updated: Unexpected phoneType:" + phoneType);
1046             }
1047         }
1048         if (mEmergencyCallDomain == domain) return;
1049         Rlog.i(TAG, "domain updated: from " + mEmergencyCallDomain + " to " + domain);
1050         mEmergencyCallDomain = domain;
1051     }
1052 
1053     /**
1054      * Handles emergency call state change.
1055      *
1056      * @param state the new call state
1057      * @param c the call whose state has changed
1058      */
onEmergencyCallStateChanged(Call.State state, android.telecom.Connection c)1059     public void onEmergencyCallStateChanged(Call.State state, android.telecom.Connection c) {
1060         if (state == Call.State.ACTIVE) {
1061             mActiveEmergencyCalls.add(c);
1062             if (Objects.equals(mOngoingConnection, c)) {
1063                 Rlog.i(TAG, "call connected " + c.getTelecomCallId());
1064                 if (mPhone != null
1065                         && isVoWiFi(mOngoingCallProperties)
1066                         && mEmergencyMode == EmergencyConstants.MODE_EMERGENCY_WLAN) {
1067                     // Recover normal service in cellular when VoWiFi is connected
1068                     mPhone.cancelEmergencyNetworkScan(true, null);
1069                 }
1070             }
1071         }
1072     }
1073 
1074     /**
1075      * Handles the change of emergency call properties.
1076      *
1077      * @param properties the new call properties.
1078      * @param c the call whose state has changed.
1079      */
onEmergencyCallPropertiesChanged(int properties, android.telecom.Connection c)1080     public void onEmergencyCallPropertiesChanged(int properties, android.telecom.Connection c) {
1081         if (Objects.equals(mOngoingConnection, c)) {
1082             mOngoingCallProperties = properties;
1083         }
1084     }
1085 
1086     /**
1087      * Handles the radio power off request.
1088      */
onCellularRadioPowerOffRequested()1089     public void onCellularRadioPowerOffRequested() {
1090         exitEmergencySmsCallbackModeAndEmergencyMode();
1091         exitEmergencyCallbackMode();
1092     }
1093 
isVoWiFi(int properties)1094     private static boolean isVoWiFi(int properties) {
1095         return (properties & android.telecom.Connection.PROPERTY_WIFI) > 0
1096                 || (properties & android.telecom.Connection.PROPERTY_CROSS_SIM) > 0;
1097     }
1098 
1099     /**
1100      * Returns {@code true} if device and carrier support emergency callback mode.
1101      *
1102      * @param phone The {@link Phone} instance to be checked.
1103      */
1104     @VisibleForTesting
isEmergencyCallbackModeSupported(Phone phone)1105     public boolean isEmergencyCallbackModeSupported(Phone phone) {
1106         if (phone == null) {
1107             return false;
1108         }
1109         int subId = phone.getSubId();
1110         int phoneId = phone.getPhoneId();
1111         if (!isSimReady(phoneId, subId)) {
1112             // If there is no SIM, refer to the saved last carrier configuration with valid
1113             // subscription.
1114             Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(phoneId));
1115             if (savedConfig == null) {
1116                 // Exceptional case such as with poor boot performance.
1117                 // Usually, the first carrier config change will update the cache.
1118                 // But with poor boot performance, the carrier config change
1119                 // can be delayed for a long time.
1120                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
1121                 savedConfig = Boolean.valueOf(
1122                         sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + phoneId, false));
1123                 Rlog.i(TAG, "ECBM value not cached, load from preference");
1124                 mNoSimEcbmSupported.put(Integer.valueOf(phoneId), savedConfig);
1125             }
1126             Rlog.i(TAG, "isEmergencyCallbackModeSupported savedConfig=" + savedConfig);
1127             return savedConfig;
1128         } else {
1129             return getConfig(subId,
1130                     CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL,
1131                     DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED);
1132         }
1133     }
1134 
1135     /**
1136      * Trigger entry into emergency callback mode.
1137      */
enterEmergencyCallbackMode()1138     private void enterEmergencyCallbackMode() {
1139         Rlog.d(TAG, "enter ECBM");
1140         setIsInEmergencyCall(false);
1141         // Check if not in ECM already.
1142         if (!isInEcm()) {
1143             setIsInEcm(true);
1144             if (!mPhone.getUnitTestMode()) {
1145                 TelephonyProperties.in_ecm_mode(true);
1146             }
1147 
1148             // Notify listeners of the entrance to ECM.
1149             sendEmergencyCallbackModeChange();
1150             if (isInImsEcm()) {
1151                 // emergency call registrants are not notified of new emergency call until entering
1152                 // ECBM (see ImsPhone#handleEnterEmergencyCallbackMode)
1153                 ((GsmCdmaPhone) mPhone).notifyEmergencyCallRegistrants(true);
1154             }
1155         } else {
1156             // Inform to reset the ECBM timer.
1157             ((GsmCdmaPhone) mPhone).notifyEcbmTimerReset(Boolean.FALSE);
1158         }
1159 
1160         setEmergencyCallbackMode(mPhone, EMERGENCY_TYPE_CALL);
1161 
1162         // Post this runnable so we will automatically exit if no one invokes
1163         // exitEmergencyCallbackMode() directly.
1164         long delayInMillis = TelephonyProperties.ecm_exit_timer()
1165                 .orElse(mEcmExitTimeoutMs);
1166         mHandler.postDelayed(mExitEcmRunnable, delayInMillis);
1167 
1168         // We don't want to go to sleep while in ECM.
1169         if (mWakeLock != null) mWakeLock.acquire(delayInMillis);
1170     }
1171 
1172     /**
1173      * Exits emergency callback mode and notifies relevant listeners.
1174      */
exitEmergencyCallbackMode()1175     public void exitEmergencyCallbackMode() {
1176         Rlog.d(TAG, "exit ECBM");
1177         // Remove pending exit ECM runnable, if any.
1178         mHandler.removeCallbacks(mExitEcmRunnable);
1179 
1180         if (isInEcm()) {
1181             setIsInEcm(false);
1182             if (!mPhone.getUnitTestMode()) {
1183                 TelephonyProperties.in_ecm_mode(false);
1184             }
1185 
1186             // Release wakeLock.
1187             releaseWakeLock();
1188 
1189             GsmCdmaPhone gsmCdmaPhone = (GsmCdmaPhone) mPhone;
1190             // Send intents that ECM has changed.
1191             sendEmergencyCallbackModeChange();
1192             gsmCdmaPhone.notifyEmergencyCallRegistrants(false);
1193 
1194             // Exit emergency mode on modem.
1195             exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL);
1196         }
1197 
1198         mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN;
1199         mIsTestEmergencyNumber = false;
1200         mPhone = null;
1201     }
1202 
releaseWakeLock()1203     private void releaseWakeLock() {
1204         // Release wakeLock.
1205         if (mWakeLock != null && mWakeLock.isHeld()) {
1206             try {
1207                 mWakeLock.release();
1208             } catch (Exception e) {
1209                 // Ignore the exception if the system has already released this WakeLock.
1210                 Rlog.d(TAG, "WakeLock already released: " + e.toString());
1211             }
1212         }
1213     }
1214 
1215     /**
1216      * Exits emergency callback mode and triggers runnable after exit response is received.
1217      */
exitEmergencyCallbackMode(Runnable onComplete)1218     public void exitEmergencyCallbackMode(Runnable onComplete) {
1219         mOnEcmExitCompleteRunnable = onComplete;
1220         exitEmergencyCallbackMode();
1221     }
1222 
1223     /**
1224      * Sends intents that emergency callback mode changed.
1225      */
sendEmergencyCallbackModeChange()1226     private void sendEmergencyCallbackModeChange() {
1227         Rlog.d(TAG, "sendEmergencyCallbackModeChange: isInEcm=" + isInEcm());
1228 
1229         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1230         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, isInEcm());
1231         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
1232         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1233     }
1234 
1235     /**
1236      * Returns {@code true} if currently in emergency callback mode.
1237      *
1238      * <p>
1239      * This is a period where the phone should be using as little power as possible and be ready to
1240      * receive an incoming call from the emergency operator.
1241      */
isInEcm()1242     public boolean isInEcm() {
1243         return mIsInEcm;
1244     }
1245 
1246     /**
1247      * Sets the emergency callback mode state.
1248      *
1249      * @param isInEcm {@code true} if currently in emergency callback mode, {@code false} otherwise.
1250      */
setIsInEcm(boolean isInEcm)1251     private void setIsInEcm(boolean isInEcm) {
1252         mIsInEcm = isInEcm;
1253     }
1254 
1255     /**
1256      * Returns {@code true} if currently in emergency callback mode over PS
1257      */
isInImsEcm()1258     public boolean isInImsEcm() {
1259         return mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_PS && isInEcm();
1260     }
1261 
1262     /**
1263      * Returns {@code true} if currently in emergency callback mode over CS
1264      */
isInCdmaEcm()1265     public boolean isInCdmaEcm() {
1266         // Phone can be null in the case where we are not actively tracking an emergency call.
1267         if (mPhone == null) return false;
1268         // Ensure that this method doesn't return true when we are attached to GSM.
1269         return mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA
1270                 && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm();
1271     }
1272 
1273     /**
1274      * Returns {@code true} if currently in emergency callback mode with the given {@link Phone}.
1275      *
1276      * @param phone the {@link Phone} for the emergency call.
1277      */
isInEcm(Phone phone)1278     public boolean isInEcm(Phone phone) {
1279         return isInEcm() && isSamePhone(mPhone, phone);
1280     }
1281 
sendEmergencyCallStateChange(Phone phone, boolean isAlive)1282     private void sendEmergencyCallStateChange(Phone phone, boolean isAlive) {
1283         if ((isAlive && !mSentEmergencyCallState && getBroadcastEmergencyCallStateChanges(phone))
1284                 || (!isAlive && mSentEmergencyCallState)) {
1285             mSentEmergencyCallState = isAlive;
1286             Rlog.i(TAG, "sendEmergencyCallStateChange: " + isAlive);
1287             Intent intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED);
1288             intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, isAlive);
1289             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phone.getPhoneId());
1290             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1291         }
1292     }
1293 
1294     /**
1295      * Starts the process of an emergency SMS.
1296      *
1297      * @param phone the {@code Phone} on which to process the emergency SMS.
1298      * @param smsId the SMS id on which to process the emergency SMS.
1299      * @param isTestEmergencyNumber whether this is a test emergency number.
1300      * @return A {@code CompletableFuture} that results in {@code DisconnectCause.NOT_DISCONNECTED}
1301      *         if the emergency SMS is successfully started.
1302      */
startEmergencySms(@onNull Phone phone, @NonNull String smsId, boolean isTestEmergencyNumber)1303     public CompletableFuture<Integer> startEmergencySms(@NonNull Phone phone, @NonNull String smsId,
1304             boolean isTestEmergencyNumber) {
1305         Rlog.i(TAG, "startEmergencySms: phoneId=" + phone.getPhoneId() + ", smsId=" + smsId
1306                 + ", scbm=" + isInScbm());
1307 
1308         // When an emergency call is in progress, it checks whether an emergency call is already in
1309         // progress on the different phone.
1310         if (mPhone != null && !isSamePhone(mPhone, phone)) {
1311             Rlog.e(TAG, "Emergency call is in progress on the other slot.");
1312             return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
1313         }
1314 
1315         boolean exitScbmInOtherPhone = false;
1316         boolean smsStartedInScbm = isInScbm();
1317 
1318         // When an emergency SMS is in progress, it checks whether an emergency SMS is already
1319         // in progress on the different phone.
1320         if (mSmsPhone != null && !isSamePhone(mSmsPhone, phone)) {
1321             if (smsStartedInScbm) {
1322                 // When other phone is in the emergency SMS callback mode, we need to stop the
1323                 // emergency SMS callback mode first.
1324                 exitScbmInOtherPhone = true;
1325                 mIsEmergencySmsStartedDuringScbm = true;
1326                 exitEmergencySmsCallbackModeAndEmergencyMode();
1327             } else {
1328                 Rlog.e(TAG, "Emergency SMS is in progress on the other slot.");
1329                 return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
1330             }
1331         }
1332 
1333         // When the previous emergency SMS is not completed yet and the device is not in SCBM,
1334         // this new request will not be allowed.
1335         if (mSmsPhone != null && isInEmergencyMode() && isEmergencyModeInProgress()
1336                 && !smsStartedInScbm) {
1337             Rlog.e(TAG, "Existing emergency SMS is in progress and not in SCBM.");
1338             return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
1339         }
1340 
1341         mSmsPhone = phone;
1342         mIsTestEmergencyNumberForSms = isTestEmergencyNumber;
1343         mOngoingEmergencySmsIds.add(smsId);
1344 
1345         if (smsStartedInScbm) {
1346             // When the device is in SCBM and emergency SMS is being sent,
1347             // completes the future immediately.
1348             if (!exitScbmInOtherPhone) {
1349                 // The emergency SMS is allowed and returns the success result.
1350                 return CompletableFuture.completedFuture(DisconnectCause.NOT_DISCONNECTED);
1351             }
1352 
1353             mSmsEmergencyModeFuture = new CompletableFuture<>();
1354         } else {
1355             // When the emergency mode is already set by the previous emergency call or SMS,
1356             // completes the future immediately.
1357             if (isInEmergencyMode() && !isEmergencyModeInProgress()) {
1358                 // The emergency SMS is allowed and returns the success result.
1359                 return CompletableFuture.completedFuture(DisconnectCause.NOT_DISCONNECTED);
1360             }
1361 
1362             mSmsEmergencyModeFuture = new CompletableFuture<>();
1363 
1364             if (!isInEmergencyMode()) {
1365                 setEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN,
1366                         MSG_SET_EMERGENCY_MODE_DONE);
1367             }
1368         }
1369 
1370         return mSmsEmergencyModeFuture;
1371     }
1372 
1373     /**
1374      * Ends an emergency SMS.
1375      * This should be called once an emergency SMS is sent.
1376      *
1377      * @param smsId the SMS id on which to end the emergency SMS.
1378      * @param success the flag specifying whether an emergency SMS is successfully sent or not.
1379      *                {@code true} if SMS is successfully sent, {@code false} otherwise.
1380      * @param domain the domain that MO SMS was sent.
1381      * @param isLastSmsPart the flag specifying whether this result is for the last SMS part or not.
1382      */
endSms(@onNull String smsId, boolean success, @NetworkRegistrationInfo.Domain int domain, boolean isLastSmsPart)1383     public void endSms(@NonNull String smsId, boolean success,
1384             @NetworkRegistrationInfo.Domain int domain, boolean isLastSmsPart) {
1385         if (success && !isLastSmsPart) {
1386             // Waits until all SMS parts are sent successfully.
1387             // Ensures that all SMS parts are sent while in the emergency mode.
1388             Rlog.i(TAG, "endSms: wait for additional SMS parts to be sent.");
1389         } else {
1390             mOngoingEmergencySmsIds.remove(smsId);
1391         }
1392 
1393         // If the outgoing emergency SMSs are empty, we can try to exit the emergency mode.
1394         if (mOngoingEmergencySmsIds.isEmpty()) {
1395             mSmsEmergencyModeFuture = null;
1396             mIsEmergencySmsStartedDuringScbm = false;
1397 
1398             if (isInEcm()) {
1399                 // When the emergency mode is not in MODE_EMERGENCY_CALLBACK,
1400                 // it needs to notify the emergency callback mode to modem.
1401                 if (mActiveEmergencyCalls.isEmpty() && mOngoingConnection == null) {
1402                     setEmergencyCallbackMode(mPhone, EMERGENCY_TYPE_CALL);
1403                 }
1404             }
1405 
1406             // If SCBM supports, SCBM will be entered here regardless of ECBM state.
1407             if (success && domain == NetworkRegistrationInfo.DOMAIN_PS
1408                     && (isInScbm() || isEmergencyCallbackModeSupported(mSmsPhone))) {
1409                 enterEmergencySmsCallbackMode();
1410             } else if (isInScbm()) {
1411                 // Sets the emergency mode to CALLBACK without re-initiating SCBM timer.
1412                 setEmergencyCallbackMode(mSmsPhone, EMERGENCY_TYPE_SMS);
1413             } else {
1414                 if (mSmsPhone != null) {
1415                     exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS);
1416                 }
1417                 clearEmergencySmsInfo();
1418             }
1419         }
1420     }
1421 
1422     /**
1423      * Called when emergency SMS is received from the network.
1424      */
onEmergencySmsReceived()1425     public void onEmergencySmsReceived() {
1426         if (isInScbm()) {
1427             Rlog.d(TAG, "Emergency SMS received, re-initiate SCBM timer");
1428             // Reinitiate the SCBM timer when receiving emergency SMS while in SCBM.
1429             enterEmergencySmsCallbackMode();
1430         }
1431     }
1432 
clearEmergencySmsInfo()1433     private void clearEmergencySmsInfo() {
1434         mOngoingEmergencySmsIds.clear();
1435         mIsEmergencySmsStartedDuringScbm = false;
1436         mIsTestEmergencyNumberForSms = false;
1437         mSmsEmergencyModeFuture = null;
1438         mSmsPhone = null;
1439     }
1440 
1441     /**
1442      * Returns {@code true} if currently in emergency SMS callback mode.
1443      */
isInScbm()1444     public boolean isInScbm() {
1445         return mIsInScbm;
1446     }
1447 
1448     /**
1449      * Sets the emergency SMS callback mode state.
1450      *
1451      * @param isInScbm {@code true} if currently in emergency SMS callback mode,
1452      *                 {@code false} otherwise.
1453      */
setIsInScbm(boolean isInScbm)1454     private void setIsInScbm(boolean isInScbm) {
1455         mIsInScbm = isInScbm;
1456     }
1457 
1458     /**
1459      * Enters the emergency SMS callback mode.
1460      */
enterEmergencySmsCallbackMode()1461     private void enterEmergencySmsCallbackMode() {
1462         Rlog.d(TAG, "enter SCBM while " + (isInScbm() ? "in" : "not in") + " SCBM");
1463         // Remove pending message if present.
1464         mHandler.removeMessages(MSG_EXIT_SCBM);
1465 
1466         if (!isInScbm()) {
1467             setIsInScbm(true);
1468         }
1469 
1470         setEmergencyCallbackMode(mSmsPhone, EMERGENCY_TYPE_SMS);
1471 
1472         // At the moment, the default SCBM timer value will be used with the same value
1473         // that is configured for emergency callback mode.
1474         int delayInMillis = Long.valueOf(mEcmExitTimeoutMs).intValue();
1475         int subId = mSmsPhone.getSubId();
1476         if (SubscriptionManager.isValidSubscriptionId(subId)) {
1477             delayInMillis = getConfig(subId,
1478                     CarrierConfigManager.KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT,
1479                     delayInMillis);
1480             if (delayInMillis == 0) {
1481                 delayInMillis = Long.valueOf(mEcmExitTimeoutMs).intValue();
1482             }
1483         }
1484         // Post the message so we will automatically exit if no one invokes
1485         // exitEmergencySmsCallbackModeAndEmergencyMode() directly.
1486         mHandler.sendEmptyMessageDelayed(MSG_EXIT_SCBM, delayInMillis);
1487     }
1488 
1489     /**
1490      * Exits emergency SMS callback mode and emergency mode if the device is in SCBM and
1491      * the emergency mode is in CALLBACK.
1492      */
exitEmergencySmsCallbackModeAndEmergencyMode()1493     private void exitEmergencySmsCallbackModeAndEmergencyMode() {
1494         Rlog.d(TAG, "exit SCBM and emergency mode");
1495         final Phone smsPhone = mSmsPhone;
1496         boolean wasInScbm = isInScbm();
1497         exitEmergencySmsCallbackMode();
1498 
1499         // The emergency mode needs to be checked to ensure that there is no ongoing emergency SMS.
1500         if (wasInScbm && mOngoingEmergencySmsIds.isEmpty()) {
1501             // Exit emergency mode on modem.
1502             exitEmergencyMode(smsPhone, EMERGENCY_TYPE_SMS);
1503         }
1504     }
1505 
1506     /**
1507      * Exits emergency SMS callback mode.
1508      */
exitEmergencySmsCallbackMode()1509     private void exitEmergencySmsCallbackMode() {
1510         // Remove pending message if present.
1511         mHandler.removeMessages(MSG_EXIT_SCBM);
1512 
1513         if (isInScbm()) {
1514             Rlog.i(TAG, "exit SCBM");
1515             setIsInScbm(false);
1516         }
1517 
1518         if (mOngoingEmergencySmsIds.isEmpty()) {
1519             mIsTestEmergencyNumberForSms = false;
1520             mSmsPhone = null;
1521         }
1522     }
1523 
1524     /**
1525      * Returns {@code true} if any phones from PhoneFactory have radio on.
1526      */
isRadioOn()1527     private boolean isRadioOn() {
1528         boolean result = false;
1529         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
1530             result |= phone.isRadioOn();
1531         }
1532         return result;
1533     }
1534 
1535     /**
1536      * Returns {@code true} if service states of all phones from PhoneFactory are radio off.
1537      */
isPowerOff()1538     private boolean isPowerOff() {
1539         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
1540             ServiceState ss = phone.getServiceStateTracker().getServiceState();
1541             if (ss.getState() != ServiceState.STATE_POWER_OFF) return false;
1542         }
1543         return true;
1544     }
1545 
registerForVoiceRegStateOrRatChanged()1546     private void registerForVoiceRegStateOrRatChanged() {
1547         if (mIsWaitingForRadioOff) return;
1548         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
1549             phone.getServiceStateTracker().registerForVoiceRegStateOrRatChanged(mHandler,
1550                     MSG_VOICE_REG_STATE_CHANGED, null);
1551         }
1552         mIsWaitingForRadioOff = true;
1553     }
1554 
unregisterForVoiceRegStateOrRatChanged()1555     private void unregisterForVoiceRegStateOrRatChanged() {
1556         if (!mIsWaitingForRadioOff) return;
1557         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
1558             phone.getServiceStateTracker().unregisterForVoiceRegStateOrRatChanged(mHandler);
1559         }
1560         mIsWaitingForRadioOff = false;
1561     }
1562 
1563     /**
1564      * Returns {@code true} if airplane mode is on.
1565      */
isAirplaneModeOn(Context context)1566     private boolean isAirplaneModeOn(Context context) {
1567         return Settings.Global.getInt(context.getContentResolver(),
1568                 Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
1569     }
1570 
1571     /**
1572      * Ensures that the radio is switched on and that DDS is switched for emergency call/SMS.
1573      *
1574      * <p>
1575      * Once radio is on and DDS switched, must call setEmergencyMode() before completing the future
1576      * and selecting emergency domain. EmergencyRegistrationResult is required to determine domain
1577      * and setEmergencyMode() is the only API that can receive it before starting domain selection.
1578      * Once domain selection is finished, the actual emergency mode will be set when
1579      * onEmergencyTransportChanged() is called.
1580      *
1581      * @param phone the {@code Phone} for the emergency call/SMS.
1582      * @param emergencyType the emergency type to identify an emergency call or SMS.
1583      * @param isTestEmergencyNumber a flag to inidicate whether the emergency call/SMS uses the test
1584      *                              emergency number.
1585      */
turnOnRadioAndSwitchDds(Phone phone, @EmergencyType int emergencyType, boolean isTestEmergencyNumber)1586     private void turnOnRadioAndSwitchDds(Phone phone, @EmergencyType int emergencyType,
1587             boolean isTestEmergencyNumber) {
1588         final boolean isAirplaneModeOn = isAirplaneModeOn(mContext);
1589         boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn;
1590         final SatelliteController satelliteController = SatelliteController.getInstance();
1591         boolean needToTurnOffSatellite = satelliteController.isSatelliteEnabled();
1592 
1593         if (isAirplaneModeOn && !isPowerOff()
1594                 && !phone.getServiceStateTracker().getDesiredPowerState()) {
1595             // power off is delayed to disconnect data connections
1596             Rlog.i(TAG, "turnOnRadioAndSwitchDds: wait for the delayed power off");
1597             registerForVoiceRegStateOrRatChanged();
1598             return;
1599         }
1600 
1601         if (needToTurnOnRadio || needToTurnOffSatellite) {
1602             Rlog.i(TAG, "turnOnRadioAndSwitchDds: phoneId=" + phone.getPhoneId() + " for "
1603                     + emergencyTypeToString(emergencyType));
1604             if (mRadioOnHelper == null) {
1605                 mRadioOnHelper = new RadioOnHelper(mContext);
1606             }
1607 
1608             final Phone phoneForEmergency = phone;
1609             final android.telecom.Connection expectedConnection = mOngoingConnection;
1610             final int waitForInServiceTimeout =
1611                     needToTurnOnRadio ? DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS : 0;
1612             Rlog.i(TAG, "turnOnRadioAndSwitchDds: timeout=" + waitForInServiceTimeout);
1613             mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() {
1614                 @Override
1615                 public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
1616                     if (!isRadioReady) {
1617                         if (satelliteController.isSatelliteEnabled()) {
1618                             // Could not turn satellite off
1619                             Rlog.e(TAG, "Failed to turn off satellite modem.");
1620                             completeEmergencyMode(emergencyType, DisconnectCause.SATELLITE_ENABLED);
1621                         } else {
1622                             // Could not turn radio on
1623                             Rlog.e(TAG, "Failed to turn on radio.");
1624                             completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF);
1625                         }
1626                     } else {
1627                         if (!Objects.equals(mOngoingConnection, expectedConnection)) {
1628                             Rlog.i(TAG, "onComplete "
1629                                     + expectedConnection.getTelecomCallId() + " canceled.");
1630                             return;
1631                         }
1632                         switchDdsAndSetEmergencyMode(phone, emergencyType);
1633                     }
1634                 }
1635 
1636                 @Override
1637                 public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
1638                     if (!Objects.equals(mOngoingConnection, expectedConnection)) {
1639                         Rlog.i(TAG, "isOkToCall "
1640                                 + expectedConnection.getTelecomCallId() + " canceled.");
1641                         return true;
1642                     }
1643                     // Wait for normal service state or timeout if required.
1644                     if (phone == phoneForEmergency
1645                             && waitForInServiceTimeout > 0
1646                             && !isNetworkRegistered(phone)) {
1647                         return false;
1648                     }
1649                     return phone.getServiceStateTracker().isRadioOn()
1650                             && !satelliteController.isSatelliteEnabled();
1651                 }
1652 
1653                 @Override
1654                 public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
1655                     if (!Objects.equals(mOngoingConnection, expectedConnection)) {
1656                         Rlog.i(TAG, "onTimeout "
1657                                 + expectedConnection.getTelecomCallId() + " canceled.");
1658                         return true;
1659                     }
1660                     // onTimeout shall be called only with the Phone for emergency
1661                     return phone.getServiceStateTracker().isRadioOn()
1662                             && !satelliteController.isSatelliteEnabled();
1663                 }
1664             }, !isTestEmergencyNumber, phone, isTestEmergencyNumber, waitForInServiceTimeout);
1665         } else {
1666             switchDdsAndSetEmergencyMode(phone, emergencyType);
1667         }
1668     }
1669 
1670     /**
1671      * If needed, block until the default data is switched for outgoing emergency call, or
1672      * timeout expires.
1673      *
1674      * @param phone            The Phone to switch the DDS on.
1675      * @param completeConsumer The consumer to call once the default data subscription has been
1676      *                         switched, provides {@code true} result if the switch happened
1677      *                         successfully or {@code false} if the operation timed out/failed.
1678      */
1679     @VisibleForTesting
switchDdsDelayed(Phone phone, Consumer<Boolean> completeConsumer)1680     public void switchDdsDelayed(Phone phone, Consumer<Boolean> completeConsumer) {
1681         if (phone == null) {
1682             // Do not block indefinitely.
1683             completeConsumer.accept(false);
1684         }
1685         try {
1686             // Waiting for PhoneSwitcher to complete the operation.
1687             CompletableFuture<Boolean> future = possiblyOverrideDefaultDataForEmergencyCall(phone);
1688             // In the case that there is an issue or bug in PhoneSwitcher logic, do not wait
1689             // indefinitely for the future to complete. Instead, set a timeout that will complete
1690             // the future as to not block the outgoing call indefinitely.
1691             CompletableFuture<Boolean> timeout = new CompletableFuture<>();
1692             mHandler.postDelayed(() -> timeout.complete(false), DEFAULT_DATA_SWITCH_TIMEOUT_MS);
1693             // Also ensure that the Consumer is completed on the main thread.
1694             CompletableFuture<Void> unused = future.acceptEitherAsync(timeout, completeConsumer,
1695                     mHandler::post);
1696         } catch (Exception e) {
1697             Rlog.w(TAG, "switchDdsDelayed - exception= " + e.getMessage());
1698         }
1699     }
1700 
1701     /**
1702      * If needed, block until Default Data subscription is switched for outgoing emergency call.
1703      *
1704      * <p>
1705      * In some cases, we need to try to switch the Default Data subscription before placing the
1706      * emergency call on DSDS devices. This includes the following situation: - The modem does not
1707      * support processing GNSS SUPL requests on the non-default data subscription. For some carriers
1708      * that do not provide a control plane fallback mechanism, the SUPL request will be dropped and
1709      * we will not be able to get the user's location for the emergency call. In this case, we need
1710      * to swap default data temporarily.
1711      *
1712      * @param phone Evaluates whether or not the default data should be moved to the phone
1713      *              specified. Should not be null.
1714      */
possiblyOverrideDefaultDataForEmergencyCall( @onNull Phone phone)1715     private CompletableFuture<Boolean> possiblyOverrideDefaultDataForEmergencyCall(
1716             @NonNull Phone phone) {
1717         int phoneCount = mTelephonyManagerProxy.getPhoneCount();
1718         // Do not override DDS if this is a single SIM device.
1719         if (phoneCount <= PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
1720             return CompletableFuture.completedFuture(Boolean.TRUE);
1721         }
1722 
1723         // Do not switch Default data if this device supports emergency SUPL on non-DDS.
1724         if (!mIsSuplDdsSwitchRequiredForEmergencyCall) {
1725             Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not "
1726                     + "require DDS switch.");
1727             return CompletableFuture.completedFuture(Boolean.TRUE);
1728         }
1729 
1730         // Only override default data if we are IN_SERVICE already.
1731         if (!isAvailableForEmergencyCalls(phone)) {
1732             Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS");
1733             return CompletableFuture.completedFuture(Boolean.TRUE);
1734         }
1735 
1736         // Only override default data if we are not roaming, we do not want to switch onto a network
1737         // that only supports data plane only (if we do not know).
1738         boolean isRoaming = phone.getServiceState().getVoiceRoaming();
1739         // In some roaming conditions, we know the roaming network doesn't support control plane
1740         // fallback even though the home operator does. For these operators we will need to do a DDS
1741         // switch anyway to make sure the SUPL request doesn't fail.
1742         boolean roamingNetworkSupportsControlPlaneFallback = true;
1743         String[] dataPlaneRoamPlmns = getConfig(phone.getSubId(),
1744                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY);
1745         if (dataPlaneRoamPlmns != null && Arrays.asList(dataPlaneRoamPlmns)
1746                 .contains(phone.getServiceState().getOperatorNumeric())) {
1747             roamingNetworkSupportsControlPlaneFallback = false;
1748         }
1749         if (isRoaming && roamingNetworkSupportsControlPlaneFallback) {
1750             Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: roaming network is assumed "
1751                     + "to support CP fallback, not switching DDS.");
1752             return CompletableFuture.completedFuture(Boolean.TRUE);
1753         }
1754         // Do not try to swap default data if we support CS fallback or it is assumed that the
1755         // roaming network supports control plane fallback, we do not want to introduce a lag in
1756         // emergency call setup time if possible.
1757         final boolean supportsCpFallback = getConfig(phone.getSubId(),
1758                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1759                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_ONLY)
1760                 != CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY;
1761         if (supportsCpFallback && roamingNetworkSupportsControlPlaneFallback) {
1762             Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, carrier "
1763                     + "supports CP fallback.");
1764             return CompletableFuture.completedFuture(Boolean.TRUE);
1765         }
1766 
1767         // Get extension time, may be 0 for some carriers that support ECBM as well. Use
1768         // CarrierConfig default if format fails.
1769         int extensionTime = 0;
1770         try {
1771             extensionTime = Integer.parseInt(getConfig(phone.getSubId(),
1772                     CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"));
1773         } catch (NumberFormatException e) {
1774             // Just use default.
1775         }
1776         CompletableFuture<Boolean> modemResultFuture = new CompletableFuture<>();
1777         try {
1778             Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: overriding DDS for "
1779                     + extensionTime + "seconds");
1780             mPhoneSwitcherProxy.getPhoneSwitcher().overrideDefaultDataForEmergency(
1781                     phone.getPhoneId(), extensionTime, modemResultFuture);
1782             // Catch all exceptions, we want to continue with emergency call if possible.
1783         } catch (Exception e) {
1784             Rlog.w(TAG,
1785                     "possiblyOverrideDefaultDataForEmergencyCall: exception = " + e.getMessage());
1786             modemResultFuture = CompletableFuture.completedFuture(Boolean.FALSE);
1787         }
1788         return modemResultFuture;
1789     }
1790 
1791     // Helper functions for easy CarrierConfigManager access
getConfig(int subId, String key, String defVal)1792     private String getConfig(int subId, String key, String defVal) {
1793         return getConfigBundle(subId, key).getString(key, defVal);
1794     }
getConfig(int subId, String key, int defVal)1795     private int getConfig(int subId, String key, int defVal) {
1796         return getConfigBundle(subId, key).getInt(key, defVal);
1797     }
getConfig(int subId, String key)1798     private String[] getConfig(int subId, String key) {
1799         return getConfigBundle(subId, key).getStringArray(key);
1800     }
getConfig(int subId, String key, boolean defVal)1801     private boolean getConfig(int subId, String key, boolean defVal) {
1802         return getConfigBundle(subId, key).getBoolean(key, defVal);
1803     }
getConfigBundle(int subId, String... keys)1804     private PersistableBundle getConfigBundle(int subId, String... keys) {
1805         if (mConfigManager == null) return new PersistableBundle();
1806         return mConfigManager.getConfigForSubId(subId, keys);
1807     }
1808 
1809     /**
1810      * Returns true if the state of the Phone is IN_SERVICE or available for emergency calling only.
1811      */
isAvailableForEmergencyCalls(Phone phone)1812     private boolean isAvailableForEmergencyCalls(Phone phone) {
1813         return ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState()
1814                 || phone.getServiceState().isEmergencyOnly();
1815     }
1816 
isNetworkRegistered(Phone phone)1817     private static boolean isNetworkRegistered(Phone phone) {
1818         ServiceState ss = phone.getServiceStateTracker().getServiceState();
1819         if (ss != null) {
1820             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
1821                     NetworkRegistrationInfo.DOMAIN_PS,
1822                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
1823             if (nri != null && nri.isNetworkRegistered()) {
1824                 // PS is IN_SERVICE state.
1825                 return true;
1826             }
1827             nri = ss.getNetworkRegistrationInfo(
1828                     NetworkRegistrationInfo.DOMAIN_CS,
1829                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
1830             if (nri != null && nri.isNetworkRegistered()) {
1831                 // CS is IN_SERVICE state.
1832                 return true;
1833             }
1834         }
1835         return false;
1836     }
1837 
1838     /**
1839      * Checks whether both {@code Phone}s are same or not.
1840      */
isSamePhone(Phone p1, Phone p2)1841     private static boolean isSamePhone(Phone p1, Phone p2) {
1842         return p1 != null && p2 != null && (p1.getPhoneId() == p2.getPhoneId());
1843     }
1844 
emergencyTypeToString(@mergencyType int emergencyType)1845     private static String emergencyTypeToString(@EmergencyType int emergencyType) {
1846         switch (emergencyType) {
1847             case EMERGENCY_TYPE_CALL: return "CALL";
1848             case EMERGENCY_TYPE_SMS: return "SMS";
1849             default: return "UNKNOWN";
1850         }
1851     }
1852 
onCarrierConfigurationChanged(int slotIndex, int subId)1853     private void onCarrierConfigurationChanged(int slotIndex, int subId) {
1854         Rlog.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex + ", subId=" + subId);
1855 
1856         if (slotIndex < 0) {
1857             return;
1858         }
1859 
1860         SharedPreferences sp = null;
1861         Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(slotIndex));
1862         if (savedConfig == null) {
1863             sp = PreferenceManager.getDefaultSharedPreferences(mContext);
1864             savedConfig = Boolean.valueOf(
1865                     sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, false));
1866             mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), savedConfig);
1867             Rlog.i(TAG, "onCarrierConfigChanged load from preference slotIndex=" + slotIndex
1868                     + ", ecbmSupported=" + savedConfig);
1869         }
1870 
1871         if (!isSimReady(slotIndex, subId)) {
1872             Rlog.i(TAG, "onCarrierConfigChanged SIM not ready");
1873             return;
1874         }
1875 
1876         PersistableBundle b = getConfigBundle(subId,
1877                 KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL,
1878                 KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
1879         if (b.isEmpty()) {
1880             Rlog.e(TAG, "onCarrierConfigChanged empty result");
1881             return;
1882         }
1883 
1884         if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) {
1885             Rlog.i(TAG, "onCarrierConfigChanged not carrier specific configuration");
1886             return;
1887         }
1888 
1889         // KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL
1890         boolean broadcast = b.getBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
1891         mBroadcastEmergencyCallStateChanges.put(
1892                 Integer.valueOf(slotIndex), Boolean.valueOf(broadcast));
1893 
1894         Rlog.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex
1895                 + ", broadcastEmergencyCallStateChanges=" + broadcast);
1896 
1897         // KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL
1898         boolean carrierConfig = b.getBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL);
1899         if (carrierConfig == savedConfig) {
1900             return;
1901         }
1902 
1903         mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), Boolean.valueOf(carrierConfig));
1904 
1905         if (sp == null) {
1906             sp = PreferenceManager.getDefaultSharedPreferences(mContext);
1907         }
1908         SharedPreferences.Editor editor = sp.edit();
1909         editor.putBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, carrierConfig);
1910         editor.apply();
1911 
1912         Rlog.i(TAG, "onCarrierConfigChanged preference updated slotIndex=" + slotIndex
1913                 + ", ecbmSupported=" + carrierConfig);
1914     }
1915 
isSimReady(int slotIndex, int subId)1916     private boolean isSimReady(int slotIndex, int subId) {
1917         return SubscriptionManager.isValidSubscriptionId(subId)
1918                 && mTelephonyManagerProxy.getSimState(slotIndex)
1919                         == TelephonyManager.SIM_STATE_READY;
1920     }
1921 
getBroadcastEmergencyCallStateChanges(Phone phone)1922     private boolean getBroadcastEmergencyCallStateChanges(Phone phone) {
1923         Boolean broadcast = mBroadcastEmergencyCallStateChanges.get(
1924                 Integer.valueOf(phone.getPhoneId()));
1925         return (broadcast == null) ? false : broadcast;
1926     }
1927 
1928     /**
1929      * Resets the emergency call state if it's in alive state.
1930      */
1931     @VisibleForTesting
maybeResetEmergencyCallStateChangedIntent()1932     public void maybeResetEmergencyCallStateChangedIntent() {
1933         Intent intent = mContext.registerReceiver(null,
1934             new IntentFilter(ACTION_EMERGENCY_CALL_STATE_CHANGED), Context.RECEIVER_NOT_EXPORTED);
1935         if (intent != null
1936                 && ACTION_EMERGENCY_CALL_STATE_CHANGED.equals(intent.getAction())) {
1937             boolean isAlive = intent.getBooleanExtra(
1938                     TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false);
1939             Rlog.i(TAG, "maybeResetEmergencyCallStateChangedIntent isAlive=" + isAlive);
1940             if (isAlive) {
1941                 intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED);
1942                 intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false);
1943                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1944             }
1945         }
1946     }
1947 
getRingingCall(Phone phone)1948     private Call getRingingCall(Phone phone) {
1949         if (phone == null) return null;
1950         Call ringingCall = phone.getRingingCall();
1951         if (ringingCall != null
1952                 && ringingCall.getState() != Call.State.IDLE
1953                 && ringingCall.getState() != Call.State.DISCONNECTED) {
1954             return ringingCall;
1955         }
1956         // Check the ImsPhoneCall in DISCONNECTING state.
1957         Phone imsPhone = phone.getImsPhone();
1958         if (imsPhone != null) {
1959             ringingCall = imsPhone.getRingingCall();
1960         }
1961         if (imsPhone != null && ringingCall != null
1962                 && ringingCall.getState() != Call.State.IDLE
1963                 && ringingCall.getState() != Call.State.DISCONNECTED) {
1964             return ringingCall;
1965         }
1966         return null;
1967     }
1968 
1969     /**
1970      * Ensures that there is no incoming call.
1971      *
1972      * @param completeConsumer The consumer to call once rejecting incoming call completes,
1973      *                         provides {@code true} result if operation completes successfully
1974      *                         or {@code false} if the operation timed out/failed.
1975      */
maybeRejectIncomingCall(Consumer<Boolean> completeConsumer)1976     private void maybeRejectIncomingCall(Consumer<Boolean> completeConsumer) {
1977         Phone[] phones = mPhoneFactoryProxy.getPhones();
1978         if (phones == null) {
1979             if (completeConsumer != null) {
1980                 completeConsumer.accept(true);
1981             }
1982             return;
1983         }
1984 
1985         Call ringingCall = null;
1986         for (Phone phone : phones) {
1987             ringingCall = getRingingCall(phone);
1988             if (ringingCall != null) {
1989                 Rlog.i(TAG, "maybeRejectIncomingCall found a ringing call");
1990                 break;
1991             }
1992         }
1993 
1994         if (ringingCall == null) {
1995             if (completeConsumer != null) {
1996                 completeConsumer.accept(true);
1997             }
1998             return;
1999         }
2000 
2001         try {
2002             ringingCall.hangup();
2003             if (completeConsumer == null) return;
2004 
2005             CompletableFuture<Boolean> future = new CompletableFuture<>();
2006             com.android.internal.telephony.Connection cn = ringingCall.getLatestConnection();
2007             cn.addListener(new OnDisconnectListener(future));
2008             // A timeout that will complete the future to not block the outgoing call indefinitely.
2009             CompletableFuture<Boolean> timeout = new CompletableFuture<>();
2010             mHandler.postDelayed(
2011                     () -> timeout.complete(false), DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS);
2012             // Ensure that the Consumer is completed on the main thread.
2013             CompletableFuture<Void> unused = future.acceptEitherAsync(timeout, completeConsumer,
2014                     mHandler::post).exceptionally((ex) -> {
2015                         Rlog.w(TAG, "maybeRejectIncomingCall - exceptionally= " + ex);
2016                         return null;
2017                     });
2018         } catch (Exception e) {
2019             Rlog.w(TAG, "maybeRejectIncomingCall - exception= " + e.getMessage());
2020             if (completeConsumer != null) {
2021                 completeConsumer.accept(false);
2022             }
2023         }
2024     }
2025 
registerForNewRingingConnection()2026     private void registerForNewRingingConnection() {
2027         Phone[] phones = mPhoneFactoryProxy.getPhones();
2028         if (phones == null) {
2029             // unit testing
2030             return;
2031         }
2032         for (Phone phone : phones) {
2033             phone.registerForNewRingingConnection(mHandler, MSG_NEW_RINGING_CONNECTION,
2034                     mRegistrantidentifier);
2035         }
2036     }
2037 
2038     /**
2039      * Hangup the new ringing call if there is an ongoing emergency call not connected.
2040      */
handleNewRingingConnection(Message msg)2041     private void handleNewRingingConnection(Message msg) {
2042         Connection c = (Connection) ((AsyncResult) msg.obj).result;
2043         if (c == null) return;
2044         if ((mNormalRoutingEmergencyConnection == null
2045                 || mNormalRoutingEmergencyConnection.getState() == STATE_ACTIVE
2046                 || mNormalRoutingEmergencyConnection.getState() == STATE_DISCONNECTED)
2047                 && (mOngoingConnection == null
2048                 || mOngoingConnection.getState() == STATE_ACTIVE
2049                 || mOngoingConnection.getState() == STATE_DISCONNECTED)) {
2050             return;
2051         }
2052         if ((c.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS)
2053                 && ((ImsPhoneConnection) c).isIncomingCallAutoRejected()) {
2054             Rlog.i(TAG, "handleNewRingingConnection auto rejected call");
2055         } else {
2056             try {
2057                 Rlog.i(TAG, "handleNewRingingConnection silently drop incoming call");
2058                 c.getCall().hangup();
2059             } catch (CallStateException e) {
2060                 Rlog.w(TAG, "handleNewRingingConnection", e);
2061             }
2062         }
2063     }
2064 
2065     /**
2066      * Indicates the start of a normal routing emergency call.
2067      *
2068      * <p>
2069      * Handles turning on radio and switching DDS.
2070      *
2071      * @param phone the {@code Phone} on which to process the emergency call.
2072      * @param c the {@code Connection} on which to process the emergency call.
2073      * @param completeConsumer The consumer to call once rejecting incoming call completes,
2074      *        provides {@code true} result if operation completes successfully
2075      *        or {@code false} if the operation timed out/failed.
2076      */
startNormalRoutingEmergencyCall(@onNull Phone phone, @NonNull android.telecom.Connection c, @NonNull Consumer<Boolean> completeConsumer)2077     public void startNormalRoutingEmergencyCall(@NonNull Phone phone,
2078             @NonNull android.telecom.Connection c, @NonNull Consumer<Boolean> completeConsumer) {
2079         Rlog.i(TAG, "startNormalRoutingEmergencyCall: phoneId=" + phone.getPhoneId()
2080                 + ", callId=" + c.getTelecomCallId());
2081 
2082         mNormalRoutingEmergencyConnection = c;
2083         maybeRejectIncomingCall(completeConsumer);
2084     }
2085 
2086     /**
2087      * Indicates the termination of a normal routing emergency call.
2088      *
2089      * @param c the normal routing emergency call disconnected.
2090      */
endNormalRoutingEmergencyCall(@onNull android.telecom.Connection c)2091     public void endNormalRoutingEmergencyCall(@NonNull android.telecom.Connection c) {
2092         if (c != mNormalRoutingEmergencyConnection) return;
2093         Rlog.i(TAG, "endNormalRoutingEmergencyCall: callId=" + c.getTelecomCallId());
2094         mNormalRoutingEmergencyConnection = null;
2095     }
2096 
2097     /**
2098      * Handles the normal routing emergency call state change.
2099      *
2100      * @param c the call whose state has changed
2101      * @param state the new call state
2102      */
onNormalRoutingEmergencyCallStateChanged(android.telecom.Connection c, @android.telecom.Connection.ConnectionState int state)2103     public void onNormalRoutingEmergencyCallStateChanged(android.telecom.Connection c,
2104             @android.telecom.Connection.ConnectionState int state) {
2105         if (c != mNormalRoutingEmergencyConnection) return;
2106 
2107         // If the call is connected, we don't need to monitor incoming call any more.
2108         if (state == android.telecom.Connection.STATE_ACTIVE
2109                 || state == android.telecom.Connection.STATE_DISCONNECTED) {
2110             endNormalRoutingEmergencyCall(c);
2111         }
2112     }
2113 
2114     /**
2115      * Determines whether switching stacks is needed or not.
2116      *
2117      * @param phone the {@code Phone} on which to process the emergency call.
2118      * @return true if switching stacks is needed.
2119      */
2120     @VisibleForTesting
needToSwitchPhone(Phone phone)2121     public boolean needToSwitchPhone(Phone phone) {
2122         int subId = phone.getSubId();
2123         int phoneId = phone.getPhoneId();
2124 
2125         if (isSimReady(phoneId, subId)) return false;
2126 
2127         boolean switchPhone = false;
2128         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2129             Rlog.i(TAG, "needToSwitchPhone SIM absent");
2130             if (phoneId != 0 || isThereOtherPhone(phoneId, true)) {
2131                 // Prefer default Phone or other Phone with a SIM regardless of lock state.
2132                 switchPhone = true;
2133             }
2134         } else {
2135             Rlog.i(TAG, "needToSwitchPhone SIM not ready");
2136             if ((phoneId == 0 && isThereOtherPhone(phoneId, false))
2137                     || (phoneId != 0 && isThereOtherPhone(phoneId, true))) {
2138                 // If there is another one with a SIM ready, switch Phones.
2139                 // Otherwise, prefer default Phone if both SIMs are locked.
2140                 switchPhone = true;
2141             }
2142         }
2143         Rlog.i(TAG, "needToSwitchPhone " + switchPhone);
2144         return switchPhone;
2145     }
2146 
isThereOtherPhone(int skipPhoneId, boolean ignoreLockState)2147     private boolean isThereOtherPhone(int skipPhoneId, boolean ignoreLockState) {
2148         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
2149             int phoneId = phone.getPhoneId();
2150             if (phoneId == skipPhoneId) {
2151                 continue;
2152             }
2153 
2154             int subId = phone.getSubId();
2155             if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2156                 Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", subId=" + subId);
2157                 continue;
2158             }
2159             int simState = mTelephonyManagerProxy.getSimState(phoneId);
2160             if ((simState == TelephonyManager.SIM_STATE_READY) || (ignoreLockState
2161                     && simState != TelephonyManager.SIM_STATE_ABSENT
2162                     && simState != TelephonyManager.SIM_STATE_NOT_READY)) {
2163                 Rlog.i(TAG, "isThereOtherPhone found, ignoreLockState=" + ignoreLockState
2164                         + ", phoneId=" + phoneId + ", simState=" + simState);
2165                 return true;
2166             }
2167             Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", simState=" + simState);
2168         }
2169 
2170         return false;
2171     }
2172 }
2173