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

Commit 420ab1a5 authored by Smriti Gupta's avatar Smriti Gupta
Browse files

Bluetooth: PBAP: Add Filters support.

This patch adds attribute filter support to PBAP. It will allow remote
devices to request the particular attributes.

Change-Id: Ia0a4f55f14925b0cf8d0553c64222d781edef2fd
CRs-Fixed: 509165
parent e7238adc
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -462,6 +462,10 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

        public boolean vcard21;

        public byte[] filter;

        public boolean ignorefilter;

        public AppParamValue() {
            maxListCount = 0xFFFF;
            listStartOffset = 0;
@@ -470,6 +474,9 @@ 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} ;
        }

        public void dump() {
@@ -484,10 +491,17 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            AppParamValue appParamValue) {
        int i = 0;
        boolean parseOk = true;
        while (i < appParam.length) {
        while ((i < appParam.length) && (parseOk == true)) {
            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];
                        }
                    }
                    i += ApplicationParameter.TRIPLET_LENGTH.FILTER_LENGTH;
                    break;
                case ApplicationParameter.TRIPLET_TAGID.ORDER_TAGID:
@@ -886,7 +900,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                return pushBytes(op, ownerVcard);
            } else {
                return mVcardManager.composeAndSendPhonebookOneVcard(op, intIndex, vcard21, null,
                        mOrderBy);
                        mOrderBy, appParamValue.ignorefilter, appParamValue.filter);
            }
       } else if (appParamValue.needTag == ContentType.SIM_PHONEBOOK) {
            if (intIndex < 0 || intIndex >= size) {
@@ -909,7 +923,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.ignorefilter, appParamValue.filter);
            }
        }
        return ResponseCodes.OBEX_HTTP_OK;
@@ -971,11 +985,11 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                    return pushBytes(op, ownerVcard);
                } else {
                    return mVcardManager.composeAndSendPhonebookVcards(op, 1, endPoint, vcard21,
                            ownerVcard);
                            ownerVcard, appParamValue.ignorefilter, appParamValue.filter);
                }
            } else {
                return mVcardManager.composeAndSendPhonebookVcards(op, startPoint, endPoint,
                        vcard21, null);
                        vcard21, null, appParamValue.ignorefilter, appParamValue.filter);
            }
        } else if (appParamValue.needTag == BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK) {
            if (startPoint == 0) {
@@ -992,7 +1006,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            }
        } else {
            return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                    startPoint + 1, endPoint + 1, vcard21);
                    startPoint + 1, endPoint + 1, vcard21, appParamValue.ignorefilter, appParamValue.filter);
        }
    }

