Merge "Declaration change of get_folder_items_list_rsp" into bt.lnx.5.0
diff --git a/certification_tools/blegatt_test/gatt_test.cpp b/certification_tools/blegatt_test/gatt_test.cpp
index 2c42333..383ad5f 100644
--- a/certification_tools/blegatt_test/gatt_test.cpp
+++ b/certification_tools/blegatt_test/gatt_test.cpp
@@ -457,13 +457,13 @@
 
     std::vector<btgatt_db_element_t> service1;
     //1st service
-    btgatt_db_element_t svc1;
+    btgatt_db_element_t svc1 = {0};
     svc1.uuid = Uuid::FromString(IMMEDIATE_ALERT_UUID, &is_valid);
     svc1.type = BTGATT_DB_PRIMARY_SERVICE;
     service1.push_back(svc1);
 
     //1st char
-    btgatt_db_element_t char1;
+    btgatt_db_element_t char1 = {0};
     char1.uuid = Uuid::FromString(ALERT_LEVEL_UUID1, &is_valid);
     char1.type = BTGATT_DB_CHARACTERISTIC;
     char1.properties = 58;
@@ -472,7 +472,7 @@
     service1.push_back(char1);
 
     //1st desc
-    btgatt_db_element_t desc1;
+    btgatt_db_element_t desc1 = {0};
     desc1.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc1.type = BTGATT_DB_DESCRIPTOR;
     desc1.permissions = 17;
@@ -480,7 +480,7 @@
     service1.push_back(desc1);
 
     //2nd char
-    btgatt_db_element_t char2;
+    btgatt_db_element_t char2 = {0};
     char2.uuid = Uuid::FromString(ALERT_LEVEL_UUID2, &is_valid);
     char2.type = BTGATT_DB_CHARACTERISTIC;
     char2.properties = 58;
@@ -489,7 +489,7 @@
     service1.push_back(char2);
 
     //2nd desc
-    btgatt_db_element_t desc2;
+    btgatt_db_element_t desc2 = {0};
     desc2.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc2.type = BTGATT_DB_DESCRIPTOR;
     desc2.permissions = 34;
@@ -498,7 +498,7 @@
 
 
     //3rd char
-    btgatt_db_element_t char3;
+    btgatt_db_element_t char3 = {0};
     char3.uuid = Uuid::FromString(ALERT_LEVEL_UUID3, &is_valid);
     char3.type = BTGATT_DB_CHARACTERISTIC;
     char3.properties = 58;
@@ -507,7 +507,7 @@
     service1.push_back(char3);
 
     //3rd desc
-    btgatt_db_element_t desc3;
+    btgatt_db_element_t desc3 = {0};
     desc3.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc3.type = BTGATT_DB_DESCRIPTOR;
     desc3.permissions = 68;
@@ -516,7 +516,7 @@
 
 
     //4th char
-    btgatt_db_element_t char4;
+    btgatt_db_element_t char4 = {0};
     char4.uuid = Uuid::FromString(AUTHENTICATION_LEVEL_UUID1, &is_valid);
     char4.type = BTGATT_DB_CHARACTERISTIC;
     char4.properties = 58;
@@ -525,7 +525,7 @@
     service1.push_back(char4);
 
     //4th desc
-    btgatt_db_element_t desc4;
+    btgatt_db_element_t desc4 = {0};
     desc4.uuid = Uuid::FromString(AUTHENTICATION_LEVEL_DESC_UUID1, &is_valid);
     desc4.type = BTGATT_DB_DESCRIPTOR;
     desc4.permissions = 34;
@@ -534,7 +534,7 @@
 
 
     //5th char
-    btgatt_db_element_t char5;
+    btgatt_db_element_t char5 = {0};
     char5.uuid = Uuid::FromString(AUTHENTICATION_LEVEL_UUID2, &is_valid);
     char5.type = BTGATT_DB_CHARACTERISTIC;
     char5.properties = 58;
