Дружим штатную громкую связь Volvo с русскими буквами

Доброго времени суток!
Несколько месяцев назад появился у меня чудесный автомобиль Volvo V50 родом из Бельгии. Бортовой компьютер и магнитолу успешно перепрошили на русский язык у официального дилера, а вот с отображением русских имен из записной книжки телефона при использовании штатной громкой связи вышла беда: все кириллические символы показывались в виде подчеркиваний. Я пользуюсь Samsung Galaxy S3 прошитым CyanogenMod 11, поэтому возникла идея подправить стандартный Bluetooth.apk для обеспечения возможности видеть имя звонящего.

Небольшое исследование показало, что в основном автомобили используют два вида профилей для получения записей телефонной книги:
  • PBAP — Phone Book Access Profile
  • HFP — Handsfree Profile

Первый является более навороченным и передает данные в формате vCard, который включает в себя практически все данные о контакте: имя, фамилию, организацию, адрес электронной почты и так далее.
Второй отправляет только имя, телефон и идентификатор записной книжки.

Путем анализа логов системы выяснилось, что мой автомобиль использует HFP с общением посредством AT-команд. За данный профиль отвечает следующий файл /packages/apps/Bluetooth/src/com/android/bluetooth/hfp/AtPhonebook.java
После недолгих поисков находим функцию int processCpbrCommand(BluetoothDevice device), в конце которой происходит формирование строки ответа на команду:
record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + name + "\"";
record = record + "\r\n\r\n";
atCommandResponse = record;
log("processCpbrCommand - atCommandResponse = "+atCommandResponse);
mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device));

Именно здесь и было бы неплохо исправить передаваемое имя. В моем случае было решено транслитерировать его. Для этих целей в класс AtPhonebook я добавил массив соответствия символов, а также функцию траслитерации:
private static final String[] charTable = new String[65536];
    static {
	charTable['А'] = "A";
	charTable['Б'] = "B";
	charTable['В'] = "V";
	charTable['Г'] = "G";
	charTable['Д'] = "D";
	charTable['Е'] = "E";
	charTable['Ё'] = "E";
	charTable['Ж'] = "ZH";
	charTable['З'] = "Z";
	charTable['И'] = "I";
	charTable['Й'] = "I";
	charTable['К'] = "K";
	charTable['Л'] = "L";
	charTable['М'] = "M";
	charTable['Н'] = "N";
	charTable['О'] = "O";
	charTable['П'] = "P";
	charTable['Р'] = "R";
	charTable['С'] = "S";
	charTable['Т'] = "T";
	charTable['У'] = "U";
	charTable['Ф'] = "F";
	charTable['Х'] = "H";
	charTable['Ц'] = "C";
	charTable['Ч'] = "CH";
	charTable['Ш'] = "SH";
	charTable['Щ'] = "SH";
	charTable['Ъ'] = "'";
	charTable['Ы'] = "Y";
	charTable['Ь'] = "'";
	charTable['Э'] = "E";
	charTable['Ю'] = "U";
	charTable['Я'] = "YA";

	for (int i = 0; i < charTable.length; i++) {
	    char idx = (char) i;
	    char lower = new String(new char[] {idx}).toLowerCase().charAt(0);
	    if (charTable[i] != null) {
		charTable[lower] = charTable[i].toLowerCase();
	    }
	}
}

public static String toTranslit(String text) {
	char charBuffer[] = text.toCharArray();
	StringBuilder sb = new StringBuilder(text.length());
	for (char symbol : charBuffer) {
	    String replace = charTable[symbol];
	    sb.append(replace == null ? symbol : replace);
	}
	return sb.toString();
}

После этого нужно вызвать функцию при передаче команды:
record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + toTranslit(name) + "\"";
record = record + "\r\n\r\n";

Теперь остается лишь скомпилировать приложение Bluetooth и вставить в архив с прошивкой CM.
Тесты после перепрошивки показали полную работоспособность решения. Теперь все имена из записной книжки отображаются транслитом.

