FORUMS
Remove All Ads from XDA

Fix kitkat SMS MAP (bluetooth) originator

2,644 posts
Thanks Meter: 2,750
 
By garyd9, Inactive Recognized Developer on 25th May 2014, 06:00 PM
Post Reply Email Thread
I've found that bluetooth SMS messaging doesn't interact too well with some car head units. In particular, Chrysler/Dodge/Jeep "uconnect" systems have issues understanding SMS originators with many kitkat phones. The reason is simple: "uconnect" (and other head units, I suppose) expect bluetooth map "vcards" to have an originator phone number in a raw (unformatted) format, while AOSP kitkat puts in pretty formatted phone numbers.

Good: +12345678901
Bad: (234) 567-8901

This module resolves that little issue.

...and here's the xposed repo link: http://repo.xposed.info/module/org.g...ed.btsmsmapfix

As for source, I just whipped this up in eclipse in windows, and I never bothered getting git working properly in windows... (I suppose I could copy this to one of my linux boxes, but I'm really too lazy.) So, I'll just paste the source below.

Licensing is simple: The method I'm replacing (and somewhat duplicating) is copyrighted by Samsung and licensed under Apache. (Standard AOSP licensing.) My modifications are PUBLIC DOMAIN, or the least restrictive possible license that is compatible with Samsung's copyright and the Apache License.

Don't expect too much support on this. I wrote it to fix an issue for my wife with her LG G2, and it just so happens that LG is using the AOSP MAP code pretty much intact. She's happy, so I consider my support contract fulfilled.

I've tested this on the G2, but not on anything running AOSP.

Code:
/* Copyrights...
 * 
 * Portions of this file are taken from AOSP with the following copyright notice:
 * 
 * Copyright (C) 2013 Samsung System LSI
 * 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.
 * 
 * The remainder of the source is released to the PUBLIC DOMAIN or to the
 * least restrictive licensing allowable in order to co-exist with the 
 * above mentioned license.
 * 
 */


package org.garyndenise.xposed.btsmsmapfix;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XposedHelpers.ClassNotFoundError;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;

import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;


public class BTSmsMapFix implements IXposedHookLoadPackage  {

    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
    	if (!lpparam.packageName.equals("com.android.bluetooth"))
    		return;

    	/*
    	 * When bluetooth in kitkat AOSP (and LG, apparently) attempts to 
    	 * create a vCard for inclusion in a MAP bMessage, it's using the
    	 * version 3 vcard, and supplying pretty-formatted phone numbers.  For
    	 * some MAP clients (car head units), this isn't a problem.  However 
    	 * some head units (such as Chrysler "uconnect" systems) insist on 
    	 * having the phone number in raw SMS format (such as +1xxxyyyzzzz in
    	 * the USA) and not in a more local "(xxx) yyy-zzzz" format.
    	 * 
    	 * Intercept and replace the method used by android's BT to create a
    	 * vCard from a phone number so that if it's an incoming vCard, use
    	 * the older 2.1 version, and instead of pulling in all the phone 
    	 * numbers and emails for the contact, just stick the raw originator
    	 * phone number (unformatted) into the vcard with a name.
    	 * 
    	 */
    	
    	try {
	    	Class<?> CBluetoothMapbMessage = XposedHelpers.findClass("com.android.bluetooth.map.BluetoothMapbMessage", lpparam.classLoader);
	
	    	try {
		    	findAndHookMethod("com.android.bluetooth.map.BluetoothMapContent", 
		    			lpparam.classLoader, 
		    			"setVCardFromPhoneNumber",
		    			CBluetoothMapbMessage,
		    			String.class,
		    			boolean.class,
		    			new XC_MethodReplacement() {
		    		/* 
		    		 * Most of the replaced method is identical to the original in
		    		 * AOSP, with the exception of if the 'incoming' flag is true.
		    		 * In that case, set the only phone number for the card as 
		    		 * whatever was passed in, and leave the vcard in 2.1 format
		    		 */
					@Override
					protected Object replaceHookedMethod(MethodHookParam param)
							throws Throwable {
				        String contactId = null, contactName = null;
				        String[] phoneNumbers = null;
				        String[] emailAddresses = null;
				        Cursor p;
		
						String phone = (String)param.args[1];
						boolean incoming = (boolean)param.args[2];
				        ContentResolver mResolver = (ContentResolver) XposedHelpers.getObjectField(param.thisObject, "mResolver");
		
				        
				        Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
				                Uri.encode(phone));
		
				        String[] projection = {Contacts._ID, Contacts.DISPLAY_NAME};
				        String selection = Contacts.IN_VISIBLE_GROUP + "=1";
				        String orderBy = Contacts._ID + " ASC";
		
				        // Get the contact _ID and name
				        p = mResolver.query(uri, projection, selection, null, orderBy);
				        if (p != null && p.getCount() >= 1) {
				            p.moveToFirst();
				            contactId = p.getString(p.getColumnIndex(Contacts._ID));
				            contactName = p.getString(p.getColumnIndex(Contacts.DISPLAY_NAME));
				        }
				        p.close();
		
				        // Bail out if we are unable to find a contact, based on the phone number
				        if (incoming || (contactId == null)) {
				            phoneNumbers = new String[1];
				            phoneNumbers[0] = phone;
				            XposedHelpers.callMethod(param.args[0], "addOriginator", contactName, phoneNumbers, emailAddresses);
				        } else {
				            // Fetch all contact phone numbers
				            p = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
				                ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
				                new String[]{contactId},
				                null);
				            if(p != null) {
				                int i = 0;
				                phoneNumbers = new String[p.getCount()];
				                while (p != null && p.moveToNext()) {
				                    String number = p.getString(
				                        p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
				                    phoneNumbers[i++] = number;
				                }
				                p.close();
				            }
				            // Fetch contact e-mail addresses
				            p = mResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
				                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
				                    new String[]{contactId},
				                    null);
				            if(p != null) {
				                int i = 0;
				                emailAddresses = new String[p.getCount()];
				                while (p != null && p.moveToNext()) {
				                    String emailAddress = p.getString(
				                        p.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
				                    emailAddresses[i++] = emailAddress;
				                }
				                p.close();
				            }
				            XposedHelpers.callMethod(param.args[0], "addRecipient", contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
				        }
						return null;
					}
		    	});
	    	} catch (NoSuchMethodError e) {
	    		XposedBridge.log("ERROR:  Unable to find method com.android.bluetooth.map.BluetoothMapContent.setVCardFromPhoneNumber");
	    	}
    	} catch (ClassNotFoundError e) {
    		XposedBridge.log("ERROR: unable to find class com.android.bluetooth.map.BluetoothMapbMessage");
    	}
    }
}
Edit: This bug has been submitted to google as https://code.google.com/p/android/is...etail?id=70160. I'd submit a full fix to them in gerrit, but I really don't want to see it ignored by google for 2 years, and then marked as "won't merge", "already fixed" or somehow ignored. Again.
The Following 5 Users Say Thank You to garyd9 For This Useful Post: [ View ] Gift garyd9 Ad-Free
 
 
26th May 2014, 12:38 AM |#2  
garyd9's Avatar
OP Inactive Recognized Developer
Flag Pittsburgh, PA
Thanks Meter: 2,750
 
