Matching incoming and outgoing phone numbers - android

I'm currently making an SMS viewing application and using the ContentResolver to obtain all SMS messages on the phone (Yes, I understand the risks). Like other applications, I want to group all messages from the same person to one thread, display the latest message from them, and order the contacts by date of the last message.
When it comes to the address values of the incoming messages, they all contain the country code (e.g. +44123456789). But when the user saves his contacts, he could ignore the country code and simply type in the local format. So all outgoing messages are stored as 0123456789.
So, the database will contain the same address in both formats, +44123456789 and 0123456789. How do you match this 2 and remove the duplicate address?
Note:
1) Messages from the same person may not have the same "thread id"
2) There may not be a "contact id"/"display name" value for the address

Actually, messages to and from the same contact are in the same thread, therefore they have the same thread_id. (Apart from multiple recipient messages, which are in their own thread).
By looking in content://sms and storing a list of obtained thread_ids you can make sure there's no duplicates. With the address value you can use the following code to obtain the Display name.
Now, I'm trying to optimise this:
private String quickCallerId(String phoneNumber){
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
ContentResolver resolver=getContentResolver();
Cursor cur = resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME}, null, null, null);
if(cur!=null&&cur.moveToFirst()){
String value=cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME));
if(value!=null){
cur.close();
return value;
}
}
cur.close();
return "";
}

I don't have the code on me, but it's pretty easy to parse a string from right to left. You could do this and simply set an arbitrary limit on how accurate it must be to stop.
For instance (pseudo-code), given 2 strings (string1 and string2):
if first-char = '+'
len = 9
else
len = length(string1)
end
len = min(len, length(string2))
match = true
for i = len to 1
if substr( string2, i, 1) != substr( string2, i, 1)
match = false
quit
end
i--
end
You could get fancier by checking the characters immediately following the '+' sign to determine the country code, which would let you know how long that country's phone numbers are likely to be.
You would also need to check for people entering numbers as e.g. '(123) 456-7890 x1234' if that's a possibility. So it might be simpler to use some regexp variant...
Rory

Related

Compare phone number from database in different condition

I'm developing sms APP and want to receive sms from the specific numbers. But number can be changed sometime with country code as +923201234567 or sometime without country code 03201234567 how I can compare number from database? because don't know in which format number is saved in database(with country code or without country code)
public boolean isMember(String phone, long id){
String query = "SELECT * from members where phone = ? AND active = 1 AND gid = ?";
Cursor c = dbActions.rawQuery(query, new String[]{String.valueOf(phone), String.valueOf(id)});
return c.moveToFirst();
}
Suppose if the number is saved in database without country code 03201234567 then my requirement is to get true if I compare it with country code. +923201234567. Country code could be changed.
PhoneNumberUtils.compare(); is not useful because it not compare with database.
If you can't acquire the correct information always; then you need to look into heuristics.
Meaning: you could write your own comparisons; and when you encounter two numbers like:
03201234567
+923201234567
you can figure: their "tail" is equal; the only difference is that the first one starts with 0 (so no country code) and the second one with +92. So it might be reasonable to declare those two numbers to be equal.
So a "solution" would do things like "normalize" your input (remove all non-digit content; except for leading + signs); and to then make such "tail-bound" comparisons.
If that is "too" fuzzy; I guess then you should step back and describe the requirement that you actually try to resolve here. Why are you comparing numbers; and what do you intend to do with the output of that comparison?!
Normalize all of the phone numbers into the same format before you put them into the database. That way you can just do a normal db search.
The other thing I've done for phone numbers is to convert all letters into the appropriate number, then remove all non digits, then just compare the last 7 digits.

AutoCompleteTextView for contacts email can't get LIKE to work properly

I am creating an AutoCompleteTextView field on a form that I want to possibly populate with a matching selection from the CONTACTS email addresses.
Doing some searching, I was able to find some older examples on here (that have alot of depreciated code... nothing newer) but with some trial and error I was able to get it to work matching the first characters of the email address as I type... although I don't have a 100% understanding of exactly how this works.
What I would really like to do is have it show ANY match ANYWHERE in the email addresses on file. That is, if I type gma, I would like it to show: gmartin#xyz.com, gregmaster#yahoo.com, jim#gmail.com, sam#gmail.com, etc.
As I understand it, I need to use a LIKE command in the query. But no matter how I format it, I get the same results... only matches the start of the email address.
Here is my current code attempt with the LIKE....
ArrayList<String> emailAddressCollection = new ArrayList<String>();
ContentResolver cr = getContentResolver();
String[] projection={ContactsContract.CommonDataKinds.Email.DATA};
Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, ContactsContract.CommonDataKinds.Email.ADDRESS + " LIKE '%A%'", null, null);
while (emailCur.moveToNext())
{
String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
emailAddressCollection.add(email);
}
emailCur.close();
String[] emailAddresses = new String[emailAddressCollection.size()];
emailAddressCollection.toArray(emailAddresses);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line, emailAddresses);
AutoCompleteTextView actextView = (AutoCompleteTextView)findViewById(idTo);
actextView.setAdapter(adapter);
Any idea what I am missing here?
Also, another somewhat related question, in my dropdownlist, i would like to show the email address match plus the NAME listed in that record... and just return the email address when selected.
Can this be accomplished using this code or do I need to look at something else?
AutoCompleteTextView is designed by default to match based ONLY on the starting characters. So the gma in sam#gmail.com will not be recognized. You can implement your own widget which does a lookup based on the 'LIKE' criteria. Android only searches through the first few characters for each entry in the adapter elements.
If you must choose to search by 'LIKE' criteria, it is possible although it would be quite a task in itself. You could simply search by whether the string contains the text and then choose to filter by that - no need to query everytime. Alternatively, you could try searching for a library which does this.

