Added a field to track if the call is to a voicemail instance.
Refactored common code between CallerInfo and CallerInfoAsyncQuery that deal
with voicemail number comparison.
In CallerInfo.java added a new field mIsVoiceMail to indicate this is a
voicemail call.
Added a new method to convert the CallerInfo into a VM instance.
Added a new method to generate a debug string from an instance.
PhoneNumberUtils has a new method "isVoiceMailNumber" to check if a number
is a VM one. I left the method as hidden. Previously any security exception
failure was cached in a static variable. I removed that and
privilege the optmistic scenario. I am not sure if the security exception
is only for the 'regular' telephony layer and if it applies if a 3rd party
VM app is installed (e.g googlevoice), hence i removed the cashing to make
sure we can pick up new voicemail providers when installed/enabled/disabled.
Bug:2112640
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4368464..2672c6d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -129,6 +129,8 @@
return uri.getSchemeSpecificPart();
}
+ // TODO: We don't check for SecurityException here (requires
+ // READ_PHONE_STATE permission).
if (scheme.equals("voicemail")) {
return TelephonyManager.getDefault().getVoiceMailNumber();
}
@@ -1179,6 +1181,35 @@
}
/**
+ * isVoiceMailNumber: checks a given number against the voicemail
+ * number provided by the RIL and SIM card. The caller must have
+ * the READ_PHONE_STATE credential.
+ *
+ * @param number the number to look up.
+ * @return true if the number is in the list of voicemail. False
+ * otherwise, including if the caller does not have the permission
+ * to read the VM number.
+ * @hide TODO: pending API Council approval
+ */
+ public static boolean isVoiceMailNumber(String number) {
+ String vmNumber;
+
+ try {
+ vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ } catch (SecurityException ex) {
+ return false;
+ }
+
+ // Strip the separators from the number before comparing it
+ // to the list.
+ number = extractNetworkPortion(number);
+
+ // compare tolerates null so we need to make sure that we
+ // don't return true when both are null.
+ return !TextUtils.isEmpty(number) && compare(number, vmNumber);
+ }
+
+ /**
* Translates any alphabetic letters (i.e. [A-Za-z]) in the
* specified phone number into the equivalent numeric digits,
* according to the phone keypad letter mapping described in
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index c8490e9..01b1746 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -101,13 +101,12 @@
public boolean isCachedPhotoCurrent;
private boolean mIsEmergency;
-
- // Don't keep checking VM if it's going to throw an exception for this proc.
- private static boolean sSkipVmCheck = false;
+ private boolean mIsVoiceMail;
public CallerInfo() {
// TODO: Move all the basic initialization here?
mIsEmergency = false;
+ mIsVoiceMail = false;
}
/**
@@ -220,32 +219,15 @@
public static CallerInfo getCallerInfo(Context context, String number) {
if (TextUtils.isEmpty(number)) {
return null;
- } else {
- // Change the callerInfo number ONLY if it is an emergency number
- // or if it is the voicemail number. If it is either, take a
- // shortcut and skip the query.
- if (PhoneNumberUtils.isEmergencyNumber(number)) {
- return new CallerInfo().markAsEmergency(context);
- } else {
- try {
- if (!sSkipVmCheck && PhoneNumberUtils.compare(number,
- TelephonyManager.getDefault().getVoiceMailNumber())) {
- CallerInfo ci = new CallerInfo();
+ }
- // Note we're setting the phone number here (refer to javadoc
- // comments at the top of CallerInfo class).
- ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag();
- // TODO: FIND ANOTHER ICON
- //info.photoResource = android.R.drawable.badge_voicemail;
- return ci;
- }
- } catch (SecurityException ex) {
- // Don't crash if this process doesn't have permission to
- // retrieve VM number. It's still allowed to look up caller info.
- // But don't try it again.
- sSkipVmCheck = true;
- }
- }
+ // Change the callerInfo number ONLY if it is an emergency number
+ // or if it is the voicemail number. If it is either, take a
+ // shortcut and skip the query.
+ if (PhoneNumberUtils.isEmergencyNumber(number)) {
+ return new CallerInfo().markAsEmergency(context);
+ } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ return new CallerInfo().markAsVoiceMail();
}
Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
@@ -304,6 +286,13 @@
}
/**
+ * @return true if the caller info is a voicemail number.
+ */
+ public boolean isVoiceMailNumber() {
+ return mIsVoiceMail;
+ }
+
+ /**
* Mark this CallerInfo as an emergency call.
* @param context To lookup the localized 'Emergency Number' string.
* @return this instance.
@@ -323,6 +312,37 @@
return this;
}
+
+ /**
+ * Mark this CallerInfo as a voicemail call. The voicemail label
+ * is obtained from the telephony manager. Caller must hold the
+ * READ_PHONE_STATE permission otherwise the phoneNumber will be
+ * set to null.
+ * @return this instance.
+ */
+ // TODO: As in the emergency number handling, we end up writing a
+ // string in the phone number field.
+ /* package */ CallerInfo markAsVoiceMail() {
+ mIsVoiceMail = true;
+
+ try {
+ String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+
+ phoneNumber = voiceMailLabel;
+ } catch (SecurityException se) {
+ // Should never happen: if this process does not have
+ // permission to retrieve VM tag, it should not have
+ // permission to retrieve VM number and would not call
+ // this method.
+ // Leave phoneNumber untouched.
+ Log.e(TAG, "Cannot access VoiceMail.", se);
+ }
+ // TODO: There is no voicemail picture?
+ // FIXME: FIND ANOTHER ICON
+ // photoResource = android.R.drawable.badge_voicemail;
+ return this;
+ }
+
private static String normalize(String s) {
if (s == null || s.length() > 0) {
return s;
@@ -330,4 +350,31 @@
return null;
}
}
+
+ /**
+ * @return a string debug representation of this instance.
+ */
+ public String toString() {
+ return new StringBuilder(384)
+ .append("\nname: " + name)
+ .append("\nphoneNumber: " + phoneNumber)
+ .append("\ncnapName: " + cnapName)
+ .append("\nnumberPresentation: " + numberPresentation)
+ .append("\nnamePresentation: " + namePresentation)
+ .append("\ncontactExits: " + contactExists)
+ .append("\nphoneLabel: " + phoneLabel)
+ .append("\nnumberType: " + numberType)
+ .append("\nnumberLabel: " + numberLabel)
+ .append("\nphotoResource: " + photoResource)
+ .append("\nperson_id: " + person_id)
+ .append("\nneedUpdate: " + needUpdate)
+ .append("\ncontactRefUri: " + contactRefUri)
+ .append("\ncontactRingtoneUri: " + contactRefUri)
+ .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+ .append("\ncachedPhoto: " + cachedPhoto)
+ .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+ .append("\nemergency: " + mIsEmergency)
+ .append("\nvoicemail " + mIsVoiceMail)
+ .toString();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 4227a84..802e79b 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -47,9 +47,6 @@
private CallerInfoAsyncQueryHandler mHandler;
- // Don't keep checking VM if it's going to throw an exception for this proc.
- private static boolean sSkipVmCheck = false;
-
/**
* Interface for a CallerInfoAsyncQueryHandler result return.
*/
@@ -227,18 +224,7 @@
// comments at the top of CallerInfo class).
mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
} else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
- mCallerInfo = new CallerInfo();
- try {
- // Note we're setting the phone number here (refer to javadoc
- // comments at the top of CallerInfo class).
- mCallerInfo.phoneNumber =
- TelephonyManager.getDefault().getVoiceMailAlphaTag();
- } catch (SecurityException ex) {
- // Should never happen: if this process does not have
- // permission to retrieve VM tag, it should not have
- // permission to retrieve VM number and would not generate
- // an EVENT_VOICEMAIL_NUMBER. But if it happens, don't crash.
- }
+ mCallerInfo = new CallerInfo().markAsVoiceMail();
} else {
mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
// Use the number entered by the user for display.
@@ -258,7 +244,7 @@
//notify the listener that the query is complete.
if (cw.listener != null) {
if (DBG) log("notifying listener: " + cw.listener.getClass().toString() +
- " for token: " + token);
+ " for token: " + token + mCallerInfo);
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
}
}
@@ -315,23 +301,10 @@
// check to see if these are recognized numbers, and use shortcuts if we can.
if (PhoneNumberUtils.isEmergencyNumber(number)) {
cw.event = EVENT_EMERGENCY_NUMBER;
+ } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ cw.event = EVENT_VOICEMAIL_NUMBER;
} else {
- String vmNumber = null;
- if (!sSkipVmCheck){
- try {
- vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
- } catch (SecurityException ex) {
- // Don't crash if this process doesn't have permission to
- // retrieve VM number. It's still allowed to look up caller info.
- // But don't try it again.
- sSkipVmCheck = true;
- }
- }
- if (PhoneNumberUtils.compare(number, vmNumber)) {
- cw.event = EVENT_VOICEMAIL_NUMBER;
- } else {
- cw.event = EVENT_NEW_QUERY;
- }
+ cw.event = EVENT_NEW_QUERY;
}
c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml
index c0cc0d5..b2a481b 100644
--- a/telephony/tests/TelephonyTest/AndroidManifest.xml
+++ b/telephony/tests/TelephonyTest/AndroidManifest.xml
@@ -28,8 +28,9 @@
</intent-filter>
</activity>
</application>
- <instrumentation android:name=".TelephonyUnitTestRunner"
- android:targetPackage="com.android.telephonytest"
- android:label="Telephony unit tests InstrumentationRunner">
- </instrumentation>
+ <instrumentation android:name=".TelephonyUnitTestRunner"
+ android:targetPackage="com.android.telephonytest"
+ android:label="Telephony unit tests InstrumentationRunner">
+ </instrumentation>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
index 5da940d..9e1af31 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
@@ -37,6 +37,7 @@
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
+ suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class);
return suite;
}
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
index 4cd0266..0f24f15 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
@@ -107,6 +107,16 @@
assertIsValidEmergencyCallerInfo();
}
+ // TODO: Add more tests:
+ /**
+ * Check if the voice mail number cannot be retrieved that the
+ * original phone number is preserved.
+ */
+ /**
+ * Check the markAs* methods work.
+ */
+
+
//
// Helpers
//
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
new file mode 100644
index 0000000..2d3c548
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+
+/*
+ * Check the PhoneNumberUtils utility class works as expected.
+ *
+ */
+
+public class PhoneNumberUtilsUnitTest extends AndroidTestCase {
+ private String mVoiceMailNumber;
+ private static final String TAG = "PhoneNumberUtilsUnitTest";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // FIXME: Why are we getting a security exception here? The
+ // permission is declared in the manifest....
+ // mVoiceMailNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Basic checks for the VoiceMail number.
+ * Assumes READ_PHONE_STATE permission and we don't have it.
+ */
+ // TODO: Figure out why we don't have the permission declared in the manifest.
+ @SmallTest
+ public void testWithNumberNotEqualToVoiceMail() throws Exception {
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("911"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
+ // FIXME:
+ // assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+ }
+
+}