+189 −9
Original line number Diff line number Diff line
@@ -455,7 +455,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, boolean ignorefilter, byte[] filter) {
        if (startPoint < 1 || startPoint > endPoint) {
            Log.e(TAG, "internal error: startPoint or endPoint is not correct.");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -512,11 +512,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, null, false, ignorefilter, filter);
    }

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

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

        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true);
        return composeAndSendVCards(op, selection, vcardType21, ownerVCard, true, ignorefilter, filter);
    }
    public final int composeAndSendSIMPhonebookVcards(Operation op, final int startPoint,
            final int endPoint, final boolean vcardType21, String ownerVCard) {
@@ -604,7 +604,7 @@ public class BluetoothPbapVcardManager {
    }

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

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

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

    public final int composeAndSendSIMPhonebookOneVcard(Operation op, final int offset,
@@ -700,12 +700,16 @@ public class BluetoothPbapVcardManager {
    }

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

        if (isContacts) {
            VCardComposer composer = null;
            FilterVcard vcardfilter= new FilterVcard();
            if (!ignorefilter) {
                vcardfilter.setFilter(filter);
            }
            HandlerForStringBuffer buffer = null;
            try {
                // Currently only support Generic Vcard 2.1 and 3.0
@@ -715,8 +719,7 @@ public class BluetoothPbapVcardManager {
                } else {
                    vcardType = VCardConfig.VCARD_TYPE_V30_GENERIC;
                }

                if (!BluetoothPbapConfig.includePhotosInVcard()) {
                if (!vcardfilter.isPhotoEnabled()) {
                    vcardType |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT;
                }

@@ -752,6 +755,9 @@ public class BluetoothPbapVcardManager {
                        break;
                    }
                    String vcard = composer.createOneEntry();
                    if (!ignorefilter) {
                        vcard = vcardfilter.applyFilter(vcard, vcardType21);
                    }
                    if (vcard == null) {
                        Log.e(TAG, "Failed to read a contact. Error reason: "
                                + composer.getErrorReason());
@@ -879,4 +885,178 @@ public class BluetoothPbapVcardManager {
            }
        }
    }

    public class FilterVcard{

        public FilterVcard(){
        };

        private final int FN_BIT = 1;

        private boolean fn = true;

        private final int PHOTO_BIT = 3;

        private boolean photo = true;

        //BDAY falls under events
        private final int BDAY_BIT = 4;

        private boolean bday = true;

        private final int ADR_BIT = 5;

        private boolean adr = true;

        private final int EMAIL_BIT = 8;

        private boolean email = true;

        private final int TITLE_BIT = 12;

        private boolean title = true;

        private final int ORG_BIT = 16;

        private boolean org = true;

        private final int NOTES_BIT = 17;

        private boolean notes = true;

        private final int URL_BIT = 20;

        private boolean url = true;

        private final int NICKNAME_BIT = 23;

        private boolean nickname = true;

        public void setFilter(byte[] filter){

           fn = checkbit(FN_BIT, filter);
           photo = checkbit(PHOTO_BIT, filter);
           bday = checkbit(BDAY_BIT, filter);
           adr = checkbit(ADR_BIT, filter);
           email = checkbit(EMAIL_BIT, filter);
           title = checkbit(TITLE_BIT, filter);
           org = checkbit(ORG_BIT, filter);
           notes = checkbit(NOTES_BIT, filter);
           url = checkbit(URL_BIT, filter);
           nickname = checkbit(NICKNAME_BIT, filter);
        }

        private boolean checkbit (int attr_bit, byte[] filter){
            int filterlen = filter.length;
            if( ((filter[filterlen -1 -((int)attr_bit/8)] >> (attr_bit%8)) & 0x01) == 0) {
                return false;
            }
            return true;
        }

        public boolean isPhotoEnabled(){
            return photo;
        }

        public String applyFilter ( String vCard, boolean vCardType21){
            String attr [] = vCard.split(System.getProperty("line.separator"));

            //FN is not the mandatory field in 3.0 vacrd
            if(((!fn) && (vCardType21)) && (vCard.contains("FN"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("FN")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

          //NOTE: No need to check photo, we already refrained it if it is not set in the filter
            if((!bday) && (vCard.contains("BDAY"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("BDAY")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!adr) && (vCard.contains("ADR"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("ADR")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!email) && (vCard.contains("EMAIL"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("EMAIL")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!title) && (vCard.contains("TITLE"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("TITLE")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!org) && (vCard.contains("ORG"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("ORG")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!notes) && (vCard.contains("NOTE"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("NOTE")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }
            /*Nickname is not supported in 2.1 version.
             *Android still ads it for 2.1 with nickname mentioned in lower case, and therefore
             *we need to check for both cases.
             */
            if(((!nickname) || (vCardType21)) && (vCard.toUpperCase().contains("NICKNAME"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].toUpperCase().contains("NICKNAME")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if((!url) && (vCard.contains("URL"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].contains("URL")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }
            /*Since PBAP does not have filter bit for IM and SIP,
             *removing them by default.
            */
            if(vCard.toUpperCase().contains("IM")) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].toUpperCase().contains("IM")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            if(vCard.toUpperCase().contains("SIP")) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].toUpperCase().contains("SIP")){
                        vCard = vCard.replace(attr[i] + "\n", "");
                    }
                }
            }

            return vCard;
        }
    }
}