HFP 1.7 profile update (1/4)

-> Added AG support for HFP 1.7 version upgrade which
   adds new type of indicator called HF(headset) indicators.
-> Added support for two new AT commands AT + BIND and AT + BIEV
   which have been appended to Hands-Free SLC sequence.
-> Added support to propagate the above commands and their data to
   the upper layers.

Bug: 19983867
Change-Id: I93d5b2af949f9fb99507a954e623cd0927ddc976
diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
index 3d52cef..285a967 100644
--- a/bta/ag/bta_ag_act.c
+++ b/bta/ag/bta_ag_act.c
@@ -432,6 +432,9 @@
     p_scb->hsp_version = HSP_VERSION_1_2;
     bta_ag_at_reinit(&p_scb->at_cb);
 
+    memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
+    memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
+
     /* stop timers */
     alarm_cancel(p_scb->ring_timer);
 #if (BTM_WBS_INCLUDED == TRUE)
diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c
index cfe298a..e5893e1 100644
--- a/bta/ag/bta_ag_cfg.c
+++ b/bta/ag/bta_ag_cfg.c
@@ -52,9 +52,24 @@
                                                                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
 #endif
 
+#ifndef BTA_AG_BIND_INFO
+#define BTA_AG_BIND_INFO "(1)"
+#endif
+
+const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] =
+{
+    /* The first row contains the number of indicators. Need to be updated accordingly */
+    {BTA_AG_NUM_LOCAL_HF_IND,   0,  0,  0,  0},
+
+    {1,    1,   1,   0,    1},     /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
+    {2,    1,   1,   0,    100}    /* Battery Level Status, supported, enabled, range 0 ~ 100 */
+};
+
 const tBTA_AG_CFG bta_ag_cfg =
 {
     BTA_AG_CIND_INFO,
+    BTA_AG_BIND_INFO,
+    BTA_AG_NUM_LOCAL_HF_IND,
     BTA_AG_CONN_TIMEOUT,
     BTA_AG_SCO_PKT_TYPES,
     BTA_AG_CHLD_VAL_ECC,
diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
index 2ab9f51..110b531 100644
--- a/bta/ag/bta_ag_cmd.c
+++ b/bta/ag/bta_ag_cmd.c
@@ -111,6 +111,8 @@
     BTA_AG_HF_CMD_CBC,
     BTA_AG_HF_CMD_BCC,
     BTA_AG_HF_CMD_BCS,
+    BTA_AG_HF_CMD_BIND,
+    BTA_AG_HF_CMD_BIEV,
     BTA_AG_HF_CMD_BAC
 };
 
@@ -152,6 +154,8 @@
     {"+CBC",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   100},
     {"+BCC",    BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
     {"+BCS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   BTA_AG_CMD_MAX_VAL},
+    {"+BIND",   BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST , BTA_AG_AT_STR,   0,   0},
+    {"+BIEV",   BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
     {"+BAC",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
     {"",        BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0}
 };
@@ -194,6 +198,7 @@
     BTA_AG_RES_COPS,
     BTA_AG_RES_CMEE,
     BTA_AG_RES_BCS,
+    BTA_AG_RES_BIND,
     BTA_AG_RES_UNAT
 };
 
@@ -223,6 +228,7 @@
     {"+COPS: ", BTA_AG_RES_FMT_STR},
     {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
     {"+BCS: ",  BTA_AG_RES_FMT_INT},
+    {"+BIND: ", BTA_AG_RES_FMT_STR},
     {"",        BTA_AG_RES_FMT_STR}
 };
 
@@ -268,6 +274,8 @@
     BTA_AG_AT_CBC_EVT,      /* BTA_AG_HF_CMD_CBC */
     0,                      /* BTA_AG_HF_CMD_BCC */
     BTA_AG_AT_BCS_EVT,      /* BTA_AG_HF_CMD_BCS */
+    BTA_AG_AT_BIND_EVT,     /* BTA_AG_HF_CMD_BIND */
+    BTA_AG_AT_BIEV_EVT,     /* BTA_AG_HF_CMD_BIEV */
     BTA_AG_AT_BAC_EVT       /* BTA_AG_HF_CMD_BAC */
 };
 
@@ -294,6 +302,7 @@
     0,                  /* BTA_AG_CALL_CANCEL_RES */
     0,                  /* BTA_AG_END_CALL_RES */
     0,                  /* BTA_AG_IN_CALL_HELD_RES */
+    BTA_AG_RES_BIND,    /* BTA_AG_BIND_RES */
     BTA_AG_RES_UNAT     /* BTA_AG_UNAT_RES */
 };
 
