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