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

Commit 746ba58b authored by Danny Baumann's avatar Danny Baumann
Browse files

Revert "Revert "Added support for Filter parameter for PBAP function PullPhoneBook""

This reverts commit 0a0864e9 and
additionally removes the filtering code added in commit 420ab1a5.

The CAF PBAP filter code is a piece of junk compared to the version we
carry. It post-processes formatted vcards instead of filtering their
creation.

Change-Id: I35b32e15163cb8a42fa2893fdd5306afb023f3e5
parent 8b93989b
Loading
Loading
Loading
Loading
+49 −29
Original line number Diff line number Diff line
@@ -462,9 +462,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

        public boolean vcard21;

        public byte[] filter;

        public boolean ignorefilter;
        public long filter;

        public AppParamValue() {
            maxListCount = 0xFFFF;
@@ -474,15 +472,27 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            order = "";
            needTag = 0x00;
            vcard21 = true;
            //Filter is not set by default
            ignorefilter = true;
            filter = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} ;
            filter = BluetoothPbapVcardComposer.FILTER_VERSION;
        }

        public void dump() {
            Log.i(TAG, "maxListCount=" + maxListCount + " listStartOffset=" + listStartOffset
                    + " searchValue=" + searchValue + " searchAttr=" + searchAttr + " needTag="
                    + needTag + " vcard21=" + vcard21 + " order=" + order);
        public long getActualFilter() {
            // Spec says:
            // "All attributes of the vCard shall be returned if this header is not
            //  specified or carries the value 0x00000000"
            // This causes trouble in many car kits because they receive fields they
            // cannot handle. So we send only the minimum set if there is no filter
            // specified. If the filter parameter is 0, we send all fields according
            // to spec.
            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;
        }
    }

@@ -495,18 +505,21 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            switch (appParam[i]) {
                case ApplicationParameter.TRIPLET_TAGID.FILTER_TAGID:
                    i += 2; // length and tag field in triplet
                    for (int index=0; index < ApplicationParameter.TRIPLET_LENGTH.FILTER_LENGTH;
                         index++) {
                        if (appParam[i+index] != 0){
                            appParamValue.ignorefilter = false;
                            appParamValue.filter[index] = appParam[i+index];
                        }
                    }
                    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:
@@ -522,12 +535,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:
@@ -539,6 +554,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:
@@ -546,6 +562,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:
@@ -553,6 +570,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:
@@ -562,8 +580,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            }
        }

        if (D) appParamValue.dump();

        return parseOk;
    }

@@ -896,11 +912,12 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                return ResponseCodes.OBEX_HTTP_NOT_FOUND;
            } else if (intIndex == 0) {
                // For PB_PATH, 0.vcf is the phone number of this phone.
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21,null);
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21,
                        appParamValue.getActualFilter());
                return pushBytes(op, ownerVcard);
            } else {
                return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null,
                        mOrderBy, appParamValue.ignorefilter, appParamValue.filter);
                        mOrderBy, appParamValue.getActualFilter());
            }
       } else if (appParamValue.needTag == ContentType.SIM_PHONEBOOK) {
            if (intIndex < 0 || intIndex >= size) {
@@ -908,7 +925,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                return ResponseCodes.OBEX_HTTP_OK;
            } else if (intIndex == 0) {
                // For PB_PATH, 0.vcf is the phone number of this phone.
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21, null);
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21,
                        appParamValue.getActualFilter());
                return pushBytes(op, ownerVcard);
            } else {
                return mVcardManager.composeAndSendSIMPhonebookOneVcard(op, intIndex, vcard21, null,
@@ -923,7 +941,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            // begin from 1.vcf
            if (intIndex >= 1) {
                return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                        intIndex, intIndex, vcard21, appParamValue.ignorefilter, appParamValue.filter);
                        intIndex, intIndex, vcard21, appParamValue.getActualFilter());
            }
        }
        return ResponseCodes.OBEX_HTTP_OK;
@@ -980,20 +998,22 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        boolean vcard21 = appParamValue.vcard21;
        if (appParamValue.needTag == BluetoothPbapObexServer.ContentType.PHONEBOOK) {
            if (startPoint == 0) {
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21, null);
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21,
                        appParamValue.getActualFilter());
                if (endPoint == 0) {
                    return pushBytes(op, ownerVcard);
                } else {
                    return mVcardManager.composeAndSendPhonebookVcards(op, 1, endPoint, vcard21,
                            ownerVcard, appParamValue.ignorefilter, appParamValue.filter);
                            appParamValue.getActualFilter(), ownerVcard);
                }
            } else {
                return mVcardManager.composeAndSendPhonebookVcards(op, startPoint, endPoint,
                        vcard21, null, appParamValue.ignorefilter, appParamValue.filter);
                        vcard21, appParamValue.getActualFilter(), null);
            }
        } else if (appParamValue.needTag == BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK) {
            if (startPoint == 0) {
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21, null);
                String ownerVcard = mVcardManager.getOwnerPhoneNumberVcard(vcard21,
                        appParamValue.getActualFilter());
                if (endPoint == 0) {
                    return pushBytes(op, ownerVcard);
                } else {
@@ -1006,7 +1026,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            }
        } else {
            return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                    startPoint + 1, endPoint + 1, vcard21, appParamValue.ignorefilter, appParamValue.filter);
                    startPoint + 1, endPoint + 1, vcard21, appParamValue.getActualFilter());
        }
    }

