Merge "Allow test numbers to be dialed from APM and wait for IN_SERVICE"
am: c02ca66716
Change-Id: I7627e03c55610461273f51b6220b1c0e42a98161
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index cd08289..288c72c 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -93,13 +93,12 @@
* get an onServiceStateChanged() callback when the radio successfully comes up.
*/
private void powerOnRadio() {
- Log.d(this, "powerOnRadio().");
// If airplane mode is on, we turn it off the same way that the Settings activity turns it
// off.
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) > 0) {
- Log.d(this, "==> Turning off airplane mode.");
+ Log.d(this, "==> Turning off airplane mode for emergency call.");
// Change the system setting
Settings.Global.putInt(mContext.getContentResolver(),
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 91a7d77..729f6a9 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -46,16 +46,16 @@
}
// Number of times to retry the call, and time between retry attempts.
+ // not final for testing
private static int MAX_NUM_RETRIES = 5;
+ // not final for testing
private static long TIME_BETWEEN_RETRIES_MILLIS = 5000; // msec
// Handler message codes; see handleMessage()
- @VisibleForTesting
- public static final int MSG_START_SEQUENCE = 1;
+ private static final int MSG_START_SEQUENCE = 1;
@VisibleForTesting
public static final int MSG_SERVICE_STATE_CHANGED = 2;
- @VisibleForTesting
- public static final int MSG_RETRY_TIMEOUT = 3;
+ private static final int MSG_RETRY_TIMEOUT = 3;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index e0db44e..6d7c1f0 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -40,8 +40,8 @@
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
@@ -68,6 +68,7 @@
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Queue;
import java.util.regex.Pattern;
@@ -208,26 +209,47 @@
};
// TelephonyManager Proxy interface for testing
+ @VisibleForTesting
public interface TelephonyManagerProxy {
int getPhoneCount();
boolean hasIccCard(int slotId);
+ boolean isCurrentEmergencyNumber(String number);
+ Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList();
}
- private TelephonyManagerProxy mTelephonyManagerProxy = new TelephonyManagerProxy() {
- private final TelephonyManager sTelephonyManager = TelephonyManager.getDefault();
+ private TelephonyManagerProxy mTelephonyManagerProxy;
+
+ private class TelephonyManagerProxyImpl implements TelephonyManagerProxy {
+ private final TelephonyManager mTelephonyManager;
+
+
+ TelephonyManagerProxyImpl(Context context) {
+ mTelephonyManager = new TelephonyManager(context);
+ }
@Override
public int getPhoneCount() {
- return sTelephonyManager.getPhoneCount();
+ return mTelephonyManager.getPhoneCount();
}
@Override
public boolean hasIccCard(int slotId) {
- return sTelephonyManager.hasIccCard(slotId);
+ return mTelephonyManager.hasIccCard(slotId);
}
- };
+
+ @Override
+ public boolean isCurrentEmergencyNumber(String number) {
+ return mTelephonyManager.isCurrentEmergencyNumber(number);
+ }
+
+ @Override
+ public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
+ return mTelephonyManager.getCurrentEmergencyNumberList();
+ }
+ }
//PhoneFactory proxy interface for testing
+ @VisibleForTesting
public interface PhoneFactoryProxy {
Phone getPhone(int index);
Phone getDefaultPhone();
@@ -286,6 +308,7 @@
public void onCreate() {
super.onCreate();
Log.initLogging(this);
+ setTelephonyManagerProxy(new TelephonyManagerProxyImpl(getApplicationContext()));
mExpectedComponentName = new ComponentName(this, this.getClass());
mEmergencyTonePlayer = new EmergencyTonePlayer(this);
TelecomAccountRegistry.getInstance(this).setTelephonyConnectionService(this);
@@ -387,9 +410,13 @@
}
}
+ final boolean isEmergencyNumber = mTelephonyManagerProxy.isCurrentEmergencyNumber(number);
+ // Find out if this is a test emergency number
+ final boolean isTestEmergencyNumber = isEmergencyNumberTestNumber(number);
+
// Convert into emergency number if necessary
// This is required in some regions (e.g. Taiwan).
- if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number)) {
+ if (isEmergencyNumber) {
final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
handle.getSchemeSpecificPart());
// We only do the conversion if the phone is not in service. The un-converted
@@ -408,9 +435,6 @@
}
final String numberToDial = number;
- final boolean isEmergencyNumber =
- PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
-
final boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
@@ -437,7 +461,12 @@
@Override
public boolean isOkToCall(Phone phone, int serviceState) {
- if (isEmergencyNumber) {
+ // HAL 1.4 introduced a new variant of dial for emergency calls, which includes
+ // an isTesting parameter. For HAL 1.4+, do not wait for IN_SERVICE, this will
+ // be handled at the RIL/vendor level by emergencyDial(...).
+ boolean waitForInServiceToDialEmergency = isTestEmergencyNumber
+ && phone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4);
+ if (isEmergencyNumber && !waitForInServiceToDialEmergency) {
// We currently only look to make sure that the radio is on before dialing.
// We should be able to make emergency calls at any time after the radio has
// been powered on and isn't in the UNAVAILABLE state, even if it is
@@ -445,9 +474,10 @@
return (phone.getState() == PhoneConstants.State.OFFHOOK)
|| phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
} else {
- // It is not an emergency number, so 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.
+ // 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
+ // it is a test emergency number and we have to wait for the device to move
+ // IN_SERVICE before the call can take place over normal routing.
return (phone.getState() == PhoneConstants.State.OFFHOOK)
|| serviceState == ServiceState.STATE_IN_SERVICE;
}
@@ -487,6 +517,24 @@
}
}
+ private boolean isEmergencyNumberTestNumber(String number) {
+ Map<Integer, List<EmergencyNumber>> list =
+ mTelephonyManagerProxy.getCurrentEmergencyNumberList();
+ // Do not worry about which subscription the test emergency call is on yet, only detect that
+ // it is an emergency.
+ for (Integer sub : list.keySet()) {
+ for (EmergencyNumber eNumber : list.get(sub)) {
+ if (number.equals(eNumber.getNumber())
+ && eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)) {
+ Log.i(this, "isEmergencyNumberTestNumber: " + number + " has been detected as "
+ + "a test emergency number.,");
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Whether the cellular radio is power off because the device is on Bluetooth.
*/
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index fb214cc..d9de2e8 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -16,17 +16,25 @@
package com.android.services.telephony;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.os.AsyncResult;
import android.os.Handler;
-import android.telephony.ServiceState;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.filters.FlakyTest;
+import android.telephony.ServiceState;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.TelephonyTestBase;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.ServiceStateTracker;
import org.junit.After;
import org.junit.Before;
@@ -34,16 +42,6 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.when;
-
/**
* Tests the RadioOnStateListener, which listens to one Phone and waits until its service
* state changes to accepting emergency calls or in service. If it can not find a tower to camp onto
@@ -52,21 +50,26 @@
@RunWith(AndroidJUnit4.class)
public class RadioOnStateListenerTest extends TelephonyTestBase {
- private static final long TIMEOUT_MS = 100;
+ private static final long TIMEOUT_MS = 1000;
@Mock Phone mMockPhone;
@Mock RadioOnStateListener.Callback mCallback;
RadioOnStateListener mListener;
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
mListener = new RadioOnStateListener();
}
+ @Override
@After
public void tearDown() throws Exception {
+ // Wait for the queue to clear...
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /*ms timeout*/);
mListener.getHandler().removeCallbacksAndMessages(null);
+ mListener = null;
super.tearDown();
}
@@ -86,8 +89,9 @@
}
/**
- * {@link RadioOnStateListener.Callback#isOkToCall(int)} returns true, so we are expecting
- * {@link RadioOnStateListener.Callback#onComplete(boolean)} to return true.
+ * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns true, so we are
+ * expecting {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
+ * return true.
*/
@Test
@SmallTest
@@ -107,8 +111,9 @@
}
/**
- * We never receive a {@link RadioOnStateListener.Callback#onComplete(boolean)} because
- * {@link RadioOnStateListener.Callback#isOkToCall(int)} returns false.
+ * We never receive a
+ * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
+ * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns false.
*/
@Test
@SmallTest
@@ -129,27 +134,27 @@
}
/**
- * Tests {@link RadioOnStateListener.Callback#isOkToCall(int)} returning false and hitting the
- * max number of retries. This should result in
- * {@link RadioOnStateListener.Callback#onComplete(boolean)} returning false.
+ * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returning false and
+ * hitting the max number of retries. This should result in
+ * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning
+ * false.
*/
@Test
- @FlakyTest
+ @SmallTest
public void testTimeout_RetryFailure() {
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_POWER_OFF);
when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
when(mMockPhone.getServiceState()).thenReturn(state);
when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
- mListener.setTimeBetweenRetriesMillis(50);
+ mListener.setTimeBetweenRetriesMillis(0/*ms*/);
mListener.setMaxNumRetries(2);
// Wait for the timer to expire and check state manually in onRetryTimeout
mListener.waitForRadioOn(mMockPhone, mCallback);
- waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 500);
+ waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
verify(mCallback).onComplete(eq(mListener), eq(false));
verify(mMockPhone, times(2)).setRadioPower(eq(true));
}
-
}