Loading src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +90 −7 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhoneConnection; import com.android.internal.telephony.satellite.SatelliteController; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; import java.lang.annotation.Retention; Loading Loading @@ -141,6 +143,8 @@ public class EmergencyStateTracker { private final Handler mHandler; private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall; private final int mWaitForInServiceTimeoutMs; private final boolean mTurnOffOemEnabledSatelliteDuringEmergencyCall; private final boolean mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; private final PowerManager.WakeLock mWakeLock; private RadioOnHelper mRadioOnHelper; @EmergencyConstants.EmergencyMode Loading Loading @@ -488,13 +492,24 @@ public class EmergencyStateTracker { * @param context The context of the application. * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for * emergency call. * @param turnOffOemEnabledSatelliteDuringEmergencyCall Specifying whether OEM enabled satellite * should be turned off during emergency * call. * @param turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall Specifying whether non-emergency * NB-IOT NTN satellite should be * turned off for emergency call. * @param featureFlags The telephony feature flags. */ public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, @NonNull FeatureFlags featureFlags) { int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, @NonNull FeatureFlags featureFlags) { if (INSTANCE == null) { INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(), isSuplDdsSwitchRequiredForEmergencyCall, waitForInServiceTimeout, featureFlags); isSuplDdsSwitchRequiredForEmergencyCall, waitForInServiceTimeout, turnOffOemEnabledSatelliteDuringEmergencyCall, turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, featureFlags); } } Loading @@ -515,12 +530,18 @@ public class EmergencyStateTracker { */ private EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, @NonNull FeatureFlags featureFlags) { mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS; mContext = context; mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; mWaitForInServiceTimeoutMs = waitForInServiceTimeout; mTurnOffOemEnabledSatelliteDuringEmergencyCall = turnOffOemEnabledSatelliteDuringEmergencyCall; mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall = turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; mFeatureFlags = featureFlags; PowerManager pm = context.getSystemService(PowerManager.class); mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Loading Loading @@ -557,6 +578,12 @@ public class EmergencyStateTracker { * modem to get in-service state when emergency * call is dialed in airplane mode before * starting the emergency call. * @param turnOffOemEnabledSatelliteDuringEmergencyCall Specifying whether OEM enabled satellite * should be turned off during emergency * call. * @param turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall Specifying whether non-emergency * NB-IOT NTN satellite should be * turned off for emergency call. * @param phoneFactoryProxy The {@link PhoneFactoryProxy} to be injected. * @param phoneSwitcherProxy The {@link PhoneSwitcherProxy} to be injected. * @param telephonyManagerProxy The {@link TelephonyManagerProxy} to be Loading @@ -567,6 +594,8 @@ public class EmergencyStateTracker { @VisibleForTesting public EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy, PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy, RadioOnHelper radioOnHelper, long ecmExitTimeoutMs, FeatureFlags featureFlags) { Loading @@ -574,6 +603,10 @@ public class EmergencyStateTracker { mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; mWaitForInServiceTimeoutMs = waitForInServiceTimeout; mTurnOffOemEnabledSatelliteDuringEmergencyCall = turnOffOemEnabledSatelliteDuringEmergencyCall; mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall = turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; mPhoneFactoryProxy = phoneFactoryProxy; mPhoneSwitcherProxy = phoneSwitcherProxy; mTelephonyManagerProxy = telephonyManagerProxy; Loading Loading @@ -1732,8 +1765,7 @@ public class EmergencyStateTracker { boolean isTestEmergencyNumber) { final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; final SatelliteController satelliteController = SatelliteController.getInstance(); boolean needToTurnOffSatellite = satelliteController.isSatelliteEnabledOrBeingEnabled(); boolean needToTurnOffSatellite = shouldExitSatelliteMode(); if (isAirplaneModeOn && !isPowerOff() && !phone.getServiceStateTracker().getDesiredPowerState()) { Loading Loading @@ -1769,7 +1801,7 @@ public class EmergencyStateTracker { return; } if (!isRadioReady) { if (satelliteController.isSatelliteEnabledOrBeingEnabled()) { if (shouldExitSatelliteMode()) { // Could not turn satellite off Rlog.e(TAG, "Failed to turn off satellite modem."); completeEmergencyMode(emergencyType, DisconnectCause.SATELLITE_ENABLED); Loading Loading @@ -1802,7 +1834,7 @@ public class EmergencyStateTracker { return false; } return phone.getServiceStateTracker().isRadioOn() && !satelliteController.isSatelliteEnabledOrBeingEnabled(); && !shouldExitSatelliteMode(); } @Override Loading @@ -1814,7 +1846,7 @@ public class EmergencyStateTracker { } // onTimeout shall be called only with the Phone for emergency return phone.getServiceStateTracker().isRadioOn() && !satelliteController.isSatelliteEnabledOrBeingEnabled(); && !shouldExitSatelliteMode(); } }, !isTestEmergencyNumber, phone, isTestEmergencyNumber, waitForInServiceTimeout); } else { Loading Loading @@ -2324,4 +2356,55 @@ public class EmergencyStateTracker { return false; } /** * Checks whether the satellite mode should be turned off to proceed with an emergency call * when satellite mode is enabled or an NTN(Non Terrestrial Network) session is in progress. * * @return {@code true} if satellite mode should be exited before an emergency call is being * processed, {@code false} otherwise. */ @VisibleForTesting public boolean shouldExitSatelliteMode() { final SatelliteController satelliteController = SatelliteController.getInstance(); if (!satelliteController.isSatelliteEnabledOrBeingEnabled()) { return false; } if (!mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall) { // Carrier return false; } if (satelliteController.isDemoModeEnabled()) { // If user makes emergency call in demo mode, end the satellite session return true; } else if (mFeatureFlags.carrierRoamingNbIotNtn() && !satelliteController.getRequestIsEmergency()) { // If satellite is not for emergency, end the satellite session return true; } else { // satellite is for emergency if (mFeatureFlags.carrierRoamingNbIotNtn()) { int subId = satelliteController.getSelectedSatelliteSubId(); SubscriptionInfoInternal info = SubscriptionManagerService.getInstance() .getSubscriptionInfoInternal(subId); if (info == null) { Rlog.e(TAG, "satellite is/being enabled, but satellite sub " + subId + " is null"); return false; } if (info.getOnlyNonTerrestrialNetwork() == 1) { // OEM return mTurnOffOemEnabledSatelliteDuringEmergencyCall; } else { // Carrier return satelliteController.shouldTurnOffCarrierSatelliteForEmergencyCall(); } } else { return mTurnOffOemEnabledSatelliteDuringEmergencyCall; } } } } src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +13 −16 Original line number Diff line number Diff line Loading @@ -259,6 +259,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private Optional<Integer> mCurrentlyConnectedSubId = Optional.empty(); private final MmTelFeatureListener mMmTelFeatureListener = new MmTelFeatureListener(); private com.android.server.telecom.flags.FeatureFlags mTelecomFlags = new com.android.server.telecom.flags.FeatureFlagsImpl(); private class MmTelFeatureListener extends MmTelFeature.Listener { private IImsCallSessionListener processIncomingCall(@NonNull IImsCallSession c, Loading Loading @@ -312,11 +314,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // activeCall could be null if the foreground call is in a disconnected // state. If either of the calls is null there is no need to check if // one will be disconnected on answer. // Use VideoProfile.STATE_BIDIRECTIONAL to not affect existing // implementation. Video state of user response is handled in acceptCall(). boolean answeringWillDisconnect = shouldDisconnectActiveCallOnAnswer(activeCall, imsCall, VideoProfile.STATE_BIDIRECTIONAL); shouldDisconnectActiveCallOnAnswer(activeCall, imsCall); conn.setActiveCallDisconnectedOnAnswer(answeringWillDisconnect); } } Loading Loading @@ -2223,7 +2222,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { ImsCall ringingCall = mRingingCall.getImsCall(); if (mForegroundCall.hasConnections() && mRingingCall.hasConnections()) { answeringWillDisconnect = shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall, videoState); shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall); } // Cache video state for pending MT call. Loading Loading @@ -4086,6 +4085,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { + " in the single call unhold case"); } } ImsPhoneConnection conn = findConnection(imsCall); // Send connection event so that Telecom can unhold the call the bg call that was held // for calls across phone accounts. if (mTelecomFlags.enableCallSequencing() && conn != null && conn.getState() != ImsPhoneCall.State.DISCONNECTED) { conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_RESUME_FAILED, null); } mPhone.notifySuppServiceFailed(Phone.SuppService.RESUME); mMetrics.writeOnImsCallResumeFailed(mPhone.getPhoneId(), imsCall.getCallSession(), reasonInfo); Loading Loading @@ -5535,13 +5541,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { * * @param activeCall The active call. * @param incomingCall The incoming call. * @param incomingCallVideoState The media type of incoming call acceptance. * {@link VideoProfile.VideoState} * @return {@code true} if answering the incoming call will cause the active call to be * disconnected, {@code false} otherwise. */ private boolean shouldDisconnectActiveCallOnAnswer(ImsCall activeCall, ImsCall incomingCall, int incomingCallVideoState) { ImsCall incomingCall) { if (activeCall == null || incomingCall == null) { return false; Loading @@ -5556,14 +5560,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { boolean isActiveCallOnWifi = activeCall.isWifiCall(); boolean isVoWifiEnabled = mImsManager.isWfcEnabledByPlatform() && mImsManager.isWfcEnabledByUser(); boolean isIncomingCallAudio = true; if (!mFeatureFlags.terminateActiveVideoCallWhenAcceptingSecondVideoCallAsAudioOnly()) { isIncomingCallAudio = !incomingCall.isVideoCall(); } else { isIncomingCallAudio = !incomingCall.isVideoCall() || incomingCallVideoState == VideoProfile.STATE_AUDIO_ONLY; } boolean isIncomingCallAudio = !incomingCall.isVideoCall(); log("shouldDisconnectActiveCallOnAnswer : isActiveCallVideo=" + isActiveCallVideo + " isActiveCallOnWifi=" + isActiveCallOnWifi + " isIncomingCallAudio=" + isIncomingCallAudio + " isVowifiEnabled=" + isVoWifiEnabled); Loading src/java/com/android/internal/telephony/satellite/SatelliteController.java +26 −7 Original line number Diff line number Diff line Loading @@ -9195,23 +9195,42 @@ public class SatelliteController extends Handler { * @return Supported modes {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE} */ public int getSatelliteDataServicePolicyForPlmn(int subId, String plmn) { if (plmn != null && isValidSubscriptionId(subId)) { plogd("getSatelliteDataServicePolicyForPlmn: subId=" + subId + " plmn=" + plmn); if (isValidSubscriptionId(subId)) { Map<String, Integer> dataServicePolicy; synchronized (mSupportedSatelliteServicesLock) { Map<String, Integer> dataServicePolicy = mEntitlementDataServicePolicyMapPerCarrier.get( subId); logd("data policy available for sub id:" + dataServicePolicy); if (dataServicePolicy != null && dataServicePolicy.containsKey(plmn) && !plmn.isEmpty()) { dataServicePolicy = mEntitlementDataServicePolicyMapPerCarrier.get(subId); } plogd("getSatelliteDataServicePolicyForPlmn: dataServicePolicy=" + dataServicePolicy); if (dataServicePolicy != null) { if (!TextUtils.isEmpty(plmn) && dataServicePolicy.containsKey(plmn)) { plogd("getSatelliteDataServicePolicyForPlmn: " + "return policy using dataServicePolicy map"); return dataServicePolicy.get(plmn); } else if (TextUtils.isEmpty(plmn)) { int preferredPolicy = CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; for (String plmnKey : dataServicePolicy.keySet()) { int policy = dataServicePolicy.get(plmnKey); // higher value has higher preference if (policy > preferredPolicy) { preferredPolicy = policy; } } plogd("getSatelliteDataServicePolicyForPlmn: " + "return preferredPolicy=" + preferredPolicy); return preferredPolicy; } } if (isSatelliteDataServicesAllowed(subId, plmn)) { plogd("getSatelliteDataServicePolicyForPlmn: return data support mode from config"); return getCarrierSatelliteDataSupportedModeFromConfig(subId); } } plogd("getSatelliteDataServicePolicyForPlmn: return data support only restricted"); return CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; } Loading src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +3 −5 Original line number Diff line number Diff line Loading @@ -3919,12 +3919,10 @@ public class SubscriptionManagerService extends ISub.Stub { case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC: final Phone phone = PhoneFactory.getPhone(getSlotIndex(subId)); if (phone != null) { String number = phone.getLine1Number(); if (!TextUtils.isEmpty(number)) { return number; } } return TextUtils.emptyIfNull(phone.getLine1Number()); } else { return subInfo.getNumber(); } case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER: return subInfo.getNumberFromCarrier(); case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS: Loading tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +104 −4 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; Loading @@ -91,6 +92,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; Loading Loading @@ -149,8 +151,10 @@ public class EmergencyStateTrackerTest extends TelephonyTest { EmergencyStateTracker.getInstance(); }); EmergencyStateTracker .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags); EmergencyStateTracker.make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, true, /* turnOffOemEnabledSatelliteDuringEmergencyCall */ true, /* turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall */ mFeatureFlags); assertNotNull(EmergencyStateTracker.getInstance()); } Loading @@ -158,8 +162,10 @@ public class EmergencyStateTrackerTest extends TelephonyTest { @Test @SmallTest public void getInstance_returnsSameInstance() { EmergencyStateTracker .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags); EmergencyStateTracker.make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, true, /* turnOffOemEnabledSatelliteDuringEmergencyCall */ true, /* turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall */ mFeatureFlags); EmergencyStateTracker instance1 = EmergencyStateTracker.getInstance(); EmergencyStateTracker instance2 = EmergencyStateTracker.getInstance(); Loading Loading @@ -3300,6 +3306,91 @@ public class EmergencyStateTrackerTest extends TelephonyTest { anyBoolean(), eq(0)); } @Test @SmallTest public void testShouldExitSatelliteModeWhenSatelliteModeNotEnabled() { // Satellite mode is not enabled. doReturn(false).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true); assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenConfigTurnOffNonEmergencyNbIotNtnSessionDisabled() { doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); // Config for turning off non-emergency NB-IOT NTN session for emergency call: false EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, false); assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenSatelliteDemoModeEnabled() { doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); // Satellite demo mode is enabled doReturn(true).when(mSatelliteController).isDemoModeEnabled(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, true); assertTrue(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenCarrierRoamingNbIotNtnEnabledAndNtnNonEmergency() { // carrierRoamingNbIotNtn feature enabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); doReturn(false).when(mSatelliteController).isDemoModeEnabled(); // NTN non-emergency session is in progress doReturn(false).when(mSatelliteController).getRequestIsEmergency(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, true); assertTrue(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenNtnEmergency() { // carrierRoamingNbIotNtn feature enabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); doReturn(false).when(mSatelliteController).isDemoModeEnabled(); doReturn(true).when(mSatelliteController).getRequestIsEmergency(); doReturn(null).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); boolean turnOffOemEnabledSatelliteDuringEmergencyCall = true; EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( true, turnOffOemEnabledSatelliteDuringEmergencyCall, true); // No valid subscription assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); SubscriptionInfoInternal subInfo = Mockito.mock(SubscriptionInfoInternal.class); doReturn(1).when(subInfo).getOnlyNonTerrestrialNetwork(); doReturn(subInfo).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); // Only non-terrestrial networks assertEquals(turnOffOemEnabledSatelliteDuringEmergencyCall, emergencyStateTracker.shouldExitSatelliteMode()); doReturn(0).when(subInfo).getOnlyNonTerrestrialNetwork(); // Not only non-terrestrial networks emergencyStateTracker.shouldExitSatelliteMode(); verify(mSatelliteController).shouldTurnOffCarrierSatelliteForEmergencyCall(); // carrierRoamingNbIotNtn feature disabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(false); assertEquals(turnOffOemEnabledSatelliteDuringEmergencyCall, emergencyStateTracker.shouldExitSatelliteMode()); } /** * Test Phone selection. * SIM absent and SIM ready on the other Phone. Loading Loading @@ -3571,11 +3662,20 @@ public class EmergencyStateTrackerTest extends TelephonyTest { private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { return setupEmergencyStateTracker(isSuplDdsSwitchRequiredForEmergencyCall, true, true); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); doNothing().when(mPhoneSwitcher).overrideDefaultDataForEmergency( anyInt(), anyInt(), any()); return new EmergencyStateTracker(mContext, mTestableLooper.getLooper(), isSuplDdsSwitchRequiredForEmergencyCall, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, turnOffOemEnabledSatelliteDuringEmergencyCall, turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS, mFeatureFlags); } Loading Loading
src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +90 −7 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhoneConnection; import com.android.internal.telephony.satellite.SatelliteController; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; import java.lang.annotation.Retention; Loading Loading @@ -141,6 +143,8 @@ public class EmergencyStateTracker { private final Handler mHandler; private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall; private final int mWaitForInServiceTimeoutMs; private final boolean mTurnOffOemEnabledSatelliteDuringEmergencyCall; private final boolean mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; private final PowerManager.WakeLock mWakeLock; private RadioOnHelper mRadioOnHelper; @EmergencyConstants.EmergencyMode Loading Loading @@ -488,13 +492,24 @@ public class EmergencyStateTracker { * @param context The context of the application. * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for * emergency call. * @param turnOffOemEnabledSatelliteDuringEmergencyCall Specifying whether OEM enabled satellite * should be turned off during emergency * call. * @param turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall Specifying whether non-emergency * NB-IOT NTN satellite should be * turned off for emergency call. * @param featureFlags The telephony feature flags. */ public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, @NonNull FeatureFlags featureFlags) { int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, @NonNull FeatureFlags featureFlags) { if (INSTANCE == null) { INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(), isSuplDdsSwitchRequiredForEmergencyCall, waitForInServiceTimeout, featureFlags); isSuplDdsSwitchRequiredForEmergencyCall, waitForInServiceTimeout, turnOffOemEnabledSatelliteDuringEmergencyCall, turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, featureFlags); } } Loading @@ -515,12 +530,18 @@ public class EmergencyStateTracker { */ private EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, @NonNull FeatureFlags featureFlags) { mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS; mContext = context; mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; mWaitForInServiceTimeoutMs = waitForInServiceTimeout; mTurnOffOemEnabledSatelliteDuringEmergencyCall = turnOffOemEnabledSatelliteDuringEmergencyCall; mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall = turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; mFeatureFlags = featureFlags; PowerManager pm = context.getSystemService(PowerManager.class); mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Loading Loading @@ -557,6 +578,12 @@ public class EmergencyStateTracker { * modem to get in-service state when emergency * call is dialed in airplane mode before * starting the emergency call. * @param turnOffOemEnabledSatelliteDuringEmergencyCall Specifying whether OEM enabled satellite * should be turned off during emergency * call. * @param turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall Specifying whether non-emergency * NB-IOT NTN satellite should be * turned off for emergency call. * @param phoneFactoryProxy The {@link PhoneFactoryProxy} to be injected. * @param phoneSwitcherProxy The {@link PhoneSwitcherProxy} to be injected. * @param telephonyManagerProxy The {@link TelephonyManagerProxy} to be Loading @@ -567,6 +594,8 @@ public class EmergencyStateTracker { @VisibleForTesting public EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy, PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy, RadioOnHelper radioOnHelper, long ecmExitTimeoutMs, FeatureFlags featureFlags) { Loading @@ -574,6 +603,10 @@ public class EmergencyStateTracker { mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; mWaitForInServiceTimeoutMs = waitForInServiceTimeout; mTurnOffOemEnabledSatelliteDuringEmergencyCall = turnOffOemEnabledSatelliteDuringEmergencyCall; mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall = turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall; mPhoneFactoryProxy = phoneFactoryProxy; mPhoneSwitcherProxy = phoneSwitcherProxy; mTelephonyManagerProxy = telephonyManagerProxy; Loading Loading @@ -1732,8 +1765,7 @@ public class EmergencyStateTracker { boolean isTestEmergencyNumber) { final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; final SatelliteController satelliteController = SatelliteController.getInstance(); boolean needToTurnOffSatellite = satelliteController.isSatelliteEnabledOrBeingEnabled(); boolean needToTurnOffSatellite = shouldExitSatelliteMode(); if (isAirplaneModeOn && !isPowerOff() && !phone.getServiceStateTracker().getDesiredPowerState()) { Loading Loading @@ -1769,7 +1801,7 @@ public class EmergencyStateTracker { return; } if (!isRadioReady) { if (satelliteController.isSatelliteEnabledOrBeingEnabled()) { if (shouldExitSatelliteMode()) { // Could not turn satellite off Rlog.e(TAG, "Failed to turn off satellite modem."); completeEmergencyMode(emergencyType, DisconnectCause.SATELLITE_ENABLED); Loading Loading @@ -1802,7 +1834,7 @@ public class EmergencyStateTracker { return false; } return phone.getServiceStateTracker().isRadioOn() && !satelliteController.isSatelliteEnabledOrBeingEnabled(); && !shouldExitSatelliteMode(); } @Override Loading @@ -1814,7 +1846,7 @@ public class EmergencyStateTracker { } // onTimeout shall be called only with the Phone for emergency return phone.getServiceStateTracker().isRadioOn() && !satelliteController.isSatelliteEnabledOrBeingEnabled(); && !shouldExitSatelliteMode(); } }, !isTestEmergencyNumber, phone, isTestEmergencyNumber, waitForInServiceTimeout); } else { Loading Loading @@ -2324,4 +2356,55 @@ public class EmergencyStateTracker { return false; } /** * Checks whether the satellite mode should be turned off to proceed with an emergency call * when satellite mode is enabled or an NTN(Non Terrestrial Network) session is in progress. * * @return {@code true} if satellite mode should be exited before an emergency call is being * processed, {@code false} otherwise. */ @VisibleForTesting public boolean shouldExitSatelliteMode() { final SatelliteController satelliteController = SatelliteController.getInstance(); if (!satelliteController.isSatelliteEnabledOrBeingEnabled()) { return false; } if (!mTurnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall) { // Carrier return false; } if (satelliteController.isDemoModeEnabled()) { // If user makes emergency call in demo mode, end the satellite session return true; } else if (mFeatureFlags.carrierRoamingNbIotNtn() && !satelliteController.getRequestIsEmergency()) { // If satellite is not for emergency, end the satellite session return true; } else { // satellite is for emergency if (mFeatureFlags.carrierRoamingNbIotNtn()) { int subId = satelliteController.getSelectedSatelliteSubId(); SubscriptionInfoInternal info = SubscriptionManagerService.getInstance() .getSubscriptionInfoInternal(subId); if (info == null) { Rlog.e(TAG, "satellite is/being enabled, but satellite sub " + subId + " is null"); return false; } if (info.getOnlyNonTerrestrialNetwork() == 1) { // OEM return mTurnOffOemEnabledSatelliteDuringEmergencyCall; } else { // Carrier return satelliteController.shouldTurnOffCarrierSatelliteForEmergencyCall(); } } else { return mTurnOffOemEnabledSatelliteDuringEmergencyCall; } } } }
src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +13 −16 Original line number Diff line number Diff line Loading @@ -259,6 +259,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private Optional<Integer> mCurrentlyConnectedSubId = Optional.empty(); private final MmTelFeatureListener mMmTelFeatureListener = new MmTelFeatureListener(); private com.android.server.telecom.flags.FeatureFlags mTelecomFlags = new com.android.server.telecom.flags.FeatureFlagsImpl(); private class MmTelFeatureListener extends MmTelFeature.Listener { private IImsCallSessionListener processIncomingCall(@NonNull IImsCallSession c, Loading Loading @@ -312,11 +314,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // activeCall could be null if the foreground call is in a disconnected // state. If either of the calls is null there is no need to check if // one will be disconnected on answer. // Use VideoProfile.STATE_BIDIRECTIONAL to not affect existing // implementation. Video state of user response is handled in acceptCall(). boolean answeringWillDisconnect = shouldDisconnectActiveCallOnAnswer(activeCall, imsCall, VideoProfile.STATE_BIDIRECTIONAL); shouldDisconnectActiveCallOnAnswer(activeCall, imsCall); conn.setActiveCallDisconnectedOnAnswer(answeringWillDisconnect); } } Loading Loading @@ -2223,7 +2222,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { ImsCall ringingCall = mRingingCall.getImsCall(); if (mForegroundCall.hasConnections() && mRingingCall.hasConnections()) { answeringWillDisconnect = shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall, videoState); shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall); } // Cache video state for pending MT call. Loading Loading @@ -4086,6 +4085,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { + " in the single call unhold case"); } } ImsPhoneConnection conn = findConnection(imsCall); // Send connection event so that Telecom can unhold the call the bg call that was held // for calls across phone accounts. if (mTelecomFlags.enableCallSequencing() && conn != null && conn.getState() != ImsPhoneCall.State.DISCONNECTED) { conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_RESUME_FAILED, null); } mPhone.notifySuppServiceFailed(Phone.SuppService.RESUME); mMetrics.writeOnImsCallResumeFailed(mPhone.getPhoneId(), imsCall.getCallSession(), reasonInfo); Loading Loading @@ -5535,13 +5541,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { * * @param activeCall The active call. * @param incomingCall The incoming call. * @param incomingCallVideoState The media type of incoming call acceptance. * {@link VideoProfile.VideoState} * @return {@code true} if answering the incoming call will cause the active call to be * disconnected, {@code false} otherwise. */ private boolean shouldDisconnectActiveCallOnAnswer(ImsCall activeCall, ImsCall incomingCall, int incomingCallVideoState) { ImsCall incomingCall) { if (activeCall == null || incomingCall == null) { return false; Loading @@ -5556,14 +5560,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { boolean isActiveCallOnWifi = activeCall.isWifiCall(); boolean isVoWifiEnabled = mImsManager.isWfcEnabledByPlatform() && mImsManager.isWfcEnabledByUser(); boolean isIncomingCallAudio = true; if (!mFeatureFlags.terminateActiveVideoCallWhenAcceptingSecondVideoCallAsAudioOnly()) { isIncomingCallAudio = !incomingCall.isVideoCall(); } else { isIncomingCallAudio = !incomingCall.isVideoCall() || incomingCallVideoState == VideoProfile.STATE_AUDIO_ONLY; } boolean isIncomingCallAudio = !incomingCall.isVideoCall(); log("shouldDisconnectActiveCallOnAnswer : isActiveCallVideo=" + isActiveCallVideo + " isActiveCallOnWifi=" + isActiveCallOnWifi + " isIncomingCallAudio=" + isIncomingCallAudio + " isVowifiEnabled=" + isVoWifiEnabled); Loading
src/java/com/android/internal/telephony/satellite/SatelliteController.java +26 −7 Original line number Diff line number Diff line Loading @@ -9195,23 +9195,42 @@ public class SatelliteController extends Handler { * @return Supported modes {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE} */ public int getSatelliteDataServicePolicyForPlmn(int subId, String plmn) { if (plmn != null && isValidSubscriptionId(subId)) { plogd("getSatelliteDataServicePolicyForPlmn: subId=" + subId + " plmn=" + plmn); if (isValidSubscriptionId(subId)) { Map<String, Integer> dataServicePolicy; synchronized (mSupportedSatelliteServicesLock) { Map<String, Integer> dataServicePolicy = mEntitlementDataServicePolicyMapPerCarrier.get( subId); logd("data policy available for sub id:" + dataServicePolicy); if (dataServicePolicy != null && dataServicePolicy.containsKey(plmn) && !plmn.isEmpty()) { dataServicePolicy = mEntitlementDataServicePolicyMapPerCarrier.get(subId); } plogd("getSatelliteDataServicePolicyForPlmn: dataServicePolicy=" + dataServicePolicy); if (dataServicePolicy != null) { if (!TextUtils.isEmpty(plmn) && dataServicePolicy.containsKey(plmn)) { plogd("getSatelliteDataServicePolicyForPlmn: " + "return policy using dataServicePolicy map"); return dataServicePolicy.get(plmn); } else if (TextUtils.isEmpty(plmn)) { int preferredPolicy = CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; for (String plmnKey : dataServicePolicy.keySet()) { int policy = dataServicePolicy.get(plmnKey); // higher value has higher preference if (policy > preferredPolicy) { preferredPolicy = policy; } } plogd("getSatelliteDataServicePolicyForPlmn: " + "return preferredPolicy=" + preferredPolicy); return preferredPolicy; } } if (isSatelliteDataServicesAllowed(subId, plmn)) { plogd("getSatelliteDataServicePolicyForPlmn: return data support mode from config"); return getCarrierSatelliteDataSupportedModeFromConfig(subId); } } plogd("getSatelliteDataServicePolicyForPlmn: return data support only restricted"); return CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; } Loading
src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +3 −5 Original line number Diff line number Diff line Loading @@ -3919,12 +3919,10 @@ public class SubscriptionManagerService extends ISub.Stub { case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC: final Phone phone = PhoneFactory.getPhone(getSlotIndex(subId)); if (phone != null) { String number = phone.getLine1Number(); if (!TextUtils.isEmpty(number)) { return number; } } return TextUtils.emptyIfNull(phone.getLine1Number()); } else { return subInfo.getNumber(); } case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER: return subInfo.getNumberFromCarrier(); case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS: Loading
tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +104 −4 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; Loading @@ -91,6 +92,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; Loading Loading @@ -149,8 +151,10 @@ public class EmergencyStateTrackerTest extends TelephonyTest { EmergencyStateTracker.getInstance(); }); EmergencyStateTracker .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags); EmergencyStateTracker.make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, true, /* turnOffOemEnabledSatelliteDuringEmergencyCall */ true, /* turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall */ mFeatureFlags); assertNotNull(EmergencyStateTracker.getInstance()); } Loading @@ -158,8 +162,10 @@ public class EmergencyStateTrackerTest extends TelephonyTest { @Test @SmallTest public void getInstance_returnsSameInstance() { EmergencyStateTracker .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags); EmergencyStateTracker.make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, true, /* turnOffOemEnabledSatelliteDuringEmergencyCall */ true, /* turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall */ mFeatureFlags); EmergencyStateTracker instance1 = EmergencyStateTracker.getInstance(); EmergencyStateTracker instance2 = EmergencyStateTracker.getInstance(); Loading Loading @@ -3300,6 +3306,91 @@ public class EmergencyStateTrackerTest extends TelephonyTest { anyBoolean(), eq(0)); } @Test @SmallTest public void testShouldExitSatelliteModeWhenSatelliteModeNotEnabled() { // Satellite mode is not enabled. doReturn(false).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true); assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenConfigTurnOffNonEmergencyNbIotNtnSessionDisabled() { doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); // Config for turning off non-emergency NB-IOT NTN session for emergency call: false EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, false); assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenSatelliteDemoModeEnabled() { doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); // Satellite demo mode is enabled doReturn(true).when(mSatelliteController).isDemoModeEnabled(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, true); assertTrue(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenCarrierRoamingNbIotNtnEnabledAndNtnNonEmergency() { // carrierRoamingNbIotNtn feature enabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); doReturn(false).when(mSatelliteController).isDemoModeEnabled(); // NTN non-emergency session is in progress doReturn(false).when(mSatelliteController).getRequestIsEmergency(); EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(true, true, true); assertTrue(emergencyStateTracker.shouldExitSatelliteMode()); } @Test @SmallTest public void testShouldExitSatelliteModeWhenNtnEmergency() { // carrierRoamingNbIotNtn feature enabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled(); doReturn(false).when(mSatelliteController).isDemoModeEnabled(); doReturn(true).when(mSatelliteController).getRequestIsEmergency(); doReturn(null).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); boolean turnOffOemEnabledSatelliteDuringEmergencyCall = true; EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( true, turnOffOemEnabledSatelliteDuringEmergencyCall, true); // No valid subscription assertFalse(emergencyStateTracker.shouldExitSatelliteMode()); SubscriptionInfoInternal subInfo = Mockito.mock(SubscriptionInfoInternal.class); doReturn(1).when(subInfo).getOnlyNonTerrestrialNetwork(); doReturn(subInfo).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); // Only non-terrestrial networks assertEquals(turnOffOemEnabledSatelliteDuringEmergencyCall, emergencyStateTracker.shouldExitSatelliteMode()); doReturn(0).when(subInfo).getOnlyNonTerrestrialNetwork(); // Not only non-terrestrial networks emergencyStateTracker.shouldExitSatelliteMode(); verify(mSatelliteController).shouldTurnOffCarrierSatelliteForEmergencyCall(); // carrierRoamingNbIotNtn feature disabled when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(false); assertEquals(turnOffOemEnabledSatelliteDuringEmergencyCall, emergencyStateTracker.shouldExitSatelliteMode()); } /** * Test Phone selection. * SIM absent and SIM ready on the other Phone. Loading Loading @@ -3571,11 +3662,20 @@ public class EmergencyStateTrackerTest extends TelephonyTest { private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { return setupEmergencyStateTracker(isSuplDdsSwitchRequiredForEmergencyCall, true, true); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall, boolean turnOffOemEnabledSatelliteDuringEmergencyCall, boolean turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); doNothing().when(mPhoneSwitcher).overrideDefaultDataForEmergency( anyInt(), anyInt(), any()); return new EmergencyStateTracker(mContext, mTestableLooper.getLooper(), isSuplDdsSwitchRequiredForEmergencyCall, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, turnOffOemEnabledSatelliteDuringEmergencyCall, turnOffNonEmergencyNbIotNtnSatelliteForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS, mFeatureFlags); } Loading