Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b91caab0 authored by Martin Gerczuk's avatar Martin Gerczuk Committed by Danny Baumann
Browse files

Added support for Filter parameter for PBAP function PullPhoneBook



VW Premium car kit sometimes behaves strangely if it receives entries with unexpected fields.
E.g. it does not like mail addresses with additional attributes.

Change-Id: Ie36a6103bcb08d70d4d1826d1d6f1553d12808b3
AOSP-Change-Id: I6d3145d802ad87e5fb47217a213f9bcb12670f60
Signed-off-by: default avatarMartin Gerczuk <admin@android-rsap.com>
parent 4a0840b0
Loading
Loading
Loading
Loading
+36 −11
Original line number Diff line number Diff line
@@ -449,6 +449,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

        public boolean vcard21;

        public long filter;

        public AppParamValue() {
            maxListCount = 0xFFFF;
            listStartOffset = 0;
@@ -457,12 +459,22 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            order = "";
            needTag = 0x00;
            vcard21 = true;
            filter = 0L;
        }

        public void dump() {
            Log.i(TAG, "maxListCount=" + maxListCount + " listStartOffset=" + listStartOffset
                    + " searchValue=" + searchValue + " searchAttr=" + searchAttr + " needTag="
                    + needTag + " vcard21=" + vcard21 + " order=" + order);
        public long getActualFilter() {
            // All attributes of the vCard shall be returned if this header is not
            // specified or carries the value 0x00000000
            if (filter == 0L)
                return -1L;

            long mandatory = BluetoothPbapVcardComposer.FILTER_VERSION |
                             BluetoothPbapVcardComposer.FILTER_N |
                             BluetoothPbapVcardComposer.FILTER_TEL;
            if (!vcard21)
                mandatory |= BluetoothPbapVcardComposer.FILTER_FN;

            return filter | mandatory;
        }
    }

@@ -475,11 +487,21 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            switch (appParam[i]) {
                case ApplicationParameter.TRIPLET_TAGID.FILTER_TAGID:
                    i += 2; // length and tag field in triplet
                    appParamValue.filter = ((appParam[i+0] << 56) & 0xFF00000000000000L) |
                                           ((appParam[i+1] << 48) & 0x00FF000000000000L) |
                                           ((appParam[i+2] << 40) & 0x0000FF0000000000L) |
                                           ((appParam[i+3] << 32) & 0x000000FF00000000L) |
                                           ((appParam[i+4] << 24) & 0x00000000FF000000L) |
                                           ((appParam[i+5] << 16) & 0x0000000000FF0000L) |
                                           ((appParam[i+6] <<  8) & 0x000000000000FF00L) |
                                           ((appParam[i+7] <<  0) & 0x00000000000000FFL);
                    if (D) Log.i(TAG, "AppParam filter=" + appParamValue.filter);
                    i += ApplicationParameter.TRIPLET_LENGTH.FILTER_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.ORDER_TAGID:
                    i += 2; // length and tag field in triplet
                    appParamValue.order = Byte.toString(appParam[i]);
                    if (D) Log.i(TAG, "AppParam order=" + appParamValue.order);
                    i += ApplicationParameter.TRIPLET_LENGTH.ORDER_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.SEARCH_VALUE_TAGID:
@@ -495,12 +517,14 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                    } else {
                        appParamValue.searchValue = new String(appParam, i + 1, length);
                    }
                    if (D) Log.i(TAG, "AppParam searchValue=" + appParamValue.searchValue);
                    i += length;
                    i += 1;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.SEARCH_ATTRIBUTE_TAGID:
                    i += 2;
                    appParamValue.searchAttr = Byte.toString(appParam[i]);
                    if (D) Log.i(TAG, "AppParam searchAttr=" + appParamValue.searchAttr);
                    i += ApplicationParameter.TRIPLET_LENGTH.SEARCH_ATTRIBUTE_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.MAXLISTCOUNT_TAGID:
@@ -512,6 +536,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                        int lowValue = appParam[i + 1] & 0xff;
                        appParamValue.maxListCount = highValue * 256 + lowValue;
                    }
                    if (D) Log.i(TAG, "AppParam maxListCount=" + appParamValue.maxListCount);
                    i += ApplicationParameter.TRIPLET_LENGTH.MAXLISTCOUNT_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.LISTSTARTOFFSET_TAGID:
@@ -519,6 +544,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                    int highValue = appParam[i] & 0xff;
                    int lowValue = appParam[i + 1] & 0xff;
                    appParamValue.listStartOffset = highValue * 256 + lowValue;
                    if (D) Log.i(TAG, "AppParam listStartOffset=" + appParamValue.listStartOffset);
                    i += ApplicationParameter.TRIPLET_LENGTH.LISTSTARTOFFSET_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.FORMAT_TAGID:
@@ -526,6 +552,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                    if (appParam[i] != 0) {
                        appParamValue.vcard21 = false;
                    }
                    if (D) Log.i(TAG, "AppParam format=" + appParam[i]);
                    i += ApplicationParameter.TRIPLET_LENGTH.FORMAT_LENGTH;
                    break;
                default:
@@ -535,8 +562,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            }
        }

        if (D) appParamValue.dump();

        return parseOk;
    }

@@ -888,7 +913,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                return pushBytes(op, ownerVcard);
            } else {
                return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null,
                        mOrderBy );
                        mOrderBy, appParamValue.getActualFilter());
            }
        } else {
            if (intIndex <= 0 || intIndex > size) {
@@ -899,7 +924,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            // begin from 1.vcf
            if (intIndex >= 1) {
                return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                        intIndex, intIndex, vcard21);
                        intIndex, intIndex, vcard21, appParamValue.getActualFilter());
            }
        }
        return ResponseCodes.OBEX_HTTP_OK;
@@ -960,15 +985,15 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                    return pushBytes(op, ownerVcard);
                } else {
                    return mVcardManager.composeAndSendPhonebookVcards(op, 1, endPoint, vcard21,
                            ownerVcard);
                            appParamValue.getActualFilter(), ownerVcard);
                }
            } else {
                return mVcardManager.composeAndSendPhonebookVcards(op, startPoint, endPoint,
                        vcard21, null);
                        vcard21, appParamValue.getActualFilter(), null);
            }
        } else {
            return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                    startPoint + 1, endPoint + 1, vcard21);
                    startPoint + 1, endPoint + 1, vcard21, appParamValue.getActualFilter());
        }
    }

+120 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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.
 */
package com.android.bluetooth.pbap;

import android.content.ContentValues;
import android.content.Context;
import android.pim.vcard.VCardComposer;
import android.pim.vcard.VCardBuilder;
import android.pim.vcard.VCardConfig;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.telephony.PhoneNumberUtils;
import android.util.Log;

import java.util.List;
import java.util.Map;

public class BluetoothPbapVcardComposer extends VCardComposer
{
    private static final String LOG_TAG = "BluetoothPbapVcardComposer";

    public static final long FILTER_VERSION = (1L << 0); // vCard Version
    public static final long FILTER_FN = (1L << 1); // Formatted Name
    public static final long FILTER_N = (1L << 2); // Structured Presentation of Name
    public static final long FILTER_PHOTO = (1L << 3); // Associated Image or Photo
    public static final long FILTER_BDAY = (1L << 4); // Birthday
    public static final long FILTER_ADR = (1L << 5); // Delivery Address
    public static final long FILTER_LABEL = (1L << 6); // Delivery
    public static final long FILTER_TEL = (1L << 7); // Telephone Number
    public static final long FILTER_EMAIL = (1L << 8); // Electronic Mail Address
    public static final long FILTER_MAILER = (1L << 9); // Electronic Mail
    public static final long FILTER_TZ = (1L << 10); // Time Zone
    public static final long FILTER_GEO = (1L << 11); // Geographic Position
    public static final long FILTER_TITLE = (1L << 12); // Job
    public static final long FILTER_ROLE = (1L << 13); // Role within the Organization
    public static final long FILTER_LOGO = (1L << 14); // Organization Logo
    public static final long FILTER_AGENT = (1L << 15); // vCard of Person Representing
    public static final long FILTER_ORG = (1L << 16); // Name of Organization
    public static final long FILTER_NOTE = (1L << 17); // Comments
    public static final long FILTER_REV = (1L << 18); // Revision
    public static final long FILTER_SOUND = (1L << 19); // Pronunciation of Name
    public static final long FILTER_URL = (1L << 20); // Uniform Resource Locator
    public static final long FILTER_UID = (1L << 21); // Unique ID
    public static final long FILTER_KEY = (1L << 22); // Public Encryption Key
    public static final long FILTER_NICKNAME = (1L << 23); // Nickname
    public static final long FILTER_CATEGORIES = (1L << 24); // Categories
    public static final long FILTER_PROID = (1L << 25); // Product ID
    public static final long FILTER_CLASS = (1L << 26); // Class information
    public static final long FILTER_SORT_STRING = (1L << 27); // String used for sorting operations
    public static final long FILTER_X_IRMC_CALL_DATETIME = (1L << 28); // Time stamp

