com.android.bluetooth.map.BluetoothMapContent.java Source code

Java tutorial

Introduction

Here is the source code for com.android.bluetooth.map.BluetoothMapContent.java

Source

/*
* Copyright (C) 2013 Samsung System LSI
* 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.map;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import android.text.Html;
import android.text.format.Time;

import org.apache.http.util.ByteArrayBuffer;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import android.os.ParcelFileDescriptor;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.Telephony.Mms;
import android.provider.Telephony.Sms;
import android.provider.Telephony.Threads;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.TimeFormatException;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Body;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.EmailContent.BodyColumns;
import com.android.emailcommon.provider.EmailContent.MessageColumns;
import com.android.emailcommon.provider.EmailContent.SyncColumns;

import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.google.android.mms.pdu.CharacterSets;
import com.google.android.mms.pdu.PduHeaders;
import android.database.sqlite.SQLiteException;
import com.android.bluetooth.map.BluetoothMapAppParams;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.*;
import org.apache.commons.codec.net.QuotedPrintableCodec;
import org.apache.commons.codec.DecoderException;

public class BluetoothMapContent {
    private static final String TAG = "BluetoothMapContent";

    private static final boolean D = BluetoothMapService.DEBUG;
    private static final boolean V = Log.isLoggable(BluetoothMapService.LOG_TAG, Log.VERBOSE) ? true : false;

    private static final int MASK_SUBJECT = 0x1;
    private static final int MASK_DATETIME = 0x2;
    private static final int MASK_SENDER_NAME = 0x4;
    private static final int MASK_SENDER_ADDRESSING = 0x8;

    private static final int MASK_RECIPIENT_NAME = 0x10;
    private static final int MASK_RECIPIENT_ADDRESSING = 0x20;
    private static final int MASK_TYPE = 0x40;
    private static final int MASK_SIZE = 0x80;

    private static final int MASK_RECEPTION_STATUS = 0x100;
    private static final int MASK_TEXT = 0x200;
    private static final int MASK_ATTACHMENT_SIZE = 0x400;
    private static final int MASK_PRIORITY = 0x800;

    private static final int MASK_READ = 0x1000;
    private static final int MASK_SENT = 0x2000;
    private static final int MASK_PROTECTED = 0x4000;
    private static final int MASK_REPLYTO_ADDRESSING = 0x8000;
    private static final String HONDA_CARKIT = "64:D4:BD";

    /* OMA-TS-MMS-ENC defined many types in X-Mms-Message-Type.
       Only m-send-req (128) m-retrieve-conf (132), m-notification-ind (130)
       are interested by user */
    private static final String INTERESTED_MESSAGE_TYPE_CLAUSE = "( m_type = 128 OR m_type = 132 OR m_type = 130 )";

    /* Type of MMS address. From Telephony.java it must be one of PduHeaders.BCC, */
    /* PduHeaders.CC, PduHeaders.FROM, PduHeaders.TO. These are from PduHeaders.java */
    public static final int MMS_FROM = 0x89;
    public static final int MMS_TO = 0x97;
    public static final int MMS_BCC = 0x81;
    public static final int MMS_CC = 0x82;

    /* Type of Email address. */
    public static final int EMAIL_FROM = 0x89;
    public static final int EMAIL_TO = 0x97;
    public static final int EMAIL_BCC = 0x81;
    public static final int EMAIL_CC = 0x82;
    public static final String AUTHORITY = "com.android.email.provider";
    public static final Uri EMAIL_URI = Uri.parse("content://" + AUTHORITY);
    public static final Uri EMAIL_ACCOUNT_URI = Uri.withAppendedPath(EMAIL_URI, "account");
    public static final Uri EMAIL_BOX_URI = Uri.withAppendedPath(EMAIL_URI, "mailbox");
    public static final Uri EMAIL_MESSAGE_URI = Uri.withAppendedPath(EMAIL_URI, "message");
    public static final String RECORD_ID = "_id";
    public static final String DISPLAY_NAME = "displayName";
    public static final String SERVER_ID = "serverId";
    public static final String ACCOUNT_KEY = "accountKey";
    public static final String MAILBOX_KEY = "mailboxKey";
    public static final String EMAIL_ADDRESS = "emailAddress";
    public static final String IS_DEFAULT = "isDefault";
    public static final String EMAIL_TYPE = "type";
    public String msgListingFolder = null;
    public static final String[] EMAIL_BOX_PROJECTION = new String[] { RECORD_ID, DISPLAY_NAME, ACCOUNT_KEY,
            EMAIL_TYPE };

    private Context mContext;
    private ContentResolver mResolver;
    private static final String[] ACCOUNT_ID_PROJECTION = new String[] { RECORD_ID, EMAIL_ADDRESS, IS_DEFAULT };

    static final String[] EMAIL_PROJECTION = new String[] { EmailContent.RECORD_ID, MessageColumns.DISPLAY_NAME,
            MessageColumns.TIMESTAMP, MessageColumns.SUBJECT, MessageColumns.FLAG_READ,
            MessageColumns.FLAG_ATTACHMENT, MessageColumns.FLAGS, SyncColumns.SERVER_ID, MessageColumns.DRAFT_INFO,
            MessageColumns.MESSAGE_ID, MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY,
            MessageColumns.FROM_LIST, MessageColumns.TO_LIST, MessageColumns.CC_LIST, MessageColumns.BCC_LIST,
            MessageColumns.REPLY_TO_LIST, SyncColumns.SERVER_TIMESTAMP, MessageColumns.MEETING_INFO,
            MessageColumns.SNIPPET, MessageColumns.PROTOCOL_SEARCH_INFO, MessageColumns.THREAD_TOPIC };

    static final String[] SMS_PROJECTION = new String[] { BaseColumns._ID, Sms.THREAD_ID, Sms.ADDRESS, Sms.BODY,
            Sms.DATE, Sms.READ, Sms.TYPE, Sms.STATUS, Sms.LOCKED, Sms.ERROR_CODE, };

    static final String[] MMS_PROJECTION = new String[] { BaseColumns._ID, Mms.THREAD_ID, Mms.MESSAGE_ID,
            Mms.MESSAGE_SIZE, Mms.SUBJECT, Mms.CONTENT_TYPE, Mms.TEXT_ONLY, Mms.DATE, Mms.DATE_SENT, Mms.READ,
            Mms.MESSAGE_BOX, Mms.STATUS, Mms.PRIORITY, Mms.MESSAGE_TYPE, };

    private class FilterInfo {
        public static final int TYPE_SMS = 0;
        public static final int TYPE_MMS = 1;
        public static final int TYPE_EMAIL = 2;

        int msgType = TYPE_SMS;
        int phoneType = 0;
        String phoneNum = null;
        String phoneAlphaTag = null;
    }

    public BluetoothMapContent(final Context context) {
        mContext = context;
        mResolver = mContext.getContentResolver();
        if (mResolver == null) {
            Log.e(TAG, "getContentResolver failed");
        }
    }

    private void addSmsEntry() {
        if (D)
            Log.d(TAG, "*** Adding dummy sms ***");

        ContentValues mVal = new ContentValues();
        mVal.put(Sms.ADDRESS, "1234");
        mVal.put(Sms.BODY, "Hello!!!");
        mVal.put(Sms.DATE, System.currentTimeMillis());
        mVal.put(Sms.READ, "0");

        Uri mUri = mResolver.insert(Sms.CONTENT_URI, mVal);
    }

    private BluetoothMapAppParams buildAppParams() {
        BluetoothMapAppParams ap = new BluetoothMapAppParams();
        try {
            int paramMask = (MASK_SUBJECT | MASK_DATETIME | MASK_SENDER_NAME | MASK_SENDER_ADDRESSING
                    | MASK_RECIPIENT_NAME | MASK_RECIPIENT_ADDRESSING | MASK_TYPE | MASK_SIZE
                    | MASK_RECEPTION_STATUS | MASK_TEXT | MASK_ATTACHMENT_SIZE | MASK_PRIORITY | MASK_READ
                    | MASK_SENT | MASK_PROTECTED);
            ap.setMaxListCount(5);
            ap.setStartOffset(0);
            ap.setFilterMessageType(0);
            ap.setFilterPeriodBegin("20130101T000000");
            ap.setFilterPeriodEnd("20131230T000000");
            ap.setFilterReadStatus(0);
            ap.setParameterMask(paramMask);
            ap.setSubjectLength(10);
            /* ap.setFilterOriginator("Sms*"); */
            /* ap.setFilterRecipient("41*"); */
        } catch (ParseException e) {
            return null;
        }
        return ap;
    }

    private void printSms(Cursor c) {
        String body = c.getString(c.getColumnIndex(Sms.BODY));
        if (D)
            Log.d(TAG,
                    "printSms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) + " "
                            + Sms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Sms.THREAD_ID)) + " " + Sms.ADDRESS
                            + " : " + c.getString(c.getColumnIndex(Sms.ADDRESS)) + " " + Sms.BODY + " : "
                            + body.substring(0, Math.min(body.length(), 8)) + " " + Sms.DATE + " : "
                            + c.getLong(c.getColumnIndex(Sms.DATE)) + " " + Sms.TYPE + " : "
                            + c.getInt(c.getColumnIndex(Sms.TYPE)));
    }

    private void printMms(Cursor c) {
        if (D)
            Log.d(TAG,
                    "printMms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) + "\n   "
                            + Mms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Mms.THREAD_ID)) + "\n   "
                            + Mms.MESSAGE_ID + " : " + c.getString(c.getColumnIndex(Mms.MESSAGE_ID)) + "\n   "
                            + Mms.SUBJECT + " : " + c.getString(c.getColumnIndex(Mms.SUBJECT)) + "\n   "
                            + Mms.CONTENT_TYPE + " : " + c.getString(c.getColumnIndex(Mms.CONTENT_TYPE)) + "\n   "
                            + Mms.TEXT_ONLY + " : " + c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) + "\n   " + Mms.DATE
                            + " : " + c.getLong(c.getColumnIndex(Mms.DATE)) + "\n   " + Mms.DATE_SENT + " : "
                            + c.getLong(c.getColumnIndex(Mms.DATE_SENT)) + "\n   " + Mms.READ + " : "
                            + c.getInt(c.getColumnIndex(Mms.READ)) + "\n   " + Mms.MESSAGE_BOX + " : "
                            + c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)) + "\n   " + Mms.STATUS + " : "
                            + c.getInt(c.getColumnIndex(Mms.STATUS)) + "\n   " + Mms.MESSAGE_TYPE + " : "
                            + c.getInt(c.getColumnIndex(Mms.MESSAGE_TYPE)));
    }

    private void printMmsAddr(long id) {
        final String[] projection = null;
        String selection = new String("msg_id=" + id);
        String uriStr = String.format("content://mms/%d/addr", id);
        Uri uriAddress = Uri.parse(uriStr);
        Cursor c = mResolver.query(uriAddress, projection, selection, null, null);

        if (c != null && c.moveToFirst()) {
            do {
                String add = c.getString(c.getColumnIndex("address"));
                Integer type = c.getInt(c.getColumnIndex("type"));
                if (type == MMS_TO) {
                    if (D)
                        Log.d(TAG, "   recipient: " + add + " (type: " + type + ")");
                } else if (type == MMS_FROM) {
                    if (D)
                        Log.d(TAG, "   originator: " + add + " (type: " + type + ")");
                } else {
                    if (D)
                        Log.d(TAG, "   address other: " + add + " (type: " + type + ")");
                }

            } while (c.moveToNext());
            c.close();
        }
    }

    private void printMmsPartImage(long partid) {
        String uriStr = String.format("content://mms/part/%d", partid);
        Uri uriAddress = Uri.parse(uriStr);
        int ch;
        StringBuffer sb = new StringBuffer("");
        InputStream is = null;

        try {
            is = mResolver.openInputStream(uriAddress);

            while ((ch = is.read()) != -1) {
                sb.append((char) ch);
            }
            if (D)
                Log.d(TAG, sb.toString());

        } catch (IOException e) {
            // do nothing for now
            e.printStackTrace();
        }
    }

    private static void close(Closeable c) {
        try {
            if (c != null)
                c.close();
        } catch (IOException e) {
        }
    }

    private void printMmsParts(long id) {
        final String[] projection = null;
        String selection = new String("mid=" + id);
        String uriStr = String.format("content://mms/%d/part", id);
        Uri uriAddress = Uri.parse(uriStr);
        Cursor c = mResolver.query(uriAddress, projection, selection, null, null);

        if (D)
            Log.d(TAG, "   parts:");
        if (c != null && c.moveToFirst()) {
            do {
                Long partid = c.getLong(c.getColumnIndex(BaseColumns._ID));
                String ct = c.getString(c.getColumnIndex("ct"));
                String name = c.getString(c.getColumnIndex("name"));
                String charset = c.getString(c.getColumnIndex("chset"));
                String filename = c.getString(c.getColumnIndex("fn"));
                String text = c.getString(c.getColumnIndex("text"));
                Integer fd = c.getInt(c.getColumnIndex("_data"));
                String cid = c.getString(c.getColumnIndex("cid"));
                String cl = c.getString(c.getColumnIndex("cl"));
                String cdisp = c.getString(c.getColumnIndex("cd"));

                if (D)
                    Log.d(TAG,
                            "     _id : " + partid + "\n     ct : " + ct + "\n     partname : " + name
                                    + "\n     charset : " + charset + "\n     filename : " + filename
                                    + "\n     text : " + text + "\n     fd : " + fd + "\n     cid : " + cid
                                    + "\n     cl : " + cl + "\n     cdisp : " + cdisp);

                /* if (ct.equals("image/jpeg")) { */
                /*     printMmsPartImage(partid); */
                /* } */
            } while (c.moveToNext());
            c.close();
        }
    }

    public void dumpMmsTable() {
        if (D)
            Log.d(TAG, "**** Dump of mms table ****");
        Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, null, null, "_id DESC");
        if (c != null) {
            if (D)
                Log.d(TAG, "c.getCount() = " + c.getCount());
            c.moveToPosition(-1);
            while (c.moveToNext()) {
                printMms(c);
                long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                printMmsAddr(id);
                printMmsParts(id);
            }
            c.close();
        } else {
            Log.d(TAG, "query failed");
        }
    }

    public void dumpSmsTable() {
        addSmsEntry();
        if (D)
            Log.d(TAG, "**** Dump of sms table ****");
        Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, null, null, "_id DESC");
        if (c != null) {
            if (D)
                Log.d(TAG, "c.getCount() = " + c.getCount());
            c.moveToPosition(-1);
            while (c.moveToNext()) {
                printSms(c);
            }
            c.close();
        } else {
            Log.d(TAG, "query failed");
        }

    }

    /**
     * Get SMS RecipientAddresses for DRAFT folder based on threadId
     *
    */
    private String getMessageSmsRecipientAddress(int threadId) {
        String[] RECIPIENT_ID_PROJECTION = { "recipient_ids" };
        /*
         1. Get Recipient Ids from Threads.CONTENT_URI
         2. Get Recipient Address for corresponding Id from canonical-addresses table.
        */

        Uri sAllCanonical = Uri.parse("content://mms-sms/canonical-addresses");
        Uri sAllThreadsUri = Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
        Cursor cr = null;
        String recipientAddress = "";
        String recipientIds = null;
        String whereClause = "_id=" + threadId;
        if (V)
            Log.v(TAG, "whereClause is " + whereClause);
        cr = mContext.getContentResolver().query(sAllThreadsUri, RECIPIENT_ID_PROJECTION, whereClause, null, null);
        if (cr != null && cr.moveToFirst()) {
            recipientIds = cr.getString(0);
            if (V)
                Log.v(TAG, "cursor.getCount(): " + cr.getCount() + "recipientIds: " + recipientIds + "whrClus: "
                        + whereClause);
        }
        if (cr != null) {
            cr.close();
            cr = null;
        }

        if (V)
            Log.v(TAG, "recipientIds with spaces: " + recipientIds + "\n");

        if (recipientIds != null) {
            String recipients[] = null;
            whereClause = "";
            recipients = recipientIds.split(" ");
            for (String id : recipients) {
                if (whereClause.length() != 0)
                    whereClause += " OR ";
                whereClause += "_id=" + id;
            }
            if (V)
                Log.v(TAG, "whereClause is " + whereClause);
            cr = mContext.getContentResolver().query(sAllCanonical, null, whereClause, null, null);
            if (cr != null && cr.moveToFirst()) {
                do {
                    //TODO: Multiple Recipeints are appended with ";" for now.
                    if (recipientAddress.length() != 0)
                        recipientAddress += ";";
                    recipientAddress += cr.getString(cr.getColumnIndex("address"));
                } while (cr.moveToNext());
            }
            if (cr != null)
                cr.close();

        }

        if (V)
            Log.v(TAG, "Final recipientAddress : " + recipientAddress);
        return recipientAddress;

    }

    public void dumpMessages() {
        dumpSmsTable();
        dumpMmsTable();

        BluetoothMapAppParams ap = buildAppParams();
        if (ap != null) {
            if (D)
                Log.d(TAG, "message listing size = " + msgListingSize("inbox", ap));
            BluetoothMapMessageListing mList = msgListing("inbox", ap);
            try {
                mList.encode();
            } catch (UnsupportedEncodingException ex) {
                /* do nothing */
            }
            mList = msgListing("sent", ap);
            try {
                mList.encode();
            } catch (UnsupportedEncodingException ex) {
                /* do nothing */
            }
        } else {
            if (D)
                Log.d(TAG, "dumPMessage AppParams not available ");
        }
    }

    public static String decodeEncodedWord(String checkEncoded) {
        if (checkEncoded == null) {
            if (V)
                Log.v(TAG, " Decode Invalid Input");
            return null;
        }
        if (checkEncoded != null && (checkEncoded.contains("=?") == false)) {
            if (V)
                Log.v(TAG, " Decode NotRequired" + checkEncoded);
            return checkEncoded;
        }

        int begin = checkEncoded.indexOf("=?", 0);

        int endScan = begin + 2;
        if (begin != -1) {
            int qm1 = checkEncoded.indexOf('?', endScan + 2);
            int qm2 = checkEncoded.indexOf('?', qm1 + 1);
            if (qm2 != -1) {
                endScan = qm2 + 1;
            }
        }

        int end = begin == -1 ? -1 : checkEncoded.indexOf("?=", endScan);
        if (end == -1)
            return checkEncoded;
        checkEncoded = checkEncoded.substring((endScan - 1), (end + 1));

        // TODO: Handle encoded words as defined by MIME standard RFC 2047
        // Encoded words will have the form =?charset?enc?Encoded word?= where
        // enc is either 'Q' or 'q' for quoted-printable and 'B' or 'b' for Base64
        QuotedPrintableCodec qpDecode = new QuotedPrintableCodec("UTF-8");
        String decoded = null;
        try {
            decoded = qpDecode.decode(checkEncoded);
        } catch (DecoderException e) {
            if (V)
                Log.v(TAG, "decode exception");
            return checkEncoded;
        }
        if (decoded == null) {
            return checkEncoded;
        }
        return decoded;
    }

    private void setProtected(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_PROTECTED) != 0) {
            String protect = "no";
            if (D)
                Log.d(TAG, "setProtected: " + protect);
            e.setProtect(protect);
        }
    }

    private void setSent(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        String sent = null;
        if ((ap.getParameterMask() & MASK_SENT) != 0) {
            int msgType = 0;
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                msgType = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
            } else {
                msgType = c.getInt(c.getColumnIndex(MessageColumns.MAILBOX_KEY));
                if (msgType == 4) {
                    sent = "yes";
                } else {
                    sent = "no";
                }
                if (D)
                    Log.d(TAG, "setSent: " + sent);
                e.setSent(sent);
                return;
            }
            if (msgType == 2) {
                sent = "yes";
            } else {
                sent = "no";
            }
            if (D)
                Log.d(TAG, "setSent: " + sent);
            e.setSent(sent);
        }
    }

    private void setRead(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        int read = 0;
        if (fi.msgType == FilterInfo.TYPE_SMS) {
            read = c.getInt(c.getColumnIndex(Sms.READ));
        } else if (fi.msgType == FilterInfo.TYPE_MMS) {
            read = c.getInt(c.getColumnIndex(Mms.READ));
        } else {
            read = c.getInt(c.getColumnIndex(MessageColumns.FLAG_READ));
        }
        String setread = null;
        if (read == 1) {
            setread = "yes";
        } else {
            setread = "no";
        }
        if (D)
            Log.d(TAG, "setRead: " + setread);
        e.setRead(setread, ((ap.getParameterMask() & MASK_READ) != 0));
    }

    private void setPriority(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        String priority = "no";
        if ((ap.getParameterMask() & MASK_PRIORITY) != 0) {
            int pri = 0;
            if (fi.msgType == FilterInfo.TYPE_MMS) {
                pri = c.getInt(c.getColumnIndex(Mms.PRIORITY));
            }
            if (pri == PduHeaders.PRIORITY_HIGH) {
                priority = "yes";
            }
            if (D)
                Log.d(TAG, "setPriority: " + priority);
            e.setPriority(priority);
        }
    }

    /**
     * For SMS we set the attachment size to 0, as all data will be text data, hence
     * attachments for SMS is not possible.
     * For MMS all data is actually attachments, hence we do set the attachment size to
     * the total message size. To provide a more accurate attachment size, one could
     * extract the length (in bytes) of the text parts.
     */
    private void setAttachmentSize(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_ATTACHMENT_SIZE) != 0) {
            int size = 0;
            if (fi.msgType == FilterInfo.TYPE_MMS) {
                size = c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE));
            } else if (fi.msgType == FilterInfo.TYPE_EMAIL) {
                Uri uri = Uri.parse("content://com.android.email.provider/attachment");
                long msgId = Long.valueOf(c.getString(c.getColumnIndex("_id")));
                String where = setWhereFilterMessagekey(msgId);
                Cursor cr = mResolver.query(uri, new String[] { "size" }, where, null, null);
                if (cr != null && cr.moveToFirst()) {
                    do {
                        size += cr.getInt(0);
                    } while (cr.moveToNext());
                }
                if (cr != null) {
                    cr.close();
                }
            }
            if (D)
                Log.d(TAG, "setAttachmentSize: " + size);
            e.setAttachmentSize(size);
        }
    }

    private void setText(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_TEXT) != 0) {
            String hasText = "";
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                hasText = "yes";
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                int textOnly = c.getInt(c.getColumnIndex(Mms.TEXT_ONLY));
                if (textOnly == 1) {
                    hasText = "yes";
                } else {
                    long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                    String text = getTextPartsMms(id);
                    if (text != null && text.length() > 0) {
                        hasText = "yes";
                    } else {
                        hasText = "no";
                    }
                }
            } else {
                hasText = "yes";
            }
            if (D)
                Log.d(TAG, "setText: " + hasText);
            e.setText(hasText);
        }
    }

    private void setReceptionStatus(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_RECEPTION_STATUS) != 0) {
            String status = "complete";
            if (D)
                Log.d(TAG, "setReceptionStatus: " + status);
            e.setReceptionStatus(status);
        }
    }

    private void setSize(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_SIZE) != 0) {
            int size = 0;
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                String subject = c.getString(c.getColumnIndex(Sms.BODY));
                size = subject.length();
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                size = c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE));
            } else if (fi.msgType == FilterInfo.TYPE_EMAIL) {
                long msgId = Long.valueOf(c.getString(c.getColumnIndex("_id")));
                String textContent, htmlContent;
                Uri uriAddress = Uri.parse("content://com.android.email.provider/body");
                Cursor cr = mResolver.query(uriAddress, Body.CONTENT_PROJECTION, BodyColumns.MESSAGE_KEY + "=?",
                        new String[] { String.valueOf(msgId) }, null);
                if (cr != null && cr.moveToFirst()) {
                    ParcelFileDescriptor fd = null;
                    String textContentURI = cr.getString(cr.getColumnIndex(BodyColumns.TEXT_CONTENT_URI));
                    if (textContentURI != null) {
                        try {
                            Log.v(TAG, " TRY EMAIL BODY textURI " + textContentURI);
                            fd = mResolver.openFileDescriptor(Uri.parse(textContentURI), "r");
                        } catch (FileNotFoundException ex) {
                            if (V)
                                Log.w(TAG, ex);
                        }
                    }
                    if (fd == null) {
                        String htmlContentURI = cr.getString(cr.getColumnIndex(BodyColumns.HTML_CONTENT_URI));
                        if (htmlContentURI != null) {
                            try {
                                Log.v(TAG, " TRY EMAIL BODY htmlURI " + htmlContentURI);
                                fd = mResolver.openFileDescriptor(Uri.parse(htmlContentURI), "r");
                            } catch (FileNotFoundException ex) {
                                if (V)
                                    Log.w(TAG, ex);
                            }
                        }
                    }
                    if (fd != null) {
                        //Size in bytes
                        size = (Long.valueOf(fd.getStatSize()).intValue());
                        try {
                            fd.close();
                        } catch (IOException ex) {
                            if (V)
                                Log.w(TAG, ex);
                        }

                    } else {
                        Log.e(TAG, "MessageSize Email NOT AVAILABLE");
                    }
                    cr.close();
                }
            }
            if (D)
                Log.d(TAG, "setSize: " + size);
            e.setSize(size);
        }
    }

    private void setType(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_TYPE) != 0) {
            TYPE type = null;
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                if (fi.phoneType == TelephonyManager.PHONE_TYPE_GSM) {
                    type = TYPE.SMS_GSM;
                } else if (fi.phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
                    type = TYPE.SMS_CDMA;
                }
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                type = TYPE.MMS;
            } else {
                type = TYPE.EMAIL;
            }
            if (D)
                Log.d(TAG, "setType: " + type);
            e.setType(type);
        }
    }

    private void setRecipientAddressing(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_RECIPIENT_ADDRESSING) != 0) {
            String address = "";
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
                if (msgType == 1) {
                    address = fi.phoneNum;
                } else {
                    address = c.getString(c.getColumnIndex(Sms.ADDRESS));
                }
                if ((address == null) && msgListingFolder.equalsIgnoreCase("draft")) {
                    int threadIdInd = c.getColumnIndex("thread_id");
                    String threadIdStr = c.getString(threadIdInd);
                    address = getMessageSmsRecipientAddress(Integer.valueOf(threadIdStr));
                    if (V)
                        Log.v(TAG, "threadId = " + threadIdStr + " adress:" + address + "\n");
                }
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                address = getAddressMms(mResolver, id, MMS_TO);
            } else {
                int toIndex = c.getColumnIndex(MessageColumns.TO_LIST);
                address = c.getString(toIndex);
                if (address != null && address.contains("")) {
                    String[] recepientAddrStr = address.split("");
                    if (recepientAddrStr != null && recepientAddrStr.length > 0) {
                        if (V) {
                            Log.v(TAG, " ::Recepient addressing split String 0:: " + recepientAddrStr[0]
                                    + "::Recepient addressing split String 1:: " + recepientAddrStr[1]);
                        }
                        e.setRecipientAddressing(recepientAddrStr[0].trim());
                    }
                } else {
                    if (D)
                        Log.d(TAG, "setRecipientAddressing: " + address);
                    e.setRecipientAddressing(address);
                }
                return;
            }
            if (D)
                Log.d(TAG, "setRecipientAddressing: " + address);
            e.setRecipientAddressing(address);
        }
    }

    private void setRecipientName(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_RECIPIENT_NAME) != 0) {
            String name = "";
            String firstRecipient = null;
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
                if (msgType != 1) {
                    String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
                    name = getContactNameFromPhone(phone);
                } else {
                    name = fi.phoneAlphaTag;
                }
                if ((name == null) && msgListingFolder.equalsIgnoreCase("draft")) {
                    int threadIdInd = c.getColumnIndex("thread_id");
                    String threadIdStr = c.getString(threadIdInd);
                    firstRecipient = getMessageSmsRecipientAddress(Integer.valueOf(threadIdStr));
                    if (V)
                        Log.v(TAG, "threadId = " + threadIdStr + " address:" + firstRecipient + "\n");
                    if (firstRecipient != null) {
                        // Get first Recipient Name for multiple recipient addressing
                        if (firstRecipient.contains(";")) {
                            firstRecipient = firstRecipient.split(";")[0];
                        } else if (firstRecipient.contains(",")) {
                            firstRecipient = firstRecipient.split(",")[0];
                        }
                        name = getContactNameFromPhone(firstRecipient);
                    }
                }

            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                String phone = getAddressMms(mResolver, id, MMS_TO);
                name = getContactNameFromPhone(phone);
            } else {
                int toIndex = c.getColumnIndex(MessageColumns.TO_LIST);
                if (D)
                    Log.d(TAG, "setRecipientName: " + c.getString(toIndex));
                name = c.getString(toIndex);
            }
            if (D)
                Log.d(TAG, "setRecipientName: " + name);
            e.setRecipientName(name);
        }
    }

    private void setReplytoAddressing(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_REPLYTO_ADDRESSING) != 0) {
            String address = null;
            if (fi.msgType == FilterInfo.TYPE_EMAIL) {
                int replyToInd = c.getColumnIndex(MessageColumns.REPLY_TO_LIST);
                if (D)
                    Log.d(TAG, "setReplytoAddressing: " + c.getString(replyToInd));
                address = c.getString(replyToInd);
                if (address == null)
                    address = "";
            }
            if (D)
                Log.d(TAG, "setReplytoAddressing: " + address);
            e.setReplytoAddressing(address);
        }
    }

    private void setSenderAddressing(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_SENDER_ADDRESSING) != 0) {
            String address = null;
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
                if (msgType == 1) {
                    address = c.getString(c.getColumnIndex(Sms.ADDRESS));
                } else {
                    address = fi.phoneNum;
                }
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                address = getAddressMms(mResolver, id, MMS_FROM);
            } else {
                int fromIndex = c.getColumnIndex(MessageColumns.FROM_LIST);
                address = c.getString(fromIndex);
                if (address != null) {
                    if (address.contains("")) {
                        String[] senderAddrStr = address.split("");
                        if (senderAddrStr != null && senderAddrStr.length > 0) {
                            if (V) {
                                Log.v(TAG, " ::Sender Addressing split String 0:: " + senderAddrStr[0]
                                        + "::Sender Addressing split String 1:: " + senderAddrStr[1]);
                            }
                            e.setEmailSenderAddressing(senderAddrStr[0].trim());
                        }
                    } else {
                        if (address.indexOf('<') != -1 && address.indexOf('>') != -1) {
                            if (D)
                                Log.d(TAG, "setSenderAddressing: "
                                        + address.substring(address.indexOf('<') + 1, address.lastIndexOf('>')));
                            e.setEmailSenderAddressing(
                                    address.substring(address.indexOf('<') + 1, address.lastIndexOf('>')));
                        } else {
                            if (D)
                                Log.d(TAG, "setSenderAddressing: " + address);
                            e.setEmailSenderAddressing(address);
                        }
                    }
                }
                return;
            }
            if (D)
                Log.d(TAG, "setSenderAddressing: " + address);
            e.setSenderAddressing(address);
        }
    }

    private void setSenderName(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_SENDER_NAME) != 0) {
            String name = "";
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
                if (msgType == 1) {
                    String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
                    name = getContactNameFromPhone(phone);
                } else {
                    name = fi.phoneAlphaTag;
                }
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                String phone = getAddressMms(mResolver, id, MMS_FROM);
                name = getContactNameFromPhone(phone);
            } else { //email case
                int displayNameIndex = c.getColumnIndex(MessageColumns.DISPLAY_NAME);
                if (D)
                    Log.d(TAG, "setSenderName: " + c.getString(displayNameIndex));
                name = c.getString(displayNameIndex);
                if (name != null && name.contains("")) {
                    String[] senderStr = name.split("");
                    if (senderStr != null && senderStr.length > 0) {
                        if (V) {
                            Log.v(TAG, " ::Sender name split String 0:: " + senderStr[0]
                                    + "::Sender name split String 1:: " + senderStr[1]);
                        }
                        name = senderStr[1];
                    }
                }
                if (name != null) {
                    name = decodeEncodedWord(name);
                    name = name.trim();
                }

            }
            if (D)
                Log.d(TAG, "setSenderName: " + name);
            e.setSenderName(name);
        }
    }

    private void setDateTime(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        if ((ap.getParameterMask() & MASK_DATETIME) != 0) {
            long date = 0;
            int timeStamp = 0;

            if (fi.msgType == FilterInfo.TYPE_SMS) {
                date = c.getLong(c.getColumnIndex(Sms.DATE));
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                /* Use Mms.DATE for all messages. Although contract class states */
                /* Mms.DATE_SENT are for outgoing messages. But that is not working. */
                date = c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L;

                /* int msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)); */
                /* if (msgBox == Mms.MESSAGE_BOX_INBOX) { */
                /*     date = c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L; */
                /* } else { */
                /*     date = c.getLong(c.getColumnIndex(Mms.DATE_SENT)) * 1000L; */
                /* } */
            } else {
                timeStamp = c.getColumnIndex(MessageColumns.TIMESTAMP);
                String timestamp = c.getString(timeStamp);
                date = Long.valueOf(timestamp);
            }
            e.setDateTime(date);
        }
    }

    private String getTextPartsMms(long id) {
        String text = "";
        String selection = new String("mid=" + id);
        String uriStr = String.format("content://mms/%d/part", id);
        Uri uriAddress = Uri.parse(uriStr);
        Cursor c = mResolver.query(uriAddress, null, selection, null, null);
        // TODO: maybe use a projection with only "ct" and "text"
        if (c != null && c.moveToFirst()) {
            do {
                String ct = c.getString(c.getColumnIndex("ct"));
                if (ct.equals("text/plain")) {
                    text += c.getString(c.getColumnIndex("text"));
                }
            } while (c.moveToNext());
        }
        if (c != null) {
            c.close();
        }
        return text;
    }

    private String getTextPartsEmail(long id) {
        String text = "";
        String selection = new String("mid=" + id);
        String uriStr = String.format("content://mms/%d/part", id);
        Uri uriAddress = Uri.parse(uriStr);
        Cursor c = mResolver.query(uriAddress, null, selection, null, null);

        if (c != null && c.moveToFirst()) {
            do {
                String ct = c.getString(c.getColumnIndex("ct"));
                if (ct.equals("text/plain")) {
                    text += c.getString(c.getColumnIndex("text"));
                }
            } while (c.moveToNext());
        }
        if (c != null) {
            c.close();
        }
        return text;
    }

    private void setSubject(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi,
            BluetoothMapAppParams ap) {
        String subject = "";
        int subLength = ap.getSubjectLength();
        if (subLength == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
            subLength = 256;

        if (BluetoothMapService.getRemoteDevice().getAddress().startsWith(HONDA_CARKIT)
                || (ap.getParameterMask() & MASK_SUBJECT) != 0) {
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                subject = c.getString(c.getColumnIndex(Sms.BODY));
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                subject = c.getString(c.getColumnIndex(Mms.SUBJECT));
                if (subject == null || subject.length() == 0) {
                    /* Get subject from mms text body parts - if any exists */
                    long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                    subject = getTextPartsMms(id);
                }
            } else {
                subject = c.getString(c.getColumnIndex(MessageColumns.SUBJECT));
                if (subject == null || subject.length() == 0) {
                    /* Get subject from mms text body parts - if any exists */
                    long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
                    subject = getTextPartsEmail(id);
                }
            }
            if (subject != null) {
                subject = subject.substring(0, Math.min(subject.length(), subLength));
            }
            if (D)
                Log.d(TAG, "setSubject: " + subject);
            e.setSubject(subject);
        }
    }

    private void setHandle(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        long handle = c.getLong(c.getColumnIndex(BaseColumns._ID));
        TYPE type = null;
        if (fi.msgType == FilterInfo.TYPE_SMS) {
            if (fi.phoneType == TelephonyManager.PHONE_TYPE_GSM) {
                type = TYPE.SMS_GSM;
            } else if (fi.phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
                type = TYPE.SMS_CDMA;
            }
        } else if (fi.msgType == FilterInfo.TYPE_MMS) {
            type = TYPE.MMS;
        } else {
            type = TYPE.EMAIL;
        }
        if (D && type != null)
            Log.d(TAG, "setHandle: " + handle + " - Type: " + type.name());
        e.setHandle(handle, type);
    }

    private BluetoothMapMessageListingElement element(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        BluetoothMapMessageListingElement e = new BluetoothMapMessageListingElement();

        setHandle(e, c, fi, ap);
        setSubject(e, c, fi, ap);
        setDateTime(e, c, fi, ap);
        setSenderName(e, c, fi, ap);
        setSenderAddressing(e, c, fi, ap);
        setReplytoAddressing(e, c, fi, ap);
        setRecipientName(e, c, fi, ap);
        setRecipientAddressing(e, c, fi, ap);
        setType(e, c, fi, ap);
        setSize(e, c, fi, ap);
        setReceptionStatus(e, c, fi, ap);
        setText(e, c, fi, ap);
        setAttachmentSize(e, c, fi, ap);
        setPriority(e, c, fi, ap);
        setRead(e, c, fi, ap);
        setSent(e, c, fi, ap);
        setProtected(e, c, fi, ap);
        return e;
    }

    private String getContactNameFromPhone(String phone) {
        String name = "";
        if (TextUtils.isEmpty(phone)) {
            return name;
        }
        Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));

        String[] projection = { Contacts._ID, Contacts.DISPLAY_NAME };
        String selection = Contacts.IN_VISIBLE_GROUP + "=1";
        String orderBy = Contacts.DISPLAY_NAME + " ASC";

        Cursor c = mResolver.query(uri, projection, selection, null, orderBy);
        try {
            if (c != null && c.getCount() >= 1) {
                c.moveToFirst();
                name = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME));
            }
            ;
        } finally {
            close(c);
        }
        return name;
    }

    static public String getAddressMms(ContentResolver r, long id, int type) {
        String selection = new String("msg_id=" + id + " AND type=" + type);
        String uriStr = String.format("content://mms/%d/addr", id);
        Uri uriAddress = Uri.parse(uriStr);
        String addr = null;

        Cursor c = r.query(uriAddress, null, selection, null, null);
        try {
            if (c != null && c.moveToFirst()) {
                addr = c.getString(c.getColumnIndex(Mms.Addr.ADDRESS));
            }
        } finally {
            close(c);
        }

        return addr;
    }

    private boolean matchRecipientEmail(Cursor c, FilterInfo fi, String recip) {
        boolean res = false;
        String name = null;
        int toIndex = c.getColumnIndex("toList");
        name = c.getString(toIndex);

        if (name != null && name.length() > 0) {
            if (name.matches(recip)) {
                if (D)
                    Log.d(TAG, "match recipient name = " + name);
                res = true;
            } else {
                res = false;
            }
        }
        return res;
    }

    private boolean matchRecipientMms(Cursor c, FilterInfo fi, String recip) {
        boolean res;
        long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
        String phone = getAddressMms(mResolver, id, MMS_TO);
        if (phone != null && phone.length() > 0) {
            if (phone.matches(recip)) {
                if (D)
                    Log.d(TAG, "match recipient phone = " + phone);
                res = true;
            } else {
                String name = getContactNameFromPhone(phone);
                if (name != null && name.length() > 0 && name.matches(recip)) {
                    if (D)
                        Log.d(TAG, "match recipient name = " + name);
                    res = true;
                } else {
                    res = false;
                }
            }
        } else {
            res = false;
        }
        return res;
    }

    private boolean matchRecipientSms(Cursor c, FilterInfo fi, String recip) {
        boolean res;
        int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
        if (msgType == 1) {
            String phone = fi.phoneNum;
            String name = fi.phoneAlphaTag;
            if (phone != null && phone.length() > 0 && phone.replaceAll("\\s", "").matches(recip)) {
                if (D)
                    Log.d(TAG, "match recipient phone = " + phone);
                res = true;
            } else if (name != null && name.length() > 0 && name.matches(recip)) {
                if (D)
                    Log.d(TAG, "match recipient name = " + name);
                res = true;
            } else {
                res = false;
            }
        } else {
            String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
            if (phone != null && phone.length() > 0) {
                if (phone.replaceAll("\\s", "").matches(recip)) {
                    if (D)
                        Log.d(TAG, "match recipient phone = " + phone);
                    res = true;
                } else {
                    String name = getContactNameFromPhone(phone);
                    if (name != null && name.length() > 0 && name.matches(recip)) {
                        if (D)
                            Log.d(TAG, "match recipient name = " + name);
                        res = true;
                    } else {
                        res = false;
                    }
                }
            } else {
                res = false;
            }
        }
        return res;
    }

    private boolean matchRecipient(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        boolean res;
        String recip = ap.getFilterRecipient();
        if (recip != null && recip.length() > 0) {
            recip = recip.replace("*", ".*");
            recip = ".*" + recip + ".*";
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                res = matchRecipientSms(c, fi, recip);
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                res = matchRecipientMms(c, fi, recip);
            } else if (fi.msgType == FilterInfo.TYPE_EMAIL) {
                res = matchRecipientEmail(c, fi, recip);
            } else {
                if (D)
                    Log.d(TAG, "Unknown msg type: " + fi.msgType);
                res = false;
            }
        } else {
            res = true;
        }
        return res;
    }

    private boolean matchOriginatorEmail(Cursor c, FilterInfo fi, String orig) {
        boolean res = false;
        String name;
        String originatorEmail;
        int displayNameIndex = c.getColumnIndex("displayName");
        name = c.getString(displayNameIndex);
        originatorEmail = c.getString(c.getColumnIndex(MessageColumns.FROM_LIST));
        if (name != null && name.length() > 0) {
            if (name.toLowerCase().matches(orig.toLowerCase())) {
                if (D)
                    Log.d(TAG, "match originator name = " + name);
                res = true;
            }
        }
        if (originatorEmail != null && originatorEmail.length() > 0) {
            if (originatorEmail.toLowerCase().matches(orig.toLowerCase())) {
                if (D)
                    Log.d(TAG, "match originator email = " + originatorEmail);
                res = true;
            }
        }
        return res;
    }

    private boolean matchOriginatorMms(Cursor c, FilterInfo fi, String orig) {
        boolean res;
        long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
        String phone = getAddressMms(mResolver, id, MMS_FROM);
        if (phone != null && phone.length() > 0) {
            if (phone.matches(orig)) {
                if (D)
                    Log.d(TAG, "match originator phone = " + phone);
                res = true;
            } else {
                String name = getContactNameFromPhone(phone);
                if (name != null && name.length() > 0 && name.matches(orig)) {
                    if (D)
                        Log.d(TAG, "match originator name = " + name);
                    res = true;
                } else {
                    res = false;
                }
            }
        } else {
            res = false;
        }
        return res;
    }

    private boolean matchOriginatorSms(Cursor c, FilterInfo fi, String orig) {
        boolean res;
        int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
        if (msgType == 1) {
            String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
            if (phone != null && phone.length() > 0) {
                if (phone.replaceAll("\\s", "").matches(orig)) {
                    if (D)
                        Log.d(TAG, "match originator phone = " + phone);
                    res = true;
                } else {
                    String name = getContactNameFromPhone(phone);
                    if (name != null && name.length() > 0 && name.matches(orig)) {
                        if (D)
                            Log.d(TAG, "match originator name = " + name);
                        res = true;
                    } else {
                        res = false;
                    }
                }
            } else {
                res = false;
            }
        } else {
            String phone = fi.phoneNum;
            String name = fi.phoneAlphaTag;
            if (phone != null && phone.length() > 0 && phone.replaceAll("\\s", "").matches(orig)) {
                if (D)
                    Log.d(TAG, "match originator phone = " + phone);
                res = true;
            } else if (name != null && name.length() > 0 && name.matches(orig)) {
                if (D)
                    Log.d(TAG, "match originator name = " + name);
                res = true;
            } else {
                res = false;
            }
        }
        return res;
    }

    private boolean matchOriginator(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        boolean res;
        String orig = ap.getFilterOriginator();
        if (orig != null && orig.length() > 0) {
            orig = orig.replace("*", ".*");
            orig = ".*" + orig + ".*";
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                res = matchOriginatorSms(c, fi, orig);
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                res = matchOriginatorMms(c, fi, orig);
            } else if (fi.msgType == FilterInfo.TYPE_EMAIL) {
                res = matchOriginatorEmail(c, fi, orig);
            } else {
                Log.d(TAG, "Unknown msg type: " + fi.msgType);
                res = false;
            }
        } else {
            res = true;
        }
        return res;
    }

    private boolean matchAddresses(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
        if (matchOriginator(c, fi, ap) && matchRecipient(c, fi, ap)) {
            return true;
        } else {
            return false;
        }
    }

    private String getQueryWithMailBoxKey(String folder, long id) {
        Log.d(TAG, "Inside getQueryWithMailBoxKey ");
        String query = "mailboxKey = -1";
        ;
        String folderId;
        Uri uri = Uri.parse("content://com.android.email.provider/mailbox");
        if (folder == null) {
            return null;
        }
        if (folder.contains("'")) {
            folder = folder.replace("'", "''");
        }
        Cursor cr = mResolver.query(uri, null,
                "(" + ACCOUNT_KEY + "=" + id + ") AND (UPPER(displayName) = '" + folder.toUpperCase() + "')", null,
                null);
        if (cr != null) {
            if (cr.moveToFirst()) {
                do {
                    folderId = cr.getString(cr.getColumnIndex("_id"));
                    query = "mailboxKey = " + folderId;
                    break;
                } while (cr.moveToNext());
            }
            cr.close();
        }
        if (D)
            Log.d(TAG, "Returning  " + query);
        return query;
    }

    private String setWhereFilterFolderTypeEmail(String folder) {
        String where = "";
        Log.d(TAG, "Inside setWhereFilterFolderTypeEmail ");
        Log.d(TAG, "folder is  " + folder);
        where = getQueryWithMailBoxKey(folder, BluetoothMapUtils.getEmailAccountId(mContext)/*1*/);
        if (D)
            Log.d(TAG, "where query is  " + where);
        return where;
    }

    private String setWhereFilterFolderTypeSms(String folder) {
        String where = "";
        if ("inbox".equalsIgnoreCase(folder)) {
            where = "type = 1 AND thread_id <> -1";
        } else if ("outbox".equalsIgnoreCase(folder)) {
            where = "(type = 4 OR type = 5 OR type = 6) AND thread_id <> -1";
        } else if ("sent".equalsIgnoreCase(folder)) {
            where = "type = 2 AND thread_id <> -1";
        } else if ("draft".equalsIgnoreCase(folder)) {
            where = "type = 3 AND thread_id <> -1";
        } else if ("deleted".equalsIgnoreCase(folder)) {
            where = "thread_id = -1";
        }

        return where;
    }

    private String setWhereFilterFolderTypeMms(String folder) {
        String where = "";
        if ("inbox".equalsIgnoreCase(folder)) {
            where = "msg_box = 1 AND thread_id <> -1";
        } else if ("outbox".equalsIgnoreCase(folder)) {
            where = "msg_box = 4 AND thread_id <> -1";
        } else if ("sent".equalsIgnoreCase(folder)) {
            where = "msg_box = 2 AND thread_id <> -1";
        } else if ("draft".equalsIgnoreCase(folder)) {
            where = "msg_box = 3 AND thread_id <> -1";
        } else if ("deleted".equalsIgnoreCase(folder)) {
            where = "thread_id = -1";
        }

        return where;
    }

    private String setWhereFilterFolderType(String folder, FilterInfo fi) {
        String where = "";
        if (fi.msgType == FilterInfo.TYPE_SMS) {
            where = setWhereFilterFolderTypeSms(folder);
        } else if (fi.msgType == FilterInfo.TYPE_MMS) {
            where = setWhereFilterFolderTypeMms(folder);
        } else {
            where = setWhereFilterFolderTypeEmail(folder);

        }

        return where;
    }

    private String setWhereFilterReadStatus(BluetoothMapAppParams ap, FilterInfo fi) {
        String where = "";
        if (ap.getFilterReadStatus() != -1) {
            if ((fi.msgType == FilterInfo.TYPE_SMS) || (fi.msgType == FilterInfo.TYPE_MMS)) {
                if ((ap.getFilterReadStatus() & 0x01) != 0) {
                    where = " AND read=0 ";
                }

                if ((ap.getFilterReadStatus() & 0x02) != 0) {
                    where = " AND read=1 ";
                }
            } else {
                if ((ap.getFilterReadStatus() & 0x01) != 0) {
                    where = " AND flagRead=0 ";
                }

                if ((ap.getFilterReadStatus() & 0x02) != 0) {
                    where = " AND flagRead=1 ";
                }
            }
        }

        return where;
    }

    private String setWhereFilterPeriod(BluetoothMapAppParams ap, FilterInfo fi) {
        String where = "";
        if ((ap.getFilterPeriodBegin() != -1)) {
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                where = " AND date >= " + ap.getFilterPeriodBegin();
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                where = " AND date >= " + (ap.getFilterPeriodBegin() / 1000L);
            } else {
                Time time = new Time();
                try {
                    time.parse(ap.getFilterPeriodBeginString().trim());
                    where += " AND timeStamp >= " + time.toMillis(false);
                } catch (TimeFormatException e) {
                    Log.d(TAG, "Bad formatted FilterPeriodBegin, Ignore" + ap.getFilterPeriodBeginString());
                }
            }
        }

        if ((ap.getFilterPeriodEnd() != -1)) {
            if (fi.msgType == FilterInfo.TYPE_SMS) {
                where += " AND date <= " + ap.getFilterPeriodEnd();
            } else if (fi.msgType == FilterInfo.TYPE_MMS) {
                where += " AND date <= " + (ap.getFilterPeriodEnd() / 1000L);
            } else {
                Time time = new Time();
                try {
                    time.parse(ap.getFilterPeriodEndString().trim());
                    where += " AND timeStamp <= " + time.toMillis(false);
                } catch (TimeFormatException e) {
                    Log.d(TAG, "Bad formatted FilterPeriodEnd, Ignore" + ap.getFilterPeriodEndString());
                }
            }
        }

        return where;
    }

    private String setWhereFilterPhones(String str) {
        String where = "";
        str = str.replace("*", "%");

        Cursor c = mResolver.query(ContactsContract.Contacts.CONTENT_URI, null,
                ContactsContract.Contacts.DISPLAY_NAME + " like ?", new String[] { str },
                ContactsContract.Contacts.DISPLAY_NAME + " ASC");

        try {
            while (c != null && c.moveToNext()) {
                String contactId = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));

                Cursor p = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { contactId },
                        null);

                try {
                    while (p != null && p.moveToNext()) {
                        String number = p
                                .getString(p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

                        where += " address = " + "'" + number + "'";
                        if (!p.isLast())
                            where += " OR ";
                    }
                } finally {
                    close(p);
                }

                if (!c.isLast())
                    where += " OR ";
            }
        } finally {
            close(c);
        }

        if (str != null && str.length() > 0) {
            if (where.length() > 0) {
                where += " OR ";
            }
            where += " address like " + "'" + str + "'";
        }

        return where;
    }

    private String setWhereFilterOriginator(BluetoothMapAppParams ap, FilterInfo fi) {
        String where = "";
        String orig = ap.getFilterOriginator();

        if (orig != null && orig.length() > 0) {
            String phones = setWhereFilterPhones(orig);

            if (phones.length() > 0) {
                where = " AND ((type <> 1) OR ( " + phones + " ))";
            } else {
                where = " AND (type <> 1)";
            }

            orig = orig.replace("*", ".*");
            orig = ".*" + orig + ".*";

            boolean localPhoneMatchOrig = false;
            if (fi.phoneNum != null && fi.phoneNum.length() > 0 && fi.phoneNum.matches(orig)) {
                localPhoneMatchOrig = true;
            }

            if (fi.phoneAlphaTag != null && fi.phoneAlphaTag.length() > 0 && fi.phoneAlphaTag.matches(orig)) {
                localPhoneMatchOrig = true;
            }

            if (!localPhoneMatchOrig) {
                where += " AND (type = 1)";
            }
        }

        return where;
    }

    private String setWhereFilterPriority(BluetoothMapAppParams ap, FilterInfo fi) {
        String where = "";
        int pri = ap.getFilterPriority();
        /*only MMS have priority info */
        if (fi.msgType == FilterInfo.TYPE_MMS) {
            if (pri == 0x0002) {
                where += " AND " + Mms.PRIORITY + "<=" + Integer.toString(PduHeaders.PRIORITY_NORMAL);
            } else if (pri == 0x0001) {
                where += " AND " + Mms.PRIORITY + "=" + Integer.toString(PduHeaders.PRIORITY_HIGH);
            }
        }
        return where;
    }

    private String setWhereFilterRecipient(BluetoothMapAppParams ap, FilterInfo fi) {
        String where = "";
        String recip = ap.getFilterRecipient();

        if (recip != null && recip.length() > 0) {
            String phones = setWhereFilterPhones(recip);

            if (phones.length() > 0) {
                where = " AND ((type = 1) OR ( " + phones + " ))";
            } else {
                where = " AND (type = 1)";
            }

            recip = recip.replace("*", ".*");
            recip = ".*" + recip + ".*";

            boolean localPhoneMatchOrig = false;
            if (fi.phoneNum != null && fi.phoneNum.length() > 0 && fi.phoneNum.matches(recip)) {
                localPhoneMatchOrig = true;
            }

            if (fi.phoneAlphaTag != null && fi.phoneAlphaTag.length() > 0 && fi.phoneAlphaTag.matches(recip)) {
                localPhoneMatchOrig = true;
            }

            if (!localPhoneMatchOrig) {
                where += " AND (type <> 1)";
            }
        }

        return where;
    }

    private String setWhereFilterAccountKey(long id) {
        String where = "";
        where = "accountkey=" + id;
        return where;
    }

    private String setWhereFilterMessagekey(long id) {
        String where = "";
        where = " messageKey = " + id;
        return where;
    }

    private String setWhereFilterServerId(String path) {
        String where = "";
        if (path.equals("msg")) {
            where = "serverId =" + DISPLAY_NAME;
        } else {
            where = "serverId LIKE '%" + path + "/%'";
        }
        return where;
    }

    private String setWhereFilter(String folder, FilterInfo fi, BluetoothMapAppParams ap) {
        String where = "";

        where += setWhereFilterFolderType(folder, fi);
        where += setWhereFilterReadStatus(ap, fi);
        where += setWhereFilterPeriod(ap, fi);
        where += setWhereFilterPriority(ap, fi);
        /* where += setWhereFilterOriginator(ap, fi); */
        /* where += setWhereFilterRecipient(ap, fi); */

        if (D)
            Log.d(TAG, "where: " + where);

        return where;
    }

    private boolean smsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
        int msgType = ap.getFilterMessageType();
        int phoneType = fi.phoneType;

        if (msgType == -1)
            return true;
        if ((msgType & 0x03) == 0)
            return true;

        if (((msgType & 0x01) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_GSM))
            return true;

        if (((msgType & 0x02) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_CDMA))
            return true;

        return false;
    }

    private boolean mmsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
        int msgType = ap.getFilterMessageType();

        if (msgType == -1)
            return true;

        if ((msgType & 0x08) == 0)
            return true;

        return false;
    }

    private void setFilterInfo(FilterInfo fi) {
        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if (tm != null) {
            fi.phoneType = tm.getPhoneType();
            fi.phoneNum = tm.getLine1Number();
            fi.phoneAlphaTag = tm.getLine1AlphaTag();
            if (D)
                Log.d(TAG, "phone type = " + fi.phoneType + " phone num = " + fi.phoneNum + " phone alpha tag = "
                        + fi.phoneAlphaTag);
        }
    }

    /**
     * Return Email sub folder list for the id and serverId path
     * @param context the calling Context
     * @param id the email account id
     * @return the list of   server id's of Email sub folder
     */
    public List<String> getEmailFolderListAtPath(Context context, long id, String path) {
        if (V)
            Log.v(TAG, "getEmailFolderListAtPath: id = " + id + "path: " + path);
        String where = "";
        ArrayList<String> list = new ArrayList<String>();
        where += setWhereFilterAccountKey(id);
        where += " AND ";
        where += setWhereFilterServerId(path);
        Cursor cr = context.getContentResolver().query(EMAIL_BOX_URI, null, where, null, null);
        if (cr != null) {
            if (cr.moveToFirst()) {
                final int columnIndex = cr.getColumnIndex(SERVER_ID);
                do {
                    final String value = cr.getString(columnIndex);
                    list.add(value);
                    if (V)
                        Log.v(TAG, "adding: " + value);
                } while (cr.moveToNext());
            }
            cr.close();
        }
        return list;
    }

    private boolean emailSelected(FilterInfo fi, BluetoothMapAppParams ap) {
        int msgType = ap.getFilterMessageType();
        if (D)
            Log.d(TAG, "emailSelected, msgType : " + msgType);

        if (msgType == -1)
            return true;

        if ((msgType & 0x04) == 0) {
            return true;
        } else {
            if (V)
                Log.v(TAG, "Invalid Message Filter");
            return false;
        }

    }

    private void printEmail(Cursor c) {
        if (D)
            Log.d(TAG,
                    "printEmail " + c.getLong(c.getColumnIndex("_id")) + "\n   " + "displayName" + " : "
                            + c.getString(c.getColumnIndex("displayName")) + "\n   " + "subject" + " : "
                            + c.getString(c.getColumnIndex("subject")) + "\n   " + "flagRead" + " : "
                            + c.getString(c.getColumnIndex("flagRead")) + "\n   " + "flagAttachment" + " : "
                            + c.getInt(c.getColumnIndex("flagAttachment")) + "\n   " + "flags" + " : "
                            + c.getInt(c.getColumnIndex("flags")) + "\n   " + "syncServerId" + " : "
                            + c.getInt(c.getColumnIndex("syncServerId")) + "\n   " + "clientId" + " : "
                            + c.getInt(c.getColumnIndex("clientId")) + "\n   " + "messageId" + " : "
                            + c.getInt(c.getColumnIndex("messageId")) + "\n   " + "timeStamp" + " : "
                            + c.getInt(c.getColumnIndex("timeStamp")) + "\n   " + "mailboxKey" + " : "
                            + c.getInt(c.getColumnIndex("mailboxKey")) + "\n   " + "accountKey" + " : "
                            + c.getInt(c.getColumnIndex("accountKey")) + "\n   " + "fromList" + " : "
                            + c.getString(c.getColumnIndex("fromList")) + "\n   " + "toList" + " : "
                            + c.getString(c.getColumnIndex("toList")) + "\n   " + "ccList" + " : "
                            + c.getString(c.getColumnIndex("ccList")) + "\n   " + "bccList" + " : "
                            + c.getString(c.getColumnIndex("bccList")) + "\n   " + "replyToList" + " : "
                            + c.getString(c.getColumnIndex("replyToList")) + "\n   " + "meetingInfo" + " : "
                            + c.getString(c.getColumnIndex("meetingInfo")) + "\n   " + "snippet" + " : "
                            + c.getString(c.getColumnIndex("snippet")) + "\n   " + "protocolSearchInfo" + " : "
                            + c.getString(c.getColumnIndex("protocolSearchInfo")) + "\n   " + "threadTopic" + " : "
                            + c.getString(c.getColumnIndex("threadTopic")));
    }

    /**
     * Get the folder name (MAP representation) for Email based on the
     * mailboxKey value in message table
     */
    private String getContainingFolderEmail(int folderId) {
        Cursor cr;
        String folderName = null;
        String whereClause = "_id = " + folderId;
        cr = mResolver.query(Uri.parse("content://com.android.email.provider/mailbox"), null, whereClause, null,
                null);
        if (cr != null) {
            if (cr.getCount() > 0) {
                cr.moveToFirst();
                folderName = cr.getString(cr.getColumnIndex(MessageColumns.DISPLAY_NAME));
            }
            cr.close();
        }
        if (V)
            Log.v(TAG, "getContainingFolderEmail returning " + folderName);
        return folderName;
    }

    private void extractEmailAddresses(long id, BluetoothMapbMessageMmsEmail message) {
        if (V)
            Log.v(TAG, "extractEmailAddresses with id " + id);
        String urlEmail = "content://com.android.email.provider/message";
        Uri uriEmail = Uri.parse(urlEmail);
        StringTokenizer emailId;
        String tempEmail = null;
        Cursor c = mResolver.query(uriEmail, EMAIL_PROJECTION, "_id = " + id, null, null);
        if (c != null && c.moveToFirst()) {
            String senderName = null;
            if ((senderName = c.getString(c.getColumnIndex(MessageColumns.FROM_LIST))) != null) {
                if (V)
                    Log.v(TAG, " senderName " + senderName);
                if (senderName.contains("")) {
                    String[] senderStr = senderName.split("");
                    if (senderStr != null && senderStr.length > 0) {
                        if (V)
                            Log.v(TAG, " senderStr[1] " + senderStr[1].trim());
                        if (V)
                            Log.v(TAG, " senderStr[0] " + senderStr[0].trim());
                        setVCardFromEmailAddress(message, senderStr[1].trim(), true);
                        if (senderStr[0].indexOf('<') != -1 && senderStr[0].indexOf('>') != -1) {
                            if (V)
                                Log.v(TAG, "from addressing is " + senderName
                                        .substring(senderStr[0].indexOf('<') + 1, senderStr[0].lastIndexOf('>')));
                            message.addFrom(null, senderStr[0].substring(senderStr[0].indexOf('<') + 1,
                                    senderStr[0].lastIndexOf('>')));
                        } else {
                            message.addFrom(null, senderStr[0].trim());
                        }
                    }
                } else {
                    if (V)
                        Log.v(TAG, " senderStr is" + senderName.trim());
                    setVCardFromEmailAddress(message, senderName.trim(), true);
                    if (senderName.indexOf('<') != -1 && senderName.indexOf('>') != -1) {
                        if (V)
                            Log.v(TAG, "from addressing is " + senderName.substring(senderName.indexOf('<') + 1,
                                    senderName.lastIndexOf('>')));
                        message.addFrom(null,
                                senderName.substring(senderName.indexOf('<') + 1, senderName.lastIndexOf('>')));
                    } else {
                        message.addFrom(null, senderName.trim());
                    }
                }
            }
            String recipientName = null;
            String multiRecepients = null;
            if ((recipientName = c.getString(c.getColumnIndex(MessageColumns.TO_LIST))) != null) {
                if (V)
                    Log.v(TAG, " recipientName " + recipientName);
                if (recipientName.contains("")) {
                    String[] recepientStr = recipientName.split("");
                    if (recepientStr != null && recepientStr.length > 0) {
                        if (V) {
                            Log.v(TAG, " recepientStr[1] " + recepientStr[1].trim());
                            Log.v(TAG, " recepientStr[0] " + recepientStr[0].trim());
                        }
                        setVCardFromEmailAddress(message, recepientStr[1].trim(), false);
                        message.addTo(recepientStr[1].trim(), recepientStr[0].trim());
                    }
                } else if (recipientName.contains("")) {
                    multiRecepients = recipientName.replace('', ';');
                    if (multiRecepients != null) {
                        if (V) {
                            Log.v(TAG, " Setting ::Recepient name :: " + multiRecepients.trim());
                        }
                        emailId = new StringTokenizer(multiRecepients.trim(), ";");
                        do {
                            setVCardFromEmailAddress(message, emailId.nextElement().toString(), false);
                        } while (emailId.hasMoreElements());

                        message.addTo(multiRecepients.trim(), multiRecepients.trim());
                    }
                } else if (recipientName.contains(",")) {
                    multiRecepients = recipientName.replace(", \"", "; \"");
                    multiRecepients = recipientName.replace(", ", "; ");
                    multiRecepients = recipientName.replace(",", ";");
                    if (multiRecepients != null) {
                        if (V) {
                            Log.v(TAG, "Setting ::Recepient name :: " + multiRecepients.trim());
                        }
                        emailId = new StringTokenizer(multiRecepients.trim(), ";");
                        do {
                            tempEmail = emailId.nextElement().toString();
                            setVCardFromEmailAddress(message, tempEmail, false);

                            if (tempEmail.indexOf('<') != -1) {
                                if (D)
                                    Log.d(TAG, "Adding to: " + tempEmail.substring(tempEmail.indexOf('<') + 1,
                                            tempEmail.indexOf('>')));
                                message.addTo(null,
                                        tempEmail.substring(tempEmail.indexOf('<') + 1, tempEmail.indexOf('>')));
                            } else {
                                message.addTo(null, tempEmail);
                            }
                        } while (emailId.hasMoreElements());
                    }
                } else {
                    Log.v(TAG, " Setting ::Recepient name :: " + recipientName.trim());
                    setVCardFromEmailAddress(message, recipientName.trim(), false);
                    if (recipientName.indexOf('<') != -1 && recipientName.indexOf('>') != -1) {
                        if (V)
                            Log.v(TAG, "to addressing is " + recipientName.substring(recipientName.indexOf('<') + 1,
                                    recipientName.lastIndexOf('>')));
                        message.addTo(null, recipientName.substring(recipientName.indexOf('<') + 1,
                                recipientName.lastIndexOf('>')));
                    } else {
                        message.addTo(null, recipientName.trim());
                    }
                }
            }

            recipientName = null;
            multiRecepients = null;
            if ((recipientName = c.getString(c.getColumnIndex(MessageColumns.CC_LIST))) != null) {
                if (V)
                    Log.v(TAG, " recipientName " + recipientName);
                if (recipientName.contains("^B")) {
                    String[] recepientStr = recipientName.split("^B");
                    if (recepientStr != null && recepientStr.length > 0) {
                        if (V) {
                            Log.v(TAG, " recepientStr[1] " + recepientStr[1].trim());
                            Log.v(TAG, " recepientStr[0] " + recepientStr[0].trim());
                        }
                        setVCardFromEmailAddress(message, recepientStr[1].trim(), false);
                        message.addCc(recepientStr[1].trim(), recepientStr[0].trim());
                    }
                } else if (recipientName.contains("")) {
                    multiRecepients = recipientName.replace('', ';');
                    if (multiRecepients != null) {
                        if (V) {
                            Log.v(TAG, " Setting ::Recepient name :: " + multiRecepients.trim());
                        }
                        emailId = new StringTokenizer(multiRecepients.trim(), ";");
                        do {
                            setVCardFromEmailAddress(message, emailId.nextElement().toString(), false);
                        } while (emailId.hasMoreElements());

                        message.addCc(multiRecepients.trim(), multiRecepients.trim());
                    }
                } else if (recipientName.contains(",")) {
                    multiRecepients = recipientName.replace(", \"", "; \"");
                    multiRecepients = recipientName.replace(", ", "; ");
                    multiRecepients = recipientName.replace(",", ";");

                    if (multiRecepients != null) {
                        if (V) {
                            Log.v(TAG, "Setting ::Recepient name :: " + multiRecepients.trim());
                        }
                        emailId = new StringTokenizer(multiRecepients.trim(), ";");
                        do {
                            tempEmail = emailId.nextElement().toString();
                            setVCardFromEmailAddress(message, tempEmail, false);
                            message.addCc(null, tempEmail);
                        } while (emailId.hasMoreElements());
                    }
                } else {
                    if (V)
                        Log.v(TAG, " Setting ::Recepient name :: " + recipientName.trim());
                    setVCardFromEmailAddress(message, recipientName.trim(), false);
                    if (recipientName.indexOf('<') != -1 && recipientName.indexOf('>') != -1) {
                        if (V)
                            Log.v(TAG, "CC addressing is " + recipientName.substring(recipientName.indexOf('<') + 1,
                                    recipientName.lastIndexOf('>')));
                        message.addCc(null, recipientName.substring(recipientName.indexOf('<') + 1,
                                recipientName.lastIndexOf('>')));
                    } else {
                        message.addCc(null, recipientName.trim());
                    }
                }
            }
            c.close();
        }
    }

    /**
     * Read out a mms data part and return the data in a byte array.
     * @param partid the content provider id of the mms.
     * @return
     */
    private byte[] readEmailDataPart(long partid) {
        String uriStr = String.format("content://mms/part/%d", partid);
        Uri uriAddress = Uri.parse(uriStr);
        InputStream is = null;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        int bufferSize = 8192;
        byte[] buffer = new byte[bufferSize];
        byte[] retVal = null;

        try {
            is = mResolver.openInputStream(uriAddress);
            int len = 0;
            if ((is != null) && (os != null)) {
                while ((len = is.read(buffer)) != -1) {
                    os.write(buffer, 0, len); // We need to specify the len, as it can be != bufferSize
                }
            }
            retVal = os.toByteArray();
        } catch (IOException e) {
            // do nothing for now
            Log.w(TAG, "Error reading part data", e);
        } finally {
            try {
                os.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
            }
        }
        return retVal;
    }

    /*
     * Read  email body data under content URI.
     */
    private String readEmailBodyForMessageFd(ParcelFileDescriptor fd) {
        StringBuilder email = new StringBuilder("");
        FileInputStream is = null;
        try {
            int len = -1;
            is = new FileInputStream(fd.getFileDescriptor());
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1) {
                email.append(new String(buffer, 0, len));
                if (V)
                    Log.v(TAG, "Email part = " + new String(buffer, 0, len) + " len=" + len);
            }
        } catch (NullPointerException e) {
            Log.w(TAG, e);
        } catch (IOException e) {
            Log.w(TAG, e);
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
            }
        }
        return email.toString();
    }

    /**
     * Read out the mms parts and update the bMessage object provided i {@linkplain message}
     * @param id the content provider ID of the message
     * @param message the bMessage object to add the information to
     */
    private void extractEmailParts(long id, BluetoothMapbMessageMmsEmail message) {
        if (V)
            Log.v(TAG, "extractEmailParts with id " + id);
        String emailBody = "";
        Uri uriAddress = Uri.parse("content://com.android.email.provider/body");
        BluetoothMapbMessageMmsEmail.MimePart part;
        Cursor c = null;
        try {
            c = mResolver.query(uriAddress, Body.CONTENT_PROJECTION, BodyColumns.MESSAGE_KEY + "=?",
                    new String[] { String.valueOf(id) }, null);
        } catch (Exception e) {

            Log.w(TAG, " EMAIL BODY QUERY FAILDED " + e);
        }
        if (c != null) {
            if (V)
                Log.v(TAG, "cursor not null");
            if (c.moveToFirst()) {
                String textContentURI = c.getString(c.getColumnIndex(BodyColumns.TEXT_CONTENT_URI));
                String htmlContentURI = c.getString(c.getColumnIndex(BodyColumns.HTML_CONTENT_URI));
                if (textContentURI != null || htmlContentURI != null) {
                    if (V) {
                        Log.v(TAG, " EMAIL BODY textURI " + textContentURI);
                        Log.v(TAG, " EMAIL BODY htmlURI " + htmlContentURI);
                    }
                    // GET FD to parse text or HTML content
                    ParcelFileDescriptor fd = null;
                    if (textContentURI != null) {
                        try {
                            Log.v(TAG, " TRY EMAIL BODY textURI " + textContentURI);
                            fd = mResolver.openFileDescriptor(Uri.parse(textContentURI), "r");
                        } catch (FileNotFoundException e) {
                            if (V)
                                Log.w(TAG, e);
                        }
                    }
                    if (fd == null) {
                        if (htmlContentURI != null) {
                            //Try HTML content if  TEXT CONTENT NULL
                            try {
                                Log.v(TAG, " TRY EMAIL BODY htmlURI " + htmlContentURI);
                                fd = mResolver.openFileDescriptor(Uri.parse(htmlContentURI), "r");
                            } catch (FileNotFoundException e) {
                                if (V)
                                    Log.w(TAG, e);
                            } catch (NullPointerException e) {
                                if (V)
                                    Log.w(TAG, e);
                            }
                            String msgBody = null;
                            if (fd != null) {
                                msgBody = readEmailBodyForMessageFd(fd);
                            } else {
                                Log.w(TAG, " FETCH Email BODY File HTML URI FAILED");
                            }
                            if (msgBody != null) {
                                msgBody = msgBody.replaceAll("(?s)(<title>)(.*?)(</title>)", "");
                                msgBody = msgBody.replaceAll("(?s)(<style type=\"text/css\".*?>)(.*?)(</style>)",
                                        "");
                                CharSequence msgText = Html.fromHtml(msgBody);
                                emailBody = msgText.toString();
                                emailBody = emailBody.replaceAll("(?s)(<!--)(.*?)(-->)", "");
                                // Solves problem with Porche Car-kit and Gmails.
                                // Changes unix style line conclusion to DOS style
                                emailBody = emailBody.replaceAll("(?s)(\\r)", "");
                                emailBody = emailBody.replaceAll("(?s)(\\n)", "\r\n");
                            }
                        } else {
                            Log.w(TAG, " FETCH Email BODY File HTML URI FAILED");
                        }
                    } else {
                        emailBody = readEmailBodyForMessageFd(fd);
                    }
                    //Set BMessage emailBody
                    message.setEmailBody(emailBody);
                    //Parts
                    Long partId = c.getLong(c.getColumnIndex(BaseColumns._ID));
                    String contentType = "Content-Type: text/plain; charset=\"UTF-8\"";
                    String name = null;//c.getString(c.getColumnIndex("displayName"));
                    String text = null;

                    if (D)
                        Log.d(TAG, "     _id : " + partId + "\n     ct : " + contentType + "\n     partname : "
                                + name);

                    part = message.addMimePart();
                    part.contentType = contentType;
                    part.partName = name;

                    try {
                        if (emailBody != null) {
                            part.data = emailBody.getBytes("UTF-8");
                            part.charsetName = "utf-8";
                        }
                    } catch (NumberFormatException e) {
                        Log.d(TAG, "extractEmailParts", e);
                        part.data = null;
                        part.charsetName = null;
                    } catch (UnsupportedEncodingException e) {
                        Log.d(TAG, "extractEmailParts", e);
                        part.data = null;
                        part.charsetName = null;
                    } finally {
                    }
                    try {
                        if (fd != null)
                            fd.close();
                    } catch (IOException e) {
                    }
                } else {
                    Log.w(TAG, " FETCH Email BODY File URI FAILED");
                }
            }
            c.close();
        }
        message.updateCharset();
        message.setEncoding("8BIT");
    }

    /**
     *
     * @param id the content provider id for the message to fetch.
     * @param appParams The application parameter object received from the client.
     * @return a byte[] containing the utf-8 encoded bMessage to send to the client.
     * @throws UnsupportedEncodingException if UTF-8 is not supported,
     * which is guaranteed to be supported on an android device
     */
    public byte[] getEmailMessage(long id, BluetoothMapAppParams appParams) throws UnsupportedEncodingException {
        if (V)
            Log.v(TAG, "getEmailMessage with is " + id);
        int msgBox, threadId;
        String urlEmail = "content://com.android.email.provider/message";
        Uri uriEmail = Uri.parse(urlEmail);
        BluetoothMapbMessageMmsEmail message = new BluetoothMapbMessageMmsEmail();
        Cursor c = mResolver.query(uriEmail, EMAIL_PROJECTION, "_id = " + id, null, null);
        if (c != null && c.moveToFirst()) {
            message.setType(TYPE.EMAIL);

            // The EMAIL info:
            if (c.getString(c.getColumnIndex(MessageColumns.FLAG_READ)).equalsIgnoreCase("1"))
                message.setStatus(true);
            else
                message.setStatus(false);

            msgBox = c.getInt(c.getColumnIndex(MessageColumns.MAILBOX_KEY));
            message.setFolder(getContainingFolderEmail(msgBox));

            message.setSubject(c.getString(c.getColumnIndex(MessageColumns.SUBJECT)));
            message.setContentType("Content-Type: text/plain; charset=\"UTF-8\"");
            message.setDate(c.getLong(c.getColumnIndex(MessageColumns.TIMESTAMP)));
            message.setIncludeAttachments(appParams.getAttachment() == 0 ? false : true);

            // The parts
            extractEmailParts(id, message);

            // The addresses
            extractEmailAddresses(id, message);

            c.close();

            return message.encodeEmail();
        } else if (c != null) {
            c.close();
        }

        throw new IllegalArgumentException("MMS handle not found");
    }

    public BluetoothMapMessageListing msgListingEmail(String folder, BluetoothMapAppParams ap) {
        Log.d(TAG, "msgListing: folder = " + folder);
        String urlEmail = "content://com.android.email.provider/message";
        Uri uriEmail = Uri.parse(urlEmail);
        BluetoothMapMessageListing bmList = new BluetoothMapMessageListing();
        BluetoothMapMessageListingElement e = null;

        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);

        if (emailSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_EMAIL;

            String where = setWhereFilter(folder, fi, ap);
            where += " AND " + Message.FLAG_LOADED_SELECTION;
            Log.d(TAG, "where clause is = " + where);
            where += " order by timeStamp desc ";
            //Fetch only maxListCount emails from  startOffset
            if (ap.getMaxListCount() > 0 && ap.getMaxListCount() < 65536) {
                where += " LIMIT " + ap.getMaxListCount();
            }
            if (ap.getStartOffset() > 0 && ap.getStartOffset() < 65536) {
                where += " OFFSET " + ap.getStartOffset();
            }
            if (V)
                Log.d(TAG, "where clause is = " + where);
            try {
                Cursor c = mResolver.query(uriEmail, EMAIL_PROJECTION,
                        where + " AND " + Message.FLAG_LOADED_SELECTION, null, "timeStamp desc");
                if (c == null) {
                    Log.e(TAG, "Cursor is null. Returning from here");
                }

                if (c != null) {
                    while (c.moveToNext()) {
                        if (matchAddresses(c, fi, ap) && ((ap.getFilterPriority() == 0)
                                || (ap.getFilterPriority() == 0x02) || (ap.getFilterPriority() == -1))) {
                            printEmail(c);
                            e = element(c, fi, ap);
                            bmList.add(e);
                        }
                    }
                    c.close();
                }
            } catch (SQLiteException es) {
                Log.e(TAG, "SQLite exception: " + es);
            }
        }

        /* Enable this if post sorting and segmenting needed */
        bmList.sort();
        //Handle OFFSET and MAXLISTCOUNT from DB query
        //        bmList.segment(ap.getMaxListCount(), ap.getStartOffset());

        return bmList;
    }

    public int msgListingSizeEmail(String folder, BluetoothMapAppParams ap) {
        if (D)
            Log.d(TAG, "msgListingSize: folder = " + folder);
        int cnt = 0;
        String urlEmail = "content://com.android.email.provider/message";
        Uri uriEmail = Uri.parse(urlEmail);

        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);

        if (emailSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_EMAIL;
            String where = setWhereFilter(folder, fi, ap);
            Cursor c = mResolver.query(uriEmail, EMAIL_PROJECTION, where, null, "timeStamp desc");

            if (c != null) {
                cnt += c.getCount();
                c.close();
            }
        }

        if (D)
            Log.d(TAG, "msgListingSize: size = " + cnt);
        return cnt;
    }

    /**
     * Return true if there are unread messages in the requested list of messages
     * @param folder folder where the message listing should come from
     * @param ap application parameter object
     * @return true if unread messages are in the list, else false
     */
    public boolean msgListingHasUnreadEmail(String folder, BluetoothMapAppParams ap) {
        if (D)
            Log.d(TAG, "msgListingHasUnread: folder = " + folder);
        int cnt = 0;
        String urlEmail = "content://com.android.email.provider/message";
        Uri uriEmail = Uri.parse(urlEmail);

        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);

        if (emailSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_EMAIL;
            String where = setWhereFilterFolderType(folder, fi);
            where += " AND flagRead=0 ";
            where += setWhereFilterPeriod(ap, fi);
            Cursor c = mResolver.query(uriEmail, EMAIL_PROJECTION, where, null, "timeStamp desc");

            if (c != null) {
                cnt += c.getCount();
                c.close();
            }
        }

        if (D)
            Log.d(TAG, "msgListingHasUnread: numUnread = " + cnt);
        return (cnt > 0) ? true : false;
    }

    public BluetoothMapMessageListing msgListing(String folder, BluetoothMapAppParams ap) {
        Log.d(TAG, "msgListing: folder = " + folder);
        BluetoothMapMessageListing bmList = new BluetoothMapMessageListing();
        BluetoothMapMessageListingElement e = null;
        msgListingFolder = folder;
        Log.d(TAG, "msgListingFolder = " + msgListingFolder);
        /* We overwrite the parameter mask here if it is 0 or not present, as this
         * should cause all parameters to be included in the message list. */
        if (ap.getParameterMask() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER || ap.getParameterMask() == 0) {
            ap.setParameterMask(BluetoothMapAppParams.PARAMETER_MASK_ALL_ENABLED);
            if (V)
                Log.w(TAG, "msgListing(): appParameterMask is zero or not present, " + "changing to: "
                        + ap.getParameterMask());
        }
        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);
        if (smsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_SMS;
            if (ap.getFilterPriority() != 1) { /*SMS cannot have high priority*/
                String where = setWhereFilter(folder, fi, ap);

                Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null, "date DESC");

                if (c != null) {
                    while (c.moveToNext()) {
                        if (matchAddresses(c, fi, ap)) {
                            printSms(c);
                            e = element(c, fi, ap);
                            bmList.add(e);
                        }
                    }
                    c.close();
                }
            }
        }

        if (mmsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_MMS;

            String where = setWhereFilter(folder, fi, ap);
            where += " AND " + INTERESTED_MESSAGE_TYPE_CLAUSE;
            Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, where, null, "date DESC");

            if (c != null) {
                int cnt = 0;
                while (c.moveToNext()) {
                    if (matchAddresses(c, fi, ap)) {
                        printMms(c);
                        e = element(c, fi, ap);
                        bmList.add(e);
                    }
                }
                c.close();
            }
        }

        /* Enable this if post sorting and segmenting needed */
        bmList.sort();
        bmList.segment(ap.getMaxListCount(), ap.getStartOffset());

        return bmList;
    }

    public int msgListingSize(String folder, BluetoothMapAppParams ap) {
        if (D)
            Log.d(TAG, "msgListingSize: folder = " + folder);
        int cnt = 0;

        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);

        if (smsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_SMS;
            String where = setWhereFilter(folder, fi, ap);
            Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null, "date DESC");

            if (c != null) {
                cnt = c.getCount();
                c.close();
            }
        }

        if (mmsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_MMS;
            String where = setWhereFilter(folder, fi, ap);
            where += " AND " + INTERESTED_MESSAGE_TYPE_CLAUSE;
            Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, where, null, "date DESC");

            if (c != null) {
                cnt += c.getCount();
                c.close();
            }
        }

        if (D)
            Log.d(TAG, "msgListingSize: size = " + cnt);
        return cnt;
    }

    /**
     * Return true if there are unread messages in the requested list of messages
     * @param folder folder where the message listing should come from
     * @param ap application parameter object
     * @return true if unread messages are in the list, else false
     */
    public boolean msgListingHasUnread(String folder, BluetoothMapAppParams ap) {
        if (D)
            Log.d(TAG, "msgListingHasUnread: folder = " + folder);
        int cnt = 0;

        /* Cache some info used throughout filtering */
        FilterInfo fi = new FilterInfo();
        setFilterInfo(fi);

        if (smsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_SMS;
            String where = setWhereFilterFolderType(folder, fi);
            where += " AND read=0 ";
            where += setWhereFilterPeriod(ap, fi);
            Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null, "date DESC");

            if (c != null)
                cnt += c.getCount();
            c.close();
        }

        if (mmsSelected(fi, ap)) {
            fi.msgType = FilterInfo.TYPE_MMS;
            String where = setWhereFilterFolderType(folder, fi);
            where += " AND read=0 ";
            where += setWhereFilterPeriod(ap, fi);
            Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, where, null, "date DESC");

            if (c != null) {
                cnt += c.getCount();
                c.close();
            }
        }

        if (D)
            Log.d(TAG, "msgListingHasUnread: numUnread = " + cnt);
        return (cnt > 0) ? true : false;
    }

    /**
     * Get the folder name of an SMS message or MMS message.
     * @param c the cursor pointing at the message
     * @return the folder name.
     */
    private String getFolderName(int type, int threadId) {

        if (threadId == -1)
            return "deleted";

        switch (type) {
        case 1:
            return "inbox";
        case 2:
            return "sent";
        case 3:
            return "draft";
        case 4: // Just name outbox, failed and queued "outbox"
        case 5:
        case 6:
            return "outbox";
        }
        return "";
    }

    public void msgUpdate() {
        if (D)
            Log.d(TAG, "Message Update");
        long accountId = BluetoothMapUtils.getEmailAccountId(mContext);
        if (V)
            Log.v(TAG, " Account id for Inbox Update: " + accountId);
        Intent emailIn = new Intent();
        emailIn.setAction("com.android.email.intent.action.MAIL_SERVICE_WAKEUP");
        emailIn.putExtra("com.android.email.intent.extra.ACCOUNT", accountId);
        mContext.sendBroadcast(emailIn);
    }

    public byte[] getMessage(String handle, BluetoothMapAppParams appParams) throws UnsupportedEncodingException {
        TYPE type = BluetoothMapUtils.getMsgTypeFromHandle(handle);
        long id = BluetoothMapUtils.getCpHandle(handle);
        if (appParams == null) {
            throw new IllegalArgumentException("Invalid No appParams Charset");
        }
        switch (type) {
        case SMS_GSM:
        case SMS_CDMA:
            return getSmsMessage(id, appParams.getCharset());
        case MMS:
            if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE) {
                throw new IllegalArgumentException("Invalid Charset: Native for Message Type MMS");
            }
            return getMmsMessage(id, appParams);
        case EMAIL:
            if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE) {
                throw new IllegalArgumentException("Invalid Charset: Native for Message Type Email");
            }
            return getEmailMessage(id, appParams);
        }
        throw new IllegalArgumentException("Invalid message handle.");
    }

    private void setVCardFromEmailAddress(BluetoothMapbMessage message, String emailAddr, boolean incoming) {
        if (D)
            Log.d(TAG, "setVCardFromEmailAddress, emailAdress is " + emailAddr);
        String contactId = null, contactName = null;
        String[] phoneNumbers = { "" };
        String[] emailAddresses = new String[1];
        StringTokenizer emailId;
        Cursor p;

        if (incoming == true) {
            emailAddresses[0] = emailAddr;
            if (V)
                Log.v(TAG, "Adding addOriginator " + emailAddresses[0]);
            message.addOriginator(emailAddr, phoneNumbers, emailAddresses);
        } else {
            emailAddresses[0] = emailAddr;
            if (V)
                Log.v(TAG, "Adding Receipient " + emailAddresses[0]);
            message.addRecipient(emailAddr, phoneNumbers, emailAddresses);
        }
    }

    private void setVCardFromPhoneNumber(BluetoothMapbMessage message, String phone, boolean incoming) {
        if (TextUtils.isEmpty(phone)) {
            return;
        }
        String contactId = null, contactName = null;
        String[] phoneNumbers = null;
        String[] emailAddresses = null;

        Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));

        String[] projection = { Contacts._ID, Contacts.DISPLAY_NAME };
        String selection = Contacts.IN_VISIBLE_GROUP + "=1";
        String orderBy = Contacts._ID + " ASC";

        // Get the contact _ID and name
        Cursor p = mResolver.query(uri, projection, selection, null, orderBy);

        try {
            if (p != null && p.getCount() >= 1) {
                p.moveToFirst();
                contactId = p.getString(p.getColumnIndex(Contacts._ID));
                contactName = p.getString(p.getColumnIndex(Contacts.DISPLAY_NAME));
            }

            // Bail out if we are unable to find a contact, based on the phone number
            if (contactId == null) {
                phoneNumbers = new String[1];
                phoneNumbers[0] = phone;
            } else {
                // use only actual phone number
                phoneNumbers = new String[1];
                phoneNumbers[0] = phone;

                // Fetch contact e-mail addresses
                close(p);
                p = mResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { contactId },
                        null);
                if (p != null) {
                    int i = 0;
                    emailAddresses = new String[p.getCount()];
                    while (p != null && p.moveToNext()) {
                        String emailAddress = p
                                .getString(p.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
                        emailAddresses[i++] = emailAddress;
                    }
                }
            }
        } finally {
            close(p);
        }
        if (incoming == true)
            message.addOriginator(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
        else
            message.addRecipient(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
    }

    public static final int MAP_MESSAGE_CHARSET_NATIVE = 0;
    public static final int MAP_MESSAGE_CHARSET_UTF8 = 1;

    public byte[] getSmsMessage(long id, int charset) throws UnsupportedEncodingException {
        int type, threadId;
        long time = -1;
        String msgBody;
        BluetoothMapbMessageSms message = new BluetoothMapbMessageSms();
        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, "_ID = " + id, null, null);
        if (c == null || !c.moveToFirst()) {
            throw new IllegalArgumentException("SMS handle not found");
        }

        try {
            if (V)
                Log.v(TAG, "c.count: " + c.getCount());

            if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
                message.setType(TYPE.SMS_GSM);
            } else if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
                message.setType(TYPE.SMS_CDMA);
            } else {
                // set SMS_GSM by default
                message.setType(TYPE.SMS_GSM);
            }

            String read = c.getString(c.getColumnIndex(Sms.READ));
            if (read.equalsIgnoreCase("1"))
                message.setStatus(true);
            else
                message.setStatus(false);

            type = c.getInt(c.getColumnIndex(Sms.TYPE));
            threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID));
            message.setFolder(getFolderName(type, threadId));

            msgBody = c.getString(c.getColumnIndex(Sms.BODY));

            String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));

            time = c.getLong(c.getColumnIndex(Sms.DATE));
            if (type == 1) // Inbox message needs to set the vCard as originator
                setVCardFromPhoneNumber(message, phone, true);
            else // Other messages sets the vCard as the recipient
                setVCardFromPhoneNumber(message, phone, false);

            if (charset == MAP_MESSAGE_CHARSET_NATIVE) {
                if (type == 1) //Inbox
                    message.setSmsBodyPdus(BluetoothMapSmsPdu.getDeliverPdus(msgBody, phone, time));
                else
                    message.setSmsBodyPdus(BluetoothMapSmsPdu.getSubmitPdus(msgBody, phone));
            } else /*if (charset == MAP_MESSAGE_CHARSET_UTF8)*/ {
                message.setSmsBody(msgBody);
            }
        } finally {
            close(c);
        }

        return message.encode();
    }

    private void extractMmsAddresses(long id, BluetoothMapbMessageMmsEmail message) {
        final String[] projection = null;
        String selection = new String("msg_id=" + id);
        String uriStr = String.format("content://mms/%d/addr", id);
        Uri uriAddress = Uri.parse(uriStr);
        Cursor c = mResolver.query(uriAddress, projection, selection, null, null);
        /* TODO: Change the setVCard...() to return the vCard, and use the name in message.addXxx() */
        if (c != null && c.moveToFirst()) {
            do {
                String address = c.getString(c.getColumnIndex("address"));
                Integer type = c.getInt(c.getColumnIndex("type"));
                switch (type) {
                case MMS_FROM:
                    setVCardFromPhoneNumber(message, address, true);
                    message.addFrom(null, address);
                    break;
                case MMS_TO:
                    setVCardFromPhoneNumber(message, address, false);
                    message.addTo(null, address);
                    break;
                case MMS_CC:
                    setVCardFromPhoneNumber(message, address, false);
                    message.addCc(null, address);
                    break;
                case MMS_BCC:
                    setVCardFromPhoneNumber(message, address, false);
                    message.addBcc(null, address);
                default:
                    break;
                }
            } while (c.moveToNext());
            c.close();
        }
    }

    /**
     * Read out a mms data part and return the data in a byte array.
     * @param partid the content provider id of the mms.
     * @return
     */
    private byte[] readMmsDataPart(long partid) {
        String uriStr = String.format("content://mms/part/%d", partid);
        Uri uriAddress = Uri.parse(uriStr);
        InputStream is = null;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        int bufferSize = 8192;
        byte[] buffer = new byte[bufferSize];
        byte[] retVal = null;

        try {
            is = mResolver.openInputStream(uriAddress);
            int len = 0;
            if (is != null) {
                while ((len = is.read(buffer)) != -1) {
                    if (os != null) {
                        os.write(buffer, 0, len); // We need to specify the len, as it can be != bufferSize
                    }
                }
            }
            if (os != null) {
                retVal = os.toByteArray();

            }
        } catch (IOException e) {
            // do nothing for now
            Log.w(TAG, "Error reading part data", e);
        } finally {
            try {
                if (os != null)
                    os.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
            }
        }
        return retVal;
    }

    /**
     * Read out the mms parts and update the bMessage object provided i {@linkplain message}
     * @param id the content provider ID of the message
     * @param message the bMessage object to add the information to
     */
    private void extractMmsParts(long id, BluetoothMapbMessageMmsEmail message) {
        /* TODO: If the attachment appParam is set to "no", only add the text parts.
         * (content type contains "text" - case insensitive) */
        final String[] projection = null;
        String selection = new String("mid=" + id);
        String uriStr = String.format("content://mms/%d/part", id);
        Uri uriAddress = Uri.parse(uriStr);
        BluetoothMapbMessageMmsEmail.MimePart part;
        Cursor c = mResolver.query(uriAddress, projection, selection, null, null);

        if (c != null && c.moveToFirst()) {
            do {
                Long partId = c.getLong(c.getColumnIndex(BaseColumns._ID));
                String contentType = c.getString(c.getColumnIndex("ct"));
                String name = c.getString(c.getColumnIndex("name"));
                String charset = c.getString(c.getColumnIndex("chset"));
                String filename = c.getString(c.getColumnIndex("fn"));
                String text = c.getString(c.getColumnIndex("text"));
                Integer fd = c.getInt(c.getColumnIndex("_data"));
                String cid = c.getString(c.getColumnIndex("cid"));
                String cl = c.getString(c.getColumnIndex("cl"));
                String cdisp = c.getString(c.getColumnIndex("cd"));

                if (D)
                    Log.d(TAG,
                            "     _id : " + partId + "\n     ct : " + contentType + "\n     partname : " + name
                                    + "\n     charset : " + charset + "\n     filename : " + filename
                                    + "\n     text : " + text + "\n     fd : " + fd + "\n     cid : " + cid
                                    + "\n     cl : " + cl + "\n     cdisp : " + cdisp);

                part = message.addMimePart();
                part.contentType = contentType;
                part.partName = name;
                part.contentId = cid;
                part.contentLocation = cl;
                part.contentDisposition = cdisp;

                try {
                    if (text != null) {
                        part.data = text.getBytes("UTF-8");
                        part.charsetName = "utf-8";
                    } else {
                        part.data = readMmsDataPart(partId);
                        if (charset != null)
                            part.charsetName = CharacterSets.getMimeName(Integer.parseInt(charset));
                    }
                } catch (NumberFormatException e) {
                    Log.d(TAG, "extractMmsParts", e);
                    part.data = null;
                    part.charsetName = null;
                } catch (UnsupportedEncodingException e) {
                    Log.d(TAG, "extractMmsParts", e);
                    part.data = null;
                    part.charsetName = null;
                } finally {
                }
                part.fileName = filename;
            } while (c.moveToNext());
            c.close();
        }

        message.updateCharset();
    }

    /**
     *
     * @param id the content provider id for the message to fetch.
     * @param appParams The application parameter object received from the client.
     * @return a byte[] containing the utf-8 encoded bMessage to send to the client.
     * @throws UnsupportedEncodingException if UTF-8 is not supported,
     * which is guaranteed to be supported on an android device
     */
    public byte[] getMmsMessage(long id, BluetoothMapAppParams appParams) throws UnsupportedEncodingException {
        int msgBox, threadId;
        BluetoothMapbMessageMmsEmail message = new BluetoothMapbMessageMmsEmail();
        Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, "_ID = " + id, null, null);
        if (c == null || !c.moveToFirst()) {
            throw new IllegalArgumentException("MMS handle not found");
        }

        try {
            message.setType(TYPE.MMS);

            // The MMS info:
            String read = c.getString(c.getColumnIndex(Mms.READ));
            if (read.equalsIgnoreCase("1"))
                message.setStatus(true);
            else
                message.setStatus(false);

            msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
            threadId = c.getInt(c.getColumnIndex(Mms.THREAD_ID));
            message.setFolder(getFolderName(msgBox, threadId));

            message.setSubject(c.getString(c.getColumnIndex(Mms.SUBJECT)));
            message.setMessageId(c.getString(c.getColumnIndex(Mms.MESSAGE_ID)));
            message.setContentType(c.getString(c.getColumnIndex(Mms.CONTENT_TYPE)));
            message.setDate(c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L);
            message.setTextOnly(c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) == 0 ? false : true); // - TODO: Do we need this - yes, if we have only text, we should not make this a multipart message
            message.setIncludeAttachments(appParams.getAttachment() == 0 ? false : true);

            extractMmsParts(id, message);
            extractMmsAddresses(id, message);
        } finally {
            close(c);
        }

        return message.encode();
    }
}