Add "potential" variants for PhoneNumberUtils.isEmergencyNumber()
The phone app needs a way to distinguish between (a) numbers that are
definitely emergency numbers, and (b) numbers that *might* result in an
emergency call being dialed, but aren't specifically emergency numbers
themselves.
(The phone app needs this distinction in order to enforce the restriction
that 3rd party apps should not be allowed to make emergency calls using
the ACTION_CALL intent, while still making sure that the in-call UI only
displays the "emergency call" state for numbers that are *definitely*
emergency numbers. See bug 5493790 for the full details;)
So this change adds a full set of "isPotentialEmergencyNumber()" methods
to go along with the "isEmergencyNumber()" methods we've had all along.
The "potential" variants behave identically to the original methods,
*except* that they ultimately use number.startsWith() rather than
number.equals() when comparing against the list of emergency numbers.
TESTED:
- Unit test 'PhoneNumberUtilsTest#testIsEmergencyNumber' passes.
(The PhoneNumberUtilsTest class doesn't pass in its entirety, but it was
broken before this change also.)
- Also see the commit description of change
Ib949fea3c0ce6b341a90e617a03ba3f22c69018b for the exact tests I ran
against the phone app.
This change should be submitted along with
Change-Id: Ib949fea3c0ce6b341a90e617a03ba3f22c69018b
in apps/Phone (but this change must go in first to avoid breaking the
build.)
Bug: 5493790
Change-Id: Ic528cfcc555734cdaf4ca8a18a50199771ba49b1
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 34f8848..f2ccb5b 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1513,14 +1513,65 @@
static final int MIN_MATCH = 7;
/**
- * isEmergencyNumber: checks a given number against the list of
- * emergency numbers provided by the RIL and SIM card.
+ * Checks a given number against the list of
+ * emergency numbers provided by the RIL and SIM card.
*
* @param number the number to look up.
- * @return if the number is in the list of emergency numbers
- * listed in the ril / sim, then return true, otherwise false.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, otherwise return false.
*/
public static boolean isEmergencyNumber(String number) {
+ // Return true only if the specified number *exactly* matches
+ // one of the emergency numbers listed by the RIL / SIM.
+ return isEmergencyNumberInternal(number, true /* useExactMatch */);
+ }
+
+ /**
+ * Checks if given number might *potentially* result in
+ * a call to an emergency service on the current network.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number according to the list managed by the RIL or
+ * SIM, *or* if the specified number simply starts with the same
+ * digits as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param number the number to look up.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, *or* if the number starts with the
+ * same digits as any of those emergency numbers.
+ *
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(String number) {
+ // Check against the emergency numbers listed by the RIL / SIM,
+ // and *don't* require an exact match.
+ return isEmergencyNumberInternal(number, false /* useExactMatch */);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String) and
+ * isPotentialEmergencyNumber(String).
+ *
+ * @param number the number to look up.
+ *
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ * (Setting useExactMatch to false allows you to identify
+ * number that could *potentially* result in emergency calls
+ * since many networks will actually ignore trailing digits
+ * after a valid emergency number.)
+ *
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / sim, otherwise return false.
+ */
+ private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
// If the number passed in is null, just return false:
if (number == null) return false;
@@ -1540,16 +1591,26 @@
// searches through the comma-separated list for a match,
// return true if one is found.
for (String emergencyNum : numbers.split(",")) {
- if (number.startsWith(emergencyNum)) {
- return true;
+ if (useExactMatch) {
+ if (number.equals(emergencyNum)) {
+ return true;
+ }
+ } else {
+ if (number.startsWith(emergencyNum)) {
+ return true;
+ }
}
}
// no matches found against the list!
return false;
}
- //no ecclist system property, so use our own list.
- return (number.startsWith("112") || number.startsWith("911"));
+ // No ecclist system property, so use our own list.
+ if (useExactMatch) {
+ return (number.equals("112") || number.equals("911"));
+ } else {
+ return (number.startsWith("112") || number.startsWith("911"));
+ }
}
/**
@@ -1559,31 +1620,81 @@
* @param defaultCountryIso the specific country which the number should be checked against
* @return if the number is an emergency number for the specific country, then return true,
* otherwise false
+ *
* @hide
*/
public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
- PhoneNumberUtil util = PhoneNumberUtil.getInstance();
- try {
- PhoneNumber pn = util.parse(number, defaultCountryIso);
- // libphonenumber guarantees short numbers such as emergency numbers are classified as
- // invalid. Therefore, if the number passes the validation test, we believe it is not an
- // emergency number.
- // TODO: Compare against a list of country-specific known emergency numbers instead, once
- // that has been collected.
- if (util.isValidNumber(pn)) {
- return false;
- } else if ("BR".equalsIgnoreCase(defaultCountryIso) && number.length() >= 8) {
- // This is to prevent Brazilian local numbers which start with 911 being incorrectly
- // classified as emergency numbers. 911 is not an emergency number in Brazil; it is also
- // not possible to append additional digits to an emergency number to dial the number in
- // Brazil - it won't connect.
- // TODO: Clean this up once a list of country-specific known emergency numbers is
- // collected.
- return false;
+ return isEmergencyNumberInternal(number,
+ defaultCountryIso,
+ true /* useExactMatch */);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for a specific country.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the specified country, *or* if the number
+ * simply starts with the same digits as any emergency number for that
+ * country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return true if the number is an emergency number for the specific
+ * country, *or* if the number starts with the same digits as
+ * any of those emergency numbers.
+ *
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
+ return isEmergencyNumberInternal(number,
+ defaultCountryIso,
+ false /* useExactMatch */);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String, String) and
+ * isPotentialEmergencyNumber(String, String).
+ *
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the number is an emergency number for the specified country.
+ */
+ private static boolean isEmergencyNumberInternal(String number,
+ String defaultCountryIso,
+ boolean useExactMatch) {
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ try {
+ PhoneNumber pn = util.parse(number, defaultCountryIso);
+ // libphonenumber guarantees short numbers such as emergency numbers are classified as
+ // invalid. Therefore, if the number passes the validation test, we believe it is not an
+ // emergency number.
+ // TODO: Compare against a list of country-specific known emergency numbers instead, once
+ // that has been collected.
+ if (util.isValidNumber(pn)) {
+ return false;
+ } else if ("BR".equalsIgnoreCase(defaultCountryIso) && number.length() >= 8) {
+ // This is to prevent Brazilian local numbers which start with 911 being incorrectly
+ // classified as emergency numbers. 911 is not an emergency number in Brazil; it is also
+ // not possible to append additional digits to an emergency number to dial the number in
+ // Brazil - it won't connect.
+ // TODO: Clean this up once a list of country-specific known emergency numbers is
+ // collected.
+ return false;
+ }
+ } catch (NumberParseException e) {
}
- } catch (NumberParseException e) {
- }
- return isEmergencyNumber(number);
+ return isEmergencyNumberInternal(number, useExactMatch);
}
/**
@@ -1592,12 +1703,66 @@
*
* @param number the number to look up.
* @param context the specific context which the number should be checked against
- * @return if a phone number is an emergency number for a local country, based on the
- * CountryDetector.
+ * @return true if the specified number is an emergency number for a local country, based on the
+ * CountryDetector.
+ *
* @see android.location.CountryDetector
* @hide
*/
public static boolean isLocalEmergencyNumber(String number, Context context) {
+ return isLocalEmergencyNumberInternal(number,
+ context,
+ true /* useExactMatch */);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for the country that the user is in. The current
+ * country is determined using the CountryDetector.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the current country, *or* if the number
+ * simply starts with the same digits as any emergency number for the
+ * current country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @return true if the specified number is an emergency number for a local country, based on the
+ * CountryDetector.
+ *
+ * @see android.location.CountryDetector
+ * @hide
+ */
+ public static boolean isPotentialLocalEmergencyNumber(String number, Context context) {
+ return isLocalEmergencyNumberInternal(number,
+ context,
+ false /* useExactMatch */);
+ }
+
+ /**
+ * Helper function for isLocalEmergencyNumber() and
+ * isPotentialLocalEmergencyNumber().
+ *
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the specified number is an emergency number for a
+ * local country, based on the CountryDetector.
+ *
+ * @see android.location.CountryDetector
+ */
+ private static boolean isLocalEmergencyNumberInternal(String number,
+ Context context,
+ boolean useExactMatch) {
String countryIso;
CountryDetector detector = (CountryDetector) context.getSystemService(
Context.COUNTRY_DETECTOR);
@@ -1609,7 +1774,7 @@
Log.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ countryIso);
}
- return isEmergencyNumber(number, countryIso);
+ return isEmergencyNumberInternal(number, countryIso, useExactMatch);
}
/**
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index e2349af..d34a7c5 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -550,21 +550,51 @@
}
@SmallTest
public void testIsEmergencyNumber() {
- assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US"));
- assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US"));
- // The next two numbers are not valid phone numbers in the US, but can be used to trick the
- // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of
- // addressing that, they are also classified as emergency numbers in the US.
- assertTrue(PhoneNumberUtils.isEmergencyNumber("91112345", "US"));
- assertTrue(PhoneNumberUtils.isEmergencyNumber("11212345", "US"));
- // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
- // in Singapore, as 911 is not an emergency number there.
- assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG"));
- // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
- // in Brazil, as 112 is not an emergency number there.
- assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR"));
- // A valid local phone number from Brazil shouldn't be classified as an emergency number in
- // Brazil.
- assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "BR"));
+ // There are two parallel sets of tests here: one for the
+ // regular isEmergencyNumber() method, and the other for
+ // isPotentialEmergencyNumber().
+ //
+ // (The difference is that isEmergencyNumber() will return true
+ // only if the specified number exactly matches an actual
+ // emergency number, but isPotentialEmergencyNumber() will
+ // return true if the specified number simply starts with the
+ // same digits as any actual emergency number.)
+
+ // Tests for isEmergencyNumber():
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US"));
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US"));
+ // The next two numbers are not valid phone numbers in the US,
+ // so do not count as emergency numbers (but they *are* "potential"
+ // emergency numbers; see below.)
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "US"));
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("11212345", "US"));
+ // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
+ // in Singapore, as 911 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG"));
+ // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
+ // in Brazil, as 112 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR"));
+ // A valid local phone number from Brazil shouldn't be classified as an emergency number in
+ // Brazil.
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "BR"));
+
+ // Tests for isPotentialEmergencyNumber():
+ // These first two are obviously emergency numbers:
+ assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("911", "US"));
+ assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("112", "US"));
+ // The next two numbers are not valid phone numbers in the US, but can be used to trick the
+ // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of
+ // addressing that, they are also classified as "potential" emergency numbers in the US.
+ assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US"));
+ assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US"));
+ // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
+ // in Singapore, as 911 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+ // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
+ // in Brazil, as 112 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR"));
+ // A valid local phone number from Brazil shouldn't be classified as an emergency number in
+ // Brazil.
+ assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "BR"));
}
}