Compare phone number with incoming phone call number from ANY country (algorithm/library/anything)

Viewed 264

How can I get my app to know which contact name is calling? I'd like the app to check the entire number, if that's possible. I saw someone here on SO saying to check only a part of the number, and that's a partial solution. But would it be possible to check the entire number? I think it must be, because Dialer always knows who's calling me (unless they cheat somewhere by getting the country of the phone or something).

For example in Portugal we have +351 123 456 789. On other contries the number are bigger or smaller, and the code is different. From what I saw here (https://en.wikipedia.org/wiki/E.164):

As described in by the ITU, the E.164 general format must contain only digits split as follows:

- Country code (1 to 3 digits)
- Subscriber number (max 12 digits)

So I can't check remove the first 3 digits because there are countries with 1 or 2 digits. Also I can't check 12 digits because as a start, in Portugal we have only 9. I read there are countries with 7 digits, so that would be the minimum, and 12 would be the maximum. But I'd have to put the minimum and it could get the number wrong. But the Dialer app always knows somehow. Does anyone know how to do it properly?

I've thought already in checking all the codes from all the countries (would need a list) and check the first digits to see if any match any country code. But 2 problems came: I'd have to be updating it, and more important, let's say a country has +35 as code. Then the person's number starts with a 1. That's +351, which is from Portugal. No idea how I can avoid these situations.

Hopefully there's an easier way, maybe even some class from Google which I don't know about, or some library or if not, maybe someone has better ideas.

Just in case it might be useful, here's a link from Wikipedia with all the country codes: https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers.

Any help would be greatly appreciated!

NOTE: I haven't put Android on the tags, but I'm currently working on it. This doesn't matter to the question because I only need to know the algorithm, UNLESS there is some easier way of checking the phone number from the Android library or anything related to Android and in that case, I give preference to the Android solution.

Update: I could check from the end to the beginning of both numbers and see if they match until the smaller one end. For example +351 123 456 789 called and I have saved 123 456 789 only. But in another country a number might be +35 1123 456 789, and in this case, I'd be excluding the country code of some countries. Are there any other ideas?

2 Answers

Why would you want to remove the country codes? They belong to the phone number.

You don't need to figure out if there is country code or not. When comparing the incoming call with the contact book just check the length of the incoming number and the one in the address book.

If the calling number is longer just replace the delta with a 0 (as calls from within the country will have 0 as prefix). Then procced to compare the number. If you saved an international number it will have the country code stored as well so you can just compare them.

For example:

Calling: +351 123 456 789 -> length 13 digits (including the +)

Saved contact: 0123 456 789 -> length 10 numbers

+35 will be replaced with 0 and the numbers are the same.

I came across this repository on GitHub from Google itself: https://github.com/google/libphonenumber. Seems it's what they use since Android 4. Then I found out the library is already in the Android SDK (since API 1, so I'm confused on when they started using this, but anyways): android.telephony.PhoneNumberUtils (https://developer.android.com/reference/android/telephony/PhoneNumberUtils). And there's a compare() method on it that says:

Compare phone numbers a and b, and return true if they're identical enough for caller ID purposes.

No idea what the "enough" means, but this is Google, and the Dialer works just fine, that I know of, so I'm trusting it will be actually good enough.

Also [as an update to what I was writing, I just found out] there are 2 compare() methods. As I couldn't understand what the one that requires context was actually doing from Android Developers site, I found this answer by chance, which explains it: https://stackoverflow.com/a/53447538/8228163 (inside thread What do "strict" or "loose" comparisons mean for PhoneNumberUtils.compare?). Very good idea to read that. The conclusion from there seems to be to use the method that requires the context, so that the phone can get if the carrier allows you to use the strict method (the compare(String, String) method always uses the loose comparision, at least for now: "We've used loose comparation at least Eclair, which may change in the future."). Strict would be the best, it seems (search "1-650-555-1234" here: https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/android/telephony/PhoneNumberUtils.java and read what says there about it, which doesn't happen on the loose comparision (and I tested that in a comment on the answer linked above).

If you have internal methods and classes showing, you can force the app to use it like I just did xD. Just not sure if there are downsides to this since I'm forcing it, but it seems to work even though my carrier seems not to allow it (what I did to know that is on the answer I linked above). Worked perfectly as intended on what I said to search on the source code, when I called compareStrictly(String, String) directly.

Now. There's another version of the method: compareStrictly(String, String, boolean), in which the boolean argument reads acceptInvalidCCCPrefix. I could call it with that as false, but I don't know what I'd actually be doing, since the calls to that method are always with that argument being true on the source code of PhoneNumberUtils. Wonder if I could put it as false, so it detects better, or if it's true because it's not ready or something, as reads on compareStrictly(String, String, boolean) source code, 4 lines bellow if (okToIgnorePrefix) { (I didn't understand what they meant there) - if anyone knows if I can put it as false, please say something (also if anyone knows what CCC prefix means, please say something too, as I didn't find anything conciso with Google that I can be sure of being that).

The library on GitHub is not only in Java, so I've removed the language tag from the thread. It's in C++, Java and JavaScript, officially, and there are ports to other languages, like Go, C#, Objective-C, PHP, Python,......, all with links in the Google repository. Hopefully the library in the repository has everything the Android source code has (I didn't check that, but I guess it should have everything).

Related