@@ -319,7 +328,8 @@
     BTA_AG_CALLSETUP_NONE,      /* BTA_AG_OUT_CALL_CONN_RES */
     BTA_AG_CALLSETUP_NONE,      /* BTA_AG_CALL_CANCEL_RES */
     BTA_AG_CALLSETUP_NONE,      /* BTA_AG_END_CALL_RES */
-    BTA_AG_CALLSETUP_NONE       /* BTA_AG_IN_CALL_HELD_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_IN_CALL_HELD_RES */
+    0                           /* BTA_AG_BIND_RES */
 };
 
 /*******************************************************************************
@@ -858,6 +868,222 @@
 
 /*******************************************************************************
 **
+** Function         bta_ag_find_empty_hf_ind)
+**
+** Description      This function returns the index of an empty HF indicator
+**                  structure.
+**
+** Returns          int : index of the empty HF indicator structure or
+**                            -1 if no empty indicator
+**                            is available.
+**
+*******************************************************************************/
+static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB *p_scb)
+{
+    for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++)
+    {
+        if (p_scb->peer_hf_indicators[index].ind_id == 0)
+            return index;
+    }
+
+    return -1;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_find_hf_ind_by_id
+**
+** Description      This function returns the index of the HF indicator
+**                  structure by the indicator id
+**
+** Returns          int : index of the HF indicator structure
+**                            -1 if the indicator
+**                            was not found.
+**
+*******************************************************************************/
+static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND *p_hf_ind, int size, uint32_t ind_id)
+{
+    for (int index = 0; index < size; index++)
+    {
+        if (p_hf_ind[index].ind_id == ind_id)
+            return index;
+    }
+
+    return -1;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_bind_set
+**
+** Description      Parse AT+BIND set command and save the indicators
+**
+** Returns          true if successful
+**
+*******************************************************************************/
+static bool bta_ag_parse_bind_set(tBTA_AG_SCB *p_scb, tBTA_AG_VAL val)
+{
+    char *p_token = strtok(val.str, ",");
+    if (p_token == NULL)
+        return false;
+
+    while (p_token != NULL)
+    {
+        uint16_t rcv_ind_id = atoi(p_token);
+        int index = bta_ag_find_empty_hf_ind(p_scb);
+        if (index == -1)
+        {
+            APPL_TRACE_WARNING("%s Can't save more indicators", __func__);
+            return false;
+        }
+
+        p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
+        APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
+
+        p_token = strtok(NULL, ",");
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_bind_response
+**
+** Description      Send response for the AT+BIND command (HFP 1.7) received
+**                  from the headset based on the argument types.
+**
+** Returns          Void
+**
+*******************************************************************************/
+static void bta_ag_bind_response(tBTA_AG_SCB *p_scb, uint8_t arg_type)
+{
+    char buffer[BTA_AG_AT_MAX_LEN];
+    memset(buffer, 0, BTA_AG_AT_MAX_LEN);
+
+    if (arg_type == BTA_AG_AT_TEST)
+    {
+        int index = 0;
+        buffer[index++] = '(';
+
+        for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
+        {
+            if (bta_ag_local_hf_ind_cfg[i+1].is_supported == true)
+            {
+                /* Add ',' from second indicator */
+                if (index > 1)
+                    buffer[index++] = ',';
+                sprintf(&buffer[index++], "%d", bta_ag_local_hf_ind_cfg[i+1].ind_id);
+            }
+        }
+
+        buffer[index++] = ')';
+
+        bta_ag_send_result(p_scb, BTA_AG_RES_BIND, buffer, 0);
+        bta_ag_send_ok(p_scb);
+    }
+    else if (arg_type == BTA_AG_AT_READ)
+    {
+        char *p = buffer;
+
+        /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */
+        for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
+        {
+            if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND)
+            {
+                APPL_TRACE_WARNING("%s No space for more HF indicators", __func__);
+                break;
+            }
+
+            p_scb->local_hf_indicators[i].ind_id = bta_ag_local_hf_ind_cfg[i+1].ind_id;
+            p_scb->local_hf_indicators[i].is_supported = bta_ag_local_hf_ind_cfg[i+1].is_supported;
+            p_scb->local_hf_indicators[i].is_enable = bta_ag_local_hf_ind_cfg[i+1].is_enable;
+
+            int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+                                                    BTA_AG_MAX_NUM_PEER_HF_IND,
+                                                    p_scb->local_hf_indicators[i].ind_id);
+
+            /* Check whether local and peer sides support this indicator */
+            if (p_scb->local_hf_indicators[i].is_supported == true && peer_index != -1)
+            {
+                /* In the format of ind, state */
+                p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].ind_id, p);
+                *p++ = ',';
+                p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].is_enable, p);
+
+                bta_ag_send_result(p_scb, BTA_AG_RES_BIND, buffer, 0);
+
+                memset(buffer, 0, sizeof(buffer));
+                p = buffer;
+            } else {
+                /* If indicator is not supported, also set it to disable */
+                p_scb->local_hf_indicators[i].is_enable = false;
+            }
+        }
+
+        bta_ag_send_ok(p_scb);
+
+        /* If the service level connection wan't already open, now it's open */
+        if (!p_scb->svc_conn)
+            bta_ag_svc_conn_open(p_scb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_biev_response
+**
+** Description      Send response for AT+BIEV command (HFP 1.7) received from
+**                  the headset based on the argument types.
+**
+** Returns          true if the response was parsed successfully
+**
+*******************************************************************************/
+static bool bta_ag_parse_biev_response(tBTA_AG_SCB *p_scb, tBTA_AG_VAL *val)
+{
+    char *p_token = strtok(val->str, ",");
+    uint16_t rcv_ind_id = atoi(p_token);
+
+    p_token = strtok(NULL, ",");
+    uint16_t rcv_ind_val = atoi(p_token);
+
+    APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, rcv_ind_val);
+
+    /* Check whether indicator ID is valid or not */
+    if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND)
+    {
+        APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__, rcv_ind_id);
+        return false;
+    }
+
+    /* Check this indicator is support or not and enabled or not */
+    int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+                                BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
+    if (local_index == -1 ||
+        p_scb->local_hf_indicators[local_index].is_supported != true ||
+        p_scb->local_hf_indicators[local_index].is_enable != true)
+    {
+        APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__, rcv_ind_id);
+        return false;
+    }
+
+    /* For each indicator ID, check whether the indicator value is in range */
+    if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val ||
+        rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val)
+    {
+        APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val);
+        return false;
+    }
+
+    val->lidx = rcv_ind_id;
+    val->num = rcv_ind_val;
+
+    return true;
+}
+
+/*******************************************************************************
+**
 ** Function         bta_ag_at_hfp_cback
 **
 ** Description      AT command processing callback for HFP.
@@ -889,6 +1115,7 @@
 
     val.hdr.handle = bta_ag_scb_to_idx(p_scb);
     val.hdr.app_id = p_scb->app_id;
+    val.hdr.status = BTA_AG_SUCCESS;
     val.num = int_arg;
     bdcpy(val.bd_addr, p_scb->peer_addr);
     strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
@@ -1017,6 +1244,37 @@
             }
             break;
 
+        case BTA_AG_HF_CMD_BIND:
+            APPL_TRACE_DEBUG("%s BTA_AG_HF_CMD_BIND arg_type: %d", __func__, arg_type);
+            if (arg_type == BTA_AG_AT_SET)
+            {
+                if (bta_ag_parse_bind_set(p_scb, val))
+                {
+                    bta_ag_send_ok(p_scb);
+                } else {
+                    event = 0;/* don't call callback */
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+                }
+            } else {
+                bta_ag_bind_response(p_scb, arg_type);
+
+                /* Need not pass this command beyond BTIF.*/
+                /* Stack handles it internally */
+                event = 0;/* don't call callback */
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BIEV:
+            if (bta_ag_parse_biev_response(p_scb, &val))
+            {
+                bta_ag_send_ok(p_scb);
+            } else {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+                /* don't call callback receiving invalid indicator */
+                event = 0;
+            }
+            break;
+
         case BTA_AG_HF_CMD_CIND:
             if (arg_type == BTA_AG_AT_TEST)
             {
@@ -1089,7 +1347,12 @@
 
         case BTA_AG_HF_CMD_BRSF:
             /* store peer features */
-            p_scb->peer_features = (UINT16) int_arg;
+            p_scb->peer_features = (uint16_t) int_arg;
+#if (BTA_HFP_VERSION < HFP_VERSION_1_7 || BTA_HFP_HF_IND_SUPPORTED != true)
+            p_scb->features &= ~BTA_AG_FEAT_HF_IND;
+#endif
+            APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__,
+                p_scb->peer_features, p_scb->features);
 
             /* send BRSF, send OK */
             bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
@@ -1317,6 +1580,7 @@
     {
         val.hdr.handle = bta_ag_scb_to_idx(p_scb);
         val.hdr.app_id = p_scb->app_id;
+        val.hdr.status = BTA_AG_SUCCESS;
         val.num = 0;
         strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
         (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
@@ -1452,7 +1716,6 @@
 void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
 {
     UINT8 code = bta_ag_trans_result[p_result->result];
-
     APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
 
     switch(p_result->result)
@@ -1709,12 +1972,53 @@
             }
             break;
 
-       default:
+        case BTA_AG_BIND_RES:
+        {
+            /* Find whether ind_id is supported by local device or not */
+            int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+                                      BTA_AG_MAX_NUM_LOCAL_HF_IND, p_result->data.ind.id);
+            if (local_index == -1)
+            {
+                APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+                    p_result->data.ind.id);
+                return;
+            }
+
+            /* Find whether ind_id is supported by peer device or not */
+            int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+                                      BTA_AG_MAX_NUM_PEER_HF_IND, p_result->data.ind.id);
+            if (peer_index == -1)
+            {
+                APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+                    p_result->data.ind.id);
+                return;
+            } else {
+                /* If the current state is different from the one upper layer request
+                   change current state and send out the result */
+                if (p_scb->local_hf_indicators[local_index].is_enable != p_result->data.ind.on_demand)
+                {
+                    char buffer[BTA_AG_AT_MAX_LEN] = {0};
+                    char *p = buffer;
+
+                    p_scb->local_hf_indicators[local_index].is_enable = p_result->data.ind.on_demand;
+                    p += utl_itoa(p_result->data.ind.id, p);
+                    *p++ = ',';
+                    p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
+
+                    bta_ag_send_result(p_scb, code, buffer, 0);
+                } else {
+                    APPL_TRACE_DEBUG("%s HF Indicator %d already %s", p_result->data.ind.id,
+                        (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
+                }
+            }
+            break;
+        }
+
+        default:
             break;
     }
 }
 
