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

Commit e6daab5d authored by Hemant Gupta's avatar Hemant Gupta
Browse files

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
parent d9566000
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -451,6 +451,10 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

        public boolean vcard21;

        public byte[] filter;

        public boolean ignorefilter;

        public AppParamValue() {
            maxListCount = 0xFFFF;
            listStartOffset = 0;
@@ -459,6 +463,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() {
@@ -473,10 +480,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:
@@ -854,7 +868,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 (intIndex <= 0 || intIndex > size) {
@@ -865,7 +879,8 @@ 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;
@@ -926,15 +941,16 @@ 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 {
            return mVcardManager.composeAndSendCallLogVcards(appParamValue.needTag, op,
                    startPoint + 1, endPoint + 1, vcard21);
                    startPoint + 1, endPoint + 1, vcard21, appParamValue.ignorefilter,
                    appParamValue.filter);
        }
    }

+308 −9
Original line number Diff line number Diff line
@@ -341,7 +341,8 @@ 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;
@@ -401,11 +402,12 @@ 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;
@@ -449,11 +451,13 @@ 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 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;
@@ -504,16 +508,22 @@ 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 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
@@ -523,8 +533,7 @@ public class BluetoothPbapVcardManager {
                } else {
                    vcardType = VCardConfig.VCARD_TYPE_V30_GENERIC;
                }

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

@@ -565,6 +574,11 @@ public class BluetoothPbapVcardManager {
                                + composer.getErrorReason());
                        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
                    }
                    Log.v (TAG , "vCard from composer: " + vcard);
                    if (!ignorefilter) {
                        vcard = vcardfilter.applyFilter(vcard, vcardType21);
                        Log.v (TAG , "vCard on applying filter: " + vcard);
                    }
                    vcard = StripTelephoneNumber(vcard);
                    if (V) {
                        Log.v(TAG, "Vcard Entry:");
@@ -709,4 +723,289 @@ 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;
        }

        private boolean checkValidFilter (String attr) {
            if((attr.startsWith("N:")) || (attr.startsWith("TEL"))
                || (attr.startsWith("VERSION")) || (attr.startsWith("URL"))
                || (attr.startsWith("FN")) || (attr.startsWith("BDAY"))
                || (attr.startsWith("ADR")) || (attr.startsWith("EMAIL"))
                || (attr.startsWith("TITLE")) || (attr.startsWith("ORG"))
                || (attr.startsWith("NOTE")) || (attr.startsWith("NICKNAME"))) {
                return true;
            }
            return false;
        }

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

            //FN is not the mandatory field in 2.1 vCard
            if(((!fn) && (vCardType21)) && (vCard.contains("FN"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("FN")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

          //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].startsWith("BDAY")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!adr) && (vCard.contains("ADR"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("ADR")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!email) && (vCard.contains("EMAIL"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("EMAIL")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!title) && (vCard.contains("TITLE"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("TITLE")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!org) && (vCard.contains("ORG"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("ORG")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!notes) && (vCard.contains("NOTE"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("NOTE")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }
            /*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.contains("NICKNAME"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("NICKNAME")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }

            if((!url) && (vCard.contains("URL"))) {
                for (int i=0; i < attr.length; i++) {
                    if(attr[i].startsWith("URL")){
                        attr[i] = "";
                        /** Remove multiline Content, if any */
                        /** End traversal before END:VCARD */
                        for (int j = i+1; j < attr.length - 1; j++) {
                            if (checkValidFilter(attr[j])) {
                                break;
                            } else {
                                /** Continuation of above attribute, remove */
                                attr[j] = "";
                            }
                        }
                    }
                }
            }
            /*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", "");
                    }
                }
            }

            Log.v(TAG, "Tokens after applying filter: ");

            for (int i=0; i < attr.length; i++) {
                if(!attr[i].equals("")){
                    filteredVcard = filteredVcard.concat(attr[i] + "\n");
                }
            }

            return filteredVcard;
        }
    }
}