@@ -543,7 +543,7 @@
     service1.push_back(char5);
 
     //5th desc
-    btgatt_db_element_t desc5;
+    btgatt_db_element_t desc5 = {0};
     desc5.uuid = Uuid::FromString(AUTHENTICATION_LEVEL_DESC_UUID2, &is_valid);
     desc5.type = BTGATT_DB_DESCRIPTOR;
     desc5.permissions = 68;
@@ -551,7 +551,7 @@
     service1.push_back(desc5);
 
     //6th char
-    btgatt_db_element_t char6;
+    btgatt_db_element_t char6 = {0};
     char6.uuid = Uuid::FromString(ALERT_LEVEL_UUID4, &is_valid);
     char6.type = BTGATT_DB_CHARACTERISTIC;
     char6.properties = 4;
@@ -560,7 +560,7 @@
     service1.push_back(char6);
 
     //6th desc
-    btgatt_db_element_t desc6;
+    btgatt_db_element_t desc6 = {0};
     desc6.uuid = Uuid::FromString(DISC_LEVEL_UUID1, &is_valid);
     desc6.type = BTGATT_DB_DESCRIPTOR;
     desc6.permissions = 16;
@@ -568,7 +568,7 @@
     service1.push_back(desc6);
 
     //7th char
-    btgatt_db_element_t char7;
+    btgatt_db_element_t char7 = {0};
     char7.uuid = Uuid::FromString(ALERT_LEVEL_UUID5, &is_valid);
     char7.type = BTGATT_DB_CHARACTERISTIC;
     char7.properties = 114;
@@ -577,7 +577,7 @@
     service1.push_back(char7);
 
     //7th desc
-    btgatt_db_element_t desc7;
+    btgatt_db_element_t desc7 = {0};
     desc7.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc7.type = BTGATT_DB_DESCRIPTOR;
     desc7.permissions = 129;
@@ -585,7 +585,7 @@
     service1.push_back(desc7);
 
     //8th char
-    btgatt_db_element_t char8;
+    btgatt_db_element_t char8 = {0};
     char8.uuid = Uuid::FromString(ALERT_LEVEL_UUID6, &is_valid);
     char8.type = BTGATT_DB_CHARACTERISTIC;
     char8.properties = 66;
@@ -594,7 +594,7 @@
     service1.push_back(char8);
 
     //8th desc
-    btgatt_db_element_t desc8;
+    btgatt_db_element_t desc8 = {0};
     desc8.uuid = Uuid::FromString(DISC_LEVEL_UUID2, &is_valid);
     desc8.type = BTGATT_DB_DESCRIPTOR;
     desc8.permissions = 129;
@@ -602,7 +602,7 @@
     service1.push_back(desc8);
 
     //9th char
-    btgatt_db_element_t char9;
+    btgatt_db_element_t char9 = {0};
     char9.uuid = Uuid::FromString(ALERT_LEVEL_WRITENORESPONSEWITHREADABLE2, &is_valid);
     char9.type = BTGATT_DB_CHARACTERISTIC;
     char9.properties = 6;
@@ -611,7 +611,7 @@
     service1.push_back(char9);
 
     //9th desc
-    btgatt_db_element_t desc9;
+    btgatt_db_element_t desc9 = {0};
     desc9.uuid = Uuid::FromString(DISC_LEVEL_UUID7, &is_valid);
     desc9.type = BTGATT_DB_DESCRIPTOR;
     desc9.permissions = 17;
@@ -619,7 +619,7 @@
     service1.push_back(desc9);
 
     //10th char
-    btgatt_db_element_t char10;
+    btgatt_db_element_t char10 = {0};
     char10.uuid = Uuid::FromString(ALERT_LEVEL_UUID18, &is_valid);
     char10.type = BTGATT_DB_CHARACTERISTIC;
     char10.properties = 58;