-
 /*******************************************************************************
 **
 ** Function         bta_ag_result
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index a95f0a8..b721ac0 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -42,13 +42,6 @@
 /*****************************************************************************
 **  Constants
 *****************************************************************************/
-#define HFP_VERSION_1_1         0x0101
-#define HFP_VERSION_1_5         0x0105
-#define HFP_VERSION_1_6         0x0106
-
-#define HSP_VERSION_1_0         0x0100
-#define HSP_VERSION_1_2         0x0102
-
 /* Number of SCBs (AG service instances that can be registered) */
 #ifndef BTA_AG_NUM_SCB
 #define BTA_AG_NUM_SCB          2
@@ -62,6 +55,10 @@
 /* RFCOMM MTU SIZE */
 #define BTA_AG_MTU              256
 
+/* Max number of peer and local HF indicators */
+#define BTA_AG_MAX_NUM_PEER_HF_IND     20
+#define BTA_AG_MAX_NUM_LOCAL_HF_IND    4
+
 /* Internal profile indexes */
 #define BTA_AG_HSP              0       /* index for HSP */
 #define BTA_AG_HFP              1       /* index for HFP */
@@ -77,6 +74,7 @@
                                       BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT  | \
                                       BTA_AG_FEAT_ECS  | BTA_AG_FEAT_ECC     | \
                                       BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+                                      BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO  | \
                                       BTA_AG_FEAT_VOIP)
 
 #define BTA_AG_SDP_FEAT_SPEC         (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR    | \
