Loading src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +69 −13 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.internal.telephony.emergency; import static android.telecom.Connection.STATE_ACTIVE; import static android.telecom.Connection.STATE_DISCONNECTED; import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL; import static android.telephony.CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL; import static com.android.internal.telephony.TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; Loading Loading @@ -159,6 +161,7 @@ public class EmergencyStateTracker { private boolean mIsTestEmergencyNumber; private Runnable mOnEcmExitCompleteRunnable; private int mOngoingCallProperties; private boolean mSentEmergencyCallState; /** For emergency SMS */ private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>(); Loading @@ -174,6 +177,8 @@ public class EmergencyStateTracker { private final android.util.ArrayMap<Integer, Boolean> mNoSimEcbmSupported = new android.util.ArrayMap<>(); private final android.util.ArrayMap<Integer, Boolean> mBroadcastEmergencyCallStateChanges = new android.util.ArrayMap<>(); private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged( slotIndex, subId); Loading Loading @@ -466,6 +471,9 @@ public class EmergencyStateTracker { mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context); registerForNewRingingConnection(); // To recover the abnormal state after crash of com.android.phone process maybeResetEmergencyCallStateChangedIntent(); } /** Loading Loading @@ -581,6 +589,7 @@ public class EmergencyStateTracker { mPhone = phone; mOngoingConnection = c; mIsTestEmergencyNumber = isTestEmergencyNumber; sendEmergencyCallStateChange(mPhone, true); maybeRejectIncomingCall(null); return mCallEmergencyModeFuture; } Loading @@ -589,6 +598,7 @@ public class EmergencyStateTracker { mPhone = phone; mOngoingConnection = c; mIsTestEmergencyNumber = isTestEmergencyNumber; sendEmergencyCallStateChange(mPhone, true); maybeRejectIncomingCall(result -> { Rlog.i(TAG, "maybeRejectIncomingCall : result = " + result); turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, mIsTestEmergencyNumber); Loading @@ -611,6 +621,7 @@ public class EmergencyStateTracker { if (Objects.equals(mOngoingConnection, c)) { mOngoingConnection = null; mOngoingCallProperties = 0; sendEmergencyCallStateChange(mPhone, false); } if (wasActive && mActiveEmergencyCalls.isEmpty() Loading Loading @@ -1199,6 +1210,18 @@ public class EmergencyStateTracker { && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm(); } private void sendEmergencyCallStateChange(Phone phone, boolean isAlive) { if ((isAlive && !mSentEmergencyCallState && getBroadcastEmergencyCallStateChanges(phone)) || (!isAlive && mSentEmergencyCallState)) { mSentEmergencyCallState = isAlive; Rlog.i(TAG, "sendEmergencyCallStateChange: " + isAlive); Intent intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, isAlive); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phone.getPhoneId()); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } } /** * Starts the process of an emergency SMS. * Loading Loading @@ -1654,9 +1677,9 @@ public class EmergencyStateTracker { private boolean getConfig(int subId, String key, boolean defVal) { return getConfigBundle(subId, key).getBoolean(key, defVal); } private PersistableBundle getConfigBundle(int subId, String key) { private PersistableBundle getConfigBundle(int subId, String... keys) { if (mConfigManager == null) return new PersistableBundle(); return mConfigManager.getConfigForSubId(subId, key); return mConfigManager.getConfigForSubId(subId, keys); } /** Loading Loading @@ -1710,10 +1733,6 @@ public class EmergencyStateTracker { return; } updateNoSimEcbmSupported(slotIndex, subId); } private void updateNoSimEcbmSupported(int slotIndex, int subId) { SharedPreferences sp = null; Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(slotIndex)); if (savedConfig == null) { Loading @@ -1721,8 +1740,8 @@ public class EmergencyStateTracker { savedConfig = Boolean.valueOf( sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, false)); mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), savedConfig); Rlog.i(TAG, "updateNoSimEcbmSupported load from preference slotIndex=" + slotIndex + ", supported=" + savedConfig); Rlog.i(TAG, "onCarrierConfigChanged load from preference slotIndex=" + slotIndex + ", ecbmSupported=" + savedConfig); } if (!SubscriptionManager.isValidSubscriptionId(subId)) { Loading @@ -1730,17 +1749,28 @@ public class EmergencyStateTracker { return; } PersistableBundle b = getConfigBundle(subId, KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); PersistableBundle b = getConfigBundle(subId, KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL); if (b.isEmpty()) { Rlog.e(TAG, "updateNoSimEcbmSupported empty result"); Rlog.e(TAG, "onCarrierConfigChanged empty result"); return; } if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) { Rlog.i(TAG, "updateNoSimEcbmSupported not carrier specific configuration"); Rlog.i(TAG, "onCarrierConfigChanged not carrier specific configuration"); return; } // KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL boolean broadcast = b.getBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL); mBroadcastEmergencyCallStateChanges.put( Integer.valueOf(slotIndex), Boolean.valueOf(broadcast)); Rlog.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex + ", broadcastEmergencyCallStateChanges=" + broadcast); // KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL boolean carrierConfig = b.getBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); if (carrierConfig == savedConfig) { return; Loading @@ -1755,8 +1785,34 @@ public class EmergencyStateTracker { editor.putBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, carrierConfig); editor.apply(); Rlog.i(TAG, "updateNoSimEcbmSupported preference updated slotIndex=" + slotIndex + ", supported=" + carrierConfig); Rlog.i(TAG, "onCarrierConfigChanged preference updated slotIndex=" + slotIndex + ", ecbmSupported=" + carrierConfig); } private boolean getBroadcastEmergencyCallStateChanges(Phone phone) { Boolean broadcast = mBroadcastEmergencyCallStateChanges.get( Integer.valueOf(phone.getPhoneId())); return (broadcast == null) ? false : broadcast; } /** * Resets the emergency call state if it's in alive state. */ @VisibleForTesting public void maybeResetEmergencyCallStateChangedIntent() { Intent intent = mContext.registerReceiver(null, new IntentFilter(ACTION_EMERGENCY_CALL_STATE_CHANGED), Context.RECEIVER_NOT_EXPORTED); if (intent != null && ACTION_EMERGENCY_CALL_STATE_CHANGED.equals(intent.getAction())) { boolean isAlive = intent.getBooleanExtra( TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); Rlog.i(TAG, "maybeResetEmergencyCallStateChangedIntent isAlive=" + isAlive); if (isAlive) { intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } } } /** Loading tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +162 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyVararg; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; Loading @@ -49,10 +50,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.UserHandle; import android.provider.Settings; import android.telephony.AccessNetworkConstants; Loading @@ -74,6 +77,7 @@ import com.android.internal.telephony.Connection; import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.PhoneSwitcher; Loading Loading @@ -2326,6 +2330,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { false /* isRadioOn */); when(phone.getSubId()).thenReturn(1); setEcmSupportedConfig(phone, true); PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(phone.getSubId()); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg()); EmergencyStateTracker testEst = setupEmergencyStateTracker( false /* isSuplDdsSwitchRequiredForEmergencyCall */); Loading Loading @@ -2675,6 +2681,162 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } } /** * Test that emergency call state changes are sent. */ @Test @SmallTest public void testSendEmergencyCallStateChanges() { mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); when(testPhone.getSubId()).thenReturn(1); ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); CarrierConfigManager cfgManager = (CarrierConfigManager) mContext .getSystemService(Context.CARRIER_CONFIG_SERVICE); verify(cfgManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); CarrierConfigManager.CarrierConfigChangeListener carrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); assertNotNull(carrierConfigChangeListener); PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(testPhone.getSubId()); bundle.putBoolean(CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, true); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg()); // onCarrierConfigChanged with valid subscription carrierConfigChangeListener.onCarrierConfigChanged( testPhone.getPhoneId(), testPhone.getSubId(), TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); // Start emergency call CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, mTestConnection1, false); // Verify intent is sent that emergency call state is changed ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(1)).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); Intent intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertTrue(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, true)); // End emergency call emergencyStateTracker.endCall(mTestConnection1); // Verify intent is sent that emergency call state is changed verify(mContext, times(2)).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertFalse(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false)); } /** * Test that emergency call state change is reset after crash. */ @Test @SmallTest public void testResetEmergencyCallStateChanges() { Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, true); doReturn(intent).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); // Verify intent is sent that emergency call state is changed verify(mContext).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertFalse(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false)); } /** * Test that emergency call state is not reset after crash * if it's already reset. */ @Test @SmallTest public void testResetEmergencyCallStateChangesAlreadyReset() { Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); doReturn(intent).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); // Verify intent is not sent. verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); } /** * Test that emergency call state is not reset after crash * if it has never been sent. */ @Test @SmallTest public void testResetEmergencyCallStateChangesNotSent() { doReturn(null).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); // Verify intent is not sent. verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); Loading Loading
src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +69 −13 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.internal.telephony.emergency; import static android.telecom.Connection.STATE_ACTIVE; import static android.telecom.Connection.STATE_DISCONNECTED; import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL; import static android.telephony.CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL; import static com.android.internal.telephony.TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; Loading Loading @@ -159,6 +161,7 @@ public class EmergencyStateTracker { private boolean mIsTestEmergencyNumber; private Runnable mOnEcmExitCompleteRunnable; private int mOngoingCallProperties; private boolean mSentEmergencyCallState; /** For emergency SMS */ private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>(); Loading @@ -174,6 +177,8 @@ public class EmergencyStateTracker { private final android.util.ArrayMap<Integer, Boolean> mNoSimEcbmSupported = new android.util.ArrayMap<>(); private final android.util.ArrayMap<Integer, Boolean> mBroadcastEmergencyCallStateChanges = new android.util.ArrayMap<>(); private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged( slotIndex, subId); Loading Loading @@ -466,6 +471,9 @@ public class EmergencyStateTracker { mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context); registerForNewRingingConnection(); // To recover the abnormal state after crash of com.android.phone process maybeResetEmergencyCallStateChangedIntent(); } /** Loading Loading @@ -581,6 +589,7 @@ public class EmergencyStateTracker { mPhone = phone; mOngoingConnection = c; mIsTestEmergencyNumber = isTestEmergencyNumber; sendEmergencyCallStateChange(mPhone, true); maybeRejectIncomingCall(null); return mCallEmergencyModeFuture; } Loading @@ -589,6 +598,7 @@ public class EmergencyStateTracker { mPhone = phone; mOngoingConnection = c; mIsTestEmergencyNumber = isTestEmergencyNumber; sendEmergencyCallStateChange(mPhone, true); maybeRejectIncomingCall(result -> { Rlog.i(TAG, "maybeRejectIncomingCall : result = " + result); turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, mIsTestEmergencyNumber); Loading @@ -611,6 +621,7 @@ public class EmergencyStateTracker { if (Objects.equals(mOngoingConnection, c)) { mOngoingConnection = null; mOngoingCallProperties = 0; sendEmergencyCallStateChange(mPhone, false); } if (wasActive && mActiveEmergencyCalls.isEmpty() Loading Loading @@ -1199,6 +1210,18 @@ public class EmergencyStateTracker { && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm(); } private void sendEmergencyCallStateChange(Phone phone, boolean isAlive) { if ((isAlive && !mSentEmergencyCallState && getBroadcastEmergencyCallStateChanges(phone)) || (!isAlive && mSentEmergencyCallState)) { mSentEmergencyCallState = isAlive; Rlog.i(TAG, "sendEmergencyCallStateChange: " + isAlive); Intent intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, isAlive); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phone.getPhoneId()); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } } /** * Starts the process of an emergency SMS. * Loading Loading @@ -1654,9 +1677,9 @@ public class EmergencyStateTracker { private boolean getConfig(int subId, String key, boolean defVal) { return getConfigBundle(subId, key).getBoolean(key, defVal); } private PersistableBundle getConfigBundle(int subId, String key) { private PersistableBundle getConfigBundle(int subId, String... keys) { if (mConfigManager == null) return new PersistableBundle(); return mConfigManager.getConfigForSubId(subId, key); return mConfigManager.getConfigForSubId(subId, keys); } /** Loading Loading @@ -1710,10 +1733,6 @@ public class EmergencyStateTracker { return; } updateNoSimEcbmSupported(slotIndex, subId); } private void updateNoSimEcbmSupported(int slotIndex, int subId) { SharedPreferences sp = null; Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(slotIndex)); if (savedConfig == null) { Loading @@ -1721,8 +1740,8 @@ public class EmergencyStateTracker { savedConfig = Boolean.valueOf( sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, false)); mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), savedConfig); Rlog.i(TAG, "updateNoSimEcbmSupported load from preference slotIndex=" + slotIndex + ", supported=" + savedConfig); Rlog.i(TAG, "onCarrierConfigChanged load from preference slotIndex=" + slotIndex + ", ecbmSupported=" + savedConfig); } if (!SubscriptionManager.isValidSubscriptionId(subId)) { Loading @@ -1730,17 +1749,28 @@ public class EmergencyStateTracker { return; } PersistableBundle b = getConfigBundle(subId, KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); PersistableBundle b = getConfigBundle(subId, KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL); if (b.isEmpty()) { Rlog.e(TAG, "updateNoSimEcbmSupported empty result"); Rlog.e(TAG, "onCarrierConfigChanged empty result"); return; } if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) { Rlog.i(TAG, "updateNoSimEcbmSupported not carrier specific configuration"); Rlog.i(TAG, "onCarrierConfigChanged not carrier specific configuration"); return; } // KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL boolean broadcast = b.getBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL); mBroadcastEmergencyCallStateChanges.put( Integer.valueOf(slotIndex), Boolean.valueOf(broadcast)); Rlog.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex + ", broadcastEmergencyCallStateChanges=" + broadcast); // KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL boolean carrierConfig = b.getBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); if (carrierConfig == savedConfig) { return; Loading @@ -1755,8 +1785,34 @@ public class EmergencyStateTracker { editor.putBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, carrierConfig); editor.apply(); Rlog.i(TAG, "updateNoSimEcbmSupported preference updated slotIndex=" + slotIndex + ", supported=" + carrierConfig); Rlog.i(TAG, "onCarrierConfigChanged preference updated slotIndex=" + slotIndex + ", ecbmSupported=" + carrierConfig); } private boolean getBroadcastEmergencyCallStateChanges(Phone phone) { Boolean broadcast = mBroadcastEmergencyCallStateChanges.get( Integer.valueOf(phone.getPhoneId())); return (broadcast == null) ? false : broadcast; } /** * Resets the emergency call state if it's in alive state. */ @VisibleForTesting public void maybeResetEmergencyCallStateChangedIntent() { Intent intent = mContext.registerReceiver(null, new IntentFilter(ACTION_EMERGENCY_CALL_STATE_CHANGED), Context.RECEIVER_NOT_EXPORTED); if (intent != null && ACTION_EMERGENCY_CALL_STATE_CHANGED.equals(intent.getAction())) { boolean isAlive = intent.getBooleanExtra( TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); Rlog.i(TAG, "maybeResetEmergencyCallStateChangedIntent isAlive=" + isAlive); if (isAlive) { intent = new Intent(ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } } } /** Loading
tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +162 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyVararg; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; Loading @@ -49,10 +50,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.UserHandle; import android.provider.Settings; import android.telephony.AccessNetworkConstants; Loading @@ -74,6 +77,7 @@ import com.android.internal.telephony.Connection; import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.PhoneSwitcher; Loading Loading @@ -2326,6 +2330,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { false /* isRadioOn */); when(phone.getSubId()).thenReturn(1); setEcmSupportedConfig(phone, true); PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(phone.getSubId()); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg()); EmergencyStateTracker testEst = setupEmergencyStateTracker( false /* isSuplDdsSwitchRequiredForEmergencyCall */); Loading Loading @@ -2675,6 +2681,162 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } } /** * Test that emergency call state changes are sent. */ @Test @SmallTest public void testSendEmergencyCallStateChanges() { mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); when(testPhone.getSubId()).thenReturn(1); ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); CarrierConfigManager cfgManager = (CarrierConfigManager) mContext .getSystemService(Context.CARRIER_CONFIG_SERVICE); verify(cfgManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); CarrierConfigManager.CarrierConfigChangeListener carrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); assertNotNull(carrierConfigChangeListener); PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(testPhone.getSubId()); bundle.putBoolean(CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, true); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg()); // onCarrierConfigChanged with valid subscription carrierConfigChangeListener.onCarrierConfigChanged( testPhone.getPhoneId(), testPhone.getSubId(), TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); // Start emergency call CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, mTestConnection1, false); // Verify intent is sent that emergency call state is changed ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(1)).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); Intent intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertTrue(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, true)); // End emergency call emergencyStateTracker.endCall(mTestConnection1); // Verify intent is sent that emergency call state is changed verify(mContext, times(2)).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertFalse(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false)); } /** * Test that emergency call state change is reset after crash. */ @Test @SmallTest public void testResetEmergencyCallStateChanges() { Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, true); doReturn(intent).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); // Verify intent is sent that emergency call state is changed verify(mContext).sendStickyBroadcastAsUser( intentCaptor.capture(), eq(UserHandle.ALL)); intent = intentCaptor.getValue(); assertNotNull(intent); assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED, intent.getAction()); assertFalse(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false)); } /** * Test that emergency call state is not reset after crash * if it's already reset. */ @Test @SmallTest public void testResetEmergencyCallStateChangesAlreadyReset() { Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); doReturn(intent).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); // Verify intent is not sent. verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); } /** * Test that emergency call state is not reset after crash * if it has never been sent. */ @Test @SmallTest public void testResetEmergencyCallStateChangesNotSent() { doReturn(null).when(mContext).registerReceiver(eq(null), any(), eq(Context.RECEIVER_NOT_EXPORTED)); // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); emergencyStateTracker.maybeResetEmergencyCallStateChangedIntent(); ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); verify(mContext).registerReceiver(eq(null), filterCaptor.capture(), eq(Context.RECEIVER_NOT_EXPORTED)); IntentFilter filter = filterCaptor.getValue(); assertNotNull(filter); assertTrue(filter.hasAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)); // Verify intent is not sent. verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); Loading