@@ -628,7 +628,7 @@
     service1.push_back(char10);
 
     //10th desc
-    btgatt_db_element_t desc10;
+    btgatt_db_element_t desc10 = {0};
     desc10.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc10.type = BTGATT_DB_DESCRIPTOR;
     desc10.permissions = 17;
@@ -636,7 +636,7 @@
     service1.push_back(desc10);
 
     //11th char
-    btgatt_db_element_t char11;
+    btgatt_db_element_t char11 = {0};
     char11.uuid = Uuid::FromString(ALERT_LEVEL_UUID19, &is_valid);
     char11.type = BTGATT_DB_CHARACTERISTIC;
     char11.properties = 58;
@@ -645,7 +645,7 @@
     service1.push_back(char11);
 
     //11th desc
-    btgatt_db_element_t desc11;
+    btgatt_db_element_t desc11 = {0};
     desc11.uuid = Uuid::FromString(ClientCharConfigUUID, &is_valid);
     desc11.type = BTGATT_DB_DESCRIPTOR;
     desc11.permissions = 17;
@@ -659,7 +659,7 @@
     //Second Service - longvalue service
     std::vector<btgatt_db_element_t> service2;
     //2nd service
-    btgatt_db_element_t svc2;
+    btgatt_db_element_t svc2 = {0};
     svc2.uuid = Uuid::FromString(IMMEDIATE_ALERT_UUID1, &is_valid);
     svc2.type = BTGATT_DB_PRIMARY_SERVICE;
     service2.push_back(svc2);
@@ -814,7 +814,7 @@
     //3rd service
     std::vector<btgatt_db_element_t> service3;
 
-    btgatt_db_element_t svc3;
+    btgatt_db_element_t svc3 = {0};
     svc3.uuid = Uuid::FromString(IMMEDIATE_ALERT_UUID2, &is_valid);
     svc3.type = BTGATT_DB_PRIMARY_SERVICE;
     service3.push_back(svc3);
@@ -860,7 +860,7 @@
     //4th service with no value set
     std::vector<btgatt_db_element_t> service4;
 
-    btgatt_db_element_t svc4;
+    btgatt_db_element_t svc4 = {0};
     svc4.uuid = Uuid::FromString(IMMEDIATE_ALERT_UUID3, &is_valid);
     svc4.type = BTGATT_DB_PRIMARY_SERVICE;
     service4.push_back(svc4);
@@ -881,7 +881,7 @@
     //5th service will all kinds of descriptors
     std::vector<btgatt_db_element_t> service5;
 
-    btgatt_db_element_t svc5;
+    btgatt_db_element_t svc5 = {0};
     svc5.uuid = Uuid::FromString(IMMEDIATE_ALERT_UUID6, &is_valid);
     svc5.type = BTGATT_DB_PRIMARY_SERVICE;
     service5.push_back(svc5);
@@ -971,7 +971,7 @@
     service5.push_back(desc11);
 
     //12th desc
-    btgatt_db_element_t desc12;
+    btgatt_db_element_t desc12 = {0};
     desc12.uuid = Uuid::FromString(CharacteristicAggregateFormat, &is_valid);
     desc12.type = BTGATT_DB_DESCRIPTOR;
     desc12.permissions = 17;
@@ -1002,7 +1002,7 @@
     btgatt_response_t  gatt_resp;
     int status = BT_STATUS_SUCCESS;
     std::vector<uint8_t> cccd_val;
-    uint8_t val[2];
+    uint8_t val[2] = {};
     gatt_resp.handle = attr_handle;
     gatt_resp.attr_value.handle = attr_handle;
     gatt_resp.attr_value.offset = offset;
@@ -1062,7 +1062,7 @@
     printf("%s:: conn_id=%d, trans_id=%d, attr_handle=%d \n", __FUNCTION__, conn_id, trans_id, attr_handle);
     bt_status_t        Ret;
     int status = BT_STATUS_SUCCESS;