Python - Get Contact from Phone Number

Using SL4A and Python, is there an easy way to get a Contact ID from a phone number?
The phone number is from the 'address' field of an SMS.
I am trying to avoid searching through all contacts.
I use m = droid.smsGetMessageById(id, None).result to get the SMS message. The result looks like:
{u'read': u'1', u'body': u"Hello! Your mobile bill's now ready to view at virginmobile.co.uk/youraccount. We'll collect your Direct Debit of 12.12 on or just after 19th Nov.", u'_id': u'1323', u'date': u'1415372649502', u'address': u'1234567890'}
The value in the address entry is the phone number that sent the SMS.
I want to get a contact ID using this number, but, if possible, I want to avoid searching all my contacts.
I figured it out:
def contactFromPhone(phone):
uri='content://com.android.contacts/data'
filter='data4 LIKE ?'
args=['%'+phone+'%']
columns=['contact_id']
contacts=droid.queryContent(uri, columns, filter, args).result
cs=[]
if len(contacts)>0:
for c in contacts:
cs.append(c['contact_id'])
return cs
'phone' is a normalized phone number
returns a list of contact_id

Android - Possible to add broadcast to separate application?

This might be a stretch, but I was wondering if it is possible to add functionality to an application that is already created for the android device. Specifically, I would like to send a broadcast whenever the user tries to make a new search in the internet browser. There might be another way to act only when the user searches the browser, but I thought this would be the easiest. If this isn't possible (or is completely the wrong way of going about this), please let me know. Any help is appreciated.
You can probably query the Browser provider and get search data from it. Here is some basic code on how to do it:
Cursor cursor = this.context.getContentResolver().query(Browser.SEARCHES_URI, null, null, null, null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
final int indexDate = cursor.getColumnIndex(Browser.SearchColumns.DATE);
final int indexTerm = cursor.getColumnIndex(Browser.SearchColumns.SEARCH);
String date = cursor.getString(indexDate);
String term = cursor.getString(indexTerm);
cursor.moveToNext();
}
}
cursor.close();
Keep in mind that it would be better if you run queries on a separate Thread using the Loader framework.
I do not think there is a broadcast sent when a new search is performed.

What is the correct URI to pass to a ContentObserver for sent SMSes in Jelly Bean?

I'm trying to tally the number of outgoing SMSes sent by the user. Currently, my code goes like this:
class SentSMSObserver extends ContentObserver {
....
}
SentSMSObserver sso = new SentSMSObserver(new Handler());
ContentResolver cr = this.getContentResolver();
cr.registerContentObserver(Uri.parse("content://sms"), true, sso);
I tried to run the app in an emulator sporting Jelly Bean and for some reason, when I send a text message via the native SMS app, it increments my tally by three.
Now, I decided to replace content://sms with content://sms/sent as the related StackOverflow q&a's would suggest, but when I run the app with that setting, it never even executes my content observer's onChange(). What do I do?
the callback on registerContentObserver will be called when the db updater calls the exact uri for which you have registered. But in your case the MMS app does not use content://sms/sent but uses something like content://sms/10 and keeps moving it from type QUEUED to OUTBOX and then to SENT . So i guess thats why you are recieving 3 updates when you register for content://sms/
MMS App changes the TYPE column each time after it is queued.
One way to solve this problem is each time you get the content change callback query for the uri and then get "type" column and check if its value is Telephony.Sms.MESSAGE_TYPE_SENT .
From the answer suggested by Lalit Poptani, you need to get the value of the "type" of record the cursor is currently pointing at.
// cr is the content resolver
Cursor cursor = cr.query(Uri.parse("content://sms"), null, null, null, null);
int columnIndex = cursor.getColumnIndex("type");
while (cursor.moveToNext()) {
int type = cursor.getInt(columnIndex);
if (type == 2) {
// do your stuff here
}
}
As mentioned in my discussion with nandeesh, the message types are not part of the public API, but they can be found here.
Currently, I'm fixing a bug where Android makes inaccurate counts of a single sent SMS message when it is directed to more than one recipient (sending to two people counts three, sending to three counts 5). It seems that even when you filter out the message types, the content observer gets invoked more than once even for just a single message. I will post updates to this answer when I've fixed it.

Categories

Resources