В процессе поиска готового решения выяснилось, что проблемы бывают и с профилем PBAP, опять же с автомобилями Volvo, например XC60.
Модуль громкой связи в данном авто использует кодировку CP1251, тогда как стандартное приложение Bluetooth телефона на Android передает данные по профилю PBAP с указанием кодировки UTF-8, что выражается в отображении данных символами подчеркивания.

Для решения данной проблемы можно изменить конструктор класса BluetoothPbapVcardComposer (/packages/apps/Bluetooth/src/com/android/bluetooth/pbap/BluetoothPbapVcardComposer.java)
public BluetoothPbapVcardComposer(final Context context, final int vcardType,
    long filter, final boolean careHandlerErrors) {
    super(context, vcardType, "CP1251", careHandlerErrors);
    mVCardType = vcardType;
    mCharset = "CP1251";
    mFilter = filter;
}

Здесь можно явно задать кодировку для суперкласса.
В принципе можно попробовать провернуть трюк с транслитерацией и здесь, копать нужно в сторону формирования vCard (функция buildVCard)
К сожалению XC60 или другой машины, использующей PBAP, у меня пока нет, поэтому проверить не смог.

Прикладываю пару вариантов пересобранного Bluetooth.apk
  1. Транслит HFP (http://yadi.sk/d/QlGKIPfXLMNXx)
  2. CP1251 PBAP (http://yadi.sk/d/qrbUVrtuLMRan)


Данное решение может также помочь и обладателям других авто со встроенной громкой связью, не понимающей русский язык.
Share post

Comments 11

    0
    Это очень классная идея!
    А можно было бы небольшой мануал по установке, настройке и определению необходимых параметров?
      0
      Прежде всего нужно выяснить как телефон общается с авто, для этого ставится программа наподобие alogcat, ей дается root-доступ, а затем пишется лог того, что происходит при «спаривании» телефона и авто. По тем сообщениям можно будет понять какой профиль используется. Современные авто почти все пользуются PBAP (например BMW даже отображает аватарки). В ближайшее время потестирую Х3, правда он и так русский нормально понимает.
      Можно просто взять один из приложеннных скомпилированных apk, заменить в архиве прошивки на него Bluetooth.apk и прошить телефон.
        0
        Я просто заменить apk на рутованном телефоне нельзя?
          0
          У меня так ставиться отказалось, в логах пишет, что не может устанавливаться, так как есть уже одно. Можно конечно попробовать поднять версию, чтобы система приняла как обновление. Попробовать не могу сейчас, так как виртуальная машина для разработки поломалась, вот починю и попробую.
            0
            Разработчики на Хабре настолько суровы, что используют для телефонных звонков в автомобиле виртуальные машины.
              0
              Можно установить через adb install -r package.apk
              adb install [-l] [-r] [-s] [--algo --key <hex-encoded key> --iv <hex-encoded iv>] — push this package file to the device and install it
              ('-l' means forward-lock the app)
              ('-r' means reinstall the app, keeping its data)
              ('-s' means install on SD card instead of internal storage)
                0
                Да, действительно, можно и через адб подсунуть, только приложение лежит в разделе system, а его сначала нужно будет примонтировать с правом записи. Вобщем мне было проще в архиве заменить и перепрошить, не так и много времени заняло
        0
        [deleted]
        не в ту ветку
          0
          Вот бы в мой V40 модуль Громкой связи… Не приветствуют шведы кастомизацию — дабы добавить оговариваемый модуль нужно сменить как минимум 3 блока — заведомо затратное дело…
            0
            То ли дело фокусы, там при наличии правильной магнитолы достаточно блок громкой связи за 3 тысячи купить и микрофон, причем велика вероятность, что даже проводка в машине уже вся будет, даже с разъемами
              0
              Шведы ставят магнитолу из разряда «только наша»… да и как определить что она «правильная»? Плюс ко всему — машинка еще на гарантии (2013 года). Но буду рад любой полезной информации по этому вопросу.

          Only users with full accounts can post comments. Log in, please.