More
As I mentioned, I wasn't able to test it on any kitkat device that is AOSP or AOSP based (cyanogenmod, omnirom, etc), so I'd appreciate any feedback on if it works on those. (For AOSP, the specific device is less important than the specific firmware name and version.)

thanks
Gary
26th May 2014, 01:46 PM |#3  
nalab1's Avatar
Senior Member
Flag Dunstable
Thanks Meter: 39
 
More
Hi!

I tried this on my Sony z1 running 4.4.2 in the hope that it would fix the bluetooth issue that I have with my car audio system.. In that it pairs of and I get the call logs bit it will not download the phonebook to the car audio.. I tried it but it did not work.. Oh well thanks for the module anyway... Is there anything that you could suggest that could resolve this?

Regards,

Alan
26th May 2014, 09:50 PM |#4  
garyd9's Avatar
OP Inactive Recognized Developer
Flag Pittsburgh, PA
Thanks Meter: 2,750
 
More
Quote:
Originally Posted by nalab1

In that it pairs of and I get the call logs bit it will not download the phonebook to the car audio..

This module could only fix the specific situation I described in the original post. The MAP code is very isolated from the phonebook code...

Not sure if there's anything I can suggest to resolve the problem your having...

Take care and good luck...
Gary


Sent from my HTC One_M8
27th May 2014, 04:38 AM |#5  
Junior Member
Flag El Paso
Thanks Meter: 0
 
Donate to Me
More
Thumbs up Uconnect Fix
Does this fix the problems with only AOSP, or will it work on stock rooted devices as well? I have a 2012 Dodge with the 430N RHB. I've had messaging problems and "phone call completed" error since the 4.4.2 update. I appreciate the code, and I'm sure many others will find this post helpful as well.
27th May 2014, 02:17 PM |#6  
nalab1's Avatar
Senior Member
Flag Dunstable
Thanks Meter: 39
 
More
Unhappy
Quote:
Originally Posted by garyd9

This module could only fix the specific situation I described in the original post. The MAP code is very isolated from the phonebook code...