@@ -298,6 +296,10 @@
     tBTA_AG_SCO_MSBC_SETTINGS codec_msbc_settings; /* settings to be used for the impending eSCO */
 #endif
 
+    tBTA_AG_HF_IND      peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND];   /* Peer supported
+                                                                      HF indicators */
+    tBTA_AG_HF_IND      local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
+                                                                      HF indicators */
 } tBTA_AG_SCB;
 
 /* type for sco data */
@@ -342,6 +344,7 @@
 
 /* config struct */
 extern tBTA_AG_CFG *p_bta_ag_cfg;
+extern tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
 
 /*****************************************************************************
 **  Function prototypes
diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c
index cb5bd80..aa43c02 100644
--- a/bta/ag/bta_ag_sdp.c
+++ b/bta/ag/bta_ag_sdp.c
@@ -159,7 +159,7 @@
     if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
     {
         profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
-        version = HFP_VERSION_1_6;
+        version = BTA_HFP_VERSION;
     }
     else
     {
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index ff85c9b..fa76a57 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -30,6 +30,24 @@
 /*****************************************************************************
 **  Constants and data types
 *****************************************************************************/
+#define HFP_VERSION_1_1         0x0101
+#define HFP_VERSION_1_5         0x0105
+#define HFP_VERSION_1_6         0x0106
+#define HFP_VERSION_1_7         0x0107
+
+#define HSP_VERSION_1_0         0x0100
+#define HSP_VERSION_1_2         0x0102
+
+/* Note, if you change the default version here, please also change the one in
+ * bta_hs_api.h, they are meant to be the same.
+ */
+#ifndef BTA_HFP_VERSION
+#define BTA_HFP_VERSION         HFP_VERSION_1_7
+#endif
+
+#ifndef BTA_HFP_HF_IND_SUPPORTED
+#define BTA_HFP_HF_IND_SUPPORTED    TRUE
+#endif
 
 /* AG feature masks */
 #define BTA_AG_FEAT_3WAY    0x00000001   /* Three-way calling */
