Merge "Incremental stack ext changes for HAL 2.0" into bt.lnx.5.0
diff --git a/Android.mk b/Android.mk
index f0d1960..5701414 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+TMP_LOCAL_PATH := $(LOCAL_PATH)
+
 include $(LOCAL_PATH)/BATestApp/Android.mk
+include $(TMP_LOCAL_PATH)/certification_tools/Android.mk
 
diff --git a/BATestApp/Android.mk b/BATestApp/Android.mk
index bc1f5d1..ba23089 100644
--- a/BATestApp/Android.mk
+++ b/BATestApp/Android.mk
@@ -2,7 +2,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := debug
 LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
 LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
 LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
diff --git a/certification_tools/blegatt_test/Android.mk b/certification_tools/blegatt_test/Android.mk
index 653c5e1..afb9a8c 100644
--- a/certification_tools/blegatt_test/Android.mk
+++ b/certification_tools/blegatt_test/Android.mk
@@ -6,7 +6,7 @@
 
 LOCAL_C_INCLUDES += . \
     vendor/qcom/opensource/commonsys/system/bt/stack/include \
-    vendor/qcom/opensource/commonsys/system/bt/include \
+    system/bt/include \
     system/bt/types \
     vendor/qcom/opensource/commonsys/system/bt/internal_include \
     vendor/qcom/opensource/commonsys/system/bt/stack/l2cap \
@@ -20,7 +20,6 @@
 
 LOCAL_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug optional
 
 LOCAL_MODULE:= gatt_tool_qti_internal
 
diff --git a/certification_tools/blegatt_test/gatt_test.cpp b/certification_tools/blegatt_test/gatt_test.cpp
index 74c5092..383ad5f 100644
--- a/certification_tools/blegatt_test/gatt_test.cpp
+++ b/certification_tools/blegatt_test/gatt_test.cpp
@@ -68,6 +68,7 @@
 #include <time.h>
 
 #include <base/bind.h>
+#include <base/callback.h>
 
 using bluetooth::Uuid;
 #define bluetooth_module_t "bluetooth_test"
@@ -117,6 +118,11 @@
 #define INTERVAL_MEDIUM  2
 #define INTERVAL_HIGH    3
 
+#define L2CAP_LE_DEFAULT_MTU 512
+#define L2CAP_LE_DEFAULT_MPS 230
+#define L2CAP_LE_MAX_CREDIT 65535
+#define L2CAP_LE_DEFAULT_CREDIT 1
+
 /************************************************************************************
 **  Local type definitions
 ************************************************************************************/
@@ -320,18 +326,18 @@
 tL2CAP_FCR_OPTS ertm_fcr_opts_def = {
     L2CAP_FCR_ERTM_MODE,
     3, /* Tx window size */
-    MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+    20, /* Maximum transmissions before disconnecting */
     2000, /* Retransmission timeout (2 secs) */
-    MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+    12000, /* Monitor timeout (12 secs) */
     100 /* MPS segment size */
 };
 
 tL2CAP_FCR_OPTS stream_fcr_opts_def = {
     L2CAP_FCR_STREAM_MODE,
     3,/* Tx window size */
-    MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+    20, /* Maximum transmissions before disconnecting */
     2000, /* Retransmission timeout (2 secs) */
-    MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+    12000, /* Monitor timeout (12 secs) */
     100 /* MPS segment size */
 };
 static tL2CAP_ERTM_INFO t_ertm_info = {0, 0, 0, 0, 0, 0};
@@ -451,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;
@@ -466,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;
@@ -474,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;
@@ -483,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;
@@ -492,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;
@@ -501,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;
@@ -510,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;
@@ -519,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;
@@ -528,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;
@@ -537,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;
@@ -545,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;
@@ -554,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;
@@ -562,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;
@@ -571,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;
@@ -579,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;
@@ -588,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;
@@ -596,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;
@@ -605,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;
@@ -613,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;
@@ -622,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;
@@ -630,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;
@@ -639,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;
@@ -653,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);
@@ -808,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);
@@ -854,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);
@@ -875,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);
@@ -965,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;
@@ -996,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;
@@ -1056,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;
@@ -2031,20 +2037,20 @@
        if (psm == 200)
        {
            printf("No Resources Available\n");
-           result = L2CAP_LE_NO_RESOURCES;
-           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+           result = L2CAP_LE_RESULT_NO_RESOURCES;
+           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_RESULT_CONN_OK,&local_coc_cfg);
        }
        else if(psm == 201)
        {
            printf("L2CAP_LE_CONN_INSUFFI_AUTHORIZATION \n");
-           result = L2CAP_LE_INSUFFICIENT_AUTHORIZATION;
-           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+           result = L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION;
+           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_RESULT_CONN_OK,&local_coc_cfg);
        }
        else
        {
 
-           result = L2CAP_LE_CONN_OK;
-           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+           result = L2CAP_LE_RESULT_CONN_OK;
+           sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_RESULT_CONN_OK,&local_coc_cfg);
        }
        return;
    }
@@ -2073,7 +2079,7 @@
     if (le_conn_info&&L2C_IS_VALID_LE_PSM(le_conn_info->psm))
     {
 
-        if (result == L2CAP_LE_CONN_OK) {
+        if (result == L2CAP_LE_RESULT_CONN_OK) {
             g_ConnectionState = CONNECT;
         }
         else if(le_conn_info && !le_conn_info->is_server)
@@ -2524,7 +2530,8 @@
     timeout      =  get_hex(&p, -1);
     if(FALSE == GetBdAddr(p, &bd_addr))    return;
 
-    Ret = sGattIfaceScan->client->conn_parameter_update(bd_addr, min_interval, max_interval, latency, timeout);
+    Ret = sGattIfaceScan->client->conn_parameter_update(bd_addr, min_interval,
+                max_interval, latency, timeout, 0, 0);
     printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
 
 }
@@ -2758,13 +2765,12 @@
 {
     int        uuid_len = 0, uuid_len_bytes = 0;
     tGATT_STATUS Ret =0;
-    tGATT_DISC_PARAM param;
     tGATT_DISC_TYPE disc_type; //GATT_DISC_SRVC_ALL , GATT_DISC_SRVC_BY_UUID
     bool is_valid = false;
 
     disc_type = get_int(&p, -1);  // arg1
-    param.s_handle = get_hex(&p, -1);  // arg2
-    param.e_handle = get_hex(&p, -1);  // arg3
+    uint16_t s_handle = get_hex(&p, -1);  // arg2
+    uint16_t e_handle = get_hex(&p, -1);  // arg3
 
     uuid_len    = get_int(&p, -1);  // arg4 - Size in bits for the uuid (16, 32, or 128)
     if((16==uuid_len) || (32==uuid_len) || (128==uuid_len))
@@ -2778,12 +2784,12 @@
     }
 
     std::string uuid_str = get_uuid_str(&p, uuid_len_bytes);
-    param.service = Uuid::FromString(uuid_str, &is_valid);
+    Uuid service = Uuid::FromString(uuid_str, &is_valid);
 
     printf("%s:: disc_type = %d is_valid = %d\n", __FUNCTION__, disc_type, is_valid);
 
     //if(FALSE == GetDiscType(p, &disc_type))    return;        //TODO - add the function if user input is needed
-    Ret = sGattInterface->cDiscover(g_conn_id, disc_type, &param);
+    Ret = sGattInterface->cDiscover(g_conn_id, disc_type, s_handle, e_handle, service);
     printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
 }
 
@@ -2988,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/certification_tools/l2test_ertm/Android.mk b/certification_tools/l2test_ertm/Android.mk
index 4ca568f..2adbb4f 100644
--- a/certification_tools/l2test_ertm/Android.mk
+++ b/certification_tools/l2test_ertm/Android.mk
@@ -6,7 +6,7 @@
 
 LOCAL_C_INCLUDES += . \
     vendor/qcom/opensource/commonsys/system/bt/stack/include \
-    vendor/qcom/opensource/commonsys/system/bt/include \
+    system/bt/include \
     system/bt/types \
     vendor/qcom/opensource/commonsys/system/bt/internal_include \
     vendor/qcom/opensource/commonsys/system/bt/stack/l2cap \
@@ -19,7 +19,6 @@
 
 LOCAL_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug optional
 LOCAL_MODULE:= l2test_ertm
 
 LOCAL_SHARED_LIBRARIES += libcutils   \
diff --git a/certification_tools/l2test_ertm/l2test_ertm.cpp b/certification_tools/l2test_ertm/l2test_ertm.cpp
index a97272c..2c3b4ae 100644
--- a/certification_tools/l2test_ertm/l2test_ertm.cpp
+++ b/certification_tools/l2test_ertm/l2test_ertm.cpp
@@ -139,18 +139,18 @@
 tL2CAP_FCR_OPTS ertm_fcr_opts_def = {
     L2CAP_FCR_ERTM_MODE,
     3, /* Tx window size */
-    MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+    20, /* Maximum transmissions before disconnecting */
     2000, /* Retransmission timeout (2 secs) */
-    MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+    12000, /* Monitor timeout (12 secs) */
     100 /* MPS segment size */
 };
 
 tL2CAP_FCR_OPTS stream_fcr_opts_def = {
     L2CAP_FCR_STREAM_MODE,
     3,/* Tx window size */
-    MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+    20, /* Maximum transmissions before disconnecting */
     2000, /* Retransmission timeout (2 secs) */
-    MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+    12000, /* Monitor timeout (12 secs) */
     100 /* MPS segment size */
 };
 static tL2CAP_ERTM_INFO t_ertm_info = {0,0,0,0,0,0};
diff --git a/certification_tools/mcap_tool/Android.mk b/certification_tools/mcap_tool/Android.mk.disabled
similarity index 90%
rename from certification_tools/mcap_tool/Android.mk
rename to certification_tools/mcap_tool/Android.mk.disabled
index 602d3a2..93b8326 100644
--- a/certification_tools/mcap_tool/Android.mk
+++ b/certification_tools/mcap_tool/Android.mk.disabled
@@ -6,7 +6,7 @@
 
 LOCAL_C_INCLUDES += . \
     vendor/qcom/opensource/commonsys/system/bt/stack/include \
-    vendor/qcom/opensource/commonsys/system/bt/include \
+    system/bt/include \
     system/bt/types \
     vendor/qcom/opensource/commonsys/system/bt/internal_include \
     vendor/qcom/opensource/commonsys/system/bt/stack/l2cap \
@@ -19,7 +19,6 @@
 
 LOCAL_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug optional
 
 LOCAL_MODULE:= mcap_tool_qti_internal
 
diff --git a/certification_tools/rfcommtest/Android.mk b/certification_tools/rfcommtest/Android.mk
index dcd1d0e..ddd9197 100644
--- a/certification_tools/rfcommtest/Android.mk
+++ b/certification_tools/rfcommtest/Android.mk
@@ -6,7 +6,7 @@
 
 LOCAL_C_INCLUDES += . \
     vendor/qcom/opensource/commonsys/system/bt/stack/include \
-    vendor/qcom/opensource/commonsys/system/bt/include \
+    system/bt/include \
     system/bt/types \
     vendor/qcom/opensource/commonsys/system/bt/internal_include \
     vendor/qcom/opensource/commonsys/system/bt/stack/l2cap \
@@ -19,7 +19,6 @@
 
 LOCAL_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug optional
 LOCAL_MODULE:= rfc
 
 LOCAL_SHARED_LIBRARIES += libcutils   \
diff --git a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
index c89a78e..403df02 100644
--- a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
+++ b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
@@ -63,6 +63,8 @@
 static jmethodID method_onBredrCleanup;
 static jmethodID method_iotDeviceBroadcast;
 static jmethodID method_devicePropertyChangedCallback;
+static jmethodID method_adapterPropertyChangedCallback;
+static jmethodID method_ssrCleanupCallback;
 
 static btvendor_interface_t *sBluetoothVendorInterface = NULL;
 static jobject mCallbacksObj = NULL;
@@ -115,6 +117,16 @@
     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBredrCleanup, (jboolean)status);
 }
 
+static void ssr_cleanup_callback(void){
+
+    ALOGI("%s", __FUNCTION__);
+    CallbackEnv sCallbackEnv(__func__);
+
+    if (!sCallbackEnv.valid()) return;
+
+    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_ssrCleanupCallback);
+}
+
 static void iot_device_broadcast_callback(RawAddress* bd_addr, uint16_t error,
         uint16_t error_info, uint32_t event_mask, uint8_t lmp_ver, uint16_t lmp_subver,
         uint16_t manufacturer_id, uint8_t power_level, int8_t rssi, uint8_t link_quality,
@@ -135,6 +147,49 @@
                     (jint)manufacturer_id, (jint)power_level, (jint)rssi, (jint)link_quality,
                     (jint)glitch_count);
 }
+
+static void adapter_vendor_properties_callback(bt_status_t status,
+                          int num_properties,
+                          bt_vendor_property_t *properties) {
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+  ALOGE("%s: Status is: %d, Properties: %d", __func__, status, num_properties);
+  if (status != BT_STATUS_SUCCESS) {
+    ALOGE("%s: Status %d is incorrect", __func__, status);
+    return;
+  }
+  ScopedLocalRef<jbyteArray> val(
+      sCallbackEnv.get(),
+      (jbyteArray)sCallbackEnv->NewByteArray(num_properties));
+  if (!val.get()) {
+    ALOGE("%s: Error allocating byteArray", __func__);
+    return;
+  }
+  ScopedLocalRef<jclass> mclass(sCallbackEnv.get(),
+                                sCallbackEnv->GetObjectClass(val.get()));
+  ScopedLocalRef<jobjectArray> props(
+      sCallbackEnv.get(),
+      sCallbackEnv->NewObjectArray(num_properties, mclass.get(), NULL));
+  if (!props.get()) {
+    ALOGE("%s: Error allocating object Array for properties", __func__);
+    return;
+  }
+  ScopedLocalRef<jintArray> types(
+      sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_properties));
+  if (!types.get()) {
+    ALOGE("%s: Error allocating int Array for values", __func__);
+    return;
+  }
+  jintArray typesPtr = types.get();
+  jobjectArray propsPtr = props.get();
+  if (get_properties(num_properties, properties, &typesPtr, &propsPtr) < 0) {
+    return;
+  }
+  sCallbackEnv->CallVoidMethod(mCallbacksObj,
+                               method_adapterPropertyChangedCallback,
+                               types.get(), props.get());
+}
+
 static void remote_device_properties_callback(bt_status_t status,
                           RawAddress *bd_addr, int num_properties,
                           bt_vendor_property_t *properties) {
@@ -191,6 +246,8 @@
     iot_device_broadcast_callback,
     remote_device_properties_callback,
     NULL,
+    adapter_vendor_properties_callback,
+    ssr_cleanup_callback,
 };
 
 static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -199,6 +256,10 @@
     method_iotDeviceBroadcast = env->GetMethodID(clazz, "iotDeviceBroadcast", "([BIIIIIIIIII)V");
     method_devicePropertyChangedCallback = env->GetMethodID(
       clazz, "devicePropertyChangedCallback", "([B[I[[B)V");
+    method_adapterPropertyChangedCallback = env->GetMethodID(
+      clazz, "adapterPropertyChangedCallback", "([I[[B)V");
+    method_ssrCleanupCallback = env->GetMethodID(
+      clazz, "ssr_cleanup_callback", "()V");
     ALOGI("%s: succeeds", __FUNCTION__);
 }
 
@@ -278,6 +339,17 @@
     return JNI_TRUE;
 }
 
+static bool hcicloseNative(JNIEnv *env, jobject obj) {
+
+    ALOGI("%s", __FUNCTION__);
+
+    jboolean result = JNI_FALSE;
+    if (!sBluetoothVendorInterface) return result;
+
+    sBluetoothVendorInterface->hciclose();
+    return JNI_TRUE;
+}
+
 static bool setWifiStateNative(JNIEnv *env, jobject obj, jboolean status) {
 
     ALOGI("%s", __FUNCTION__);
@@ -331,6 +403,7 @@
     {"getProfileInfoNative", "(II)Z", (void*) getProfileInfoNative},
     {"getQtiStackStatusNative", "()Z", (void*) getQtiStackStatusNative},
     {"voipNetworkWifiInfoNative", "(ZZ)Z", (void *)voipNetworkWifiInfoNative},
+    {"hcicloseNative", "()V", (void*) hcicloseNative},
 };
 
 int register_com_android_bluetooth_btservice_vendor(JNIEnv* env)
diff --git a/packages_apps_bluetooth_ext/src/avrcp/AvrcpBipRsp.java b/packages_apps_bluetooth_ext/src/avrcp/AvrcpBipRsp.java
index 028667d..b621e73 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/AvrcpBipRsp.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/AvrcpBipRsp.java
@@ -83,7 +83,7 @@
 
     public AvrcpBipRsp (Context context, int maxBipConnections) {
         mContext = context;
-        mMaxBipDevices = getMaxDevices();
+        mMaxBipDevices = maxBipConnections;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
         mHandlerThread = new HandlerThread("BipHandlerThread");
         mHandlerThread.start();
diff --git a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
index 1de651b..a57da3f 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();
     }
@@ -802,8 +809,21 @@
                     vol = convertToAvrcpVolume(vol);
                     Log.d(TAG,"vol = " + vol + "rem vol = " + deviceFeatures[deviceIndex].mRemoteVolume);
                     if(vol != deviceFeatures[deviceIndex].mRemoteVolume &&
-                       deviceFeatures[deviceIndex].isAbsoluteVolumeSupportingDevice)
+                       deviceFeatures[deviceIndex].isAbsoluteVolumeSupportingDevice &&
+                       deviceFeatures[deviceIndex].mCurrentDevice != null) {
                        setVolumeNative(vol , getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+                       if (deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice()) {
+                           AdapterService adapterService = AdapterService.getAdapterService();
+                           BluetoothDevice peer_device =
+                            adapterService.getTwsPlusPeerDevice(deviceFeatures[deviceIndex].mCurrentDevice);
+                           if (peer_device != null &&
+                               getIndexForDevice(peer_device) != INVALID_DEVICE_INDEX) {
+                               // Change volume to peer earbud as well
+                               Log.d(TAG,"setting volume to TWS+ peer also");
+                               setVolumeNative(vol, getByteAddress(peer_device));
+                           }
+                       }
+                    }
                 }
                 //mLastLocalVolume = -1;
                 break;
@@ -1342,9 +1362,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;
 
@@ -1509,6 +1548,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;
@@ -2073,6 +2142,10 @@
                     && (mA2dpState == BluetoothA2dp.STATE_PLAYING)) {
                 Log.i(TAG, "Players updated current playback state is none," +
                             " skip updating playback state");
+            } else if (device == null && newState != null &&
+                    newState.getState() == PlaybackState.STATE_ERROR) {
+                Log.i(TAG, "Players updated current playback state is error," +
+                            " skip updating playback state");
             } else {
                 updatePlaybackState(newState, device);
             }
@@ -2391,8 +2464,17 @@
                      SystemClock.elapsedRealtime() - deviceFeatures[deviceIndex].mLastStateUpdate;
                 currPosition = sinceUpdate + deviceFeatures[deviceIndex].mCurrentPlayState.getPosition();
             } else {
-                currPosition = deviceFeatures[deviceIndex].mCurrentPlayState.getPosition();
-
+                if (isPlayingState(deviceFeatures[deviceIndex].mCurrentPlayState) &&
+                    (avrcp_playstatus_blacklist && isPlayerStateUpdateBlackListed(
+                     deviceFeatures[deviceIndex].mCurrentDevice.getAddress(),
+                     deviceFeatures[deviceIndex].mCurrentDevice.getName()))) {
+                 currPosition = mCurrentPlayerState.getPosition();
+                 Log.d(TAG, "Remote is BLed for playstatus, So send playposition by fetching from "+
+                                   "mCurrentPlayerState." + currPosition);
+                } else {
+                  currPosition = deviceFeatures[deviceIndex].mCurrentPlayState.getPosition();
+                  Log.d(TAG, "getPlayPosition(): currPosition = " + currPosition);
+                }
             }
         } else {
             if (mCurrentPlayerState == null) {
@@ -3098,7 +3180,8 @@
              (mDevice.isTwsPlusDevice() && device.isTwsPlusDevice()))) {
             setActiveDevice(mDevice);
             //below line to send setAbsolute volume if device is suporting absolute volume
-            setAbsVolumeFlag(mDevice);
+            if (mDevice.equals(deviceFeatures[index].mCurrentDevice))
+                setAbsVolumeFlag(mDevice);//Do not call this funciton for second EB connect
             //When A2dp playing on DUT and Remote got connected, send proper playstatus
             if (isPlayingState(mCurrentPlayerState) &&
                 mA2dpService.isA2dpPlaying(device)) {
@@ -3549,7 +3632,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;
 
@@ -4620,7 +4705,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!");
@@ -4792,7 +4877,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) {
@@ -4993,7 +5114,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/ba/BATService.java b/packages_apps_bluetooth_ext/src/ba/BATService.java
index c2583b3..1cd459f 100644
--- a/packages_apps_bluetooth_ext/src/ba/BATService.java
+++ b/packages_apps_bluetooth_ext/src/ba/BATService.java
@@ -486,8 +486,9 @@
             } else {// a2dp active device is null.
                 // inform BA device as disconnected. we have to send noisy intent
                 // because BA seems to be last device.
-                mAudioManager.setBluetoothA2dpDeviceConnectionState(
-                    mBADevice, BluetoothProfile.STATE_DISCONNECTED,BluetoothProfile.A2DP);
+                mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+                        mBADevice, BluetoothProfile.STATE_DISCONNECTED,BluetoothProfile.A2DP,
+                        false, -1);
             }
             if (!checkAbsVolSupport()) {
                 //Abs vol not supported by AVRCP, we should update false from BA.
diff --git a/packages_apps_bluetooth_ext/src/btservice/Vendor.java b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
index 07ecd8d..6acaf4e 100644
--- a/packages_apps_bluetooth_ext/src/btservice/Vendor.java
+++ b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
@@ -92,6 +92,10 @@
         setWifiStateNative(status);
     }
 
+    public void HCIClose() {
+        hcicloseNative();
+    }
+
     public boolean getProfileInfo(int profile_id , int profile_info) {
         Log.d(TAG,"getProfileInfo profile_id: " + profile_id);
         return getProfileInfoNative(profile_id, profile_info);
@@ -146,6 +150,12 @@
         intent.putExtra(BluetoothDevice.EXTRA_GLITCH_COUNT, glitchCount);
         mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
     }
+
+    void ssr_cleanup_callback() {
+        Log.e(TAG,"ssr_cleanup_callback");
+        mService.ssrCleanupCallback();
+    }
+
     void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) {
         byte[] val;
         int type;
@@ -184,6 +194,30 @@
             }
         }
     }
+
+    void adapterPropertyChangedCallback(int[] types, byte[][] values) {
+        byte[] val;
+        int type;
+
+        if (types.length <= 0) {
+            Log.e(TAG, "No properties to update");
+            return;
+        }
+
+        for (int j = 0; j < types.length; j++) {
+            type = types[j];
+            val = values[j];
+            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;
+            }
+        }
+    }
     private native void bredrcleanupNative();
     private native void bredrstartupNative();
     private native void initNative();
@@ -193,4 +227,5 @@
     private native boolean getProfileInfoNative(int profile_id , int profile_info);
     private native boolean getQtiStackStatusNative();
     private native boolean voipNetworkWifiInfoNative(boolean isVoipStarted, boolean isNetworkWifi);
+    private native void hcicloseNative();
 }
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
index 79fec27..0e3e56f 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
@@ -214,19 +214,10 @@
         mMasInstance = masInstance;
         mMasId = mMasInstance.getMasId();
         mMapSupportedFeatures = mMasInstance.getRemoteFeatureMask();
-        if (D) Log.d(TAG, "BluetoothMapContentObserverEmail: Supported features " +
-                Integer.toHexString(mMapSupportedFeatures) ) ;
-
-        if((BluetoothMapUtils.MAP_FEATURE_EXTENDED_EVENT_REPORT_11_BIT
-                & mMapSupportedFeatures) != 0){
-            mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V11;
-        }
-        // Make sure support for all formats result in latest version returned
-        if((BluetoothMapUtils.MAP_FEATURE_EVENT_REPORT_V12_BIT
-                & mMapSupportedFeatures) != 0){
-            mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V12;
-        }
-
+        if (D) Log.d(TAG, "Supported features " +
+                Integer.toHexString(mMapSupportedFeatures));
+        setObserverRemoteFeatureMask(mMapSupportedFeatures);
+        super.setObserverRemoteFeatureMask(mMapSupportedFeatures);
         if(account != null) {
             mAuthority = Uri.parse(account.mBase_uri).getAuthority();
             Log.d(TAG,"mAuthority: "+mAuthority);
@@ -279,9 +270,19 @@
         if ((BluetoothMapUtils.MAP_FEATURE_EVENT_REPORT_V12_BIT
                 & mMapSupportedFeatures) != 0) {
             mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V12;
+        } else if (((BluetoothMapUtils.MAP_FEATURE_PARTICIPANT_PRESENCE_CHANGE_BIT
+                | BluetoothMapUtils.MAP_FEATURE_PARTICIPANT_CHAT_STATE_CHANGE_BIT)
+                & mMapSupportedFeatures) != 0) {
+            // Warning according to page 46/123 of MAP 1.3 spec
+            Log.w(TAG, "setObserverRemoteFeatureMask: Extended Event Reports 1.2 is not set even"
+                    + "though PARTICIPANT_PRESENCE_CHANGE_BIT or PARTICIPANT_CHAT_STATE_CHANGE_BIT"
+                    + " were set, mMapSupportedFeatures=" + mMapSupportedFeatures);
         }
-        if (V) Log.d(TAG, "setObserverRemoteFeatureMask Email: " + mMapEventReportVersion
-            + " mMapSupportedFeatures Email: " + mMapSupportedFeatures);
+        if (D) {
+            Log.d(TAG, "setObserverRemoteFeatureMask: mMapEventReportVersion="
+                    + mMapEventReportVersion + " mMapSupportedFeatures= "
+                    +Integer.toHexString(mMapSupportedFeatures));
+        }
     }
 
     private static boolean sendEventNewMessage(long eventFilter) {
@@ -542,8 +543,8 @@
                         /* We must filter out any actions made by the MCE, hence do not send e.g.
                          * a message deleted and/or MessageShift for messages deleted by the MCE. */
                         if (msg == null) {
-                            if(V) Log.v(TAG, "handleMsgListChangesMsg id: " + id + "folderId: "
-                                + folderId + " newFolder: " +newFolder);
+                            if(V) Log.v(TAG, "handleMsgListChangesMsg id: " + id + ", folderId: "
+                                + folderId + ", newFolder: " +newFolder);
                             listChanged = true;
                             /* New message - created with message unread */
                             msg = new Msg(id, folderId, readFlag);
@@ -846,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;
         }
@@ -876,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/BluetoothMapFixes.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
index ef166b9..443cfb1 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
@@ -29,16 +29,26 @@
 
 package com.android.bluetooth.map;
 
-import android.bluetooth.BluetoothMap;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.NotificationChannel;
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
-import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.SparseArray;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.btservice.AbstractionLayer;
 
-import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
 
 public class BluetoothMapFixes {
 
@@ -48,6 +58,20 @@
 
     public static final boolean VERBOSE = BluetoothMapService.VERBOSE;
 
+    private static final int SDP_MAP_MAS_FEATURES_ADV = 0x603ff,
+                             SDP_MAP_MAS_VERSION_ADV = 0x0103;
+    // Stores map of BD address to isRebonded for the given BT Session
+    private static HashMap<String,String> mapSdpResponse = new HashMap <String,String>();
+    // Stores map of BD address to MCE version for the given BT Session
+    private static HashMap<String,Integer> remoteVersion = new HashMap <String,Integer>();
+    private static final String MAP_NOTIFICATION_ID = "map_notification",
+                                MAP_NOTIFICATION_NAME = "BT_MAP_ADVANCE_SUPPORT";
+    private static final int RECORD_LENGTH = 6,
+                             VERSION_LENGTH = 2,
+                             MAP_ADV_NOTIFICATION_ID = -1000003,
+                             ADDRESS_LENGTH = 3;
+    private static NotificationManager mNotificationManager;
+
     /*to trigger MNS OFF to handle MCE that dosen't issue MNS OFF before MAS DISC*/
     public static void handleMnsShutdown(SparseArray<BluetoothMapMasInstance>
             mMasInstances, int masId) {
@@ -113,4 +137,140 @@
         mService.createMasInstances();
     }
 
+    static boolean isRemoteSupportsAdvMap(BluetoothDevice device) {
+        Log.d(TAG, "isRemoteSupportsAdvMap ");
+        try {
+            final String filePath = "/data/misc/bluedroid/mce_peer_entries.conf";
+            File file = new File(filePath);
+            Log.d(TAG, "file length = " + (int)file.length());
+            byte[] fileData = new byte[(int) file.length()];
+            DataInputStream dis = new DataInputStream(new FileInputStream(file));
+            dis.readFully(fileData);
+            dis.close();
+            return readRecord(fileData, device);
+        } catch (IOException io) {
+            Log.e(TAG, "File Read Failed: " + io);
+        }
+        return false;
+    }
+
+    /* Read all records and check if entry for remote device is found
+     * Returns true if 1.4 support is stored for remote else false */
+    static boolean readRecord(byte[] fileData, BluetoothDevice device) {
+        for (int j = 0 ; (j + RECORD_LENGTH) <= fileData.length;) {
+            // Read Version from MCE Entry
+            byte[] versionBytes = Arrays.copyOfRange(fileData, j, j + VERSION_LENGTH);
+            int version = byteArrayToInt(versionBytes);
+            j += VERSION_LENGTH;
+
+            // Read BD ADDRESS from MCE Entry
+            StringBuilder address = new StringBuilder();
+            address.append(String.format("%02X", fileData[j]) + ":"
+                    + String.format("%02X", fileData[j+1]) + ":"
+                    + String.format("%02X", fileData[j+2]));
+            j += ADDRESS_LENGTH;
+
+            // Read rebonded from MCE Entry
+            char isRebonded = (char)fileData[j++];
+            Log.d(TAG, "version: " + version + ", address = " + address.toString()
+                    + ", isRebonded = "+ isRebonded +" Remote Address = "
+                    + device.getAddress());
+
+            boolean isMatched = device.getAddress().toLowerCase()
+                    .startsWith(address.toString().toLowerCase());
+            mapSdpResponse.put(address.toString(), Character.toString(isRebonded));
+            remoteVersion.put(address.toString(), Integer.valueOf(version));
+            if (isMatched) {
+                return (version >= SDP_MAP_MAS_VERSION_ADV ? true : false);
+            }
+        }
+        return false;
+    }
+
+    /* Convert 2 bytes of data to integer */
+    static int byteArrayToInt(byte[] b)
+    {
+        return   b[0] & 0xFF |
+                (b[1] & 0xFF) << 8 ;
+    }
+
+    /*Creates Notification for MAP version upgrade/downgrade */
+   static void createNotification(BluetoothMapService context, boolean isUpgrade) {
+        if (VERBOSE) Log.v(TAG, "Create MAP Notification for Upgrade/Downgrade");
+        // create Notification channel.
+        if (mNotificationManager == null) {
+            mNotificationManager = (NotificationManager)
+                    context.getSystemService(Context.NOTIFICATION_SERVICE);
+            NotificationChannel mChannel = new NotificationChannel(MAP_NOTIFICATION_ID,
+                    MAP_NOTIFICATION_NAME, NotificationManager.IMPORTANCE_HIGH);
+            mNotificationManager.createNotificationChannel(mChannel);
+        }
+
+        // create notification
+        String title = isUpgrade ? "Message access Advance Feature Supported" :
+                            "Remote Message access Feature Downgrade";
+        String contentText = isUpgrade ? "Re-pair for Advance Message access Feature.":
+                "Re-pair for Message access Version Compatibility";
+        Notification notification = new Notification.Builder(context,MAP_NOTIFICATION_ID)
+            .setContentTitle(title)
+            .setContentText(contentText)
+            .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
+            .setAutoCancel(true)
+            .build();
+        if (mNotificationManager != null ) {
+            mNotificationManager.notify(MAP_ADV_NOTIFICATION_ID, notification);
+        } else {
+            Log.e(TAG,"mNotificationManager is null");
+        }
+    }
+
+    /* Checks if notification for Version Upgrade is required */
+    static void showNotification(BluetoothMapService service,
+            BluetoothDevice remoteDevice) {
+        if (service == null || remoteDevice == null || Utils.isPtsTestMode()
+                || isMapAdvDisabled()) {
+            Log.d(TAG, "Ignore showNotification , service: " + service + " remoteDevice: "
+                    + remoteDevice +" isPtsTestMode :" + Utils.isPtsTestMode()
+                    + " isMapAdvDisabled :" + isMapAdvDisabled());
+            return;
+        }
+        boolean hasMap14Support = isRemoteSupportsAdvMap(remoteDevice);
+        /* check if remote devices is rebonded by looking into its entry in hashmap using key
+         * (0,8) i.e. first 3 bytes of bd addr in string format including colon (XX:XX:XX) */
+        String isRebonded = mapSdpResponse.get(
+                remoteDevice.getAddress().substring(0,8));
+        /* fetch MCE version of remote (if present) in hashmap 'remoteVersion' from key
+         * (0,8) i.e. first 3 bytes of bd addr in string format including colon (XX:XX:XX) */
+        Integer remoteMceVersion = remoteVersion.get(
+                remoteDevice.getAddress().substring(0,8));
+        if (hasMap14Support && (isRebonded.equals("N"))) {
+            Log.d(TAG, "Remote Supports MAP 1.4 Notify user");
+            createNotification(service, true);
+        } else if (!hasMap14Support
+                && (remoteMceVersion != null &&
+                    remoteMceVersion.intValue() < SDP_MAP_MAS_VERSION_ADV)
+                && (isRebonded != null && isRebonded.equals("N"))) {
+            Log.d(TAG, "Remote MAP profile support downgraded");
+            createNotification(service, false);
+        } else {
+            Log.d(TAG, "Notification Not Required.");
+            if (mNotificationManager != null)
+                mNotificationManager.cancel(MAP_ADV_NOTIFICATION_ID);
+        }
+    }
+
+    public static boolean isMapAdvDisabled(){
+        boolean ismap14Enabled = false;
+        int MAP_0104_SUPPORT = 7;
+        try {
+            AdapterService adapterService = AdapterService.getAdapterService();
+            if (adapterService != null) {
+                ismap14Enabled = adapterService.getProfileInfo(AbstractionLayer.MAP,
+                        MAP_0104_SUPPORT);
+            }
+        } catch(Exception e) {
+            Log.w(TAG," isMapadvEnabled : " + e);
+        }
+        return !ismap14Enabled;
+    }
 }
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/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java b/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
index 09d4851..3f16e74 100644
--- a/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
+++ b/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
@@ -111,7 +111,7 @@
 
     private static final int ORDER_BY_ALPHABETICAL = 1;
 
-    static final int MAX_CONNECTED_DEVICES = 2;
+    static final int MAX_CONNECTED_DEVICES = 5;
 
     // Stores map of BD address to isRebonded for the given BT Session
     protected static HashMap<String,String> PbapSdpResponse = new HashMap <String,String>();
diff --git a/packages_apps_bluetooth_ext/src/utils/ReflectionUtils.java b/packages_apps_bluetooth_ext/src/utils/ReflectionUtils.java
new file mode 100644
index 0000000..30abe57
--- /dev/null
+++ b/packages_apps_bluetooth_ext/src/utils/ReflectionUtils.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.android.bluetooth;
+
+ import android.util.Log;
+
+ import java.lang.reflect.Method;
+ import java.lang.reflect.Field;
+ import java.lang.reflect.InvocationTargetException;
+ import java.util.ArrayList;
+ import java.util.HashMap;
+
+/* This API is added to access data members or member functions from the class which
+ * is defined in other component and the required memebers may not be available(or merged)
+ * in other component. This API helps avoiding compilation issues. */
+ public class ReflectionUtils {
+
+    private static final String TAG = "BluetoothReflectionUtils";
+
+    private static final HashMap<String, Class> primitiveClsMap =
+        new HashMap<String, Class>();
+
+    static {
+        primitiveClsMap.put("java.lang.Integer", int.class);
+        primitiveClsMap.put("java.lang.Long", long.class);
+        primitiveClsMap.put("java.lang.Character", char.class);
+        primitiveClsMap.put("java.lang.Byte", byte.class);
+        primitiveClsMap.put("java.lang.Float", float.class);
+        primitiveClsMap.put("java.lang.Double", double.class);
+        primitiveClsMap.put("java.lang.Short", short.class);
+        primitiveClsMap.put("java.lang.Boolean", boolean.class);
+    }
+
+    /**********************************************************************************
+     * Function     :  getField
+     *
+     * Description  :  fetches mentioned data member from the provided object.
+     *                 Access is restricted to public data members if package of the
+     *                 required object class is different from ReflectionUtils package.
+     *                 If package is same, protected and default can aslo be accessed.
+     *                 obj       - Object in which data member could be present
+     *                 fieldName - name of the data member in string format
+     *
+     * Returns      :  data member as 'Field'
+     *                 null if data member is not found
+     **********************************************************************************/
+    public Field getField(Object obj, String fieldName) {
+        Log.d(TAG, "getField {" + fieldName + "} class: " + obj.getClass().getName());
+        Field field = null;
+        try {
+            // get object class
+            Class cls = obj.getClass();
+            // get required field. NoSuchFieldException is thrown if field is not found
+            field = cls.getDeclaredField(fieldName);
+        } catch(NoSuchFieldException e) {
+            Log.e(TAG, "Field(" + fieldName + ") not found in class:" + obj.getClass().getName()
+                        +". Exception : " + e);
+        }
+        return field;
+    }
+
+    /**********************************************************************************
+     * Function     :  isMethodAvailable
+     *
+     * Description  :  checks if mentioned method is available in given object's class.
+     *                 Access is restricted to public member functions only if package
+     *                 of required object class is different from ReflectionUtils package.
+     *                 If package is same, protected and default func can also be accessed.
+     *                 obj        - Object in which data member could be present
+     *                 methodName - name of the member function in string format
+     *                 args       - all method arguments wrapped in Object format in
+     *                              arraylist
+     * Returns      :  true if method is present otherwise returns false
+     **********************************************************************************/
+    public boolean isMethodAvailable(Object obj, String methodName, ArrayList<Object> args) {
+        Log.d(TAG, "isMethodAvailable: " + methodName + ", Class: " + obj.getClass().getName());
+        boolean isAvailable = true;
+        Class[] cArgs = null;
+        try {
+            Class cls = obj.getClass();
+            // get parameter types of function call
+            if (args != null && args.size() > 0) {
+                int i =0;
+                cArgs = new Class[args.size()];
+                for (Object objs : args) {
+                    if (isWrapperType(objs.getClass().getName())) {
+                        cArgs[i++] = primitiveClsMap.get(objs.getClass().getName());
+                    } else {
+                        cArgs[i++] = objs.getClass();
+                    }
+                }
+            }
+            Method m = cls.getDeclaredMethod(methodName, cArgs);
+        } catch (NoSuchMethodException e) {
+            isAvailable = false;
+            Log.e(TAG, "Method not found in class:" + obj.getClass().getName()
+                    +". Exception :" + e);
+        }
+        return isAvailable;
+    }
+
+    /**********************************************************************************
+     * Function     :  invokeMethod
+     *
+     * Description  :  This is a generic method which calls required method.
+     *                 Access is restricted to public member functions only if package
+     *                 of required object class is different from ReflectionUtils package.
+     *                 If package is same, protected and default func can also be accessed.
+     *                 obj        - Object in which data member could be present
+     *                 methodName - name of the member function in string format
+     *                 args       - all method arguments wrapped in Object format in
+     *                              arraylist
+     * Returns      :  return type of the required method in 'Object' format.
+     *                 Typecasting should be done to required type.
+     **********************************************************************************/
+    public Object invokeMethod(Object obj, String methodName, ArrayList<Object> args) {
+        Log.d(TAG, "invokeMethod: " + methodName + ", From: " + obj.getClass().getName());
+        Object returnValue = null;
+        Class[] cArgs = null;
+        try {
+            // Obtain object class to call required method
+            Class cls = obj.getClass();
+
+            // create function param signeture
+            if (args != null && args.size() > 0) {
+                int i =0;
+                cArgs = new Class[args.size()];
+                for (Object objs : args) {
+                    if (isWrapperType(objs.getClass().getName())) {
+                        cArgs[i++] = primitiveClsMap.get(objs.getClass().getName());
+                    } else {
+                        cArgs[i++] = objs.getClass();
+
+                    }
+                }
+            }
+
+            // Obtain required method.
+            // throws exeption NoSuchMethodException if method is not found
+            Method m = cls.getDeclaredMethod(methodName, cArgs);
+
+            // Invoke required method call
+            if (args != null)
+                returnValue = m.invoke(obj, args.toArray());
+            else
+                returnValue = m.invoke(obj);
+        } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
+            Log.e(TAG, "Exception in invokeMethod: " + e);
+        }
+        return returnValue;
+    }
+
+    // Checks if a class belongs to Wrapper class of primitive data types
+    public boolean isWrapperType(String classType) {
+      return primitiveClsMap.containsKey(classType);
+    }
+  }
+
diff --git a/system_bt_ext/bta/include/bta_ag_twsp_dev.h b/system_bt_ext/bta/include/bta_ag_twsp_dev.h
index 9ae7678..592038c 100644
--- a/system_bt_ext/bta/include/bta_ag_twsp_dev.h
+++ b/system_bt_ext/bta/include/bta_ag_twsp_dev.h
@@ -91,7 +91,7 @@
 } tTWSPLUS_DEVICE;
 
 void twsp_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd, int16_t int_arg);
-void update_twsp_device(int eb_idx, tBTA_AG_SCB* p_scb);
+void update_twsp_device(tBTA_AG_SCB* p_scb);
 void reset_twsp_device(int eb_idx);
 bool twsp_set_ring_sent(tBTA_AG_SCB *p_scb, bool ring_sent);
 void twsp_clr_all_ring_sent();
@@ -101,5 +101,6 @@
 bool twsp_get_left_eb_addr(RawAddress& eb_addr);
 uint8_t get_twsp_role(tBTA_AG_SCB *p_scb);
 tBTA_AG_SCB* twsp_get_best_mic_scb ();
+int twsp_get_idx_by_scb(tBTA_AG_SCB* p_scb);
 
 #endif//__BTA_AG_TWSPLUS_DEV_H_
diff --git a/system_bt_ext/bta/include/bta_tws_plus_api.h b/system_bt_ext/bta/include/bta_tws_plus_api.h
index c0c8507..225303b 100644
--- a/system_bt_ext/bta/include/bta_tws_plus_api.h
+++ b/system_bt_ext/bta/include/bta_tws_plus_api.h
@@ -89,7 +89,7 @@
   tBTA_TWS_PLUS_STATUS status;
   RawAddress bd_addr;
   RawAddress  peer_eb_addr;
-  LINK_KEY key;                /* Link key associated with peer device. */
+  LinkKey key;                /* Link key associated with peer device. */
   uint8_t reason;
 } tBTA_TWS_PLUS_LK_DERIVED;
 
@@ -162,7 +162,7 @@
 extern tBTA_TWS_PLUS_STATUS BTA_TwsPlusSdpSearch(RawAddress bd_addr);
 
 extern tBTA_TWS_PLUS_STATUS BTA_TwsPlusDeriveLinkKey(RawAddress eb_addr,
-                    RawAddress peer_eb_addr, LINK_KEY key, uint8_t reason);
+                    RawAddress peer_eb_addr, LinkKey key, uint8_t reason);
 
 extern tBTA_TWS_PLUS_STATUS BTA_TwsPlusUpdatePeerEbAddr(RawAddress eb_addr,
                                                    RawAddress peer_eb_addr);
diff --git a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
index 11499ea..125e889 100644
--- a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
+++ b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
@@ -38,7 +38,11 @@
 #include "internal_include/bt_trace.h"
 #include "bta_ag_int.h"
 
+
 #if (TWS_AG_ENABLED == TRUE)
+//forward declarations
+void select_microphone_path(tBTA_AG_SCB *best_scb);
+
 
 tTWSPLUS_DEVICE twsp_devices[MAX_TWSPLUS_DEVICES];
 
@@ -48,38 +52,75 @@
     return g_latest_selected_eb_role;
 }
 
+tBTA_AG_SCB* get_twsp_with_role(uint8_t role) {
+   int i;
+   for (i=0; i<MAX_TWSPLUS_DEVICES; i++) {
+      if (twsp_devices[i].p_scb != NULL &&
+          twsp_devices[i].role == role) {
+          return twsp_devices[i].p_scb;
+      }
+   }
+   return NULL;
+}
+
 void reset_twsp_device(int  eb_idx) {
     if (eb_idx < PRIMARY_EB_IDX || eb_idx > SECONDARY_EB_IDX) {
         APPL_TRACE_WARNING("%s: Invalid eb_idx: %d\n", __func__, eb_idx);
         return;
     }
 
-     twsp_devices[eb_idx].p_scb = NULL;
-     twsp_devices[eb_idx].battery_charge = TWSPLUS_MIN_BATTERY_CHARGE;
-     twsp_devices[eb_idx].state = TWSPLUS_EB_STATE_OFF;
-     twsp_devices[eb_idx].role =  TWSPLUS_EB_ROLE_INVALID;
-     twsp_devices[eb_idx].mic_path_delay = TWSPLUS_INVALID_MICPATH_DELAY;
-     twsp_devices[eb_idx].mic_quality = TWSPLUS_MIN_MIC_QUALITY;
-     twsp_devices[eb_idx].qdsp_nr = TWSPLUS_INVALID_QDSP_VALUE;
-     twsp_devices[eb_idx].qdsp_ec = TWSPLUS_INVALID_QDSP_VALUE;
-     twsp_devices[eb_idx].ring_sent = false;
+    if (get_lat_selected_mic_eb_role() == twsp_devices[eb_idx].role) {
+        //Trigger Microphone Switch
+        uint8_t other_twsp_role =
+            (twsp_devices[eb_idx].role == TWSPLUS_EB_ROLE_LEFT) ?
+                        TWSPLUS_EB_ROLE_RIGHT : TWSPLUS_EB_ROLE_LEFT;
+        tBTA_AG_SCB *peer_scb = get_twsp_with_role(other_twsp_role);
+        if (peer_scb != NULL) {
+             select_microphone_path(peer_scb);
+        } else {
+             APPL_TRACE_WARNING("%s: peer_scb is NULL, No mic switch", __func__);
+        }
+     }
+
+    twsp_devices[eb_idx].p_scb = NULL;
+    twsp_devices[eb_idx].battery_charge = TWSPLUS_MIN_BATTERY_CHARGE;
+    twsp_devices[eb_idx].state = TWSPLUS_EB_STATE_OFF;
+    twsp_devices[eb_idx].role =  TWSPLUS_EB_ROLE_INVALID;
+    twsp_devices[eb_idx].mic_path_delay = TWSPLUS_INVALID_MICPATH_DELAY;
+    twsp_devices[eb_idx].mic_quality = TWSPLUS_MIN_MIC_QUALITY;
+    twsp_devices[eb_idx].qdsp_nr = TWSPLUS_INVALID_QDSP_VALUE;
+    twsp_devices[eb_idx].qdsp_ec = TWSPLUS_INVALID_QDSP_VALUE;
+    twsp_devices[eb_idx].ring_sent = false;
 }
 
-void update_twsp_device(int eb_idx, tBTA_AG_SCB* p_scb) {
-    if (eb_idx < PRIMARY_EB_IDX || eb_idx > SECONDARY_EB_IDX) {
-        APPL_TRACE_WARNING("%s: Invalid eb_idx: %d\n", __func__, eb_idx);
-        return;
+void update_twsp_device(tBTA_AG_SCB* p_scb) {
+    for (int i=0; i<MAX_TWSPLUS_DEVICES; i++) {
+        if (twsp_devices[i].p_scb == NULL) {
+            APPL_TRACE_WARNING("%s: idx: %d, p_scb: %x", __func__, i, p_scb);
+            twsp_devices[i].p_scb = p_scb;
+            twsp_devices[i].battery_charge = TWSPLUS_MIN_BATTERY_CHARGE;
+            twsp_devices[i].state = TWSPLUS_EB_STATE_OFF;
+
+            int other_idx = (i == PRIMARY_EB_IDX) ? SECONDARY_EB_IDX : PRIMARY_EB_IDX;
+            if (twsp_devices[other_idx].p_scb != NULL &&
+                    twsp_devices[other_idx].role == TWSPLUS_EB_ROLE_LEFT) {
+                twsp_devices[i].role = TWSPLUS_EB_ROLE_RIGHT;
+            } else {
+                twsp_devices[i].role = TWSPLUS_EB_ROLE_LEFT;
+            }
+
+            APPL_TRACE_WARNING("%s: idx: %d, role: %d", __func__, i, twsp_devices[i].role);
+            twsp_devices[i].mic_path_delay = TWSPLUS_INVALID_MICPATH_DELAY;
+            twsp_devices[i].mic_quality = TWSPLUS_MIN_MIC_QUALITY;
+            twsp_devices[i].qdsp_nr = TWSPLUS_INVALID_QDSP_VALUE;
+            twsp_devices[i].qdsp_ec = TWSPLUS_INVALID_QDSP_VALUE;
+            twsp_devices[i].ring_sent = false;
+            return;
+        }
     }
-     APPL_TRACE_WARNING("%s: idx: %d, p_scb: %x", __func__, eb_idx, p_scb);
-     twsp_devices[eb_idx].p_scb = p_scb;
-     twsp_devices[eb_idx].battery_charge = TWSPLUS_MIN_BATTERY_CHARGE;
-     twsp_devices[eb_idx].state = TWSPLUS_EB_STATE_OFF;
-     twsp_devices[eb_idx].role =  TWSPLUS_EB_ROLE_LEFT;
-     twsp_devices[eb_idx].mic_path_delay = TWSPLUS_INVALID_MICPATH_DELAY;
-     twsp_devices[eb_idx].mic_quality = TWSPLUS_MIN_MIC_QUALITY;
-     twsp_devices[eb_idx].qdsp_nr = TWSPLUS_INVALID_QDSP_VALUE;
-     twsp_devices[eb_idx].qdsp_ec = TWSPLUS_INVALID_QDSP_VALUE;
-     twsp_devices[eb_idx].ring_sent = false;
+
+    APPL_TRACE_WARNING("%s: Invalid p_scb %d\n", __func__);
+    return;
 }
 
 void init_twsp_devices() {
diff --git a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_sco.cc b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_sco.cc
index 58203fe..5f6af9b 100644
--- a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_sco.cc
+++ b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_sco.cc
@@ -276,6 +276,14 @@
                 bta_ag_create_sco(p_scb, false);
                 p_sco->state = BTA_AG_SCO_LISTEN_ST;
                 break;
+            case BTA_AG_SCO_SHUTDOWN_E:
+                /* remove listening connection */
+                bta_ag_remove_sco(p_scb, false);
+
+                if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+
+                p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+             break;
              default:
                   APPL_TRACE_WARNING("%s: BTA_AG_SCO_CODEC_ST: Ignoring event %d",
                              __func__, event);
diff --git a/system_bt_ext/bta/tws_plus/bta_tws_plus_act.cc b/system_bt_ext/bta/tws_plus/bta_tws_plus_act.cc
index f56ffd2..049cf15 100644
--- a/system_bt_ext/bta/tws_plus/bta_tws_plus_act.cc
+++ b/system_bt_ext/bta/tws_plus/bta_tws_plus_act.cc
@@ -319,17 +319,19 @@
  ******************************************************************************/
 void bta_tws_plus_derive_linkkey(tBTA_TWS_PLUS_MSG* p_data) {
   tBTA_TWS_PLUS_STATUS status = BTA_TWS_PLUS_FAILURE;
-  int i = 0;
   tBTA_TWS_PLUS result;
   memset(&result, 0, sizeof(result));
   APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_tws_plus_cb.sdp_active);
-  if(SMP_DeriveBrEdrLinkKey(p_data->derive_lk.peer_eb_addr,
-    ( uint8_t *) p_data->derive_lk.key,(uint8_t *) result.lk_derived.key)) {
-     APPL_TRACE_DEBUG("%s link key for 2nd device derived", __func__);
-     for(i = 0; i< 16 ; i++)
-      APPL_TRACE_DEBUG("%s result.key [%d] is %d", __func__, i, result.lk_derived.key[i]);
-     status = BTA_TWS_PLUS_SUCCESS;
-  }
+
+  int i = 0;
+  result.lk_derived.key = SMP_DeriveBrEdrLinkKey(p_data->derive_lk.peer_eb_addr,
+       p_data->derive_lk.key);
+
+  APPL_TRACE_DEBUG("%s link key for 2nd device derived", __func__);
+  for(i = 0; i< 16 ; i++)
+    APPL_TRACE_DEBUG("%s result.key [%d] is %d", __func__, i, result.lk_derived.key[i]);
+  status = BTA_TWS_PLUS_SUCCESS;
+
   if (bta_tws_plus_cb.p_dm_cback) {
     result.lk_derived.peer_eb_addr =  p_data->derive_lk.peer_eb_addr;
     result.lk_derived.bd_addr = p_data->derive_lk.bd_addr;
diff --git a/system_bt_ext/bta/tws_plus/bta_tws_plus_api.cc b/system_bt_ext/bta/tws_plus/bta_tws_plus_api.cc
index b81c3e4..420b7fb 100644
--- a/system_bt_ext/bta/tws_plus/bta_tws_plus_api.cc
+++ b/system_bt_ext/bta/tws_plus/bta_tws_plus_api.cc
@@ -179,7 +179,7 @@
  *
  ******************************************************************************/
 tBTA_TWS_PLUS_STATUS BTA_TwsPlusDeriveLinkKey(RawAddress eb_addr,
-          RawAddress peer_eb_addr, LINK_KEY key, uint8_t reason) {
+          RawAddress peer_eb_addr, LinkKey key, uint8_t reason) {
   tBTA_TWS_PLUS_API_DERIVE_LINKKEY* p_msg =
       (tBTA_TWS_PLUS_API_DERIVE_LINKKEY*)osi_malloc(sizeof(tBTA_TWS_PLUS_API_DERIVE_LINKKEY));
 
@@ -188,7 +188,7 @@
   p_msg->hdr.event = BTA_TWS_PLUS_API_DERIVE_LINK_KEY_EVT;
   p_msg->peer_eb_addr =  peer_eb_addr;
   p_msg->bd_addr = eb_addr;
-  memcpy(p_msg->key, key, sizeof(LINK_KEY));
+  p_msg->key = key;
   p_msg->reason = reason;
   bta_sys_sendmsg(p_msg);
 
diff --git a/system_bt_ext/bta/tws_plus/bta_tws_plus_int.h b/system_bt_ext/bta/tws_plus/bta_tws_plus_int.h
index 7b8f533..1c317f2 100644
--- a/system_bt_ext/bta/tws_plus/bta_tws_plus_int.h
+++ b/system_bt_ext/bta/tws_plus/bta_tws_plus_int.h
@@ -103,7 +103,7 @@
   BT_HDR hdr;
   RawAddress bd_addr;
   RawAddress peer_eb_addr;        /* peer eb addr for which lk has to derived */
-  LINK_KEY key;                /* Link key associated with peer device. */
+  LinkKey key;                /* Link key associated with peer device. */
   uint8_t reason;
 } tBTA_TWS_PLUS_API_DERIVE_LINKKEY;
 
diff --git a/system_bt_ext/btif/Android.bp b/system_bt_ext/btif/Android.bp
index 6047291..6089d0d 100644
--- a/system_bt_ext/btif/Android.bp
+++ b/system_bt_ext/btif/Android.bp
@@ -23,7 +23,6 @@
     ],
     srcs: [
         "src/btif_l2cap.cc",
-        "src/btif_mcap.cc",
         "src/btif_rfcomm.cc",
         "src/btif_vendor.cc",
         "src/btif_vendor_socket.cc",
@@ -33,6 +32,7 @@
         "src/btif_tws_plus.cc",
         "src/btif_ba.cc",
         "src/btif_twsp_hf.cc",
+        "src/btif_iot_config.cc",
     ],
     shared_libs: [
         "libcutils",
diff --git a/system_bt_ext/btif/include/btif_tws_plus.h b/system_bt_ext/btif/include/btif_tws_plus.h
index c1b0bb6..9075e03 100644
--- a/system_bt_ext/btif/include/btif_tws_plus.h
+++ b/system_bt_ext/btif/include/btif_tws_plus.h
@@ -81,7 +81,7 @@
 bool btif_is_tws_plus_device(const RawAddress *remote_bd_addr);
 
 bool btif_tws_plus_derive_link_key ( RawAddress eb_addr, RawAddress peer_eb_addr,
-                    LINK_KEY src_key, tLK_DERIVATION_REASON reason);
+                    LinkKey src_key, tLK_DERIVATION_REASON reason);
 
 bool btif_tws_plus_process_eir(tBTA_DM_SEARCH *p_search_data,
                                         RawAddress *peer_eb_bd_addr);
diff --git a/system_bt_ext/btif/src/btif_gatt_qual.cc b/system_bt_ext/btif/src/btif_gatt_qual.cc
index 217bfd8..8ddda44 100644
--- a/system_bt_ext/btif/src/btif_gatt_qual.cc
+++ b/system_bt_ext/btif/src/btif_gatt_qual.cc
@@ -104,10 +104,12 @@
         return Ret;
     }
 
-    tGATT_STATUS Gatt_Discover (uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_PARAM *p_param )
+	tGATT_STATUS Gatt_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                            uint16_t start_handle, uint16_t end_handle,
+                            const Uuid& uuid)
     {
         tGATT_STATUS Ret = 0;
-        Ret = GATTC_Discover(conn_id, disc_type, p_param);
+        Ret = GATTC_Discover(conn_id, disc_type, start_handle, end_handle, uuid);
         printf("%s::Ret=%d, conn_id=%d, disc_type=%d \n", __FUNCTION__, Ret, conn_id, disc_type);
         return Ret;
     }
diff --git a/system_bt_ext/btif/src/btif_iot_config.cc b/system_bt_ext/btif/src/btif_iot_config.cc
new file mode 100644
index 0000000..a4a0214
--- /dev/null
+++ b/system_bt_ext/btif/src/btif_iot_config.cc
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * *  Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ * *  Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#include "device_iot_config.h"
+#include "bta_api.h"
+#include "bt_target.h"
+#include "btif_storage.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ ******************************************************************************/
+#define COD_UNCLASSIFIED ((0x1F) << 8)
+
+
+/*******************************************************************************
+*
+* Function         btif_iot_save_pair_type
+*
+* Description      Store remote pair type to iot conf file
+*
+* Returns          void
+*
+*******************************************************************************/
+static void btif_iot_save_pair_type(const RawAddress& bdaddr, bool is_ble, bool is_ssp) {
+  if (is_ssp) {
+    if (!is_ble)
+      device_iot_config_addr_set_int(bdaddr,
+              IOT_CONF_KEY_PAIRTYPE, IOT_CONF_VAL_PAIR_TYPE_SSP);
+    else
+      device_iot_config_addr_set_int(bdaddr,
+              IOT_CONF_KEY_LE_PAIRTYPE, IOT_CONF_VAL_LE_PAIRTYPE_SECURE);
+  } else {
+    if (!is_ble)
+      device_iot_config_addr_set_int(bdaddr,
+              IOT_CONF_KEY_PAIRTYPE, IOT_CONF_VAL_PAIR_TYPE_LEGACY);
+    else
+      device_iot_config_addr_set_int(bdaddr,
+              IOT_CONF_KEY_LE_PAIRTYPE, IOT_CONF_VAL_LE_PAIRTYPE_LEGACY);
+  }
+}
+
+/*******************************************************************************
+*
+* Function         btif_iot_update_remote_info
+*
+* Description      Store remote dev info to iot conf file
+*
+* Returns          void
+*
+*******************************************************************************/
+void btif_iot_update_remote_info(tBTA_DM_AUTH_CMPL* p_auth_cmpl, bool is_ble, bool is_ssp) {
+  int name_length = 0;
+  char value[1024];
+  BD_NAME bd_name;
+  int num_properties = 0;
+  bt_property_t properties[2];
+  uint32_t cod = 0;
+  uint8_t lmp_ver = 0;
+  uint16_t lmp_subver = 0;
+  uint16_t mfct_set = 0;
+  tBTM_STATUS btm_status;
+
+  //save remote name to iot conf file
+  if (strlen((const char *)p_auth_cmpl->bd_name))
+  {
+    name_length = strlen((char *)p_auth_cmpl->bd_name) > BTM_MAX_LOC_BD_NAME_LEN ?
+            BTM_MAX_LOC_BD_NAME_LEN : strlen((char *)p_auth_cmpl->bd_name) + 1;
+    strlcpy(value, (char*)p_auth_cmpl->bd_name, name_length);
+    device_iot_config_addr_set_str(p_auth_cmpl->bd_addr,
+            IOT_CONF_KEY_REMOTE_NAME, value);
+  } else {
+    if (BTM_GetRemoteDeviceName(p_auth_cmpl->bd_addr, bd_name))
+    {
+      device_iot_config_addr_set_str(p_auth_cmpl->bd_addr,
+              IOT_CONF_KEY_REMOTE_NAME, (char *)bd_name);
+    }
+  }
+
+  //save remote dev class to iot conf file
+  //Try to retrieve cod from storage
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+          BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+  if (btif_storage_get_remote_device_property(&p_auth_cmpl->bd_addr, &properties[num_properties])
+          == BT_STATUS_SUCCESS)
+    BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod);
+  if (cod == 0) {
+    BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__);
+    cod = COD_UNCLASSIFIED;
+  }
+  device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+          IOT_CONF_KEY_DEVCLASS, (int)cod);
+  num_properties++;
+
+  //save remote dev type to iot conf file
+  bt_device_type_t dev_type;
+  uint8_t remote_dev_type;
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+          BT_PROPERTY_TYPE_OF_DEVICE, sizeof(uint8_t), &remote_dev_type);
+  if (btif_storage_get_remote_device_property(&p_auth_cmpl->bd_addr, &properties[num_properties])
+          == BT_STATUS_SUCCESS) {
+    BTIF_TRACE_DEBUG("%s retrieve dev type from storage", __func__);
+    dev_type = (bt_device_type_t)(remote_dev_type | p_auth_cmpl->dev_type);
+  } else {
+    dev_type = (bt_device_type_t)(p_auth_cmpl->dev_type);
+  }
+  device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+          IOT_CONF_KEY_DEVTYPE, (int)dev_type);
+
+  //save remote addr type to iot conf file
+  device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+          IOT_CONF_KEY_ADDRTYPE, (int)p_auth_cmpl->addr_type);
+
+  //save remote versions to iot conf file
+  btm_status = BTM_ReadRemoteVersion(p_auth_cmpl->bd_addr, &lmp_ver,
+          &mfct_set, &lmp_subver);
+
+  if (btm_status == BTM_SUCCESS)
+  {
+    device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+            IOT_CONF_KEY_MANUFACTURER, mfct_set);
+    device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+            IOT_CONF_KEY_LMPVER, lmp_ver);
+    device_iot_config_addr_set_int(p_auth_cmpl->bd_addr,
+            IOT_CONF_KEY_LMPSUBVER, lmp_subver);
+  }
+
+  //save remote pair type to iot conf file
+  btif_iot_save_pair_type(p_auth_cmpl->bd_addr, is_ble, is_ssp);
+
+  device_iot_config_flush();
+}
+
+#endif
diff --git a/system_bt_ext/btif/src/btif_mcap.cc b/system_bt_ext/btif/src/btif_mcap.cc
deleted file mode 100644
index 2a37b35..0000000
--- a/system_bt_ext/btif/src/btif_mcap.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the followin conditions are met:
- *        * Redistributions of source code must retain the above copyright
- *          notice, this list of conditions and the followin disclaimer.
- *        * Redistributions in binary form must reproduce the above copyriht
- *            notice, this list of conditions and the followin disclaimer in the
- *            documentation and/or other materials provided with the distribution.
- *        * Neither the name of The Linux Foundation nor
- *            the names of its contributors may be used to endorse or promote
- *            products derived from this software without specific prior written
- *            permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <hardware/bluetooth.h>
-
-
-#define LOG_NDDEBUG 0
-#define LOG_TAG "bluedroid"
-
-#include "btif_api.h"
-#include "bt_utils.h"
-#include "bt_testapp.h"
-#include "btm_api.h"
-#include "btu.h"
-#include "btm_api.h"
-#include "mca_api.h"
-
-#ifdef TEST_APP_INTERFACE
-
-static void McaInit(void)
-{
-    MCA_Init();
-}
-
-static tMCA_HANDLE McaRegister(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
-{
-    tMCA_HANDLE Ret = 0;
-    BTM_SetConnectability (1, 0, 0);
-    Ret = MCA_Register(p_reg, p_cback);
-    ALOGI("McaRegister");
-    return Ret;
-}
-
-static void Mca_Deregister(tMCA_HANDLE handle)
-{
-    MCA_Deregister(handle);
-    ALOGI("McaRegister");
-}
-
-static tMCA_RESULT Mca_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
-{
-    tMCA_RESULT  Ret = 0;
-    ALOGI("Mca_CreateDep Enter");
-    Ret = MCA_CreateDep(handle, p_dep, p_cs);
-    ALOGI("Mca_CreateDep Exit");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
-{
-    tMCA_RESULT  Ret = 0;
-    Ret = MCA_DeleteDep(handle, dep);
-    ALOGI("MCA_DeleteDep Exit");
-    return Ret;
-}
-
-
-static tMCA_RESULT Mca_ConnectReq(tMCA_HANDLE handle, RawAddress bd_addr, uint16_t ctrl_psm, uint16_t sec_mask)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_ConnectReq(handle, bd_addr, ctrl_psm, sec_mask);
-    ALOGI("MCA_ConnectReq");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_DisconnectReq(tMCA_CL mcl)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_DisconnectReq(mcl);
-    ALOGI("Mca_DisconnectReq");
-    return Ret;
-}
-
-
-static tMCA_RESULT Mca_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
-                                         uint16_t mdl_id, uint8_t peer_dep_id,
-                                         uint8_t cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_CreateMdl(mcl, dep, data_psm, mdl_id, peer_dep_id, cfg, p_chnl_cfg);
-    ALOGI("MCA_CreateMdl");
-    return Ret;
-}
-
-
-static tMCA_RESULT Mca_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id, uint8_t cfg, uint8_t rsp_code, const tMCA_CHNL_CFG *p_chnl_cfg)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_CreateMdlRsp(mcl, dep, mdl_id, cfg, rsp_code, p_chnl_cfg);
-    ALOGI("Mca_CreateMdlRsp");
-    return Ret;
-}
-
-
-static tMCA_RESULT Mca_CloseReq(tMCA_DL mdl)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_CloseReq(mdl);
-    ALOGI("Mca_CloseReq");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm, uint16_t mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_ReconnectMdl(mcl, dep, data_psm, mdl_id, p_chnl_cfg);
-    ALOGI("Mca_ReconnectMdl");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id, uint8_t rsp_code, const tMCA_CHNL_CFG *p_chnl_cfg)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_ReconnectMdlRsp(mcl, dep, mdl_id, rsp_code, p_chnl_cfg);
-    ALOGI("Mca_ReconnectMdl");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_DataChnlCfg(mcl, p_chnl_cfg);
-    ALOGI("Mca_DataChnlCfg");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_Abort(tMCA_CL mcl)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_Abort(mcl);
-    ALOGI("MCA_Abort");
-    return Ret;
-}
-
-
-static tMCA_RESULT Mca_Delete(tMCA_CL mcl, uint16_t mdl_id)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_Delete(mcl, mdl_id);
-    ALOGI("Mca_Delete");
-    return Ret;
-}
-
-static tMCA_RESULT Mca_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
-{
-    tMCA_RESULT Ret = 0;
-    Ret = MCA_WriteReq(mdl, p_pkt);
-    ALOGI("Mca_Delete");
-    return Ret;
-}
-
-static uint16_t Mca_GetL2CapChannel (tMCA_DL mdl)
-{
-    uint16_t Ret = 0;
-    Ret = MCA_GetL2CapChannel(mdl);
-    ALOGI("Mca_GetL2CapChannel");
-    return Ret;
-}
-
-static const btmcap_interface_t btmcaInterface = {
-    sizeof(btmcap_interface_t),
-    McaInit,
-    McaRegister,
-    Mca_Deregister,
-    Mca_CreateDep,
-    Mca_DeleteDep,
-    Mca_ConnectReq,
-    Mca_DisconnectReq,
-    Mca_CreateMdl,
-    Mca_CreateMdlRsp,
-    Mca_CloseReq,
-    Mca_ReconnectMdl,
-    Mca_ReconnectMdlRsp,
-    Mca_DataChnlCfg,
-    Mca_Abort,
-    Mca_Delete,
-    Mca_WriteReq,
-    Mca_GetL2CapChannel
-};
-
-
-const btmcap_interface_t *btif_mcap_get_interface(void)
-{
-    //BTIF_TRACE_EVENT1("%s", __FUNCTION__);
-    //printf("\n%s\n", __FUNCTION__);
-    return &btmcaInterface;
-}
-
-
-#endif
diff --git a/system_bt_ext/btif/src/btif_smp.cc b/system_bt_ext/btif/src/btif_smp.cc
index f632d86..edb0366 100644
--- a/system_bt_ext/btif/src/btif_smp.cc
+++ b/system_bt_ext/btif/src/btif_smp.cc
@@ -40,6 +40,11 @@
 #include "btif_api.h"
 #include "bt_utils.h"
 #include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+using crypto_toolbox::aes_128;
+
+
 
 #ifdef TEST_APP_INTERFACE
 #include <bt_testapp.h>
@@ -84,14 +89,12 @@
     printf("%s:: executed \n", __FUNCTION__);
 }
 
-static bool Encrypt(uint8_t *key, uint8_t key_len,
-                                        uint8_t *plain_text, uint8_t pt_len,
-                                        tSMP_ENC *p_out)
+static Octet16 Encrypt(Octet16 key, Octet16 message)
 {
-    bool Ret = 0;
-    Ret = SMP_Encrypt(key, key_len, plain_text, pt_len, p_out);
-    printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
-    return Ret;
+    Octet16 output;
+
+    output= aes_128(key, message);
+    return output;
 }
 
 static const btsmp_interface_t btsmpInterface = {
diff --git a/system_bt_ext/btif/src/btif_tws_plus.cc b/system_bt_ext/btif/src/btif_tws_plus.cc
index 320d6e4..b030604 100644
--- a/system_bt_ext/btif/src/btif_tws_plus.cc
+++ b/system_bt_ext/btif/src/btif_tws_plus.cc
@@ -82,10 +82,12 @@
 bt_status_t btif_tws_plus_replace_earbud ( RawAddress *addr,
                                     RawAddress* peer_bd_addr) {
     bt_status_t status = BT_STATUS_FAIL;
-    LINK_KEY link_key;
-    size_t size = sizeof(link_key);
+
+    LinkKey link_key;
+    size_t size = OCTET16_LEN;
+    uint8_t *key = &link_key[0];
     if (btif_config_get_bin(addr->ToString().c_str(), "LinkKey",
-                                                link_key, &size)) {
+                                                key, &size)) {
         if(btif_tws_plus_derive_link_key( *addr, *peer_bd_addr, link_key,
                                      LK_DERIVATION_REASON_REPLACE_EB)) {
           status = BT_STATUS_SUCCESS;
@@ -323,7 +325,7 @@
 }
 
 bool btif_tws_plus_derive_link_key ( RawAddress eb_addr, RawAddress peer_eb_addr,
-                    LINK_KEY src_key, tLK_DERIVATION_REASON reason) {
+                    LinkKey src_key, tLK_DERIVATION_REASON reason) {
   BTIF_TRACE_DEBUG("%s() Derive link for Bd addr %s ", __func__,
                peer_eb_addr.ToString().c_str());
   BTA_TwsPlusDeriveLinkKey( eb_addr, peer_eb_addr, src_key, reason);
@@ -332,8 +334,9 @@
 
 static void btif_tws_plus_upstreams_evt(uint16_t event, char* p_param) {
   tBTA_TWS_PLUS* p_data = (tBTA_TWS_PLUS*)p_param;
-  LINK_KEY link_key;
-  size_t size = sizeof(link_key);
+  LinkKey link_key;
+  uint8_t *key = &link_key[0];
+  size_t size = OCTET16_LEN;
 
   BTIF_TRACE_EVENT("%s:  event = %d", __func__, event);
   switch (event) {
@@ -347,7 +350,7 @@
           btif_tws_plus_set_peer_eb_addr(&p_data->sdp_search_comp.eb_addr,
                                         &p_data->sdp_search_comp.peer_eb_addr);
           if (btif_config_get_bin(p_data->sdp_search_comp.eb_addr.ToString().c_str(),
-                                  "LinkKey", link_key, &size)) {
+                                  "LinkKey", key, &size)) {
             btif_tws_plus_derive_link_key(p_data->sdp_search_comp.eb_addr,
                                           p_data->sdp_search_comp.peer_eb_addr,
                                           link_key, LK_DERIVATION_REASON_PAIR);
@@ -466,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 446c812..9d1f7f1 100644
--- a/system_bt_ext/btif/src/btif_vendor.cc
+++ b/system_bt_ext/btif/src/btif_vendor.cc
@@ -78,6 +78,7 @@
 #include "profile_config.h"
 #include "btif_tws_plus.h"
 #include "btif_api.h"
+#include "device/include/controller.h"
 
 #if TEST_APP_INTERFACE == TRUE
 #include <bt_testapp.h>
@@ -121,7 +122,6 @@
 #if TEST_APP_INTERFACE == TRUE
 extern const btl2cap_interface_t *btif_l2cap_get_interface(void);
 extern const btrfcomm_interface_t *btif_rfcomm_get_interface(void);
-extern const btmcap_interface_t *btif_mcap_get_interface(void);
 extern const btgatt_test_interface_t *btif_gatt_test_get_interface(void);
 extern const btsmp_interface_t *btif_smp_get_interface(void);
 extern const btgap_interface_t *btif_gap_get_interface(void);
@@ -146,7 +146,6 @@
     broadcast_cb_timer = alarm_new("btif_vnd.cb_timer");
     LOG_INFO(LOG_TAG,"init");
     LOG_INFO(LOG_TAG,"init done");
-    btif_enable_service(BTA_TWS_PLUS_SERVICE_ID);
     return BT_STATUS_SUCCESS;
 }
 
@@ -182,6 +181,27 @@
             broadcast_cb_data.glitch_count);
 }
 
+void btif_vendor_update_add_on_features() {
+    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.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);
+    }
+}
+
 void btif_broadcast_timer_cb(UNUSED_ATTR void *data) {
     btif_transfer_context(btif_vendor_send_iot_info_cb, 1, NULL, 0, NULL);
 }
@@ -290,6 +310,13 @@
                           NULL, 0, NULL);
 }
 
+static void hciclose(void)
+{
+    LOG_INFO(LOG_TAG,"hciclose");
+    btif_hci_close();
+}
+
+
 #if HCI_RAW_CMD_INCLUDED == TRUE
 // Callback invoked on receiving HCI event
 static void btif_vendor_hci_event_callback ( tBTM_RAW_CMPL *p)
@@ -404,8 +431,6 @@
             return btif_l2cap_get_interface();
         case TEST_APP_RFCOMM:
             return btif_rfcomm_get_interface();
-        case TEST_APP_MCAP:
-           return btif_mcap_get_interface();
         case TEST_APP_GATT:
            return btif_gatt_test_get_interface();
         case TEST_APP_SMP:
@@ -435,6 +460,7 @@
     set_property_callouts,
     cleanup,
     voip_network_type_wifi,
+    hciclose,
 };
 
 /*******************************************************************************
diff --git a/system_bt_ext/conf/bt_profile.conf b/system_bt_ext/conf/bt_profile.conf
index 02404c4..ae9cdaf 100644
--- a/system_bt_ext/conf/bt_profile.conf
+++ b/system_bt_ext/conf/bt_profile.conf
@@ -29,4 +29,5 @@
 # map_email_support default value true
 [MAP]
 map_email_support = true
+map_0104_support = true
 
diff --git a/system_bt_ext/conf/interop_database.conf b/system_bt_ext/conf/interop_database.conf
index fa948f6..774776d 100644
--- a/system_bt_ext/conf/interop_database.conf
+++ b/system_bt_ext/conf/interop_database.conf
@@ -391,6 +391,7 @@
 00:09:93 = Address_Based
 74:6f:f7 = Address_Based
 A0:56:B2 = Address_Based
+00:54:AF = Address_Based
 
 [INTEROP_DISABLE_CONNECTION_AFTER_COLLISION]
 A0:14:3D
@@ -437,6 +438,7 @@
 2c:dc:ad:08 = Address_Based
 74:6f:f7 = Address_Based
 90:03:b7 = Address_Based
+00:06:F5 = Address_Based
 
 #Some remote devices don't support sniff mode when the SCO is connected.
 #For such devices, disable sniff mode after SCO is connected and make
@@ -448,3 +450,7 @@
 50:65:83 = Address_Based
 28:3f:69 = Address_Based
 AirPods = Name_Based
+
+#Enable power level 10 adaptive control in FW side for remote devices
+#in this whitelist item.
+[INTEROP_ENABLE_PL10_ADAPTIVE_CONTROL]
diff --git a/system_bt_ext/device/Android.bp b/system_bt_ext/device/Android.bp
index 1032e5f..44babef 100644
--- a/system_bt_ext/device/Android.bp
+++ b/system_bt_ext/device/Android.bp
@@ -13,10 +13,13 @@
         "vendor/qcom/opensource/commonsys/system/bt/internal_include",
         "vendor/qcom/opensource/commonsys/system/bt/stack/include",
         "vendor/qcom/opensource/commonsys/bluetooth_ext/vhal/include",
+        "vendor/qcom/opensource/commonsys/system/bt/bta/include",
+        "vendor/qcom/opensource/commonsys/system/bt/utils/include/",
     ],
     srcs: [
         "src/interop.cc",
         "src/profile_config.cc",
+        "src/device_iot_config.cc",
     ],
     shared_libs: [
         "liblog",
@@ -25,8 +28,4 @@
         "libosi_qti",
         "libbluetooth-types",
     ],
-    cflags: [
-        "-DHAS_NO_BDROID_BUILDCFG"
-    ],
-
 }
diff --git a/system_bt_ext/device/include/device_iot_conf_defs.h b/system_bt_ext/device/include/device_iot_conf_defs.h
new file mode 100644
index 0000000..12907a0
--- /dev/null
+++ b/system_bt_ext/device/include/device_iot_conf_defs.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#define IOT_CONF_KEY_SECTION_ADAPTER                    "Adapter"
+#define IOT_CONF_KEY_ADDRESS                            "Address"
+#define IOT_CONF_KEY_BT_ONOFF_COUNT                     "BTOnOffCount"
+
+#define IOT_CONF_KEY_REMOTE_NAME                        "Name"
+#define IOT_CONF_KEY_DEVCLASS                           "DevClass"
+#define IOT_CONF_KEY_DEVTYPE                            "DevType"
+#define IOT_CONF_KEY_ADDRTYPE                           "AddrType"
+#define IOT_CONF_KEY_MANUFACTURER                       "Manufacturer"
+#define IOT_CONF_KEY_LMPVER                             "LmpVer"
+#define IOT_CONF_KEY_LMPSUBVER                          "LmpSubVer"
+#define IOT_CONF_KEY_PAIRTYPE                           "PairType"
+#define IOT_CONF_KEY_LE_PAIRTYPE                        "LE_PairType"
+#define IOT_CONF_KEY_RT_SUPP_FEATURES                   "RemoteSupportedFeatures"
+#define IOT_CONF_KEY_RT_EXT_FEATURES                    "RemoteExtendedFeatures"
+#define IOT_CONF_KEY_LE_RT_FEATURES                     "LE_RemoteSupportedFeatures"
+#define IOT_CONF_KEY_RECORDED                           "Recorded"
+
+#define IOT_CONF_KEY_GAP_CONN_COUNT                     "ProfileGap_ConnectCount"
+#define IOT_CONF_KEY_GAP_CONN_FAIL_COUNT                "ProfileGap_ConnectFailCount"
+#define IOT_CONF_KEY_GAP_DISC_COUNT                     "ProfileGap_DiscCount"
+#define IOT_CONF_KEY_GAP_DISC_AUTHFAIL_COUNT            "ProfileGap_DiscAuthFailCount"
+#define IOT_CONF_KEY_GAP_DISC_CONNTIMEOUT_COUNT         "ProfileGap_DiscConnTimeoutCount"
+#define IOT_CONF_KEY_A2DP_ROLE                          "ProfileA2dp_Role"
+#define IOT_CONF_KEY_A2DP_VERSION                       "ProfileA2dp_Version"
+#define IOT_CONF_KEY_A2DP_CODECTYPE                     "ProfileA2dp_CodecType"
+#define IOT_CONF_KEY_A2DP_CONN_COUNT                    "ProfileA2dp_ConnectCount"
+#define IOT_CONF_KEY_A2DP_CONN_FAIL_COUNT               "ProfileA2dp_ConnectFailCount"
+#define IOT_CONF_KEY_HFP_ROLE                           "ProfileHfp_Role"
+#define IOT_CONF_KEY_HFP_VERSION                        "ProfileHfp_Version"
+#define IOT_CONF_KEY_HFP_CODECTYPE                      "ProfileHfp_CodecType"
+#define IOT_CONF_KEY_HFP_SLC_CONN_COUNT                 "ProfileHfp_SlcConnectCount"
+#define IOT_CONF_KEY_HFP_SLC_CONN_FAIL_COUNT            "ProfileHfp_SlcConnectFailCount"
+#define IOT_CONF_KEY_HFP_SCO_CONN_COUNT                 "ProfileHfp_ScoConnectCount"
+#define IOT_CONF_KEY_HFP_SCO_CONN_FAIL_COUNT            "ProfileHfp_ScoConnectFailCount"
+#define IOT_CONF_KEY_HFP_FEATURES                       "ProfileHfp_Features"
+#define IOT_CONF_KEY_AVRCP_CTRL_VERSION                 "ProfileAvrcp_ControllerVersion"
+#define IOT_CONF_KEY_AVRCP_TG_VERSION                   "ProfileAvrcp_TargetVersion"
+#define IOT_CONF_KEY_AVRCP_CONN_COUNT                   "ProfileAvrcp_ConnectCount"
+#define IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT              "ProfileAvrcp_ConnectFailCount"
+#define IOT_CONF_KEY_AVRCP_FEATURES                     "ProfileAvrcp_Features"
+#define IOT_CONF_KEY_HID_ROLE                           "ProfileHid_Role"
+#define IOT_CONF_KEY_HID_VERSION                        "ProfileHid_Version"
+#define IOT_CONF_KEY_HID_CONN_COUNT                     "ProfileHid_ConnectCount"
+#define IOT_CONF_KEY_HID_CONN_FAIL_COUNT                "ProfileHid_ConnectFailCount"
+#define IOT_CONF_KEY_PBAP_ROLE                          "ProfilePbap_Role"
+#define IOT_CONF_KEY_PBAP_VERSION                       "ProfilePbap_Version"
+#define IOT_CONF_KEY_PBAP_CONN_COUNT                    "ProfilePbap_ConnectCount"
+#define IOT_CONF_KEY_PBAP_CONN_FAIL_COUNT               "ProfilePbap_ConnectFailCount"
+#define IOT_CONF_KEY_MAP_ROLE                           "ProfileMap_Role"
+#define IOT_CONF_KEY_MAP_VERSION                        "ProfileMap_Version"
+#define IOT_CONF_KEY_MAP_CONN_COUNT                     "ProfileMap_ConnectCount"
+#define IOT_CONF_KEY_MAP_CONN_FAIL_COUNT                "ProfileMap_ConnectFailCount"
+
+#define IOT_CONF_VAL_PAIR_TYPE_LEGACY                   0
+#define IOT_CONF_VAL_PAIR_TYPE_SSP                      1
+#define IOT_CONF_VAL_LE_PAIRTYPE_LEGACY                 0
+#define IOT_CONF_VAL_LE_PAIRTYPE_SECURE                 1
+#define IOT_CONF_VAL_RECORDED_DEFAULT                   0
+
+#define IOT_CONF_VAL_A2DP_ROLE_SINK                     0
+#define IOT_CONF_VAL_A2DP_ROLE_SOURCE                   1
+#define IOT_CONF_VAL_A2DP_CODECTYPE_SBC                 0x01
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTX                0x02
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXHD              0x04
+#define IOT_CONF_VAL_A2DP_CODECTYPE_AAC                 0x08
+#define IOT_CONF_VAL_A2DP_CODECTYPE_LDAC                0x10
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXADAPTIVE        0x20
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXTWS             0x40
+
+#define IOT_CONF_VAL_HFP_ROLE_CLIENT                    0
+#define IOT_CONF_VAL_HFP_ROLE_AG                        1
+#define IOT_CONF_VAL_HFP_CODECTYPE_CVSD                 0x01
+#define IOT_CONF_VAL_HFP_CODECTYPE_CVSDMSBC             0x02
+
+#define IOT_CONF_VAL_HID_ROLE_HOST                      0
+#define IOT_CONF_VAL_HID_ROLE_DEVICE                    1
+
+#define IOT_CONF_VAL_PBAP_ROLE_CLIENT                   0
+#define IOT_CONF_VAL_PBAP_ROLE_SERVER                   1
+
+#define IOT_CONF_VAL_MAP_ROLE_CLIENT                    0
+#define IOT_CONF_VAL_MAP_ROLE_SERVER                    1
+
+#define IOT_CONF_BYTE_NUM_1                             1
+#define IOT_CONF_BYTE_NUM_2                             2
+#define IOT_CONF_BYTE_NUM_3                             3
+#define IOT_CONF_BYTE_NUM_4                             4
+
diff --git a/system_bt_ext/device/include/device_iot_config.h b/system_bt_ext/device/include/device_iot_config.h
new file mode 100644
index 0000000..a4ed0fb
--- /dev/null
+++ b/system_bt_ext/device/include/device_iot_config.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *  Copyright (C) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Not a Contribution
+ *****************************************************************************/
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "device_iot_conf_defs.h"
+#include "raw_address.h"
+
+static const char DEVICE_IOT_CONFIG_MODULE[] = "device_iot_config_module";
+
+typedef struct device_iot_config_section_iter_t device_iot_config_section_iter_t;
+
+bool device_iot_config_has_section(const char* section);
+bool device_iot_config_exist(const char* section, const char* key);
+bool device_iot_config_get_int(const char* section, const char* key, int* value);
+bool device_iot_config_addr_get_int(const RawAddress& peer_addr, const char* key, int* value);
+bool device_iot_config_set_int(const char* section, const char* key, int value);
+bool device_iot_config_addr_set_int(const RawAddress& peer_addr, const char* key, int value);
+bool device_iot_config_int_add_one(const char* section, const char* key);
+bool device_iot_config_addr_int_add_one(const RawAddress& peer_addr, const char* key);
+
+bool device_iot_config_get_hex(const char* section, const char* key, int* value);
+bool device_iot_config_addr_get_hex(const RawAddress& peer_addr, const char* key, int* value);
+bool device_iot_config_set_hex(const char* section, const char* key, int value, int byte_num);
+bool device_iot_config_addr_set_hex(const RawAddress& peer_addr, const char* key, int value, int byte_num);
+bool device_iot_config_addr_set_hex_if_greater(const RawAddress& peer_addr, const char* key, int value, int byte_num);
+bool device_iot_config_get_str(const char* section, const char* key, char* value, int* size_bytes);
+bool device_iot_config_set_str(const char* section, const char* key, const char* value);
+bool device_iot_config_addr_set_str(const RawAddress& peer_addr, const char* key, const char* value);
+bool device_iot_config_get_bin(const char* section, const char* key, uint8_t* value, size_t* length);
+bool device_iot_config_set_bin(const char* section, const char* key, const uint8_t* value, size_t length);
+bool device_iot_config_addr_set_bin(const RawAddress& peer_addr, const char* key, const uint8_t* value, size_t length);
+bool device_iot_config_remove(const char* section, const char* key);
+
+size_t device_iot_config_get_bin_length(const char* section, const char* key);
+
+const device_iot_config_section_iter_t* device_iot_config_section_begin(void);
+const device_iot_config_section_iter_t* device_iot_config_section_end(void);
+const device_iot_config_section_iter_t* device_iot_config_section_next(const device_iot_config_section_iter_t* section);
+const char* device_iot_config_section_name(const device_iot_config_section_iter_t* section);
+
+void device_iot_config_flush(void);
+bool device_iot_config_clear(void);
+
+void device_debug_iot_config_dump(int fd);
+
+#endif
diff --git a/system_bt_ext/device/src/device_iot_config.cc b/system_bt_ext/device/src/device_iot_config.cc
new file mode 100644
index 0000000..b5b3d18
--- /dev/null
+++ b/system_bt_ext/device/src/device_iot_config.cc
@@ -0,0 +1,822 @@
+/******************************************************************************
+ *  Copyright (C) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Not a Contribution
+ *****************************************************************************/
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  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.
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#define LOG_TAG "device_iot_config"
+//#undef LOG_NDEBUG
+//#define LOG_NDEBUG 0
+#include "device_iot_config.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <string>
+#include <mutex>
+
+#include "bt_types.h"
+#include "btcore/include/module.h"
+#include "btif/include/btif_api.h"
+#include "btif/include/btif_util.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "osi/include/properties.h"
+
+#define BT_IOT_CONFIG_SOURCE_TAG_NUM 1010003
+
+#define INFO_SECTION "Info"
+#define VERSION_KEY "Version"
+#define FILE_CREATED_TIMESTAMP "TimeCreated"
+#define FILE_MODIFIED_TIMESTAMP "TimeModified"
+#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
+static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
+
+#ifndef DEVICES_MAX_NUM_IN_IOT_INFO_FILE
+#define DEVICES_MAX_NUM_IN_IOT_INFO_FILE  40
+#endif
+#define DEVICES_NUM_MARGIN 5
+
+#if (DEVICES_MAX_NUM_IN_IOT_INFO_FILE < DEVICES_NUM_MARGIN)
+#undef DEVICES_MAX_NUM_IN_IOT_INFO_FILE
+#define DEVICES_MAX_NUM_IN_IOT_INFO_FILE DEVICES_NUM_MARGIN
+#endif
+
+#define DEVICE_IOT_INFO_CURRENT_VERSION 1
+#define DEVICE_IOT_INFO_FIRST_VERSION 1
+
+#define IOT_CONFIG_FLUSH_EVT            0
+#define IOT_CONFIG_SAVE_TIMER_FIRED_EVT 1
+
+#if defined(OS_GENERIC)
+static const char* IOT_CONFIG_FILE_PATH = "bt_remote_dev_info.conf";
+static const char* IOT_CONFIG_BACKUP_PATH = "bt_remote_dev_info.bak";
+#else  // !defined(OS_GENERIC)
+static const char* IOT_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_remote_dev_info.conf";
+static const char* IOT_CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_remote_dev_info.bak";
+#endif  // defined(OS_GENERIC)
+static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 12000;
+
+static void timer_iot_config_save_cb(void* data);
+static void device_iot_config_write(uint16_t event, char* p_param);
+static config_t* device_iot_config_open(const char* filename);
+static int device_iot_config_get_device_num(config_t* config);
+static void device_iot_config_save(void);
+static bool is_factory_reset(void);
+static void delete_iot_config_files(void);
+
+static enum ConfigSource {
+  NOT_LOADED,
+  ORIGINAL,
+  BACKUP,
+  NEW_FILE,
+  RESET
+} device_iot_config_source = NOT_LOADED;
+
+static int device_iot_config_devices_loaded = -1;
+static char device_iot_config_time_created[TIME_STRING_LENGTH];
+
+static std::mutex config_lock;  // protects operations on |config|.
+static config_t* config;
+static alarm_t* config_timer;
+static bool iot_logging_enabled = false;
+
+#define CHECK_LOGGING_ENABLED(return_value) do { if (!iot_logging_enabled) return (return_value); } while(0)
+
+// Module lifecycle functions
+static future_t* init(void) {
+  char enabled[PROPERTY_VALUE_MAX] = {0};
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  osi_property_get("persist.vendor.service.bt.iot.enablelogging", enabled, "false");
+  iot_logging_enabled = strncmp(enabled, "true", 4) == 0;
+
+  if (!iot_logging_enabled) {
+    delete_iot_config_files();
+    return future_new_immediate(FUTURE_SUCCESS);
+  }
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (is_factory_reset())
+    delete_iot_config_files();
+
+  config = device_iot_config_open(IOT_CONFIG_FILE_PATH);
+  device_iot_config_source = ORIGINAL;
+  if (!config) {
+    LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
+          __func__, IOT_CONFIG_FILE_PATH);
+    config = device_iot_config_open(IOT_CONFIG_BACKUP_PATH);
+    device_iot_config_source = BACKUP;
+  }
+
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to load bak file; creating empty config.", __func__);
+    config = config_new_empty();
+    device_iot_config_source = NEW_FILE;
+  }
+
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+    goto error;
+  }
+
+  int version;
+  if (device_iot_config_source == NEW_FILE) {
+    version = DEVICE_IOT_INFO_CURRENT_VERSION;
+    config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_CURRENT_VERSION);
+  } else {
+    version = config_get_int(config, INFO_SECTION, VERSION_KEY, -1);
+    if (version == -1) {
+      version = DEVICE_IOT_INFO_FIRST_VERSION;
+      config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_FIRST_VERSION);
+    }
+  }
+
+  if (version != DEVICE_IOT_INFO_CURRENT_VERSION) {
+    LOG_INFO(LOG_TAG, "%s: version in file is %d, CURRENT_VERSION is %d ", __func__,
+        version, DEVICE_IOT_INFO_CURRENT_VERSION);
+    remove(IOT_CONFIG_FILE_PATH);
+    remove(IOT_CONFIG_BACKUP_PATH);
+    config_free(config);
+    config = config_new_empty();
+    if (!config) {
+      LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+      goto error;
+    }
+    config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_CURRENT_VERSION);
+    device_iot_config_source = NEW_FILE;
+  }
+
+  device_iot_config_devices_loaded = device_iot_config_get_device_num(config);
+
+  // Read or set config file creation timestamp
+  const char* time_str;
+  time_str = config_get_string(config, INFO_SECTION, FILE_CREATED_TIMESTAMP, NULL);
+  if (time_str != NULL) {
+    strlcpy(device_iot_config_time_created, time_str, TIME_STRING_LENGTH);
+  } else {
+    time_t current_time = time(NULL);
+    struct tm* time_created = localtime(&current_time);
+    if (time_created) {
+      strftime(device_iot_config_time_created, TIME_STRING_LENGTH,
+              TIME_STRING_FORMAT, time_created);
+      config_set_string(config, INFO_SECTION, FILE_CREATED_TIMESTAMP,
+              device_iot_config_time_created);
+    }
+  }
+
+  // TODO(sharvil): use a non-wake alarm for this once we have
+  // API support for it. There's no need to wake the system to
+  // write back to disk.
+  config_timer = alarm_new("btif.iot.config");
+  if (!config_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
+    goto error;
+  }
+
+  LOG_EVENT_INT(BT_IOT_CONFIG_SOURCE_TAG_NUM, device_iot_config_source);
+
+  return future_new_immediate(FUTURE_SUCCESS);
+
+error:
+  alarm_free(config_timer);
+  config_free(config);
+  config_timer = NULL;
+  config = NULL;
+  device_iot_config_source = NOT_LOADED;
+  return future_new_immediate(FUTURE_FAIL);
+}
+
+static config_t* device_iot_config_open(const char* filename) {
+  config_t* config = config_new(filename);
+  if (!config)
+    return NULL;
+
+  return config;
+}
+
+static future_t* start_up(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  device_iot_config_int_add_one(IOT_CONF_KEY_SECTION_ADAPTER, IOT_CONF_KEY_BT_ONOFF_COUNT);
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  device_iot_config_flush();
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* clean_up(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  if (config_timer != NULL && alarm_is_scheduled(config_timer))
+    device_iot_config_flush();
+
+  alarm_free(config_timer);
+  config_timer = NULL;
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_free(config);
+  config = NULL;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t device_iot_config_module = {
+  .name = DEVICE_IOT_CONFIG_MODULE,
+  .init = init,
+  .start_up = start_up,
+  .shut_down = shut_down,
+  .clean_up = clean_up
+};
+
+bool device_iot_config_has_section(const char* section) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_section(config, section);
+}
+
+bool device_iot_config_exist(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_key(config, section, key);
+}
+
+static bool device_iot_config_has_key_value(const char* section, const char* key, const char* value_str) {
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value_str != NULL);
+
+  const char* stored_value = config_get_string(config, section, key, NULL);
+
+  if (!stored_value || strcmp(value_str, stored_value) != 0)
+    return false;
+
+  return true;
+}
+
+bool device_iot_config_get_int(const char* section, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  bool ret = config_has_key(config, section, key);
+  if (ret)
+    *value = config_get_int(config, section, key, *value);
+
+  return ret;
+}
+
+bool device_iot_config_addr_get_int(const RawAddress& peer_addr, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_get_int(bdstr, key, value);
+}
+
+bool device_iot_config_set_int(const char* section, const char* key, int value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=%d", __func__, section, key, value);
+  std::unique_lock<std::mutex> lock(config_lock);
+  char value_str[32] = {0};
+  snprintf(value_str, sizeof(value_str), "%d", value);
+  if (device_iot_config_has_key_value(section, key, value_str))
+    return true;
+
+  config_set_string(config, section, key, value_str);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_int(const RawAddress& peer_addr, const char* key, int value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_int(bdstr, key, value);
+}
+
+bool device_iot_config_int_add_one(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s", __func__, section, key);
+  int result = 0;
+  std::unique_lock<std::mutex> lock(config_lock);
+  result = config_get_int(config, section, key, result);
+  result += 1;
+  config_set_int(config, section, key, result);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_int_add_one(const RawAddress& peer_addr, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_int_add_one(bdstr, key);
+}
+
+bool device_iot_config_get_hex(const char* section, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  int sscanf_ret, result = 0;
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* stored_value = config_get_string(config, section, key, NULL);
+  if (!stored_value)
+    return false;
+
+  sscanf_ret = sscanf(stored_value, "%x", &result);
+  if (sscanf_ret != 1)
+    return false;
+
+  *value = result;
+  return true;
+}
+
+bool device_iot_config_addr_get_hex(const RawAddress& peer_addr, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_get_hex(bdstr, key, value);
+}
+
+bool device_iot_config_set_hex(const char* section, const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=0x%x", __func__, section, key, value);
+  char value_str[32] = { 0 };
+  if (byte_num == 1)
+    snprintf(value_str, sizeof(value_str), "%02x", value);
+  else if (byte_num == 2)
+    snprintf(value_str, sizeof(value_str), "%04x", value);
+  else if (byte_num == 3)
+    snprintf(value_str, sizeof(value_str), "%06x", value);
+  else if (byte_num == 4)
+    snprintf(value_str, sizeof(value_str), "%08x", value);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, value_str))
+    return true;
+
+  config_set_string(config, section, key, value_str);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_hex(const RawAddress& peer_addr,
+          const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_hex(bdstr, key, value, byte_num);
+}
+
+bool device_iot_config_addr_set_hex_if_greater(const RawAddress& peer_addr,
+    const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  int stored_value = 0;
+  bool ret = device_iot_config_addr_get_hex(peer_addr, key, &stored_value);
+  if (ret && stored_value >= value)
+    return true;
+
+  return device_iot_config_addr_set_hex(peer_addr, key, value, byte_num);
+}
+
+bool device_iot_config_get_str(const char* section, const char* key, char* value, int* size_bytes) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+  CHECK(size_bytes != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* stored_value = config_get_string(config, section, key, NULL);
+
+  if (!stored_value)
+    return false;
+
+  strlcpy(value, stored_value, *size_bytes);
+  *size_bytes = strlen(value) + 1;
+
+  return true;
+}
+
+bool device_iot_config_set_str(const char* section, const char* key, const char* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=%s", __func__, section, key, value);
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, value))
+    return true;
+
+  config_set_string(config, section, key, value);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_str(const RawAddress& peer_addr,
+          const char* key, const char* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_str(bdstr, key, value);
+}
+
+bool device_iot_config_get_bin(const char* section, const char* key,
+          uint8_t* value, size_t* length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+  CHECK(length != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+
+  if (!value_str)
+    return false;
+
+  size_t value_len = strlen(value_str);
+  if ((value_len % 2) != 0 || *length < (value_len / 2))
+    return false;
+
+  for (size_t i = 0; i < value_len; ++i)
+    if (!isxdigit(value_str[i]))
+      return false;
+
+  for (*length = 0; *value_str; value_str += 2, *length += 1)
+    sscanf(value_str, "%02hhx", &value[*length]);
+
+  return true;
+}
+
+size_t device_iot_config_get_bin_length(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(0);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+
+  if (!value_str)
+    return 0;
+
+  size_t value_len = strlen(value_str);
+  return ((value_len % 2) != 0) ? 0 : (value_len / 2);
+}
+
+bool device_iot_config_set_bin(const char* section, const char* key,
+          const uint8_t* value, size_t length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  const char* lookup = "0123456789abcdef";
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: key = %s", __func__, key);
+  if (length > 0)
+    CHECK(value != NULL);
+
+  char* str = (char* )osi_calloc(length * 2 + 1);
+  if (str == NULL) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate a str.", __func__);
+    return false;
+  }
+
+  for (size_t i = 0; i < length; ++i) {
+    str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
+    str[(i * 2) + 1] = lookup[value[i] & 0x0F];
+  }
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, str))
+    return true;
+
+  config_set_string(config, section, key, str);
+  device_iot_config_save();
+
+  osi_free(str);
+  return true;
+}
+
+bool device_iot_config_addr_set_bin(const RawAddress& peer_addr,
+          const char* key, const uint8_t* value, size_t length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_bin(bdstr, key, value, length);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_begin(void) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_begin(config);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_end(void) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_end(config);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_next(const
+          device_iot_config_section_iter_t* section) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_next((const
+          config_section_node_t* )section);
+}
+
+const char* device_iot_config_section_name(const device_iot_config_section_iter_t* section) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  return config_section_name((const config_section_node_t* )section);
+}
+
+bool device_iot_config_remove(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_remove_key(config, section, key);
+}
+
+static void device_iot_config_save(void) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s", __func__);
+  alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_iot_config_save_cb, NULL);
+}
+
+void device_iot_config_flush(void) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  int event = alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT :
+          IOT_CONFIG_FLUSH_EVT;
+  LOG_VERBOSE(LOG_TAG, "%s: evt=%d", __func__, event);
+  alarm_cancel(config_timer);
+  device_iot_config_write(event, NULL);
+}
+
+bool device_iot_config_clear(void) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  alarm_cancel(config_timer);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_free(config);
+
+  config = config_new_empty();
+  if (config == NULL) {
+    return false;
+  }
+
+  bool ret = config_save(config, IOT_CONFIG_FILE_PATH);
+  device_iot_config_source = RESET;
+  return ret;
+}
+
+static void timer_iot_config_save_cb(UNUSED_ATTR void* data) {
+  // Moving file I/O to btif context instead of timer callback because
+  // it usually takes a lot of time to be completed, introducing
+  // delays during A2DP playback causing blips or choppiness.
+  LOG_VERBOSE(LOG_TAG, "%s", __func__);
+  btif_transfer_context(device_iot_config_write, IOT_CONFIG_SAVE_TIMER_FIRED_EVT, NULL, 0, NULL);
+}
+
+static void set_modified_time() {
+  time_t current_time = time(NULL);
+  struct tm* time_modified = localtime(&current_time);
+  char device_iot_config_time_modified[TIME_STRING_LENGTH];
+  if (time_modified) {
+    strftime(device_iot_config_time_modified, TIME_STRING_LENGTH,
+            TIME_STRING_FORMAT, time_modified);
+    config_set_string(config, INFO_SECTION, FILE_MODIFIED_TIMESTAMP,
+            device_iot_config_time_modified);
+  }
+}
+
+static void restrict_device_num() {
+  CHECK(config != NULL);
+
+  int curr_num = device_iot_config_get_device_num(config);
+  int removed_devices = 0;
+  int need_remove_devices_num;
+
+  if (curr_num <= DEVICES_MAX_NUM_IN_IOT_INFO_FILE) {
+    return;
+  }
+
+  need_remove_devices_num = curr_num - DEVICES_MAX_NUM_IN_IOT_INFO_FILE + DEVICES_NUM_MARGIN;
+  LOG_INFO(LOG_TAG, "%s: curr_num=%d, need_remove_num=%d", __func__,
+     curr_num, need_remove_devices_num);
+
+  const config_section_node_t* snode = config_section_begin(config);
+  while (snode != config_section_end(config)) {
+    const char* section = config_section_name(snode);
+    if (RawAddress::IsValidAddress(section)) {
+      snode = config_section_next(snode);
+      config_remove_section(config, section);
+      if (++removed_devices >= need_remove_devices_num) {
+        break;
+      }
+    } else {
+      snode = config_section_next(snode);
+    }
+  }
+}
+
+static int compare_key(const char* first, const char* second) {
+  bool first_is_profile_key = strncasecmp(first, "Profile", 7) == 0;
+  bool second_is_profile_key = strncasecmp(second, "Profile", 7) == 0;
+  if (!first_is_profile_key && !second_is_profile_key) {
+    return 0;
+  } else if (first_is_profile_key && second_is_profile_key) {
+    return strcasecmp(first, second);
+  } else {
+    return first_is_profile_key ? 1 : -1;
+  }
+}
+
+static void device_iot_config_write(uint16_t event, UNUSED_ATTR char* p_param) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_INFO(LOG_TAG, "%s: evt=%d", __func__, event);
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (event == IOT_CONFIG_SAVE_TIMER_FIRED_EVT)
+    set_modified_time();
+
+  rename(IOT_CONFIG_FILE_PATH, IOT_CONFIG_BACKUP_PATH);
+  restrict_device_num();
+  config_sections_sort_by_entry_key(config, compare_key);
+  config_save(config, IOT_CONFIG_FILE_PATH);
+}
+
+static int device_iot_config_get_device_num(config_t* conf) {
+  CHECK_LOGGING_ENABLED(0);
+
+  CHECK(conf != NULL);
+  int devices = 0;
+
+  const config_section_node_t* snode = config_section_begin(conf);
+  while (snode != config_section_end(conf)) {
+    const char* section = config_section_name(snode);
+    if (RawAddress::IsValidAddress(section)) {
+      devices++;
+    }
+    snode = config_section_next(snode);
+  }
+  return devices;
+}
+
+void device_debug_iot_config_dump(int fd) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  dprintf(fd, "\nBluetooth Iot Config:\n");
+
+  dprintf(fd, "  Config Source: ");
+  switch(device_iot_config_source) {
+    case NOT_LOADED:
+      dprintf(fd, "Not loaded\n");
+      break;
+    case ORIGINAL:
+      dprintf(fd, "Original file\n");
+      break;
+    case BACKUP:
+      dprintf(fd, "Backup file\n");
+      break;
+    case NEW_FILE:
+      dprintf(fd, "New file\n");
+      break;
+    case RESET:
+      dprintf(fd, "Reset file\n");
+      break;
+  }
+
+  dprintf(fd, "  Devices loaded: %d\n", device_iot_config_devices_loaded);
+  dprintf(fd, "  File created/tagged: %s\n", device_iot_config_time_created);
+}
+
+static bool is_factory_reset(void) {
+  char factory_reset[PROPERTY_VALUE_MAX] = {0};
+  osi_property_get("persist.bluetooth.factoryreset", factory_reset, "false");
+  return strncmp(factory_reset, "true", 4) == 0;
+}
+
+static void delete_iot_config_files(void) {
+  remove(IOT_CONFIG_FILE_PATH);
+  remove(IOT_CONFIG_BACKUP_PATH);
+}
+
+#endif
diff --git a/system_bt_ext/device/src/interop.cc b/system_bt_ext/device/src/interop.cc
index 6e209c7..b29d1c9 100644
--- a/system_bt_ext/device/src/interop.cc
+++ b/system_bt_ext/device/src/interop.cc
@@ -241,6 +241,7 @@
     CASE_RETURN_STR(INTEROP_ENABLE_AAC_CODEC)
     CASE_RETURN_STR(INTEROP_DISABLE_CONNECTION_AFTER_COLLISION)
     CASE_RETURN_STR(INTEROP_AVRCP_BROWSE_OPEN_CHANNEL_COLLISION)
+    CASE_RETURN_STR(INTEROP_ENABLE_PL10_ADAPTIVE_CONTROL)
     CASE_RETURN_STR(END_OF_INTEROP_LIST)
     CASE_RETURN_STR(INTEROP_ADV_PBAP_VER_1_2)
     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_LINK_DURING_SCO)
diff --git a/system_bt_ext/device/src/profile_config.cc b/system_bt_ext/device/src/profile_config.cc
index 8446864..ed1b0d8 100644
--- a/system_bt_ext/device/src/profile_config.cc
+++ b/system_bt_ext/device/src/profile_config.cc
@@ -85,6 +85,7 @@
 
 typedef struct {
    char map_email_support[VALUE_MAX_LENGTH];
+   char map_0104_support[VALUE_MAX_LENGTH];
 } map_feature_t;
 
 typedef struct {
@@ -131,6 +132,7 @@
     CASE_RETURN_STR(AVRCP_0103_SUPPORT)
     CASE_RETURN_STR(USE_SIM_SUPPORT)
     CASE_RETURN_STR(MAP_EMAIL_SUPPORT)
+    CASE_RETURN_STR(MAP_0104_SUPPORT)
     CASE_RETURN_STR(PBAP_0102_SUPPORT)
     CASE_RETURN_STR(END_OF_FEATURE_LIST)
   }
@@ -347,6 +349,14 @@
           LOG_WARN(LOG_TAG, "profile_feature_fetch:MAP_EMAIL_SUPPORT found %d" , feature_set);
         }
         break;
+        case MAP_0104_SUPPORT:
+        {
+          if (strncasecmp("true", db_entry->profile_feature_type.map_feature_entry.map_0104_support,
+              strlen("true")) == 0)
+            feature_set = true;
+          LOG_WARN(LOG_TAG, "profile_feature_fetch:MAP_0104_SUPPORT found %d" , feature_set);
+        }
+        break;
         default:
         {
           LOG_WARN(LOG_TAG, "profile_feature_fetch:profile = %d , feature %d not found" , profile, feature_name);
@@ -451,6 +461,14 @@
           memcpy(&entry->profile_feature_type.map_feature_entry.map_email_support, value, strlen(value));
         }
         break;
+        case MAP_0104_SUPPORT:
+        {
+          memset(&entry->profile_feature_type.map_feature_entry.map_0104_support,
+              '\0', VALUE_MAX_LENGTH);
+          memcpy(&entry->profile_feature_type.map_feature_entry.map_0104_support,
+              value, strlen(value));
+        }
+        break;
         default:
         {
           LOG_WARN(LOG_TAG,"%s is invalid key %s", __func__, key);
diff --git a/system_bt_ext/include/bt_testapp.h b/system_bt_ext/include/bt_testapp.h
index a8681ed..486b9e1 100644
--- a/system_bt_ext/include/bt_testapp.h
+++ b/system_bt_ext/include/bt_testapp.h
@@ -50,7 +50,6 @@
 #include "sdp_api.h"
 #include "gatt_api.h"
 #include "gap_api.h"
-#include "mca_api.h"
 #include <hardware/hardware.h>
 #include "btm_api.h"
 #include "bt_types.h"
@@ -138,37 +137,6 @@
 typedef struct
 {
     size_t    size;
-    void (*Init)(void);
-    tMCA_HANDLE (*Register)(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback);
-    void        (*Deregister)(tMCA_HANDLE handle);
-    tMCA_RESULT (*CreateDep)(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs);
-    tMCA_RESULT (*DeleteDep)(tMCA_HANDLE handle, tMCA_DEP dep);
-    tMCA_RESULT (*ConnectReq)(tMCA_HANDLE handle, RawAddress bd_addr,
-                                          uint16_t ctrl_psm,
-                                          uint16_t sec_mask);
-    tMCA_RESULT (*DisconnectReq)(tMCA_CL mcl);
-    tMCA_RESULT (*CreateMdl)(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
-                                         uint16_t mdl_id, uint8_t peer_dep_id,
-                                         uint8_t cfg, const tMCA_CHNL_CFG *p_chnl_cfg);
-    tMCA_RESULT (*CreateMdlRsp)(tMCA_CL mcl, tMCA_DEP dep,
-                                            uint16_t mdl_id, uint8_t cfg, uint8_t rsp_code,
-                                            const tMCA_CHNL_CFG *p_chnl_cfg);
-    tMCA_RESULT (*CloseReq)(tMCA_DL mdl);
-    tMCA_RESULT (*ReconnectMdl)(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
-                                            uint16_t mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg);
-    tMCA_RESULT (*ReconnectMdlRsp)(tMCA_CL mcl, tMCA_DEP dep,
-                                               uint16_t mdl_id, uint8_t rsp_code,
-                                               const tMCA_CHNL_CFG *p_chnl_cfg);
-    tMCA_RESULT (*DataChnlCfg)(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg);
-    tMCA_RESULT (*Abort)(tMCA_CL mcl);
-    tMCA_RESULT (*Delete)(tMCA_CL mcl, uint16_t mdl_id);
-    tMCA_RESULT (*WriteReq)(tMCA_DL mdl, BT_HDR *p_pkt);
-    uint16_t (*GetL2CapChannel) (tMCA_DL mdl);
-}btmcap_interface_t;
-
-typedef struct
-{
-    size_t    size;
     //GATT common APIs (Both client and server)
     tGATT_IF (*Register) (bluetooth::Uuid& p_app_uuid128, tGATT_CBACK *p_cb_info);
     void (*Deregister) (tGATT_IF gatt_if);
@@ -179,7 +147,9 @@
 
     //GATT Client APIs
     tGATT_STATUS (*cConfigureMTU) (uint16_t conn_id, uint16_t  mtu);
-    tGATT_STATUS (*cDiscover) (uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_PARAM *p_param );
+    tGATT_STATUS (*cDiscover) (uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                            uint16_t start_handle, uint16_t end_handle,
+                            const bluetooth::Uuid& uuid);
     tGATT_STATUS (*cRead) (uint16_t conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read);
     tGATT_STATUS (*cWrite) (uint16_t conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write);
     tGATT_STATUS (*cExecuteWrite) (uint16_t conn_id, bool is_execute);
@@ -201,7 +171,7 @@
     bool (*PairCancel) (RawAddress bd_addr);
     void (*SecurityGrant)(RawAddress bd_addr, uint8_t res);
     void (*PasskeyReply) (RawAddress bd_addr, uint8_t res, uint32_t passkey);
-    bool (*Encrypt) (uint8_t *key, uint8_t key_len, uint8_t *plain_text, uint8_t pt_len, tSMP_ENC *p_out);
+    Octet16 (*Encrypt) (Octet16 key, Octet16 message);
 }btsmp_interface_t;
 typedef struct
 {
diff --git a/system_bt_ext/stack/Android.bp b/system_bt_ext/stack/Android.bp
index 15bd5f0..c317860 100644
--- a/system_bt_ext/stack/Android.bp
+++ b/system_bt_ext/stack/Android.bp
@@ -21,10 +21,12 @@
         "vendor/qcom/opensource/commonsys/system/bt/stack/include",
         "vendor/qcom/opensource/commonsys/system/bt/stack/btm",
         "vendor/qcom/opensource/commonsys/bluetooth_ext/system_bt_ext/bta/include/",
-        "vendor/qcom/opensource/commonsys/bluetooth_ext/vhal/include"
+        "vendor/qcom/opensource/commonsys/bluetooth_ext/system_bt_ext/device/include/",
+        "vendor/qcom/opensource/commonsys/bluetooth_ext/vhal/include",
     ],
     srcs: [
         "btm/btm_csb.cc",
+        "btm/btm_iot_config.cc",
         "hcic/hcivendorcmds.cc",
         "a2dp/a2dp_vendor_aptx_tws_encoder.cc",
         "a2dp/a2dp_vendor_aptx_tws.cc",
diff --git a/system_bt_ext/stack/btm/btm_iot_config.cc b/system_bt_ext/stack/btm/btm_iot_config.cc
new file mode 100644
index 0000000..75a6ae2
--- /dev/null
+++ b/system_bt_ext/stack/btm/btm_iot_config.cc
@@ -0,0 +1,125 @@
+/******************************************************************************
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * *  Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ * *  Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#include "device_iot_config.h"
+#include "btif/include/btif_storage.h"
+#include "btif/include/btif_util.h"
+#include "btm_int_types.h"
+#include "btm_ble_api.h"
+
+
+/*******************************************************************************
+*
+* Function         btm_iot_save_remote_properties
+*
+* Description      Store remote basic properties to iot conf file
+*
+* Returns          void
+*
+*******************************************************************************/
+void btm_iot_save_remote_properties(tACL_CONN* p_acl_cb) {
+  int name_length = 0;
+  char value[1024];
+  BD_NAME bd_name;
+  bt_property_t prop_name;
+  uint32_t cod = 0;
+  tBT_DEVICE_TYPE dev_type;
+  tBLE_ADDR_TYPE  addr_type;
+
+  //save remote name to iot conf file
+  if (strlen((const char *)p_acl_cb->remote_name))
+  {
+    name_length = strlen((char *)p_acl_cb->remote_name) > BTM_MAX_REM_BD_NAME_LEN ?
+            BTM_MAX_REM_BD_NAME_LEN : strlen((char *)p_acl_cb->remote_name) + 1;
+    strlcpy(value, (char*)p_acl_cb->remote_name, name_length);
+    device_iot_config_addr_set_str(p_acl_cb->remote_addr,
+            IOT_CONF_KEY_REMOTE_NAME, value);
+  } else {
+    if (BTM_GetRemoteDeviceName(p_acl_cb->remote_addr, bd_name))
+    {
+      device_iot_config_addr_set_str(p_acl_cb->remote_addr,
+              IOT_CONF_KEY_REMOTE_NAME, (char *)bd_name);
+    }
+  }
+
+  //save remote dev class to iot conf file
+  cod = devclass2uint(p_acl_cb->remote_dc);
+  if (cod == 0) {
+    /* Try to retrieve cod from storage */
+    BTIF_STORAGE_FILL_PROPERTY(&prop_name,
+            BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+    if (btif_storage_get_remote_device_property(&p_acl_cb->remote_addr, &prop_name)
+            == BT_STATUS_SUCCESS)
+      BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod);
+    if (cod == 0) {
+      BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__);
+      cod = (0x1F) << 8;
+    }
+  }
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_DEVCLASS, (int)cod);
+
+  BTM_ReadDevInfo(p_acl_cb->remote_addr, &dev_type, &addr_type);
+
+  //save remote dev type to iot conf file
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_DEVTYPE, (int)dev_type);
+
+  //save remote addr type to iot conf file
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_ADDRTYPE, (int)addr_type);
+
+  //save default recorded value to iot conf file
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_RECORDED, IOT_CONF_VAL_RECORDED_DEFAULT);
+}
+
+/*******************************************************************************
+*
+* Function         btm_iot_save_remote_versions
+*
+* Description      Store remote versions to iot conf file
+*
+* Returns          void
+*
+*******************************************************************************/
+void btm_iot_save_remote_versions(tACL_CONN* p_acl_cb) {
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_MANUFACTURER, p_acl_cb->manufacturer);
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_LMPVER, p_acl_cb->lmp_version);
+  device_iot_config_addr_set_int(p_acl_cb->remote_addr,
+          IOT_CONF_KEY_LMPSUBVER, p_acl_cb->lmp_subversion);
+}
+
+#endif
diff --git a/vhal/include/hardware/bt_rc_ext.h b/vhal/include/hardware/bt_rc_ext.h
index 5a7f3fc..40e7862 100644
--- a/vhal/include/hardware/bt_rc_ext.h
+++ b/vhal/include/hardware/bt_rc_ext.h
@@ -500,7 +500,7 @@
 
     /* Get folder item list response from TG to CT */
      bt_status_t (*get_folder_items_list_rsp)(RawAddress *bd_addr, btrc_status_t rsp_status,
-        uint16_t uid_counter, uint8_t num_items, btrc_folder_items_t *p_items);
+        uint16_t uid_counter, uint16_t num_items, btrc_folder_items_t *p_items);
 
     /* Change path response from TG to CT */
     bt_status_t (*change_path_rsp)(RawAddress *bd_addr, btrc_status_t rsp_status,
diff --git a/vhal/include/hardware/vendor.h b/vhal/include/hardware/vendor.h
index 00a532d..2b6be6f 100644
--- a/vhal/include/hardware/vendor.h
+++ b/vhal/include/hardware/vendor.h
@@ -75,6 +75,7 @@
  USE_SIM_SUPPORT,
  MAP_EMAIL_SUPPORT,
  PBAP_0102_SUPPORT,
+ MAP_0104_SUPPORT,
  END_OF_FEATURE_LIST
  } profile_info_t;
 
@@ -88,6 +89,8 @@
     BT_VENDOR_PROPERTY_TWS_PLUS_DEVICE_TYPE = 0x01,
     BT_VENDOR_PROPERTY_TWS_PLUS_PEER_ADDR,
     BT_VENDOR_PROPERTY_TWS_PLUS_AUTO_CONNECT,
+    BT_VENDOR_PROPERTY_HOST_ADD_ON_FEATURES,
+    BT_VENDOR_PROPERTY_SOC_ADD_ON_FEATURES
 } bt_vendor_property_type_t;
 
 typedef enum {
@@ -121,10 +124,19 @@
                           RawAddress *bd_addr, int num_properties,
                           bt_vendor_property_t *properties);
 
+/** Callback to handle SSR */
+typedef void (* ssr_vendor_callback)(void);
+
 /** Bluetooth HCI event Callback */
 /* Receive any HCI event from controller for raw commands */
 typedef void (* hci_event_recv_callback)(uint8_t event_code, uint8_t *buf, uint8_t len);
 
+/** Callback to notify the remote device vendor properties.
+ */
+typedef void (* adapter_vendor_prop_callback)(bt_status_t status,
+                          int num_properties,
+                          bt_vendor_property_t *properties);
+
 /** BT-Vendor callback structure. */
 typedef struct {
     /** set to sizeof(BtVendorCallbacks) */
@@ -133,6 +145,8 @@
     btvendor_iot_device_broadcast_callback iot_device_broadcast_cb;
     remote_dev_prop_callback         rmt_dev_prop_cb;
     hci_event_recv_callback  hci_event_recv_cb;
+    adapter_vendor_prop_callback     adapter_vendor_prop_cb;
+    ssr_vendor_callback         ssr_vendor_cb;
 } btvendor_callbacks_t;
 
 typedef int (*property_set_callout)(const char* key, const char* value);
@@ -185,6 +199,8 @@
     /** Sends connectivity network type used by Voip currently to stack */
     bt_status_t (*voip_network_type_wifi) (bthf_voip_state_t is_voip_started,
                                            bthf_voip_call_network_type_t is_network_wifi);
+    void (*hciclose)(void);
+
 
 } btvendor_interface_t;