-    uint8_t cccd_val[2];
+    uint8_t cccd_val[2] = {};
     btgatt_response_t  gatt_resp;
     gatt_resp.handle = attr_handle;
     gatt_resp.attr_value.handle = attr_handle;
@@ -2994,13 +2994,13 @@
 
     std::vector<btgatt_db_element_t> service;
     //1st service
-    btgatt_db_element_t svc1;
+    btgatt_db_element_t svc1 = {0};
     svc1.uuid = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb", &is_valid);//00001800-0000-1000-8000-00805f9b34fb
     svc1.type = BTGATT_DB_PRIMARY_SERVICE;
     service.push_back(svc1);
 
     //2nd service
-    btgatt_db_element_t svc2;
+    btgatt_db_element_t svc2 = {0};
     svc2.uuid = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb", &is_valid);//00001801-0000-1000-8000-00805f9b34fb
     svc2.type = BTGATT_DB_PRIMARY_SERVICE;
     service.push_back(svc2);
diff --git a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
index 43aaf77..a4cf61a 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
@@ -171,6 +171,7 @@
     private byte changePathDirection;
     HashMap<BluetoothDevice, Integer> mVolumeMap = new HashMap();
     public static final String VOLUME_MAP = "bluetooth_volume_map";
+    private boolean isShoActive = false;
 
     private boolean twsShoEnabled = false;
     private static final String playerStateUpdateBlackListedAddr[] = {
@@ -234,6 +235,7 @@
     private final static int MESSAGE_UPDATE_ABS_VOLUME_STATUS = 31;
     private final static int MESSAGE_UPDATE_ABSOLUTE_VOLUME = 32;
     private static final int MSG_PLAY_STATUS_CMD_TIMEOUT = 33;
+    private final static int MESSAGE_START_SHO = 34;
 
     private static final int STACK_CLEANUP = 0;
     private static final int APP_CLEANUP = 1;
@@ -406,6 +408,11 @@
     };
     DeviceDependentFeature[] deviceFeatures;
 
+    private static class SHOQueue {
+        static BluetoothDevice device;
+        static boolean PlayReq;
+    }
+
     static {
         classInitNative();
     }
@@ -1353,9 +1360,28 @@
                 // This is for some remote devices, which send PLAY/PAUSE based on AVRCP State.
                 BATService mBatService = BATService.getBATService();
                 if ((mBatService == null) || !mBatService.isA2dpSuspendFromBA()) {
-                  // if this suspend was triggered by BA, then don't update AVRCP state
+                  // if this suspend was triggered by BA, then don't update AVRCP states
                   updateCurrentMediaState((BluetoothDevice)msg.obj);
                 }
+
+                if (mA2dpState == BluetoothA2dp.STATE_PLAYING) {
+                    boolean shoComplete = false;
+                    synchronized(Avrcp_ext.this) {
+                        if(isShoActive) {
+                            isShoActive = false;
+                            shoComplete = true;
+                            Log.e(TAG, "1: SHO complete");
+                        }
+
+                        if(mHandler.hasMessages(MESSAGE_START_SHO)) {
+                            mHandler.removeMessages(MESSAGE_START_SHO);
+                            triggerSHO(SHOQueue.device, SHOQueue.PlayReq);
+                        }
+                    }
+                    if(shoComplete == true) {
+                        CompleteSHO();
+                    }
+                }
               }
               break;
 
@@ -1520,6 +1546,36 @@
                 deviceFeatures[deviceIndex].isPlayStatusTimeOut = true;
                 break;
 
+            case MESSAGE_START_SHO:
+                if (mA2dpService != null)
+                    break;
+
+                synchronized (Avrcp_ext.this) {
+                    if(mHandler.hasMessages(MESSAGE_START_SHO)) {
+                        Log.e(TAG, "Queue already has another SHO pending");
+                        break;
+                    }
+                    isShoActive = true;
+                    Log.d(TAG, "2: SHO started. PlayReq = " + msg.arg1);
+                }
+
+                BluetoothDevice dev = (BluetoothDevice)msg.obj;
+                boolean PlayReq = (msg.arg1 == 1);
+                mA2dpService.startSHO(dev);
+
+                if(!PlayReq) {
+                    synchronized (Avrcp_ext.this) {
+                        isShoActive = false;
+                        Log.d(TAG, "3: SHO complete");
+                        if (mHandler.hasMessages(MESSAGE_START_SHO)) {
+                            mHandler.removeMessages(MESSAGE_START_SHO);
+                            triggerSHO(SHOQueue.device, SHOQueue.PlayReq);
+                        }
+                    }
+                    CompleteSHO();
+                }
+                break;
+
             default:
                 Log.e(TAG, "unknown message! msg.what=" + msg.what);
                 break;
@@ -3574,7 +3630,9 @@
                         mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
 
                 for (ResolveInfo info : playerList) {
-                    String displayableName = info.loadLabel(mPackageManager).toString();
+                    CharSequence displayName = info.loadLabel(mPackageManager);
+                    String displayableName =
+                            (displayName != null) ? displayName.toString():new String();
                     String serviceName = info.serviceInfo.name;
                     String packageName = info.serviceInfo.packageName;
 
@@ -4645,7 +4703,7 @@
             if((rspStatus == AvrcpConstants.RSP_NO_ERROR) && ((mA2dpService != null) &&
                     !Objects.equals(mA2dpService.getActiveDevice(), device))) {
                 Log.d(TAG, "Trigger Handoff by playItem");
-                mA2dpService.setActiveDevice(device);
+                startSHO(device, true);
             }
             if (!playItemRspNative(address, rspStatus)) {
                 Log.e(TAG, "playItemRspNative failed!");
@@ -4817,7 +4875,43 @@
     }
 
     public boolean startSHO(BluetoothDevice device, boolean PlayReq) {
-        return false;
+        synchronized (Avrcp_ext.this) {
+            if(isShoActive) {
+                mHandler.removeMessages (MESSAGE_START_SHO);
+                Message msg = mHandler.obtainMessage(MESSAGE_START_SHO, PlayReq?1:0, 0, device);
+                SHOQueue.device = device;
+                SHOQueue.PlayReq = PlayReq;
+                mHandler.sendMessageDelayed(msg, 3000);
+                Log.d(TAG, "4: SHO Queued");
+                return true;
+            } else {
+                isShoActive = true;
+                Log.d(TAG, "5: SHO started: PlayReq = " + PlayReq);
+            }
+        }
+        boolean ret = mA2dpService.startSHO(device);
+        synchronized (Avrcp_ext.this) {
+            if (!PlayReq) {
+                isShoActive = false;
+                Log.d(TAG, "6: SHO complete");
+
+                if (mHandler.hasMessages(MESSAGE_START_SHO)) {
+                    mHandler.removeMessages(MESSAGE_START_SHO);
+                    triggerSHO(SHOQueue.device, SHOQueue.PlayReq);
+                }
+            }
+        }
+        CompleteSHO();
+        return ret;
+    }
+
+    private void triggerSHO(BluetoothDevice device, boolean PlayReq) {
+        Message msg = mHandler.obtainMessage(MESSAGE_START_SHO, PlayReq?1:0, 0, device);
+        mHandler.sendMessage(msg);
+    }
+
+    public void CompleteSHO() {
+        /*For device setup after SHO*/
     }
 
     public void setActiveDevice(BluetoothDevice device) {
@@ -5018,7 +5112,7 @@
                 }
                 if (action == KeyEvent.ACTION_DOWN) {
                     Log.d(TAG, "AVRCP Trigger Handoff");
-                    mA2dpService.setActiveDevice(device);
+                    startSHO(device, true);
                 } else {
                     Log.d(TAG, "release for play PT from inactive device");
                 }
diff --git a/packages_apps_bluetooth_ext/src/btservice/Vendor.java b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
index b363eb2..6acaf4e 100644
--- a/packages_apps_bluetooth_ext/src/btservice/Vendor.java
+++ b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
@@ -198,9 +198,7 @@
     void adapterPropertyChangedCallback(int[] types, byte[][] values) {
         byte[] val;
         int type;
-        short twsPlusType;
-        boolean autoConnect;
-        byte[] mPeerAddress;
+
         if (types.length <= 0) {
             Log.e(TAG, "No properties to update");
             return;
@@ -209,16 +207,14 @@
         for (int j = 0; j < types.length; j++) {
             type = types[j];
             val = values[j];
-            if (val.length > 0) {
-                Log.d(TAG, "Property type: " + type);
-                switch (type) {
-                    case AbstractionLayer.BT_VENDOR_PROPERTY_HOST_ADD_ON_FEATURES:
-                        mService.updateHostFeatureSupport(val);
-                        break;
-                    case AbstractionLayer.BT_VENDOR_PROPERTY_SOC_ADD_ON_FEATURES:
-                        mService.updateSocFeatureSupport(val);
-                        break;
-                }
+            Log.d(TAG, "Property type: " + type);
+            switch (type) {
+                case AbstractionLayer.BT_VENDOR_PROPERTY_HOST_ADD_ON_FEATURES:
+                    mService.updateHostFeatureSupport(val);
+                    break;
+                case AbstractionLayer.BT_VENDOR_PROPERTY_SOC_ADD_ON_FEATURES:
+                    mService.updateSocFeatureSupport(val);
+                    break;
             }
         }
     }
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;
+    }
 }
diff --git a/system_bt_ext/btif/src/btif_tws_plus.cc b/system_bt_ext/btif/src/btif_tws_plus.cc
index af3d010..b030604 100644
--- a/system_bt_ext/btif/src/btif_tws_plus.cc
+++ b/system_bt_ext/btif/src/btif_tws_plus.cc
@@ -469,6 +469,7 @@
   if (twsplus_enabled == true) {
     if (b_enable) {
       BTA_TwsPlusEnable(btif_tws_plus_callback);
+      btif_tws_plus_load_tws_devices();
     } else {
       BTA_TwsPlusDisable();
     }
diff --git a/system_bt_ext/btif/src/btif_vendor.cc b/system_bt_ext/btif/src/btif_vendor.cc
index a0bb0e7..9d1f7f1 100644
--- a/system_bt_ext/btif/src/btif_vendor.cc
+++ b/system_bt_ext/btif/src/btif_vendor.cc
@@ -185,18 +185,20 @@
     uint8_t add_on_features_len = 0;
     bt_vendor_property_t vnd_prop;
     char buf[8];
+    vnd_prop.len = 0;
     const controller_t* controller = controller_get_interface();
     if(controller) {
         const bt_device_features_t* dev_features = controller->get_add_on_features(
                                     &add_on_features_len);
+
+        vnd_prop.type = BT_VENDOR_PROPERTY_SOC_ADD_ON_FEATURES;
+        vnd_prop.val = (void*)buf;
         if(dev_features && add_on_features_len > 0) {
-            vnd_prop.type = BT_VENDOR_PROPERTY_SOC_ADD_ON_FEATURES;
-            vnd_prop.val = (void*)buf;
             vnd_prop.len = add_on_features_len;
             memcpy(vnd_prop.val, dev_features, add_on_features_len);
-            HAL_CBACK(bt_vendor_callbacks, adapter_vendor_prop_cb,
-                                   BT_STATUS_SUCCESS, 1, &vnd_prop);
-         }
+        }
+        HAL_CBACK(bt_vendor_callbacks, adapter_vendor_prop_cb,
+                               BT_STATUS_SUCCESS, 1, &vnd_prop);
     }
 }