@@ -42,12 +60,15 @@
 #define BTA_AG_FEAT_ECC     0x00000080   /* Enhanced Call Control */
 #define BTA_AG_FEAT_EXTERR  0x00000100   /* Extended error codes */
 #define BTA_AG_FEAT_CODEC   0x00000200   /* Codec Negotiation */
-#define BTA_AG_FEAT_VOIP    0x00000400   /* VoIP call */
+#define BTA_AG_FEAT_HF_IND  0x00000400   /* HF Indicators */
+#define BTA_AG_FEAT_ESCO    0x00000800   /* eSCO S4 (and T2) setting supported */
+
 /* Proprietary features: using 31 ~ 16 bits */
 #define BTA_AG_FEAT_BTRH    0x00010000   /* CCAP incoming call hold */
 #define BTA_AG_FEAT_UNAT    0x00020000   /* Pass unknown AT commands to application */
 #define BTA_AG_FEAT_NOSCO   0x00040000   /* No SCO control performed by BTA AG */
 #define BTA_AG_FEAT_NO_ESCO 0x00080000   /* Do not allow or use eSCO */
+#define BTA_AG_FEAT_VOIP    0x00100000   /* VoIP call */
 
 typedef UINT32 tBTA_AG_FEAT;
 
@@ -63,6 +84,9 @@
 #define BTA_AG_FAIL_RFCOMM      2 /* Open failed due to RFCOMM */
 #define BTA_AG_FAIL_RESOURCES   3 /* out of resources failure  */
 
