blob: 58bfc528959bf90ef457dc7cee2af7af81745ef5 [file] [log] [blame]
/*
* Copyright (C) 2014 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 org.apache.http.util.ByteArrayBuffer;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Debug;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import com.android.bluetooth.mapapi.BluetoothMapContract;
import com.android.bluetooth.mapapi.BluetoothMapContract.MessageColumns;
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.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import com.android.bluetooth.map.BluetoothMapSmsPdu.SmsPdu;
import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.google.android.mms.pdu.CharacterSets;
import com.google.android.mms.pdu.PduHeaders;
import com.android.bluetooth.map.BluetoothMapAppParams;
import java.io.ByteArrayOutputStream;
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;
public class BluetoothMapContent {
private static final String TAG = "BluetoothMapContent";
private static final boolean D = BluetoothMapService.DEBUG;
private static final boolean V = BluetoothMapService.VERBOSE;
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;
/* 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;
public static final String INSERT_ADDRES_TOKEN = "insert-address-token";
private Context mContext;
private ContentResolver mResolver;
private String mBaseEmailUri = null;
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
};
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 mMsgType = TYPE_SMS;
int mPhoneType = 0;
String mPhoneNum = null;
String mPhoneAlphaTag = null;
/*column indices used to optimize queries */
public int mEmailColThreadId = -1;
public int mEmailColProtected = -1;
public int mEmailColFolder = -1;
public int mMmsColFolder = -1;
public int mSmsColFolder = -1;
public int mEmailColRead = -1;
public int mSmsColRead = -1;
public int mMmsColRead = -1;
public int mEmailColPriority = -1;
public int mMmsColAttachmentSize = -1;
public int mEmailColAttachment = -1;
public int mEmailColAttachementSize = -1;
public int mMmsColTextOnly = -1;
public int mMmsColId = -1;
public int mSmsColId = -1;
public int mEmailColSize = -1;
public int mSmsColSubject = -1;
public int mMmsColSize = -1;
public int mEmailColToAddress = -1;
public int mEmailColCcAddress = -1;
public int mEmailColBccAddress = -1;
public int mSmsColAddress = -1;
public int mSmsColDate = -1;
public int mMmsColDate = -1;
public int mEmailColDate = -1;
public int mMmsColSubject = -1;
public int mEmailColSubject = -1;
public int mSmsColType = -1;
public int mEmailColFromAddress = -1;
public int mEmailColId = -1;
public void setEmailColumns(Cursor c) {
mEmailColThreadId = c.getColumnIndex(BluetoothMapContract.MessageColumns.THREAD_ID);
mEmailColProtected = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_PROTECTED);
mEmailColFolder = c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID);
mEmailColRead = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ);
mEmailColPriority = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY);
mEmailColAttachment = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT);
mEmailColAttachementSize = c.getColumnIndex(BluetoothMapContract.MessageColumns.ATTACHMENT_SIZE);
mEmailColSize = c.getColumnIndex(BluetoothMapContract.MessageColumns.MESSAGE_SIZE);
mEmailColToAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST);
mEmailColCcAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.CC_LIST);
mEmailColBccAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.BCC_LIST);
mEmailColDate = c.getColumnIndex(BluetoothMapContract.MessageColumns.DATE);
mEmailColSubject = c.getColumnIndex(BluetoothMapContract.MessageColumns.SUBJECT);
mEmailColFromAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST);
mEmailColId = c.getColumnIndex(BluetoothMapContract.MessageColumns._ID);
}
public void setSmsColumns(Cursor c) {
mSmsColId = c.getColumnIndex(BaseColumns._ID);
mSmsColFolder = c.getColumnIndex(Sms.TYPE);
mSmsColRead = c.getColumnIndex(Sms.READ);
mSmsColSubject = c.getColumnIndex(Sms.BODY);
mSmsColAddress = c.getColumnIndex(Sms.ADDRESS);
mSmsColDate = c.getColumnIndex(Sms.DATE);
mSmsColType = c.getColumnIndex(Sms.TYPE);
}
public void setMmsColumns(Cursor c) {
mMmsColId = c.getColumnIndex(BaseColumns._ID);
mMmsColFolder = c.getColumnIndex(Mms.MESSAGE_BOX);
mMmsColRead = c.getColumnIndex(Mms.READ);
mMmsColAttachmentSize = c.getColumnIndex(Mms.MESSAGE_SIZE);
mMmsColTextOnly = c.getColumnIndex(Mms.TEXT_ONLY);
mMmsColSize = c.getColumnIndex(Mms.MESSAGE_SIZE);
mMmsColDate = c.getColumnIndex(Mms.DATE);
mMmsColSubject = c.getColumnIndex(Mms.SUBJECT);
}
}
public BluetoothMapContent(final Context context, String emailBaseUri) {
mContext = context;
mResolver = mContext.getContentResolver();
if (mResolver == null) {
if (D) Log.d(TAG, "getContentResolver failed");
}
mBaseEmailUri = emailBaseUri;
}
private void printSms(Cursor c) {
String body = c.getString(c.getColumnIndex(Sms.BODY));
if (V) Log.v(TAG, "printSms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) +
"\n " + Sms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Sms.THREAD_ID)) +
"\n " + Sms.ADDRESS + " : " + c.getString(c.getColumnIndex(Sms.ADDRESS)) +
"\n " + Sms.BODY + " : " + body.substring(0, Math.min(body.length(), 8)) +
"\n " + Sms.DATE + " : " + c.getLong(c.getColumnIndex(Sms.DATE)) +
"\n " + Sms.READ + " : " + c.getLong(c.getColumnIndex(Sms.READ)) +
"\n " + Sms.TYPE + " : " + c.getInt(c.getColumnIndex(Sms.TYPE)) +
"\n " + Sms.STATUS + " : " + c.getInt(c.getColumnIndex(Sms.STATUS)) +
"\n " + Sms.LOCKED + " : " + c.getInt(c.getColumnIndex(Sms.LOCKED)) +
"\n " + Sms.ERROR_CODE + " : " + c.getInt(c.getColumnIndex(Sms.ERROR_CODE)));
}
private void printMms(Cursor c) {
if (V) Log.v(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.PRIORITY + " : " + c.getInt(c.getColumnIndex(Mms.PRIORITY)) +
"\n " + Mms.MESSAGE_SIZE + " : " + c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE)));
}
private String getDateTimeString(long timestamp) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
Date date = new Date(timestamp);
return format.format(date); // Format to YYYYMMDDTHHMMSS local time
}
private void printEmail(Cursor c) {
if (V) Log.v(TAG, "printEmail " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) +
"\n " + BluetoothMapContract.MessageColumns.DATE + " : " + getDateTimeString(c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.DATE))) +
"\n " + BluetoothMapContract.MessageColumns.SUBJECT + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.SUBJECT)) +
"\n " + BluetoothMapContract.MessageColumns.FLAG_READ + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ)) +
"\n " + BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY)) +
"\n " + BluetoothMapContract.MessageColumns.RECEPTION_STATE + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.RECEPTION_STATE)) +
"\n " + BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT)) +
"\n " + BluetoothMapContract.MessageColumns.MESSAGE_SIZE + " : " + c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.MESSAGE_SIZE)) +
"\n " + BluetoothMapContract.MessageColumns.FLAG_PROTECTED + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_PROTECTED)) +
"\n " + BluetoothMapContract.MessageColumns.FROM_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST)) +
"\n " + BluetoothMapContract.MessageColumns.TO_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST)) +
"\n " + BluetoothMapContract.MessageColumns.CC_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.CC_LIST)) +
"\n " + BluetoothMapContract.MessageColumns.BCC_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.BCC_LIST)) +
"\n " + BluetoothMapContract.MessageColumns.REPLY_TO_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.REPLY_TO_LIST)) +
"\n " + BluetoothMapContract.MessageColumns.FOLDER_ID + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID)) +
"\n " + BluetoothMapContract.MessageColumns.ACCOUNT_ID + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.ACCOUNT_ID)) );
}
private void printMmsAddr(long id) {
final String[] projection = null;
String selection = new String("msg_id=" + id);
String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr");
Uri uriAddress = Uri.parse(uriStr);
Cursor c = mResolver.query(uriAddress, projection, selection, null, null);
if (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());
}
}
private void printMmsPartImage(long partid) {
String uriStr = new String(Mms.CONTENT_URI + "/part/" + 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 void printMmsParts(long id) {
final String[] projection = null;
String selection = new String("mid=" + id);
String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/part");
Uri uriAddress = Uri.parse(uriStr);
Cursor c = mResolver.query(uriAddress, projection, selection, null, null);
if (D) Log.d(TAG, " parts:");
if (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());
}
}
private void setProtected(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_PROTECTED) != 0) {
String protect = "no";
if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
int flagProtected = c.getInt(fi.mEmailColProtected);
if (flagProtected == 1) {
protect = "yes";
}
}
if (V) Log.d(TAG, "setProtected: " + protect + "\n");
e.setProtect(protect);
}
}
/**
* Email only
*/
private void setThreadId(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
long threadId = c.getLong(fi.mEmailColThreadId);
e.setThreadId(threadId);
if (V) Log.d(TAG, "setThreadId: " + threadId + "\n");
}
}
private void setSent(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_SENT) != 0) {
int msgType = 0;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
msgType = c.getInt(fi.mSmsColFolder);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
msgType = c.getInt(fi.mMmsColFolder);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
msgType = c.getInt(fi.mEmailColFolder);
}
String sent = null;
if (msgType == 2) {
sent = "yes";
} else {
sent = "no";
}
if (V) Log.d(TAG, "setSent: " + sent);
e.setSent(sent);
}
}
private void setRead(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
int read = 0;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
read = c.getInt(fi.mSmsColRead);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
read = c.getInt(fi.mMmsColRead);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
read = c.getInt(fi.mEmailColRead);
}
String setread = null;
if (V) Log.d(TAG, "setRead: " + setread);
e.setRead((read==1?true:false), ((ap.getParameterMask() & MASK_READ) != 0));
}
private void setPriority(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_PRIORITY) != 0) {
String priority = "no";
if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
int highPriority = c.getInt(fi.mEmailColPriority);
if (highPriority == 1) {
priority = "yes";
}
}
int pri = 0;
if (fi.mMsgType == FilterInfo.TYPE_MMS) {
pri = c.getInt(c.getColumnIndex(Mms.PRIORITY));
}
if (pri == PduHeaders.PRIORITY_HIGH) {
priority = "yes";
}
if (V) 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.mMsgType == FilterInfo.TYPE_MMS) {
if(c.getInt(fi.mMmsColTextOnly) == 0) {
size = c.getInt(fi.mMmsColAttachmentSize);
}
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
int attachment = c.getInt(fi.mEmailColAttachment);
size = c.getInt(fi.mEmailColAttachementSize);
if(attachment == 1 && size == 0) {
size = 1; /* Ensure we indicate we have attachments in the size, it the
message has attachments, in case the e-mail client do not
report a size */
}
}
if (V) 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.mMsgType == FilterInfo.TYPE_SMS) {
hasText = "yes";
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
int textOnly = c.getInt(fi.mMmsColTextOnly);
if (textOnly == 1) {
hasText = "yes";
} else {
long id = c.getLong(fi.mMmsColId);
String text = getTextPartsMms(id);
if (text != null && text.length() > 0) {
hasText = "yes";
} else {
hasText = "no";
}
}
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
hasText = "yes";
}
if (V) 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 (V) 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.mMsgType == FilterInfo.TYPE_SMS) {
String subject = c.getString(fi.mSmsColSubject);
size = subject.length();
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
size = c.getInt(fi.mMmsColSize);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
size = c.getInt(fi.mEmailColSize);
}
if (V) 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.mMsgType == FilterInfo.TYPE_SMS) {
if (fi.mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
type = TYPE.SMS_GSM;
} else if (fi.mPhoneType == TelephonyManager.PHONE_TYPE_CDMA) {
type = TYPE.SMS_CDMA;
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
type = TYPE.MMS;
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
type = TYPE.EMAIL;
}
if (V) Log.d(TAG, "setType: " + type);
e.setType(type);
}
}
private String setRecipientAddressingEmail(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi) {
String toAddress, ccAddress, bccAddress;
toAddress = c.getString(fi.mEmailColToAddress);
ccAddress = c.getString(fi.mEmailColCcAddress);
bccAddress = c.getString(fi.mEmailColBccAddress);
String address = "";
if (toAddress != null) {
address += toAddress;
if (ccAddress != null) {
address += ",";
}
}
if (ccAddress != null) {
address += ccAddress;
if (bccAddress != null) {
address += ",";
}
}
if (bccAddress != null) {
address += bccAddress;
}
return address;
}
private void setRecipientAddressing(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_RECIPIENT_ADDRESSING) != 0) {
String address = null;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
int msgType = c.getInt(fi.mSmsColType);
if (msgType == 1) {
address = fi.mPhoneNum;
} else {
address = c.getString(c.getColumnIndex(Sms.ADDRESS));
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
address = getAddressMms(mResolver, id, MMS_TO);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
/* Might be another way to handle addresses */
address = setRecipientAddressingEmail(e, c,fi);
}
if (V) Log.v(TAG, "setRecipientAddressing: " + address);
if(address == null)
address = "";
e.setRecipientAddressing(address);
}
}
private void setRecipientName(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_RECIPIENT_NAME) != 0) {
String name = null;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
int msgType = c.getInt(fi.mSmsColType);
if (msgType != 1) {
String phone = c.getString(fi.mSmsColAddress);
if (phone != null && !phone.isEmpty())
name = getContactNameFromPhone(phone);
} else {
name = fi.mPhoneAlphaTag;
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
long id = c.getLong(fi.mMmsColId);
String phone;
if(e.getRecipientAddressing() != null){
phone = getAddressMms(mResolver, id, MMS_TO);
} else {
phone = e.getRecipientAddressing();
}
if (phone != null && !phone.isEmpty())
name = getContactNameFromPhone(phone);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
/* Might be another way to handle address and names */
name = setRecipientAddressingEmail(e,c,fi);
}
if (V) Log.v(TAG, "setRecipientName: " + name);
if(name == null)
name = "";
e.setRecipientName(name);
}
}
private void setSenderAddressing(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_SENDER_ADDRESSING) != 0) {
String address = null;
String tempAddress;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
int msgType = c.getInt(fi.mSmsColType);
if (msgType == 1) { // INBOX
tempAddress = c.getString(fi.mSmsColAddress);
} else {
tempAddress = fi.mPhoneNum;
}
if(tempAddress == null) {
/* This can only happen on devices with no SIM -
hence will typically not have any SMS messages. */
} else {
address = PhoneNumberUtils.extractNetworkPortion(tempAddress);
/* extractNetworkPortion can return N if the number is a service "number" = a string
* with the a name in (i.e. "Some-Tele-company" would return N because of the N in compaNy)
* Hence we need to check if the number is actually a string with alpha chars.
* */
Boolean alpha = PhoneNumberUtils.stripSeparators(tempAddress).matches("[0-9]*[a-zA-Z]+[0-9]*");
if(address == null || address.length() < 2 || alpha) {
address = tempAddress; // if the number is a service acsii text just use it
}
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
long id = c.getLong(fi.mMmsColId);
tempAddress = getAddressMms(mResolver, id, MMS_FROM);
address = PhoneNumberUtils.extractNetworkPortion(tempAddress);
if(address == null || address.length() < 1){
address = tempAddress; // if the number is a service acsii text just use it
}
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
address = c.getString(fi.mEmailColFromAddress);
}
if (V) Log.v(TAG, "setSenderAddressing: " + address);
if(address == null)
address = "";
e.setSenderAddressing(address);
}
}
private void setSenderName(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_SENDER_NAME) != 0) {
String name = null;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
if (msgType == 1) {
String phone = c.getString(fi.mSmsColAddress);
if (phone != null && !phone.isEmpty())
name = getContactNameFromPhone(phone);
} else {
name = fi.mPhoneAlphaTag;
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
long id = c.getLong(fi.mMmsColId);
String phone;
if(e.getSenderAddressing() != null){
phone = getAddressMms(mResolver, id, MMS_FROM);
} else {
phone = e.getSenderAddressing();
}
if (phone != null && !phone.isEmpty() )
name = getContactNameFromPhone(phone);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
name = c.getString(fi.mEmailColFromAddress);
}
if (V) Log.v(TAG, "setSenderName: " + name);
if(name == null)
name = "";
e.setSenderName(name);
}
}
private void setDateTime(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
if ((ap.getParameterMask() & MASK_DATETIME) != 0) {
long date = 0;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
date = c.getLong(fi.mSmsColDate);
} else if (fi.mMsgType == 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(fi.mMmsColDate) * 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 if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
date = c.getLong(fi.mEmailColDate);
}
e.setDateTime(date);
if (V) Log.v(TAG, "setDateTime: " + e.getDateTimeString());
}
}
private String getTextPartsMms(long id) {
String text = "";
String selection = new String("mid=" + id);
String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/part");
Uri uriAddress = Uri.parse(uriStr);
// TODO: maybe use a projection with only "ct" and "text"
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")) {
String part = c.getString(c.getColumnIndex("text"));
if(part != null) {
text += part;
}
}
} 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 ((ap.getParameterMask() & MASK_SUBJECT) != 0) {
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
subject = c.getString(fi.mSmsColSubject);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
subject = c.getString(fi.mMmsColSubject);
if (subject == null || subject.length() == 0) {
/* Get subject from mms text body parts - if any exists */
long id = c.getLong(fi.mMmsColId);
subject = getTextPartsMms(id);
}
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
subject = c.getString(fi.mEmailColSubject);
}
if (subject != null && subject.length() > subLength) {
subject = subject.substring(0, subLength);
}
if (V) Log.d(TAG, "setSubject: " + subject);
e.setSubject(subject);
}
}
private void setHandle(BluetoothMapMessageListingElement e, Cursor c,
FilterInfo fi, BluetoothMapAppParams ap) {
long handle = -1;
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
handle = c.getLong(fi.mSmsColId);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
handle = c.getLong(fi.mMmsColId);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
handle = c.getLong(fi.mEmailColId);
}
if (V) Log.d(TAG, "setHandle: " + handle );
e.setHandle(handle);
}
private BluetoothMapMessageListingElement element(Cursor c, FilterInfo fi,
BluetoothMapAppParams ap) {
BluetoothMapMessageListingElement e = new BluetoothMapMessageListingElement();
setHandle(e, c, fi, ap);
setDateTime(e, c, fi, ap);
setType(e, c, fi, ap);
setRead(e, c, fi, ap);
// we set number and name for sender/recipient later
// they require lookup on contacts so no need to
// do it for all elements unless they are to be used.
e.setCursorIndex(c.getPosition());
return e;
}
private String getContactNameFromPhone(String phone) {
String name = 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.DISPLAY_NAME + " ASC";
Cursor c = mResolver.query(uri, projection, selection, null, orderBy);
if (c != null && c.getCount() >= 1) {
c.moveToFirst();
name = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME));
}
c.close();
return name;
}
static public String getAddressMms(ContentResolver r, long id, int type) {
String selection = new String("msg_id=" + id + " AND type=" + type);
String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr");
Uri uriAddress = Uri.parse(uriStr);
String addr = null;
Cursor c = r.query(uriAddress, null, selection, null, null);
if (c != null && c.moveToFirst()) {
addr = c.getString(c.getColumnIndex(Mms.Addr.ADDRESS));
if(addr.equals(INSERT_ADDRES_TOKEN))
addr = "";
}
if (c != null) {
c.close();
}
return addr;
}
/**
* Matching functions for originator and recipient for MMS
* @return true if found a match
*/
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 (V) Log.v(TAG, "matchRecipientMms: match recipient phone = " + phone);
res = true;
} else {
String name = getContactNameFromPhone(phone);
if (name != null && name.length() > 0 && name.matches(recip)) {
if (V) Log.v(TAG, "matchRecipientMms: 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.mPhoneNum;
String name = fi.mPhoneAlphaTag;
if (phone != null && phone.length() > 0 && phone.matches(recip)) {
if (V) Log.v(TAG, "matchRecipientSms: match recipient phone = " + phone);
res = true;
} else if (name != null && name.length() > 0 && name.matches(recip)) {
if (V) Log.v(TAG, "matchRecipientSms: 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.matches(recip)) {
if (V) Log.v(TAG, "matchRecipientSms: match recipient phone = " + phone);
res = true;
} else {
String name = getContactNameFromPhone(phone);
if (name != null && name.length() > 0 && name.matches(recip)) {
if (V) Log.v(TAG, "matchRecipientSms: 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.mMsgType == FilterInfo.TYPE_SMS) {
res = matchRecipientSms(c, fi, recip);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
res = matchRecipientMms(c, fi, recip);
} else {
if (D) Log.d(TAG, "matchRecipient: Unknown msg type: " + fi.mMsgType);
res = false;
}
} else {
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 (V) Log.v(TAG, "matchOriginatorMms: match originator phone = " + phone);
res = true;
} else {
String name = getContactNameFromPhone(phone);
if (name != null && name.length() > 0 && name.matches(orig)) {
if (V) Log.v(TAG, "matchOriginatorMms: 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.matches(orig)) {
if (V) Log.v(TAG, "matchOriginatorSms: match originator phone = " + phone);
res = true;
} else {
String name = getContactNameFromPhone(phone);
if (name != null && name.length() > 0 && name.matches(orig)) {
if (V) Log.v(TAG, "matchOriginatorSms: match originator name = " + name);
res = true;
} else {
res = false;
}
}
} else {
res = false;
}
} else {
String phone = fi.mPhoneNum;
String name = fi.mPhoneAlphaTag;
if (phone != null && phone.length() > 0 && phone.matches(orig)) {
if (V) Log.v(TAG, "matchOriginatorSms: match originator phone = " + phone);
res = true;
} else if (name != null && name.length() > 0 && name.matches(orig)) {
if (V) Log.v(TAG, "matchOriginatorSms: 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.mMsgType == FilterInfo.TYPE_SMS) {
res = matchOriginatorSms(c, fi, orig);
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
res = matchOriginatorMms(c, fi, orig);
} else {
if(D) Log.d(TAG, "matchOriginator: Unknown msg type: " + fi.mMsgType);
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;
}
}
/*
* Where filter functions
* */
private String setWhereFilterFolderTypeSms(String folder) {
String where = "";
if (BluetoothMapContract.FOLDER_NAME_INBOX.equalsIgnoreCase(folder)) {
where = Sms.TYPE + " = 1 AND " + Sms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_OUTBOX.equalsIgnoreCase(folder)) {
where = "(" + Sms.TYPE + " = 4 OR " + Sms.TYPE + " = 5 OR "
+ Sms.TYPE + " = 6) AND " + Sms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) {
where = Sms.TYPE + " = 2 AND " + Sms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) {
where = Sms.TYPE + " = 3 AND " + Sms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) {
where = Sms.THREAD_ID + " = -1";
}
return where;
}
private String setWhereFilterFolderTypeMms(String folder) {
String where = "";
if (BluetoothMapContract.FOLDER_NAME_INBOX.equalsIgnoreCase(folder)) {
where = Mms.MESSAGE_BOX + " = 1 AND " + Mms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_OUTBOX.equalsIgnoreCase(folder)) {
where = Mms.MESSAGE_BOX + " = 4 AND " + Mms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) {
where = Mms.MESSAGE_BOX + " = 2 AND " + Mms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) {
where = Mms.MESSAGE_BOX + " = 3 AND " + Mms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) {
where = Mms.THREAD_ID + " = -1";
}
return where;
}
private String setWhereFilterFolderTypeEmail(long folderId) {
String where = "";
if (folderId >= 0) {
where = BluetoothMapContract.MessageColumns.FOLDER_ID + " = " + folderId;
} else {
Log.e(TAG, "setWhereFilterFolderTypeEmail: not valid!" );
throw new IllegalArgumentException("Invalid folder ID");
}
return where;
}
private String setWhereFilterFolderType(BluetoothMapFolderElement folderElement, FilterInfo fi) {
String where = "";
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
where = setWhereFilterFolderTypeSms(folderElement.getName());
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
where = setWhereFilterFolderTypeMms(folderElement.getName());
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
where = setWhereFilterFolderTypeEmail(folderElement.getEmailFolderId());
}
return where;
}
private String setWhereFilterReadStatus(BluetoothMapAppParams ap, FilterInfo fi) {
String where = "";
if (ap.getFilterReadStatus() != -1) {
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
if ((ap.getFilterReadStatus() & 0x01) != 0) {
where = " AND " + Sms.READ + "= 0";
}
if ((ap.getFilterReadStatus() & 0x02) != 0) {
where = " AND " + Sms.READ + "= 1";
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
if ((ap.getFilterReadStatus() & 0x01) != 0) {
where = " AND " + Mms.READ + "= 0";
}
if ((ap.getFilterReadStatus() & 0x02) != 0) {
where = " AND " + Mms.READ + "= 1";
}
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
if ((ap.getFilterReadStatus() & 0x01) != 0) {
where = " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "= 0";
}
if ((ap.getFilterReadStatus() & 0x02) != 0) {
where = " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "= 1";
}
}
}
return where;
}
private String setWhereFilterPeriod(BluetoothMapAppParams ap, FilterInfo fi) {
String where = "";
if ((ap.getFilterPeriodBegin() != -1)) {
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
where = " AND " + Sms.DATE + " >= " + ap.getFilterPeriodBegin();
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
where = " AND " + Mms.DATE + " >= " + (ap.getFilterPeriodBegin() / 1000L);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
where = " AND " + BluetoothMapContract.MessageColumns.DATE + " >= " + (ap.getFilterPeriodBegin());
}
}
if ((ap.getFilterPeriodEnd() != -1)) {
if (fi.mMsgType == FilterInfo.TYPE_SMS) {
where += " AND " + Sms.DATE + " < " + ap.getFilterPeriodEnd();
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
where += " AND " + Mms.DATE + " < " + (ap.getFilterPeriodEnd() / 1000L);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
where += " AND " + BluetoothMapContract.MessageColumns.DATE + " < " + (ap.getFilterPeriodEnd());
}
}
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");
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);
while (p != null && p.moveToNext()) {
String number = p.getString(
p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
where += " address = " + "'" + number + "'";
if (!p.isLast()) {
where += " OR ";
}
}
if (!c.isLast()) {
where += " OR ";
}
p.close();
}
c.close();
if (str != null && str.length() > 0) {
if (where.length() > 0) {
where += " OR ";
}
where += " address like " + "'" + str + "'";
}
return where;
}
private String setWhereFilterOriginatorEmail(BluetoothMapAppParams ap) {
String where = "";
String orig = ap.getFilterOriginator();
/* Be aware of wild cards in the beginning of string, may not be valid? */
if (orig != null && orig.length() > 0) {
orig = orig.replace("*", "%");
where = " AND " + BluetoothMapContract.MessageColumns.FROM_LIST + " LIKE '%" + orig + "%'";
}
return where;
}
private String setWhereFilterPriority(BluetoothMapAppParams ap, FilterInfo fi) {
String where = "";
int pri = ap.getFilterPriority();
/*only MMS have priority info */
if(fi.mMsgType == 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 setWhereFilterRecipientEmail(BluetoothMapAppParams ap) {
String where = "";
String recip = ap.getFilterRecipient();
/* Be aware of wild cards in the beginning of string, may not be valid? */
if (recip != null && recip.length() > 0) {
recip = recip.replace("*", "%");
where = " AND ("
+ BluetoothMapContract.MessageColumns.TO_LIST + " LIKE '%" + recip + "%' OR "
+ BluetoothMapContract.MessageColumns.CC_LIST + " LIKE '%" + recip + "%' OR "
+ BluetoothMapContract.MessageColumns.BCC_LIST + " LIKE '%" + recip + "%' )";
}
return where;
}
private String setWhereFilter(BluetoothMapFolderElement folderElement,
FilterInfo fi, BluetoothMapAppParams ap) {
String where = "";
where += setWhereFilterFolderType(folderElement, fi);
if(!where.isEmpty()) {
where += setWhereFilterReadStatus(ap, fi);
where += setWhereFilterPeriod(ap, fi);
where += setWhereFilterPriority(ap,fi);
if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
where += setWhereFilterOriginatorEmail(ap);
where += setWhereFilterRecipientEmail(ap);
}
}
return where;
}
/**
* Determine from application parameter if sms should be included.
* The filter mask is set for message types not selected
* @param fi
* @param ap
* @return boolean true if sms is selected, false if not
*/
private boolean smsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
int msgType = ap.getFilterMessageType();
int phoneType = fi.mPhoneType;
if (D) Log.d(TAG, "smsSelected msgType: " + msgType);
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;
}
/**
* Determine from application parameter if mms should be included.
* The filter mask is set for message types not selected
* @param fi
* @param ap
* @return boolean true if sms is selected, false if not
*/
private boolean mmsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
int msgType = ap.getFilterMessageType();
if (D) Log.d(TAG, "mmsSelected msgType: " + msgType);
if (msgType == -1)
return true;
if ((msgType & 0x08) == 0)
return true;
return false;
}
/**
* Determine from application parameter if email should be included.
* The filter mask is set for message types not selected
* @param fi
* @param ap
* @return boolean true if sms is selected, false if not
*/
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;
return false;
}
private void setFilterInfo(FilterInfo fi) {
TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm != null) {
fi.mPhoneType = tm.getPhoneType();
fi.mPhoneNum = tm.getLine1Number();
fi.mPhoneAlphaTag = tm.getLine1AlphaTag();
if (D) Log.d(TAG, "phone type = " + fi.mPhoneType +
" phone num = " + fi.mPhoneNum +
" phone alpha tag = " + fi.mPhoneAlphaTag);
}
}
/**
* Get a listing of message in folder after applying filter.
* @param folder Must contain a valid folder string != null
* @param ap Parameters specifying message content and filters
* @return Listing object containing requested messages
*/
public BluetoothMapMessageListing msgListing(BluetoothMapFolderElement folderElement,
BluetoothMapAppParams ap) {
if (D) Log.d(TAG, "msgListing: folderName = " + folderElement.getName()
+ " folderId = " + folderElement.getEmailFolderId()
+ " messageType = " + ap.getFilterMessageType() );
BluetoothMapMessageListing bmList = new BluetoothMapMessageListing();
/* 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.v(TAG, "msgListing(): appParameterMask is zero or not present, " +
"changing to: " + ap.getParameterMask());
}
/* Cache some info used throughout filtering */
FilterInfo fi = new FilterInfo();
setFilterInfo(fi);
Cursor smsCursor = null;
Cursor mmsCursor = null;
Cursor emailCursor = null;
String limit = "";
int countNum = ap.getMaxListCount();
int offsetNum = ap.getStartOffset();
if(ap.getMaxListCount()>0){
limit=" LIMIT "+ (ap.getMaxListCount()+ap.getStartOffset());
}
if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL|
BluetoothMapAppParams.FILTER_NO_MMS|
BluetoothMapAppParams.FILTER_NO_SMS_GSM)||
ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL|
BluetoothMapAppParams.FILTER_NO_MMS|
BluetoothMapAppParams.FILTER_NO_SMS_CDMA)){
//set real limit and offset if only this type is used (only if offset/limit is used
limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset();
if(D) Log.d(TAG, "SMS Limit => "+limit);
offsetNum = 0;
}
fi.mMsgType = FilterInfo.TYPE_SMS;
if(ap.getFilterPriority() != 1){ /*SMS cannot have high priority*/
String where = setWhereFilter(folderElement, fi, ap);
if(!where.isEmpty()) {
if (D) Log.d(TAG, "msgType: " + fi.mMsgType);
smsCursor = mResolver.query(Sms.CONTENT_URI,
SMS_PROJECTION, where, null, Sms.DATE + " DESC" + limit);
if (smsCursor != null) {
BluetoothMapMessageListingElement e = null;
// store column index so we dont have to look them up anymore (optimization)
if(D) Log.d(TAG, "Found " + smsCursor.getCount() + " sms messages.");
fi.setSmsColumns(smsCursor);
while (smsCursor.moveToNext()) {
if (matchAddresses(smsCursor, fi, ap)) {
if(V) printSms(smsCursor);
e = element(smsCursor, fi, ap);
bmList.add(e);
}
}
}
}
}
}
if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL|
BluetoothMapAppParams.FILTER_NO_SMS_CDMA|
BluetoothMapAppParams.FILTER_NO_SMS_GSM)){
//set real limit and offset if only this type is used (only if offset/limit is used
limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset();
if(D) Log.d(TAG, "MMS Limit => "+limit);
offsetNum = 0;
}
fi.mMsgType = FilterInfo.TYPE_MMS;
String where = setWhereFilter(folderElement, fi, ap);
if(!where.isEmpty()) {
if (D) Log.d(TAG, "msgType: " + fi.mMsgType);
mmsCursor = mResolver.query(Mms.CONTENT_URI,
MMS_PROJECTION, where, null, Mms.DATE + " DESC" + limit);
if (mmsCursor != null) {
BluetoothMapMessageListingElement e = null;
// store column index so we dont have to look them up anymore (optimization)
fi.setMmsColumns(mmsCursor);
int cnt = 0;
if(D) Log.d(TAG, "Found " + mmsCursor.getCount() + " mms messages.");
while (mmsCursor.moveToNext()) {
if (matchAddresses(mmsCursor, fi, ap)) {
if(V) printMms(mmsCursor);
e = element(mmsCursor, fi, ap);
bmList.add(e);
}
}
}
}
}
if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) {
if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_MMS|
BluetoothMapAppParams.FILTER_NO_SMS_CDMA|
BluetoothMapAppParams.FILTER_NO_SMS_GSM)){
//set real limit and offset if only this type is used (only if offset/limit is used
limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset();
if(D) Log.d(TAG, "Email Limit => "+limit);
offsetNum = 0;
}
fi.mMsgType = FilterInfo.TYPE_EMAIL;
String where = setWhereFilter(folderElement, fi, ap);
if(!where.isEmpty()) {
if (D) Log.d(TAG, "msgType: " + fi.mMsgType);
Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE);
emailCursor = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION,
where, null, BluetoothMapContract.MessageColumns.DATE + " DESC" + limit);
if (emailCursor != null) {
BluetoothMapMessageListingElement e = null;
// store column index so we dont have to look them up anymore (optimization)
fi.setEmailColumns(emailCursor);
int cnt = 0;
while (emailCursor.moveToNext()) {
if(V) printEmail(emailCursor);
if(D) Log.d(TAG, "Found " + emailCursor.getCount() + " email messages.");
e = element(emailCursor, fi, ap);
bmList.add(e);
}
// emailCursor.close();
}
}
}
/* Enable this if post sorting and segmenting needed */
bmList.sort();
bmList.segment(ap.getMaxListCount(), offsetNum);
List<BluetoothMapMessageListingElement> list = bmList.getList();
int listSize = list.size();
Cursor tmpCursor = null;
for(int x=0;x<listSize;x++){
BluetoothMapMessageListingElement ele = list.get(x);
if((ele.getType().equals(TYPE.SMS_GSM)||ele.getType().equals(TYPE.SMS_CDMA)) && smsCursor != null){
tmpCursor = smsCursor;
fi.mMsgType = FilterInfo.TYPE_SMS;
}else if(ele.getType().equals(TYPE.MMS) && mmsCursor != null){
tmpCursor = mmsCursor;
fi.mMsgType = FilterInfo.TYPE_MMS;
}else if(ele.getType().equals(TYPE.EMAIL) && emailCursor != null){
tmpCursor = emailCursor;
fi.mMsgType = FilterInfo.TYPE_EMAIL;
}
if(tmpCursor != null){
tmpCursor.moveToPosition(ele.getCursorIndex());
setSenderAddressing(ele, tmpCursor, fi, ap);
setSenderName(ele, tmpCursor, fi, ap);
setRecipientAddressing(ele, tmpCursor, fi, ap);
setRecipientName(ele, tmpCursor, fi, ap);
setSubject(ele, tmpCursor, fi, ap);
setSize(ele, tmpCursor, fi, ap);
setReceptionStatus(ele, tmpCursor, fi, ap);
setText(ele, tmpCursor, fi, ap);
setAttachmentSize(ele, tmpCursor, fi, ap);
setPriority(ele, tmpCursor, fi, ap);
setSent(ele, tmpCursor, fi, ap);
setProtected(ele, tmpCursor, fi, ap);
setThreadId(ele, tmpCursor, fi, ap);
}
}
if(emailCursor != null)emailCursor.close();
if(smsCursor != null)smsCursor.close();
if(mmsCursor != null)mmsCursor.close();
if(D)Log.d(TAG, "messagelisting end");
return bmList;
}
/**
* Get the size of the message listing
* @param folder Must contain a valid folder string != null
* @param ap Parameters specifying message content and filters
* @return Integer equal to message listing size
*/
public int msgListingSize(BluetoothMapFolderElement folderElement,
BluetoothMapAppParams ap) {
if (D) Log.d(TAG, "msgListingSize: folder = " + folderElement.getName());
int cnt = 0;
/* Cache some info used throughout filtering */
FilterInfo fi = new FilterInfo();
setFilterInfo(fi);
if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
fi.mMsgType = FilterInfo.TYPE_SMS;
String where = setWhereFilter(folderElement, fi, ap);
Cursor c = mResolver.query(Sms.CONTENT_URI,
SMS_PROJECTION, where, null, Sms.DATE + " DESC");
if (c != null) {
cnt = c.getCount();
c.close();
}
}
if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
fi.mMsgType = FilterInfo.TYPE_MMS;
String where = setWhereFilter(folderElement, fi, ap);
Cursor c = mResolver.query(Mms.CONTENT_URI,
MMS_PROJECTION, where, null, Mms.DATE + " DESC");
if (c != null) {
cnt += c.getCount();
c.close();
}
}
if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) {
fi.mMsgType = FilterInfo.TYPE_EMAIL;
String where = setWhereFilter(folderElement, fi, ap);
if(!where.isEmpty()) {
Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE);
Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION,
where, null, BluetoothMapContract.MessageColumns.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(BluetoothMapFolderElement folderElement,
BluetoothMapAppParams ap) {
if (D) Log.d(TAG, "msgListingHasUnread: folder = " + folderElement.getName());
int cnt = 0;
/* Cache some info used throughout filtering */
FilterInfo fi = new FilterInfo();
setFilterInfo(fi);
if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
fi.mMsgType = FilterInfo.TYPE_SMS;
String where = setWhereFilterFolderType(folderElement, fi);
where += " AND " + Sms.READ + "=0 ";
where += setWhereFilterPeriod(ap, fi);
Cursor c = mResolver.query(Sms.CONTENT_URI,
SMS_PROJECTION, where, null, Sms.DATE + " DESC");
if (c != null) {
cnt = c.getCount();
c.close();
}
}
if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) {
fi.mMsgType = FilterInfo.TYPE_MMS;
String where = setWhereFilterFolderType(folderElement, fi);
where += " AND " + Mms.READ + "=0 ";
where += setWhereFilterPeriod(ap, fi);
Cursor c = mResolver.query(Mms.CONTENT_URI,
MMS_PROJECTION, where, null, Sms.DATE + " DESC");
if (c != null) {
cnt += c.getCount();
c.close();
}
}
if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) {
fi.mMsgType = FilterInfo.TYPE_EMAIL;
String where = setWhereFilterFolderType(folderElement, fi);
if(!where.isEmpty()) {
where += " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "=0 ";
where += setWhereFilterPeriod(ap, fi);
Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE);
Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION,
where, null, BluetoothMapContract.MessageColumns.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 BluetoothMapContract.FOLDER_NAME_DELETED;
switch(type) {
case 1:
return BluetoothMapContract.FOLDER_NAME_INBOX;
case 2:
return BluetoothMapContract.FOLDER_NAME_SENT;
case 3:
return BluetoothMapContract.FOLDER_NAME_DRAFT;
case 4: // Just name outbox, failed and queued "outbox"
case 5:
case 6:
return BluetoothMapContract.FOLDER_NAME_OUTBOX;
}
return "";
}
public byte[] getMessage(String handle, BluetoothMapAppParams appParams,
BluetoothMapFolderElement folderElement) throws UnsupportedEncodingException{
TYPE type = BluetoothMapUtils.getMsgTypeFromHandle(handle);
long id = BluetoothMapUtils.getCpHandle(handle);
if(appParams.getFractionRequest() == BluetoothMapAppParams.FRACTION_REQUEST_NEXT) {
throw new IllegalArgumentException("FRACTION_REQUEST_NEXT does not make sence as" +
" we always return the full message.");
}
switch(type) {
case SMS_GSM:
case SMS_CDMA:
return getSmsMessage(id, appParams.getCharset());
case MMS:
return getMmsMessage(id, appParams);
case EMAIL:
return getEmailMessage(id, appParams, folderElement);
}
throw new IllegalArgumentException("Invalid message handle.");
}
private String setVCardFromPhoneNumber(BluetoothMapbMessage message, String phone, boolean incoming) {
String contactId = null, contactName = null;
String[] phoneNumbers = null;
String[] emailAddresses = null;
Cursor p;
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
p = mResolver.query(uri, projection, selection, null, orderBy);
if (p != null && p.getCount() >= 1) {
p.moveToFirst();
contactId = p.getString(p.getColumnIndex(Contacts._ID));
contactName = p.getString(p.getColumnIndex(Contacts.DISPLAY_NAME));
}
p.close();
// 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
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;
}
p.close();
}
}
if(incoming == true) {
if(V) Log.d(TAG, "Adding originator for phone:" + phone);
message.addOriginator(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
} else {
if(V) Log.d(TAG, "Adding recipient for phone:" + phone);
message.addRecipient(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
}
return contactName;
}
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())
{
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);
}
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);
}
c.close();
return message.encode();
}
throw new IllegalArgumentException("SMS handle not found");
}
private void extractMmsAddresses(long id, BluetoothMapbMessageMms message) {
final String[] projection = null;
String selection = new String(Mms.Addr.MSG_ID + "=" + id);
String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr");
Uri uriAddress = Uri.parse(uriStr);
String contactName = null;
Cursor c = mResolver.query( uriAddress, projection, selection, null, null);
if (c.moveToFirst()) {
do {
String address = c.getString(c.getColumnIndex(Mms.Addr.ADDRESS));
if(address.equals(INSERT_ADDRES_TOKEN))
continue;
Integer type = c.getInt(c.getColumnIndex(Mms.Addr.TYPE));
switch(type) {
case MMS_FROM:
contactName = setVCardFromPhoneNumber(message, address, true);
message.addFrom(contactName, address);
break;
case MMS_TO:
contactName = setVCardFromPhoneNumber(message, address, false);
message.addTo(contactName, address);
break;
case MMS_CC:
contactName = setVCardFromPhoneNumber(message, address, false);
message.addCc(contactName, address);
break;
case MMS_BCC:
contactName = setVCardFromPhoneNumber(message, address, false);
message.addBcc(contactName, address);
break;
default:
break;
}
} while(c.moveToNext());
}
}
/**
* 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 = new String(Mms.CONTENT_URI + "/part/" + 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;
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();
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, BluetoothMapbMessageMms message)
{
/* Handling of filtering out non-text parts for exclude
* attachments is handled within the bMessage object. */
final String[] projection = null;
String selection = new String(Mms.Part.MSG_ID + "=" + id);
String uriStr = new String(Mms.CONTENT_URI + "/"+ id + "/part");
Uri uriAddress = Uri.parse(uriStr);
BluetoothMapbMessageMms.MimePart part;
Cursor c = mResolver.query(
uriAddress,
projection,
selection,
null, null);
if (c.moveToFirst()) {
do {
Long partId = c.getLong(c.getColumnIndex(BaseColumns._ID));
String contentType = c.getString(c.getColumnIndex(Mms.Part.CONTENT_TYPE));
String name = c.getString(c.getColumnIndex(Mms.Part.NAME));
String charset = c.getString(c.getColumnIndex(Mms.Part.CHARSET));
String filename = c.getString(c.getColumnIndex(Mms.Part.FILENAME));
String text = c.getString(c.getColumnIndex(Mms.Part.TEXT));
Integer fd = c.getInt(c.getColumnIndex(Mms.Part._DATA));
String cid = c.getString(c.getColumnIndex(Mms.Part.CONTENT_ID));
String cl = c.getString(c.getColumnIndex(Mms.Part.CONTENT_LOCATION));
String cdisp = c.getString(c.getColumnIndex(Mms.Part.CONTENT_DISPOSITION));
if(V) 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.mContentType = contentType;
part.mPartName = name;
part.mContentId = cid;
part.mContentLocation = cl;
part.mContentDisposition = cdisp;
try {
if(text != null) {
part.mData = text.getBytes("UTF-8");
part.mCharsetName = "utf-8";
} else {
part.mData = readMmsDataPart(partId);
if(charset != null)
part.mCharsetName = CharacterSets.getMimeName(Integer.parseInt(charset));
}
} catch (NumberFormatException e) {
Log.d(TAG,"extractMmsParts",e);
part.mData = null;
part.mCharsetName = null;
} catch (UnsupportedEncodingException e) {
Log.d(TAG,"extractMmsParts",e);
part.mData = null;
part.mCharsetName = null;
} finally {
}
part.mFileName = filename;
} while(c.moveToNext());
}
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;
if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE)
throw new IllegalArgumentException("MMS charset native not allowed for MMS - must be utf-8");
BluetoothMapbMessageMms message = new BluetoothMapbMessageMms();
Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, "_ID = " + id, null, null);
if(c != null && c.moveToFirst())
{
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);
message.setIncludeAttachments(appParams.getAttachment() == 0 ? false : true);
// c.getLong(c.getColumnIndex(Mms.DATE_SENT)); - this is never used
// c.getInt(c.getColumnIndex(Mms.STATUS)); - don't know what this is
// The parts
extractMmsParts(id, message);
// The addresses
extractMmsAddresses(id, message);
c.close();
return message.encode();
} else if(c != null) {
c.close();
}
throw new IllegalArgumentException("MMS handle not found");
}
/**
*
* @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,
BluetoothMapFolderElement currentFolder) throws UnsupportedEncodingException {
// Log print out of application parameters set
if(D && appParams != null) {
Log.d(TAG,"TYPE_MESSAGE (GET): Attachment = " + appParams.getAttachment() +
", Charset = " + appParams.getCharset() +
", FractionRequest = " + appParams.getFractionRequest());
}
// Throw exception if requester NATIVE charset for Email
// Exception is caught by MapObexServer sendGetMessageResp
if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE)
throw new IllegalArgumentException("EMAIL charset not UTF-8");
BluetoothMapbMessageEmail message = new BluetoothMapbMessageEmail();
Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE);
Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION, "_ID = " + id, null, null);
if(c != null && c.moveToFirst())
{
BluetoothMapFolderElement folderElement;
FileInputStream is = null;
ParcelFileDescriptor fd = null;
// Handle fraction requests
int fractionRequest = appParams.getFractionRequest();
if (fractionRequest != BluetoothMapAppParams.INVALID_VALUE_PARAMETER) {
// Fraction requested
if(V) {
String fractionStr = (fractionRequest == 0) ? "FIRST" : "NEXT";
Log.v(TAG, "getEmailMessage - FractionRequest " + fractionStr
+ " - send compete message" );
}
// Check if message is complete and if not - request message from server
if (c.getString(c.getColumnIndex(
BluetoothMapContract.MessageColumns.RECEPTION_STATE)).equalsIgnoreCase(
BluetoothMapContract.RECEPTION_STATE_COMPLETE) == false) {
// TODO: request message from server
Log.w(TAG, "getEmailMessage - receptionState not COMPLETE - Not Implemented!" );
}
}
// Set read status:
String read = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ));
if (read != null && read.equalsIgnoreCase("1"))
message.setStatus(true);
else
message.setStatus(false);
// Set message type:
message.setType(TYPE.EMAIL);
// Set folder:
long folderId = c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID));
folderElement = currentFolder.getEmailFolderById(folderId);
message.setCompleteFolder(folderElement.getFullPath());
// Set recipient:
String nameEmail = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST));
Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(nameEmail);
if (tokens.length != 0) {
if(D) Log.d(TAG, "Recipient count= " + tokens.length);
int i = 0;
while (i < tokens.length) {
if(V) Log.d(TAG, "Recipient = " + tokens[i].toString());
String[] emails = new String[1];
emails[0] = tokens[i].getAddress();
String name = tokens[i].getName();
message.addRecipient(name, name, null, emails);
i++;
}
}
// Set originator:
nameEmail = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST));
tokens = Rfc822Tokenizer.tokenize(nameEmail);
if (tokens.length != 0) {
if(D) Log.d(TAG, "Originator count= " + tokens.length);
int i = 0;
while (i < tokens.length) {
if(V) Log.d(TAG, "Originator = " + tokens[i].toString());
String[] emails = new String[1];
emails[0] = tokens[i].getAddress();
String name = tokens[i].getName();
message.addOriginator(name, name, null, emails);
i++;
}
}
c.close();
// Find out if we get attachments
String attStr = (appParams.getAttachment() == 0) ? "/" + BluetoothMapContract.FILE_MSG_NO_ATTACHMENTS : "";
Uri uri = Uri.parse(contentUri + "/" + id + attStr);
// Get email message body content
int count = 0;
try {
fd = mResolver.openFileDescriptor(uri, "r");
is = new FileInputStream(fd.getFileDescriptor());
StringBuilder email = new StringBuilder("");
byte[] buffer = new byte[1024];
while((count = is.read(buffer)) != -1) {
// TODO: Handle breaks within a UTF8 character
email.append(new String(buffer,0,count));
if(V) Log.d(TAG, "Email part = " + new String(buffer,0,count) + " count=" + count);
}
// Set email message body:
message.setEmailBody(email.toString());
} catch (FileNotFoundException e) {
Log.w(TAG, e);
} catch (NullPointerException e) {
Log.w(TAG, e);
} catch (IOException e) {
Log.w(TAG, e);
}
finally {
try {
if(is != null)
is.close();
} catch (IOException e) {}
try {
if(fd != null)
fd.close();
} catch (IOException e) {}
}
return message.encode();
} else if(c != null) {
c.close();
}
throw new IllegalArgumentException("EMAIL handle not found");
}
}