    private final int mVCardType;
    private final String mCharset;
    private final long mFilter;

    public BluetoothPbapVcardComposer(final Context context, final int vcardType,
            long filter, final boolean careHandlerErrors) {
        super(context, vcardType, null, careHandlerErrors);
        mVCardType = vcardType;
        mCharset = null;
        mFilter = filter;
    }

    public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
        if (contentValuesListMap == null) {
            Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
            return "";
        } else {
            Log.i(LOG_TAG, "buildVCard filter = " + mFilter);
            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
            // TODO: not perfect here - perhaps subclass VCardBuilder to separate N and FN
            if (((mFilter & FILTER_N) != 0) || ((mFilter & FILTER_FN) != 0))
                builder.appendNameProperties(contentValuesListMap
                        .get(StructuredName.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_NICKNAME) != 0)
                builder.appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_TEL) != 0)
                builder.appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_EMAIL) != 0)
                builder.appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_ADR) != 0)
                builder.appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_ORG) != 0)
                builder.appendOrganizations(contentValuesListMap
                        .get(Organization.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_URL) != 0)
                builder.appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_PHOTO) != 0)
                builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_NOTE) != 0)
                builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE));
            if ((mFilter & FILTER_BDAY) != 0)
                builder.appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE));
            // builder.appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE));
            // builder.appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
            return builder.toString();
        }
    }
}
+9 −9
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ public class BluetoothPbapVcardManager {
                size = getCallHistorySize(type);
                break;
        }
        if (V) Log.v(TAG, "getPhonebookSzie size = " + size + " type = " + type);
        if (V) Log.v(TAG, "getPhonebookSize size = " + size + " type = " + type);
        return size;
    }

@@ -268,7 +268,7 @@ public class BluetoothPbapVcardManager {
    }

    public final int composeAndSendCallLogVcards(final int type, Operation op,
            final int startPoint, final int endPoint, final boolean vcardType21) {
            final int startPoint, final int endPoint, final boolean vcardType21, long filter) {
        if (startPoint < 1 || startPoint > endPoint) {
            Log.e(TAG, "internal error: startPoint or endPoint is not correct.");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -325,11 +325,11 @@ public class BluetoothPbapVcardManager {

        if (V) Log.v(TAG, "Call log query selection is: " + selection);

        return composeAndSendVCards(op, selection, vcardType21, null, false);
        return composeAndSendVCards(op, selection, vcardType21, filter, null, false);
    }

    public final int composeAndSendPhonebookVcards(Operation op, final int startPoint,
            final int endPoint, final boolean vcardType21, String ownerVCard) {
            final int endPoint, final boolean vcardType21, long filter, String ownerVCard) {
        if (startPoint < 1 || startPoint > endPoint) {
            Log.e(TAG, "internal error: startPoint or endPoint is not correct.");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -370,11 +370,11 @@ public class BluetoothPbapVcardManager {

        if (V) Log.v(TAG, "Query selection is: " + selection);

        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true);
        return composeAndSendVCards(op, selection, vcardType21, filter, ownerVCard, true);
    }

    public final int composeAndSendPhonebookOneVcard(Operation op, final int offset,
            final boolean vcardType21, String ownerVCard, int orderByWhat) {
            final boolean vcardType21, String ownerVCard, int orderByWhat, long filter) {
        if (offset < 1) {
            Log.e(TAG, "Internal error: offset is not correct.");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -419,11 +419,11 @@ public class BluetoothPbapVcardManager {

        if (V) Log.v(TAG, "Query selection is: " + selection);

        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true);
        return composeAndSendVCards(op, selection, vcardType21, filter, ownerVCard, true);
    }

    public final int composeAndSendVCards(Operation op, final String selection,
            final boolean vcardType21, String ownerVCard, boolean isContacts) {
            final boolean vcardType21, long filter, String ownerVCard, boolean isContacts) {
        long timestamp = 0;
        if (V) timestamp = System.currentTimeMillis();

@@ -440,7 +440,7 @@ public class BluetoothPbapVcardManager {
                vcardType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
                vcardType |= VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING;

                composer = new VCardComposer(mContext, vcardType, true);
                composer = new BluetoothPbapVcardComposer(mContext, vcardType, filter, true);
                composer.addHandler(new HandlerForStringBuffer(op, ownerVCard));
                if (!composer.init(Contacts.CONTENT_URI, selection, null, Contacts._ID)) {
                    return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;