+/*Status to disallow passing AT Events after BTIF */
+
+#define BTA_AG_DISALLOW_AT      5
 typedef UINT8 tBTA_AG_STATUS;
 
 /* handle values used with BTA_AgResult */
@@ -73,6 +97,18 @@
  * SCO_NO_CHANGE is used for changing sco behavior
  * They donot interfere with each other
  */
+
+/* Number of supported HF indicators, there is one HF indicator so far i.e.
+                                                   enhanced driver status. */
+/* Number of supported HF indicators,
+   1 for Enhanced Safety Status
+   2 for Battery Level Status */
+#ifndef BTA_AG_NUM_LOCAL_HF_IND
+#define BTA_AG_NUM_LOCAL_HF_IND     2
+#endif
+
+
+
 #define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
 
 /* AG result codes used with BTA_AgResult */
@@ -98,6 +134,7 @@
 #define BTA_AG_IN_CALL_HELD_RES     19  /* Incoming call held */
 #define BTA_AG_UNAT_RES             20  /* Response to unknown AT command event */
 #define BTA_AG_MULTI_CALL_RES       21  /* SLC at three way call */
+#define BTA_AG_BIND_RES             22  /* Activate/Deactivate HF indicator */
 
 typedef UINT8 tBTA_AG_RES;
 
@@ -110,9 +147,14 @@
 #define BTA_AG_PEER_FEAT_ECS        0x0020  /* Enhanced Call Status */
 #define BTA_AG_PEER_FEAT_ECC        0x0040  /* Enhanced Call Control */
 #define BTA_AG_PEER_FEAT_CODEC      0x0080  /* Codec Negotiation */
-#define BTA_AG_PEER_FEAT_VOIP       0x0100  /* VoIP call */
+#define BTA_AG_PEER_FEAT_HF_IND     0x0100   /* HF Indicators */
+#define BTA_AG_PEER_FEAT_ESCO       0x0200   /* eSCO S4 (and T2) setting supported */
 
-typedef UINT16 tBTA_AG_PEER_FEAT;
+/* Proprietary features: using bits after 12 */
+#define BTA_AG_PEER_FEAT_UNAT       0x1000   /* Pass unknown AT command responses to application */
+#define BTA_AG_PEER_FEAT_VOIP       0x2000  /* VoIP call */
+
+typedef uint16_t tBTA_AG_PEER_FEAT;
 
 /* HFP peer supported codec masks */
 // TODO(google) This should use common definitions
@@ -204,8 +246,9 @@
 /* data associated with BTA_AG_IND_RES */
 typedef struct
 {
-    UINT16          id;
-    UINT16          value;
+    uint16_t          id;
+    uint16_t          value;
+    bool              on_demand;
 } tBTA_AG_IND;
 
 /* data type for BTA_AgResult() */
@@ -254,6 +297,8 @@
 #define BTA_AG_AT_CBC_EVT       25 /* Battery Level report from HF */
 #define BTA_AG_AT_BAC_EVT       26 /* avablable codec */
 #define BTA_AG_AT_BCS_EVT       27 /* Codec select */
+#define BTA_AG_AT_BIND_EVT      28 /* HF indicator */
+#define BTA_AG_AT_BIEV_EVT      29 /* HF indicator updates from peer */
 
 typedef UINT8 tBTA_AG_EVT;
 