Not sure if there's anything I can suggest to resolve the problem your having...

Take care and good luck...
Gary


Sent from my HTC One_M8

Hi Gary,

Thanks for your reply. Shame it didn't fix my problem.. It was worth a try though, as I have tried lots of things and nothing seems to work... ts strange that Google screwed it up in 4.4.2 when it was working perfectly in 4.2.2... Perhaps the developers ought to try regression testing their code....

Regards,

Alan
27th May 2014, 02:36 PM |#7  
garyd9's Avatar
OP Inactive Recognized Developer
Flag Pittsburgh, PA
Thanks Meter: 2,750
 
More
Quote:
Originally Posted by nalab1

strange that Google screwed it up in 4.4.2 when it was working perfectly in 4.2.2... Perhaps the developers ought to try regression testing their code....

Unless your using pure AOSP on your device, you can't assume that it was Google that broke it. In fact, with bluetooth code, it appears that many non-nexus (and non-AOSP) devices are running code very dissimilar to AOSP in kitkat. I was actually surprised to see that the LG G2's bluetooth module was extremely similar to AOSP.

Take care
Gary
27th May 2014, 03:20 PM |#8  
nalab1's Avatar
Senior Member
Flag Dunstable
Thanks Meter: 39
 
More
Unhappy
Quote:
Originally Posted by garyd9

This module could only fix the specific situation I described in the original post. The MAP code is very isolated from the phonebook code...

Not sure if there's anything I can suggest to resolve the problem your having...

Take care and good luck...
Gary


Sent from my HTC One_M8

Quote:
Originally Posted by garyd9

Unless your using pure AOSP on your device, you can't assume that it was Google that broke it. In fact, with bluetooth code, it appears that many non-nexus (and non-AOSP) devices are running code very dissimilar to AOSP in kitkat. I was actually surprised to see that the LG G2's bluetooth module was extremely similar to AOSP.

Take care
Gary

The reason I said it was Google that screwed it up is that there are a lot of people having the same problems that have a Nexus 4/5 and that runs pure Google android....

Regards,

Alan
27th May 2014, 04:42 PM |#9  
garyd9's Avatar
OP Inactive Recognized Developer
Flag Pittsburgh, PA
Thanks Meter: 2,750
 
More
Quote:
Originally Posted by SickPhone4X

Does this fix the problems with only AOSP, or will it work on stock rooted devices as well? I have a 2012 Dodge with the 430N RHB. I've had messaging problems and "phone call completed" error since the 4.4.2 update. I appreciate the code, and I'm sure many others will find this post helpful as well.

That's a trick question. This fixes one (and only one) very specific issue on any device that's using the same code as Google has published for AOSP kitkat 4.4.2.

I have no idea whatsoever if any given device's firmware is based on AOSP or based on some other bluetooth code. (I've only confirmed that the bug exists in AOSP and the LG G2 firmware... and you didn't even mention which device you have.)

For your Dodge radio, the "SMS" support in the radio might announce something like "New SMS message from XXXX" when you get a new SMS. If the SMS came from a person you have in your contact list, "XXXX" should be replaced by that contact's name. With the bug that this fixes, "XXXX" will always be replaced with something like "unknown number" (even if the message originated from someone in your contact list.)

IF you have that issue, you can try this module to see if it resolves the problem. If the problem goes away (and it announces the proper message originator), then this applies to your device. If, on the other hand, it doesn't fix the problem, then this fix won't help you. (In that case, you'll likely see one or more errors in the xposed log and you can uninstall the module. It won't HURT anything to try it.)

Note that this module has nothing to do with phone calls, phone books, etc. It's ONLY related to SMS sender info.

Take care
Gary
29th May 2014, 02:45 PM |#10  
thuddome's Avatar
Senior Member
Flag Denver
Thanks Meter: 129
 
More
Tried this on my Galaxy S5 with my Jeep 430N. No go so far, still getting "no number available" for every person.

Sent from my SM-G900V using XDA Premium 4 mobile app
29th May 2014, 03:30 PM |#11  
garyd9's Avatar
OP Inactive Recognized Developer
Flag Pittsburgh, PA
Thanks Meter: 2,750
 
More
Quote:
Originally Posted by thuddome

Tried this on my Galaxy S5 with my Jeep 430N. No go so far, still getting "no number available" for every person.

Can you post/attach a copy of the xposed log when this module is active? That should let me know if the module was able to hook the methods it expected or not.

thanks
Gary
The Following User Says Thank You to garyd9 For This Useful Post: [ View ] Gift garyd9 Ad-Free
Post Reply Subscribe to Thread

Guest Quick Reply (no urls or BBcode)
Message:
Previous Thread Next Thread
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes