[Xposed Framework Modules] garyd9:
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.garyndenise.xposed.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.

/* 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/issues/detail?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.