@@ -305,6 +350,7 @@
     char                str[BTA_AG_AT_MAX_LEN+1];
     UINT16              num;
     UINT8               idx;    /* call number used by CLCC and CHLD */
+    UINT16              lidx;    /* long index, ex, HF indicator */
 } tBTA_AG_VAL;
 
 /* union of data associated with AG callback */
@@ -368,12 +414,24 @@
 #define BTA_AG_BEARER_RES2          6   /* Reserved     */
 #define BTA_AG_BEARER_RES3          7   /* Reserved     */
 
+/* type for HF indicator */
+typedef struct
+{
+    UINT16          ind_id;
+    BOOLEAN         is_supported;
+    BOOLEAN         is_enable;
+    UINT32          ind_min_val;
+    UINT32          ind_max_val;
+} tBTA_AG_HF_IND;
+
 /* AG configuration structure */
 typedef struct
 {
     char         *cind_info;
-    INT32        conn_tout;
-    UINT16       sco_pkt_types;
+    char         *bind_info;
+    uint8_t        num_local_hf_ind;
+    int32_t        conn_tout;
+    uint16_t       sco_pkt_types;
     char         *chld_val_ecc;
     char         *chld_val;
 } tBTA_AG_CFG;
diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
index 4987bbe..6abf099 100644
--- a/btif/src/btif_hf.c
+++ b/btif/src/btif_hf.c
@@ -73,6 +73,8 @@
                              BTA_AG_FEAT_BTRH   | \
                              BTA_AG_FEAT_VREC   | \
                              BTA_AG_FEAT_CODEC |\
+                             BTA_AG_FEAT_HF_IND | \
+                             BTA_AG_FEAT_ESCO   | \
                              BTA_AG_FEAT_UNAT)
 #endif
 #else
@@ -84,6 +86,8 @@
                              BTA_AG_FEAT_EXTERR | \
                              BTA_AG_FEAT_BTRH   | \
                              BTA_AG_FEAT_VREC   | \
+                             BTA_AG_FEAT_HF_IND | \
+                             BTA_AG_FEAT_ESCO   | \
                              BTA_AG_FEAT_UNAT)
 #endif
 #endif
@@ -621,6 +625,21 @@
                         BTHF_WBS_YES : BTHF_WBS_NO, &btif_hf_cb[idx].connected_bda);
             break;
 
+        case BTA_AG_AT_BIND_EVT:
+            if (p_data->val.hdr.status == BTA_AG_SUCCESS)
+            {
+                HAL_CBACK(bt_hf_callbacks, bind_cb,p_data->val.str,
+                                                &btif_hf_cb[idx].connected_bda);
+            }
+            break;
+
+        case BTA_AG_AT_BIEV_EVT:
+            if (p_data->val.hdr.status == BTA_AG_SUCCESS)
+            {
+                HAL_CBACK(bt_hf_callbacks, biev_cb, (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
+                              &btif_hf_cb[idx].connected_bda);
+            }
+            break;
         default:
             BTIF_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
             break;
@@ -1107,6 +1126,33 @@
 
 /*******************************************************************************
 **
+** Function         bind_response
+**
+** Description      Send +BIND response
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t bind_response(bthf_hf_ind_type_t ind_id, bthf_hf_ind_status_t ind_status,
+                                 bt_bdaddr_t * bd_addr)
+{
+    CHECK_BTHF_INIT();
+
+    int index = btif_hf_idx_by_bdaddr(bd_addr);
+    if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
+        return BT_STATUS_FAIL;
+
+    tBTA_AG_RES_DATA ag_res;
+    memset(&ag_res, 0, sizeof(ag_res));
+    ag_res.ind.id = ind_id;
+    ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
+
+    BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
 ** Function         formatted_at_response
 **
 ** Description      Pre-formatted AT response, typically in response to unknown AT cmd
@@ -1581,6 +1627,7 @@
     phone_state_change,
     cleanup,
     configure_wbs,
+    bind_response,
 };
 
 /*******************************************************************************
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
index f4cffcb..a8c58c9 100644
--- a/btif/src/btif_util.c
+++ b/btif/src/btif_util.c
@@ -306,6 +306,8 @@
         CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
         CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
         CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+        CASE_RETURN_STR(BTA_AG_AT_BIND_EVT)
+        CASE_RETURN_STR(BTA_AG_AT_BIEV_EVT)
 
         default:
             return "UNKNOWN MSG ID";
diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c
index 8c374f9..952d182 100644
--- a/stack/btm/btm_sco.c
+++ b/stack/btm/btm_sco.c
@@ -34,6 +34,8 @@
 #include "btm_int.h"
 #include "hcidefs.h"
 #include "bt_utils.h"
+#include "device/include/controller.h"
+
 
 #if BTM_SCO_INCLUDED == TRUE
 
@@ -668,7 +670,7 @@
                              btm_cb.btm_sco_pkt_types_supported);
 
             /* OR in any exception packet types */
-            if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO)
+            if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_2_0)
             {
                 temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
                     (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c
index 9fa29e7..ade7a9b 100644
--- a/stack/btu/btu_hcif.c
+++ b/stack/btu/btu_hcif.c
@@ -1633,10 +1633,17 @@
     /* extract the HCI handle first */
     UINT8   status;
     UINT16  handle;
+    UINT16  interval;
+    UINT16  latency;
+    UINT16  timeout;
 
-    STREAM_TO_UINT8  (status, p);
-    STREAM_TO_UINT16 (handle, p);
-    l2cble_process_conn_update_evt(handle, status);
+    STREAM_TO_UINT8(status, p);
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT16(interval, p);
+    STREAM_TO_UINT16(latency, p);
+    STREAM_TO_UINT16(timeout, p);
+
+    l2cble_process_conn_update_evt(handle, status, interval, latency, timeout);
 }
 
 static void btu_ble_read_remote_feat_evt (UINT8 *p)
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index 44d87e7..a4d6cc2 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -281,6 +281,9 @@
 #define UUID_CODEC_MSBC                         0x0002   /* mSBC */
 #endif
 
+#define UUID_HF_IND_ENHANCED_DRIVER_SAFETY      0x0001   /* Assigned number for Enhanced Safety */
+#define UUID_HF_IND_BATTERY_LEVEL_STATUS        0x0002   /* Assigned number for Battery Status */
+
 /* Define all the 'Descriptor Type' values.
 */
 #define  NULL_DESC_TYPE                     0
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
index 4a2daa9..863530f 100644
--- a/stack/l2cap/l2c_ble.c
+++ b/stack/l2cap/l2c_ble.c
@@ -581,17 +581,16 @@
 ** Returns          void
 **
 *******************************************************************************/
-void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status)
+void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status,
+                  UINT16 interval, UINT16 latency, UINT16 timeout)
 {
-    tL2C_LCB *p_lcb;
-
-    L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt");
+    L2CAP_TRACE_DEBUG("%s", __func__);
 
     /* See if we have a link control block for the remote device */
-    p_lcb = l2cu_find_lcb_by_handle(handle);
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
     if (!p_lcb)
     {
-        L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Invalid handle: %d", handle);
+        L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle);
         return;
     }
 
@@ -599,13 +598,14 @@
 
     if (status != HCI_SUCCESS)
     {
-        L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Error status: %d", status);
+        L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status);
     }
 
     l2cble_start_conn_update(p_lcb);
 
-    L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt: conn_update_mask=%d", p_lcb->conn_update_mask);
+    L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d", __func__, p_lcb->conn_update_mask);
 }
+
 /*******************************************************************************
 **
 ** Function         l2cble_process_sig_cmd
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 54e1f03..8af47d7 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -767,7 +767,8 @@
 extern BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb);
 extern void l2cble_notify_le_connection (BD_ADDR bda);
 extern void l2c_ble_link_adjust_allocation (void);
-extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status);
+extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status,
+                        UINT16 interval, UINT16 latency, UINT16 timeout);
 
 extern void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb);
 extern void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result);