+2 −89
Original line number Diff line number Diff line
@@ -18,114 +18,27 @@
package com.android.bluetooth.pbap;

import android.content.Context;
import android.os.SystemProperties;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.bluetooth.pbap.BluetoothPbapService;
import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContactsEntity;


import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;


public class BluetoothPbapUtils {

    private static final String TAG = "FilterUtils";
    private static final boolean V = BluetoothPbapService.VERBOSE;

    public static int FILTER_PHOTO = 3;
    public static int FILTER_TEL = 7;
    public static int FILTER_NICKNAME = 23;

    public static boolean hasFilter(byte[] filter) {
        return filter != null && filter.length > 0;
    }

    public static boolean isNameAndNumberOnly(byte[] filter) {
        // For vcard 2.0: VERSION,N,TEL is mandatory
        // For vcard 3.0, VERSION,N,FN,TEL is mandatory
        // So we only need to make sure that no other fields except optionally
        // NICKNAME is set

        // Check that an explicit filter is not set. If not, this means
        // return everything
        if (!hasFilter(filter)) {
            Log.v(TAG, "No filter set. isNameAndNumberOnly=false");
            return false;
        }

        // Check bytes 0-4 are all 0
        for (int i = 0; i <= 4; i++) {
            if (filter[i] != 0) {
                return false;
            }
        }
        // On byte 5, only BIT_NICKNAME can be set, so make sure
        // rest of bits are not set
        if ((filter[5] & 0x7F) > 0) {
            return false;
        }

        // Check byte 6 is not set
        if (filter[6] != 0) {
            return false;
        }

        // Check if bit#3-6 is set. Return false if so.
        if ((filter[7] & 0x78) > 0) {
            return false;
        }

        return true;
    }

    public static boolean isFilterBitSet(byte[] filter, int filterBit) {
        if (hasFilter(filter)) {
            int byteNumber = 7 - filterBit / 8;
            int bitNumber = filterBit % 8;
            if (byteNumber < filter.length) {
                return (filter[byteNumber] & (1 << bitNumber)) > 0;
            }
        }
        return false;
    }

    public static VCardComposer createFilteredVCardComposer(final Context ctx,
            final int vcardType, final byte[] filter) {
        int vType = vcardType;
        /*
        boolean isNameNumberOnly = isNameAndNumberOnly(filter);
        if (isNameNumberOnly) {
            if (V)
                Log.v(TAG, "Creating Name/Number only VCardComposer...");
            vType |= VCardConfig.FLAG_NAME_NUMBER_ONLY_EXPORT;
        } else {
        */
        boolean includePhoto = BluetoothPbapConfig.includePhotosInVcard()
                    && (!hasFilter(filter) || isFilterBitSet(filter, FILTER_PHOTO));
        if (!includePhoto) {
            if (V) Log.v(TAG, "Excluding images from VCardComposer...");
            vType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
        }
        //}
        return new VCardComposer(ctx, vType, true);
    }

    public static boolean isProfileSet(Context context) {
        Cursor c = context.getContentResolver().query(
                Profile.CONTENT_VCARD_URI, new String[] { Profile._ID }, null,
@@ -150,11 +63,11 @@ public class BluetoothPbapUtils {
        }
        return ownerName;
    }
    public static final String createProfileVCard(Context ctx, final int vcardType,final byte[] filter) {
    public static final String createProfileVCard(Context ctx, final int vcardType, final long filter) {
        VCardComposer composer = null;
        String vcard = null;
        try {
            composer = createFilteredVCardComposer(ctx, vcardType, filter);
            composer = new BluetoothPbapVcardComposer(ctx, vcardType, filter, true);
            if (composer
                    .init(Profile.CONTENT_URI, null, null, null, null, Uri
                            .withAppendedPath(Profile.CONTENT_URI,
+139 −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.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 com.android.vcard.VCardBuilder;
import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardPhoneNumberTranslationCallback;

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;

    // BT does want PAUSE/WAIT conversion while it doesn't want the other formatting
    // done by vCard library by default.
    VCardPhoneNumberTranslationCallback callback =
            new VCardPhoneNumberTranslationCallback() {
                public String onValueReceived(
                        String rawValue, int type, String label, boolean isPrimary) {
                    // 'p' and 'w' are the standard characters for pause and wait
                    // (see RFC 3601)
                    // so use those when exporting phone numbers via vCard.
                    String numberWithControlSequence = rawValue
                            .replace(PhoneNumberUtils.PAUSE, 'p')
                            .replace(PhoneNumberUtils.WAIT, 'w');
                    return numberWithControlSequence;
                }
            };

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

    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), callback);
            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();
        }
    }
}
+11 −330

File changed.

Preview size limit exceeded, changes collapsed.