Map: Fix map multi recipient email issue
Use case:
1. Push an email from carkit to different email addresses
in to and cc fields.
2. Check sent folder in email app
Observed result:
Two separate emails are sent for to and cc email addresses.
Fix:
Parse CC and BCC emails from message body, later create list of
recipients based on parsed list and send single email with
all recipients info.
CRs-Fixed: 2388785
Change-Id: Ia57a10ac7f4b6b9234e9696b15e0c3b5ff0ccdf3
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
index a4873e0..0e3e56f 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
@@ -847,13 +847,17 @@
if (D) Log.d(TAG, "pushMessage emailBaseUri: "+emailBaseUri);
ArrayList<BluetoothMapbMessage.VCard> recipientList = msg.getRecipients();
ArrayList<BluetoothMapbMessage.VCard> originatorList = msg.getOriginators();
+ ArrayList<String> emailsTo = msg.getmRecipientTo();
+ ArrayList<String> emailsCc = msg.getmRecipientCc();
+ ArrayList<String> emailsBcc = msg.getmRecipientBCc();
+ int max_env_level = 3; // The maximum level of encapsulation shall be three
int transparent = (ap.getTransparent() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) ?
0 : ap.getTransparent();
int retry = ap.getRetry();
int charset = ap.getCharset();
long handle = -1;
long folderId = -1;
- if (recipientList == null) {
+ if (recipientList == null || recipientList.size() == 0) {
if (D) Log.d(TAG, "empty recipient list");
return -1;
}
@@ -877,92 +881,127 @@
Log.v(TAG, "part " + i + ":" + messages[i]);
}
}
- String toAddress[] = null;
+ StringBuilder addressCc = new StringBuilder();
+ StringBuilder addressBcc = new StringBuilder();
+ StringBuilder addressTo = new StringBuilder();
+ if (D) Log.v(TAG," pushMessage recipientList size:" + recipientList.size());
for (BluetoothMapbMessage.VCard recipient : recipientList) {
- if(recipient.getEnvLevel() == 0) // Only send the message to the top level recipient
- toAddress = ((BluetoothMapbMessage.VCard)recipient).getEmailAddresses();
- Uri uriInsert = BluetoothMapEmailContract
- .buildEmailMessageUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
- if (D) Log.d(TAG, "pushMessage - uriInsert= " + uriInsert.toString() +
- ", intoFolder id=" + folderElement.getFolderId());
- synchronized(getMsgListMsg()) {
- // Now insert the empty message into folder
- ContentValues values = new ContentValues();
- Time timeObj = new Time();
- timeObj.setToNow();
- folderId = folderElement.getFolderId();
- values.put(BluetoothMapEmailContract.ExtEmailMessageColumns.MAILBOX_KEY,
- folderId);
- if(((BluetoothMapbMessageExtEmail)msg).getSubject() != null) {
- values.put(BluetoothMapContract.MessageColumns.SUBJECT,
- ((BluetoothMapbMessageExtEmail)msg).getSubject());
- } else {
- values.put(BluetoothMapContract.MessageColumns.SUBJECT, "");
+ if (recipient.getEnvLevel() < max_env_level) {
+ String address[] = ((BluetoothMapbMessage.VCard)recipient).getEmailAddresses();
+ for (String s : address) {
+ if (emailsTo.contains(s)) {
+ addressTo.append(s);
+ addressTo.append(";");
+ } else if (emailsCc.contains(s)) {
+ addressCc.append(s);
+ addressCc.append(";");
+ } else if (emailsBcc.contains(s)) {
+ addressBcc.append(s);
+ addressBcc.append(";");
+ } else {
+ if (D) Log.d(TAG, "Ignoring extra address < " + s + " >");
+ }
}
- values.put("syncServerTimeStamp", 0);
- values.put("timeStamp", timeObj.toMillis(false));
- values.put("flagLoaded", "1");
- values.put("flagFavorite", "0");
- values.put("flagAttachment", "0");
- if(folderElement.getName().equalsIgnoreCase(BluetoothMapContract
- .FOLDER_NAME_DRAFT) || folderElement.getName()
- .equalsIgnoreCase(BluetoothMapEmailContract.FOLDER_NAME_DRAFTS)) {
- values.put("flags", "1179648");
- } else
- values.put("flags", "0");
- String splitStr[] = emailBaseUri.split("/");
- for (String str: splitStr)
- Log.d(TAG,"seg for mBaseUri: "+ str);
- if (mAccount != null) {
- values.put("accountKey", mAccount.getAccountId());
- values.put("displayName", mAccount.getDisplayName());
- values.put("fromList", mAccount.getEmailAddress());
- }
- values.put("mailboxKey", folderId);
- StringBuilder address = new StringBuilder();
- for (String s : toAddress) {
- address.append(s);
- address.append(";");
- }
- values.put("toList", address.toString().trim());
- values.put("flagRead", 0);
- Uri uriNew = mProviderClient.insert(uriInsert, values);
- if (D) Log.d(TAG, "pushMessage - uriNew= " + uriNew.toString());
- handle = Long.parseLong(uriNew.getLastPathSegment());
- if (V) {
- Log.v(TAG, " NEW HANDLE " + handle);
- }
- if(handle == -1) {
- Log.v(TAG, " Inavlid Handle ");
- return -1;
- }
- //Insert msgBody in DB Provider BODY TABLE
- ContentValues valuesBody = new ContentValues();
- valuesBody.put("messageKey", String.valueOf(handle));
- valuesBody.put("textContent", msgBody);
- Uri uriMsgBdyInsert = BluetoothMapEmailContract
- .buildEmailMessageBodyUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
- Log.d(TAG, "pushMessage - uriMsgBdyInsert = " + uriMsgBdyInsert.toString());
- mProviderClient.insert(uriMsgBdyInsert, valuesBody);
- // Extract the data for the inserted message, and store in local mirror, to
- // avoid sending a NewMessage Event.
- //TODO: We need to add the new 1.1 parameter as well:-) e.g. read
- Msg newMsg = new Msg(handle, folderId, 1); // TODO: Create define for read-state
- newMsg.transparent = (transparent == 1) ? true : false;
- newMsg.localInitiatedSend = true;
- if ( folderId == folderElement.getFolderByName(
- BluetoothMapContract.FOLDER_NAME_OUTBOX).getFolderId() ) {
- //Trigger Email App to send the message over network.
- Intent emailIn = new Intent();
- long accountId = mAccount.getAccountId();
- if(V) Log.d(TAG, "sendIntent SEND: " + handle + "accounId: " +accountId);
- emailIn.setAction(BluetoothMapEmailContract.ACTION_SEND_PENDING_MAIL);
- emailIn.putExtra(BluetoothMapEmailContract.EXTRA_ACCOUNT, accountId);
- mContext.sendBroadcast(emailIn);
- }
- getMsgListMsg().put(handle, newMsg);
}
}
+ // Extra check to format email list, it's should not happen
+ if (addressTo.length() == 0 && addressCc.length() == 0 && addressBcc.length() == 0) {
+ if (D) Log.v(TAG, "Parse from recipientList");
+ for (BluetoothMapbMessage.VCard recipient : recipientList) {
+ if (recipient.getEnvLevel() < max_env_level) {
+ String address[] = ((BluetoothMapbMessage.VCard)recipient)
+ .getEmailAddresses();
+ for (String s : address) {
+ addressTo.append(s);
+ addressTo.append(";");
+ }
+ }
+ }
+ }
+ Uri uriInsert = BluetoothMapEmailContract
+ .buildEmailMessageUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
+ if (D) Log.d(TAG, "pushMessage - uriInsert= " + uriInsert.toString() +
+ ", intoFolder id=" + folderElement.getFolderId());
+ synchronized(getMsgListMsg()) {
+ // Now insert the empty message into folder
+ ContentValues values = new ContentValues();
+ Time timeObj = new Time();
+ timeObj.setToNow();
+ folderId = folderElement.getFolderId();
+ values.put(BluetoothMapEmailContract.ExtEmailMessageColumns.MAILBOX_KEY,
+ folderId);
+ if(((BluetoothMapbMessageExtEmail)msg).getSubject() != null) {
+ values.put(BluetoothMapContract.MessageColumns.SUBJECT,
+ ((BluetoothMapbMessageExtEmail)msg).getSubject());
+ } else {
+ values.put(BluetoothMapContract.MessageColumns.SUBJECT, "");
+ }
+ values.put("syncServerTimeStamp", 0);
+ values.put("timeStamp", timeObj.toMillis(false));
+ values.put("flagLoaded", "1");
+ values.put("flagFavorite", "0");
+ values.put("flagAttachment", "0");
+ if(folderElement.getName().equalsIgnoreCase(BluetoothMapContract
+ .FOLDER_NAME_DRAFT) || folderElement.getName()
+ .equalsIgnoreCase(BluetoothMapEmailContract.FOLDER_NAME_DRAFTS)) {
+ values.put("flags", "1179648");
+ } else
+ values.put("flags", "0");
+ String splitStr[] = emailBaseUri.split("/");
+ for (String str: splitStr)
+ Log.d(TAG,"seg for mBaseUri: "+ str);
+ if (mAccount != null) {
+ values.put("accountKey", mAccount.getAccountId());
+ values.put("displayName", mAccount.getDisplayName());
+ values.put("fromList", mAccount.getEmailAddress());
+ }
+ values.put("mailboxKey", folderId);
+ if (addressTo.length() != 0) {
+ values.put("toList", addressTo.toString().trim());
+ } if (addressCc.length() != 0) {
+ values.put("ccList", addressCc.toString().trim());
+ } if (addressBcc.length() != 0) {
+ values.put("bccList", addressBcc.toString().trim());
+ }
+ if (D) Log.d(TAG, " toList :" + addressTo + "\n ccList :" + addressCc +
+ "\n bccList:" + addressBcc);
+ values.put("flagRead", 0);
+ Uri uriNew = mProviderClient.insert(uriInsert, values);
+ if (D) Log.d(TAG, "pushMessage - uriNew= " + uriNew.toString());
+ handle = Long.parseLong(uriNew.getLastPathSegment());
+ if (V) {
+ Log.v(TAG, " NEW HANDLE " + handle);
+ }
+ if(handle == -1) {
+ Log.v(TAG, " Inavlid Handle ");
+ return -1;
+ }
+ //Insert msgBody in DB Provider BODY TABLE
+ ContentValues valuesBody = new ContentValues();
+ valuesBody.put("messageKey", String.valueOf(handle));
+ valuesBody.put("textContent", msgBody);
+ Uri uriMsgBdyInsert = BluetoothMapEmailContract
+ .buildEmailMessageBodyUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
+ Log.d(TAG, "pushMessage - uriMsgBdyInsert = " + uriMsgBdyInsert.toString());
+ mProviderClient.insert(uriMsgBdyInsert, valuesBody);
+ // Extract the data for the inserted message, and store in local mirror, to
+ // avoid sending a NewMessage Event.
+ //TODO: We need to add the new 1.1 parameter as well:-) e.g. read
+ Msg newMsg = new Msg(handle, folderId, 1); // TODO: Create define for read-state
+ newMsg.transparent = (transparent == 1) ? true : false;
+ newMsg.localInitiatedSend = true;
+ if ( folderId == folderElement.getFolderByName(
+ BluetoothMapContract.FOLDER_NAME_OUTBOX).getFolderId() ) {
+ //Trigger Email App to send the message over network.
+ Intent emailIn = new Intent();
+ long accountId = mAccount.getAccountId();
+ if(V) Log.d(TAG, "sendIntent SEND: " + handle + "accounId: " +accountId);
+ emailIn.setAction(BluetoothMapEmailContract.ACTION_SEND_PENDING_MAIL);
+ emailIn.putExtra(BluetoothMapEmailContract.EXTRA_ACCOUNT, accountId);
+ mContext.sendBroadcast(emailIn);
+ }
+ getMsgListMsg().put(handle, newMsg);
+ }
}
// If multiple recipients return handle of last
return handle;
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
index dbf10c8..8cbe2e0 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
@@ -25,6 +25,8 @@
import java.util.Date;
import java.util.Locale;
import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import com.android.bluetooth.map.BluetoothMapSmsPdu.SmsPdu;
@@ -100,6 +102,9 @@
int pos1 = 0;
//PARSE SUBJECT
setSubject(parseSubjectEmail(body));
+ setmRecipientTo(parseEmails(body, "To:"));
+ setmRecipientCc(parseEmails(body, "Cc:"));
+ setmRecipientBCc(parseEmails(body, "Bcc:"));
//Parse Boundary
String boundary = parseBoundaryEmail(body);
if (boundary != null && !boundary.equalsIgnoreCase("")) {
@@ -289,4 +294,37 @@
}
return encodeGeneric(bodyFragments);
}
+
+ private ArrayList<String> parseEmails(String body , String type){
+ ArrayList<String> emailList =new ArrayList<>();
+ try {
+ int pos = body.indexOf(type);
+ if (pos > 0) {
+ int beginVersionPos = pos + type.length();
+ int endVersionPos = body.indexOf("\n", beginVersionPos);
+ String data= body.substring(beginVersionPos, endVersionPos);
+ if (data == null || data.isEmpty()) {
+ return emailList;
+ }
+ Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+")
+ .matcher(data);
+ while (m.find()) {
+ String email = m.group();
+ if (email.startsWith(".")) {
+ email= email.substring(1);
+ } if (email.endsWith(".")) {
+ email= email.substring(0,email.length()-1);
+ }
+ if (emailList == null) {
+ emailList=new ArrayList<>();
+ } if(!emailList.contains(email)) {
+ emailList.add(email);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG," parseEmails " + e.toString());
+ }
+ return emailList;
+ }
}