CallerInfoUtils.java revision 1a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87
17ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leepackage com.android.incallui; 27ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 37ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.content.Context; 47ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.text.TextUtils; 57ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 67ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.services.telephony.common.Call; 77ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 87ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport java.util.Arrays; 97ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee/** 117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * TODO: Insert description here. (generated by yorkelee) 127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */ 137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leepublic class CallerInfoUtils { 147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee private static final String TAG = CallerInfoUtils.class.getSimpleName(); 167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /** Define for not a special CNAP string */ 187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee private static final int CNAP_SPECIAL_CASE_NO = -1; 197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee public CallerInfoUtils() { 217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee private static final int QUERY_TOKEN = -1; 247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /** 264bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon * This is called to get caller info for a call. This will return a CallerInfo 274bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon * object immediately based off information in the call, but 287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * more information is returned to the OnQueryCompleteListener (which contains 297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * information about the phone number label, user's name, etc). 307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */ 314bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon public static CallerInfo getCallerInfoForCall(Context context, Call call, 327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee CallerInfoAsyncQuery.OnQueryCompleteListener listener) { 337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee CallerInfo info = new CallerInfo(); 347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee String number = call.getNumber(); 357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // Store CNAP information retrieved from the Connection (we want to do this 377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // here regardless of whether the number is empty or not). 387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee info.cnapName = call.getCnapName(); 397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee info.name = info.cnapName; 407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee info.numberPresentation = call.getNumberPresentation(); 417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee info.namePresentation = call.getCnapNamePresentation(); 427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 434bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // TODO: Have phoneapp send a Uri when it knows the contact that triggered this call. 447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 454bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon if (!TextUtils.isEmpty(number)) { 464bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon number = modifyForSpecialCnapCases(context, info, number, info.numberPresentation); 474bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon info.phoneNumber = number; 484bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon 494bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // For scenarios where we may receive a valid number from the network but a 504bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // restricted/unavailable presentation, we do not want to perform a contact query, 514bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // so just return the existing caller info. 524bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon if (info.numberPresentation != Call.PRESENTATION_ALLOWED) { 537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return info; 544bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon } else { 554bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // Start the query with the number provided from the call. 561a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "==> Actually starting CallerInfoAsyncQuery.startQuery()..."); 574bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context, number, listener, call); 587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 594bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon } else { 604bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // The number is null or empty (Blocked caller id or empty). Just return the 614bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon // caller info object as is, without starting a query. 624bbe4c6900dfe3584f674161dbe15e248d5adbe7Santos Cordon return info; 637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return info; 667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /** 697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Handles certain "corner cases" for CNAP. When we receive weird phone numbers 707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * from the network to indicate different number presentations, convert them to 717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * expected number and presentation values within the CallerInfo object. 727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * @param number number we use to verify if we are in a corner case 737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * @param presentation presentation value used to verify if we are in a corner case 747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * @return the new String that should be used for the phone number 757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */ 767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /* package */static String modifyForSpecialCnapCases(Context context, CallerInfo ci, 777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee String number, int presentation) { 787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // Obviously we return number if ci == null, but still return number if 797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // number == null, because in these cases the correct string will still be 807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // displayed/logged after this function returns based on the presentation value. 817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (ci == null || number == null) return number; 827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 831a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "modifyForSpecialCnapCases: initially, number=" 847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee + toLogSafePhoneNumber(number) 857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee + ", presentation=" + presentation + " ci " + ci); 867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // "ABSENT NUMBER" is a possible value we could get from the network as the 887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // phone number, so if this happens, change it to "Unknown" in the CallerInfo 897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // and fix the presentation to be the same. 907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee final String[] absentNumberValues = 917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee context.getResources().getStringArray(R.array.absent_num); 927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (Arrays.asList(absentNumberValues).contains(number) 937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee && presentation == Call.PRESENTATION_ALLOWED) { 947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee number = context.getString(R.string.unknown); 957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee ci.numberPresentation = Call.PRESENTATION_UNKNOWN; 967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // Check for other special "corner cases" for CNAP and fix them similarly. Corner 997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // cases only apply if we received an allowed presentation from the network, so check 1007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't 1017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // match the presentation passed in for verification (meaning we changed it previously 1027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // because it's a corner case and we're being called from a different entry point). 1037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (ci.numberPresentation == Call.PRESENTATION_ALLOWED 1047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee || (ci.numberPresentation != presentation 1057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee && presentation == Call.PRESENTATION_ALLOWED)) { 1067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee int cnapSpecialCase = checkCnapSpecialCases(number); 1077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) { 1087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // For all special strings, change number & numberPresentation. 1097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (cnapSpecialCase == Call.PRESENTATION_RESTRICTED) { 1107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee number = context.getString(R.string.private_num); 1117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } else if (cnapSpecialCase == Call.PRESENTATION_UNKNOWN) { 1127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee number = context.getString(R.string.unknown); 1137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1141a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "SpecialCnap: number=" + toLogSafePhoneNumber(number) 1157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee + "; presentation now=" + cnapSpecialCase); 1167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee ci.numberPresentation = cnapSpecialCase; 1177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1191a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "modifyForSpecialCnapCases: returning number string=" 1207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee + toLogSafePhoneNumber(number)); 1217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return number; 1227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 1247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /** 1257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Based on the input CNAP number string, 1267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings. 1277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Otherwise, return CNAP_SPECIAL_CASE_NO. 1287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */ 1297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee private static int checkCnapSpecialCases(String n) { 1307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (n.equals("PRIVATE") || 1317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee n.equals("P") || 1327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee n.equals("RES")) { 1331a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "checkCnapSpecialCases, PRIVATE string: " + n); 1347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return Call.PRESENTATION_RESTRICTED; 1357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } else if (n.equals("UNAVAILABLE") || 1367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee n.equals("UNKNOWN") || 1377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee n.equals("UNA") || 1387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee n.equals("U")) { 1391a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "checkCnapSpecialCases, UNKNOWN string: " + n); 1407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return Call.PRESENTATION_UNKNOWN; 1417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } else { 1421a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(TAG, "checkCnapSpecialCases, normal str. number: " + n); 1437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return CNAP_SPECIAL_CASE_NO; 1447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 1477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee /* package */static String toLogSafePhoneNumber(String number) { 1487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // For unknown number, log empty string. 1497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (number == null) { 1507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return ""; 1517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 1537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // Todo (klp): Figure out an equivalent for VDBG 1547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (false) { 1557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // When VDBG is true we emit PII. 1567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return number; 1577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee 1597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 1607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee // sanitized phone numbers. 1617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee StringBuilder builder = new StringBuilder(); 1627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee for (int i = 0; i < number.length(); i++) { 1637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee char c = number.charAt(i); 1647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee if (c == '-' || c == '@' || c == '.') { 1657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee builder.append(c); 1667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } else { 1677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee builder.append('x'); 1687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee return builder.toString(); 1717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee } 1727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee} 173