Place dial request for Emergency call soon after Radio is on.
In the current design, when airplane mode is ON and emergency
call is made, RadioOnStateListener listens for Service State
change events and then irrespective of service state if RADIO
is ON,it will place emergency call.But receiving of service
state events from modem will take time.
To overcome this delay, register for radioOff and radioOn events
in RadioOnStateListener.java, and once RADIO ON event is received
place emergency call immediately without waiting for ServiceState.
Bug:145788899
Change-Id: I34ec6d8fc43423f48b5ff930780882bb601303c0
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 981dc96..116c61d 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -110,6 +110,11 @@
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0);
+ for (Phone phone : PhoneFactory.getPhones()) {
+ Log.d(this, "powerOnRadio, enabling Radio");
+ phone.setRadioPower(true);
+ }
+
// Post the broadcast intend for change in airplane mode
// TODO: We really should not be in charge of sending this broadcast.
// If changing the setting is sufficient to trigger all of the rest of the logic,
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 52bd9cf..43269b4 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -56,6 +56,9 @@
@VisibleForTesting
public static final int MSG_SERVICE_STATE_CHANGED = 2;
private static final int MSG_RETRY_TIMEOUT = 3;
+ @VisibleForTesting
+ public static final int MSG_RADIO_ON = 4;
+ public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -75,6 +78,12 @@
case MSG_SERVICE_STATE_CHANGED:
onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result);
break;
+ case MSG_RADIO_ON:
+ onRadioOn();
+ break;
+ case MSG_RADIO_OFF_OR_NOT_AVAILABLE:
+ registerForRadioOn();
+ break;
case MSG_RETRY_TIMEOUT:
onRetryTimeout();
break;
@@ -135,6 +144,9 @@
mCallback = callback;
registerForServiceStateChanged();
+ // Register for RADIO_OFF to handle cases where emergency call is dialed before
+ // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF.
+ registerForRadioOff();
// Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see
// onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
// the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
@@ -169,6 +181,17 @@
}
}
+ private void onRadioOn() {
+ ServiceState state = mPhone.getServiceState();
+ Log.d(this, "onRadioOn, state = %s, Phone = %s", state,
+ mPhone.getPhoneId());
+ if (isOkToCall(state.getState())) {
+ onComplete(true);
+ cleanup();
+ } else {
+ Log.d(this, "onRadioOn: not ready to call yet, keep waiting.");
+ }
+ }
/**
* Callback to see if it is okay to call yet, given the current conditions.
*/
@@ -239,6 +262,8 @@
onComplete(false);
unregisterForServiceStateChanged();
+ unregisterForRadioOff();
+ unregisterForRadioOn();
cancelRetryTimer();
// Used for unregisterForServiceStateChanged() so we null it out here instead.
@@ -271,6 +296,31 @@
mHandler.removeMessages(MSG_SERVICE_STATE_CHANGED); // Clean up any pending messages too
}
+ private void registerForRadioOff() {
+ mPhone.mCi.registerForOffOrNotAvailable(mHandler, MSG_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ }
+
+ private void unregisterForRadioOff() {
+ // This method is safe to call even if we haven't set mPhone yet.
+ if (mPhone != null) {
+ mPhone.mCi.unregisterForOffOrNotAvailable(mHandler); // Safe even if unnecessary
+ }
+ mHandler.removeMessages(MSG_RADIO_OFF_OR_NOT_AVAILABLE); // Clean up any pending messages
+ }
+
+ private void registerForRadioOn() {
+ unregisterForRadioOff();
+ mPhone.mCi.registerForOn(mHandler, MSG_RADIO_ON, null);
+ }
+
+ private void unregisterForRadioOn() {
+ // This method is safe to call even if we haven't set mPhone yet.
+ if (mPhone != null) {
+ mPhone.mCi.unregisterForOn(mHandler); // Safe even if unnecessary
+ }
+ mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too
+ }
+
private void onComplete(boolean isRadioReady) {
if (mCallback != null) {
Callback tempCallback = mCallback;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index cfe614a..59e1742 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -492,7 +492,7 @@
// been powered on and isn't in the UNAVAILABLE state, even if it is
// reporting the OUT_OF_SERVICE state.
return (phone.getState() == PhoneConstants.State.OFFHOOK)
- || phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
+ || phone.getServiceStateTracker().isRadioOn();
} else {
// Wait until we are in service and ready to make calls. This can happen
// when we power down the radio on bluetooth to save power on watches or if
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index 8b46bf0..afdfab5 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -34,6 +34,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
@@ -55,6 +56,7 @@
@Mock Phone mMockPhone;
@Mock RadioOnStateListener.Callback mCallback;
+ @Mock CommandsInterface mMockCi;
RadioOnStateListener mListener;
@Override
@@ -80,6 +82,7 @@
@Test
@SmallTest
public void testRegisterForCallback() {
+ mMockPhone.mCi = mMockCi;
mListener.waitForRadioOn(mMockPhone, mCallback);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
@@ -87,6 +90,9 @@
verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
+
+ verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class),
+ eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull());
}
/**
@@ -101,6 +107,7 @@
state.setState(ServiceState.STATE_IN_SERVICE);
when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true);
+ mMockPhone.mCi = mMockCi;
mListener.waitForRadioOn(mMockPhone, mCallback);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
@@ -124,6 +131,7 @@
when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
when(mMockPhone.getServiceState()).thenReturn(state);
+ mMockPhone.mCi = mMockCi;
mListener.waitForRadioOn(mMockPhone, mCallback);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
@@ -152,6 +160,7 @@
mListener.setMaxNumRetries(2);
// Wait for the timer to expire and check state manually in onRetryTimeout
+ mMockPhone.mCi = mMockCi;
mListener.waitForRadioOn(mMockPhone, mCallback);
waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);