Bluetooth: Add support for HFP Client role.

Implementation changes in BTA and BTIF layer to support
HFP Client role.

Change-Id: I9f939c18e8f989a50f298d0b313c5a0959c030a7
diff --git a/system/bta/Android.mk b/system/bta/Android.mk
index 694e701..572cf75 100644
--- a/system/bta/Android.mk
+++ b/system/bta/Android.mk
@@ -37,6 +37,14 @@
     ./ag/bta_ag_cmd.c \
     ./ag/bta_ag_ci.c \
     ./ag/bta_ag_at.c \
+    ./hf_client/bta_hf_client_act.c \
+    ./hf_client/bta_hf_client_api.c \
+    ./hf_client/bta_hf_client_main.c \
+    ./hf_client/bta_hf_client_rfc.c \
+    ./hf_client/bta_hf_client_at.c \
+    ./hf_client/bta_hf_client_sdp.c \
+    ./hf_client/bta_hf_client_sco.c \
+    ./hf_client/bta_hf_client_cmd.c \
     ./hh/bta_hh_cfg.c \
     ./hh/bta_hh_act.c \
     ./hh/bta_hh_api.c \
diff --git a/system/bta/dm/bta_dm_cfg.c b/system/bta/dm/bta_dm_cfg.c
index e1fdcc5..fd7e551 100644
--- a/system/bta/dm/bta_dm_cfg.c
+++ b/system/bta/dm/bta_dm_cfg.c
@@ -136,25 +136,26 @@
   {BTA_ID_JV,  BTA_JV_PM_ID_1,      6},  /* app BTA_JV_PM_ID_1, reuse ftc spec table */
   {BTA_ID_JV,  BTA_ALL_APP_ID,      7},  /* reuse fts spec table */
   {BTA_ID_HL,  BTA_ALL_APP_ID,      8},  /* reuse fts spec table */
-  {BTA_ID_PAN, BTUI_PAN_ID_PANU,    9},  /*  PANU spec table */
-  {BTA_ID_PAN, BTUI_PAN_ID_NAP,    10}   /* NAP spec table */
+  {BTA_ID_HS,  BTA_ALL_APP_ID,      9},  /* HS spec table */
+  {BTA_ID_PAN, BTUI_PAN_ID_PANU,   10},  /* PANU spec table */
+  {BTA_ID_PAN, BTUI_PAN_ID_NAP,    11}   /* NAP spec table */
 #if BLE_INCLUDED == TRUE
-  ,{BTA_ID_GATTC,  BTA_ALL_APP_ID,   11}   /* gattc spec table */
-  ,{BTA_ID_GATTS,  BTA_ALL_APP_ID,   12}  /* gatts spec table */
+  ,{BTA_ID_GATTC,  BTA_ALL_APP_ID,  12}   /* gattc spec table */
+  ,{BTA_ID_GATTS,  BTA_ALL_APP_ID,  13}  /* gatts spec table */
 #endif
 };
 
 #if BLE_INCLUDED == TRUE /* add GATT PM entry for GATT over BR/EDR  */
 #ifdef BTE_SIM_APP      /* For Insight builds only, see the detail below */
-#define BTA_DM_NUM_PM_SPEC      (13 + 2)  /* additional two */
+#define BTA_DM_NUM_PM_SPEC      (14 + 2)  /* additional two */
 #else
-#define BTA_DM_NUM_PM_SPEC      13 /* additional JV*/
+#define BTA_DM_NUM_PM_SPEC      14 /* additional JV*/
 #endif
 #else
 #ifdef BTE_SIM_APP      /* For Insight builds only, see the detail below */
-#define BTA_DM_NUM_PM_SPEC      (11 + 2)  /* additional two */
+#define BTA_DM_NUM_PM_SPEC      (12 + 2)  /* additional two */
 #else
-#define BTA_DM_NUM_PM_SPEC      11  /* additional JV*/
+#define BTA_DM_NUM_PM_SPEC      12  /* additional JV*/
 #endif
 #endif
 
@@ -368,8 +369,26 @@
       {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
       {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}}     /* mode change retry */
   }
- }
+ },
 
+  /* HS */
+ {
+  (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK),                           /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+  (BTA_DM_PM_SSR2),                                              /* the SSR entry */
+#endif
+  {
+      {{BTA_DM_PM_SNIFF,  7000},   {BTA_DM_PM_NO_ACTION, 0}},   /* conn open sniff  */
+      {{BTA_DM_PM_NO_PREF,   0},   {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+      {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* app open */
+      {{BTA_DM_PM_NO_ACTION, 0},   {BTA_DM_PM_NO_ACTION, 0}},   /* app close */
+      {{BTA_DM_PM_SNIFF3, 7000},   {BTA_DM_PM_NO_ACTION, 0}},   /* sco open, active */
+      {{BTA_DM_PM_SNIFF,  7000},   {BTA_DM_PM_NO_ACTION, 0}},   /* sco close sniff  */
+      {{BTA_DM_PM_SNIFF,  7000},   {BTA_DM_PM_NO_ACTION, 0}},   /* idle */
+      {{BTA_DM_PM_ACTIVE,    0},   {BTA_DM_PM_NO_ACTION, 0}},   /* busy */
+      {{BTA_DM_PM_RETRY,  7000},   {BTA_DM_PM_NO_ACTION, 0}}    /* mode change retry */
+  }
+ }
 #if BLE_INCLUDED == TRUE
     /* GATTC */
  ,{
diff --git a/system/bta/hf_client/bta_hf_client_act.c b/system/bta/hf_client/bta_hf_client_act.c
new file mode 100644
index 0000000..854260a
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_act.c
@@ -0,0 +1,768 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for the handsfree client.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_dm_int.h"
+#include "l2c_api.h"
+#include "port_api.h"
+#include "bta_sys.h"
+#include "utl.h"
+#include "bt_utils.h"
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_HF_CLIENT_RFC_READ_MAX     512
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_register
+**
+** Description      This function initializes values of the scb and sets up
+**                  the SDP record for the services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT evt;
+    tBTA_UTL_COD   cod;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* initialize control block */
+    bta_hf_client_scb_init();
+
+    bta_hf_client_cb.scb.serv_sec_mask = p_data->api_register.sec_mask;
+    bta_hf_client_cb.scb.features = p_data->api_register.features;
+
+    /* initialize AT control block */
+    bta_hf_client_at_init();
+
+    /* create SDP records */
+    bta_hf_client_create_record(p_data);
+
+    /* Set the Audio service class bit */
+    cod.service = BTM_COD_SERVICE_AUDIO;
+    utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+    /* start RFCOMM server */
+    bta_hf_client_start_server();
+
+    /* call app callback with register event */
+    evt.reg.status = BTA_HF_CLIENT_SUCCESS;
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_REGISTER_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_deregister
+**
+** Description      This function removes the sdp records, closes the RFCOMM
+**                  servers, and deallocates the service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data)
+{
+    bta_hf_client_cb.scb.deregister = TRUE;
+
+    /* remove sdp record */
+    bta_hf_client_del_record(p_data);
+
+    /* remove rfcomm server */
+    bta_hf_client_close_server();
+
+    /* disable */
+    bta_hf_client_scb_disable();
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_dereg
+**
+** Description      Start a deregister event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data)
+{
+    bta_hf_client_cb.scb.deregister = TRUE;
+
+    /* remove sdp record */
+    bta_hf_client_del_record(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_close
+**
+** Description      Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* Take the link out of sniff and set L2C idle time to 0 */
+    bta_dm_pm_active(bta_hf_client_cb.scb.peer_addr);
+    L2CA_SetIdleTimeoutByBdAddr(bta_hf_client_cb.scb.peer_addr, 0);
+
+    /* if SCO is open close SCO and wait on RFCOMM close */
+    if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST)
+    {
+        bta_hf_client_cb.scb.sco_close_rfc = TRUE;
+    }
+    else
+    {
+        bta_hf_client_rfc_do_close(p_data);
+    }
+
+    /* always do SCO shutdown to handle all SCO corner cases */
+    bta_hf_client_sco_shutdown(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_open
+**
+** Description      This starts an HF Client open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    BD_ADDR pending_bd_addr;
+
+    /* store parameters */
+    if (p_data)
+    {
+        bdcpy(bta_hf_client_cb.scb.peer_addr, p_data->api_open.bd_addr);
+        bta_hf_client_cb.scb.cli_sec_mask = p_data->api_open.sec_mask;
+    }
+
+    /* Check if RFCOMM has any incoming connection to avoid collision. */
+    if (PORT_IsOpening (pending_bd_addr))
+    {
+        /* Let the incoming connection goes through.                        */
+        /* Issue collision for now.                                         */
+        /* We will decide what to do when we find incoming connection later.*/
+        bta_hf_client_collision_cback (0, BTA_ID_HS, 0, bta_hf_client_cb.scb.peer_addr);
+        return;
+    }
+
+    /* close server */
+    bta_hf_client_close_server();
+
+    /* set role */
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_INT;
+
+    /* do service search */
+    bta_hf_client_do_disc();
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_open
+**
+** Description      Send open callback event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_cback_open(tBTA_HF_CLIENT_DATA *p_data, tBTA_HF_CLIENT_STATUS status)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* call app callback with open event */
+    evt.open.status = status;
+    if(p_data)
+    {
+        /* if p_data is provided then we need to pick the bd address from the open api structure */
+        bdcpy(evt.open.bd_addr, p_data->api_open.bd_addr);
+    }
+    else
+    {
+        bdcpy(evt.open.bd_addr, bta_hf_client_cb.scb.peer_addr);
+    }
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPEN_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_open
+**
+** Description      Handle RFCOMM channel open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    bta_sys_conn_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_SUCCESS);
+
+    /* start SLC procedure */
+    bta_hf_client_slc_seq(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_acp_open
+**
+** Description      Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16          lcid;
+    int             i;
+    BD_ADDR         dev_addr;
+    int             status;
+
+    /* set role */
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+
+    APPL_TRACE_DEBUG2 ("bta_hf_client_rfc_acp_open: serv_handle = %d rfc.port_handle = %d",
+            bta_hf_client_cb.scb.serv_handle, p_data->rfc.port_handle);
+
+    /* get bd addr of peer */
+    if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid)))
+    {
+        APPL_TRACE_DEBUG1 ("bta_hf_client_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+    }
+
+    /* Collision Handling */
+    if (bta_hf_client_cb.scb.colli_tmr_on)
+    {
+        /* stop collision timer */
+        bta_hf_client_cb.scb.colli_tmr_on = FALSE;
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.colli_timer);
+
+        if (bdcmp (dev_addr, bta_hf_client_cb.scb.peer_addr) == 0)
+        {
+            /* If incoming and outgoing device are same, nothing more to do.            */
+            /* Outgoing conn will be aborted because we have successful incoming conn.  */
+        }
+        else
+        {
+            /* Resume outgoing connection. */
+            bta_hf_client_resume_open ();
+        }
+    }
+
+    bdcpy (bta_hf_client_cb.scb.peer_addr, dev_addr);
+    bta_hf_client_cb.scb.conn_handle = p_data->rfc.port_handle;
+
+    /* do service discovery to get features */
+    bta_hf_client_do_disc();
+
+    /* continue with open processing */
+    bta_hf_client_rfc_open(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_fail
+**
+** Description      RFCOMM connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reinitialize stuff */
+    bta_hf_client_cb.scb.conn_handle = 0;
+    bta_hf_client_cb.scb.peer_features = 0;
+    bta_hf_client_cb.scb.chld_features = 0;
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+    bta_hf_client_cb.scb.svc_conn = FALSE;
+    bta_hf_client_cb.scb.send_at_reply = FALSE;
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+    bta_hf_client_at_reset();
+
+    /* reopen server */
+    bta_hf_client_start_server();
+
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_fail
+**
+** Description      This function handles a discovery failure.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    /* reopen server */
+    bta_hf_client_start_server();
+
+    /* reinitialize stuff */
+
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_open_fail
+**
+** Description      open connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* call open cback w. failure */
+    bta_hf_client_cback_open(p_data, BTA_HF_CLIENT_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_close
+**
+** Description      RFCOMM connection closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    int i, num_active_conn = 0;
+    UNUSED(p_data);
+
+    /* reinitialize stuff */
+    bta_hf_client_cb.scb.peer_features = 0;
+    bta_hf_client_cb.scb.chld_features = 0;
+    bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+    bta_hf_client_cb.scb.svc_conn = FALSE;
+    bta_hf_client_cb.scb.send_at_reply = FALSE;
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+    bta_hf_client_at_reset();
+
+    bta_sys_conn_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    /* call close cback */
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLOSE_EVT, NULL);
+
+    /* if not deregistering reopen server */
+    if (bta_hf_client_cb.scb.deregister == FALSE)
+    {
+        /* Clear peer bd_addr so instance can be reused */
+        bdcpy(bta_hf_client_cb.scb.peer_addr, bd_addr_null);
+
+        /* start server as it might got closed on open*/
+        bta_hf_client_start_server();
+
+        bta_hf_client_cb.scb.conn_handle = 0;
+
+        /* Make sure SCO is shutdown */
+        bta_hf_client_sco_shutdown(NULL);
+
+        bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+    }
+    /* else close port and deallocate scb */
+    else
+    {
+        bta_hf_client_close_server();
+        bta_hf_client_scb_disable();
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_int_res
+**
+** Description      This function handles a discovery result when initiator.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16 event = BTA_HF_CLIENT_DISC_FAIL_EVT;
+
+    APPL_TRACE_DEBUG1 ("bta_hf_client_disc_int_res: Status: %d", p_data->disc_result.status);
+
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        if (bta_hf_client_sdp_find_attr())
+        {
+            event = BTA_HF_CLIENT_DISC_OK_EVT;
+        }
+    }
+
+    /* free discovery db */
+    bta_hf_client_free_db(p_data);
+
+    /* send ourselves sdp ok/fail event */
+    bta_hf_client_sm_execute(event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_disc_acp_res
+**
+** Description      This function handles a discovery result when acceptor.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        bta_hf_client_sdp_find_attr();
+    }
+
+    /* free discovery db */
+    bta_hf_client_free_db(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_data
+**
+** Description      Read and process data from RFCOMM.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UINT16  len;
+    char    buf[BTA_HF_CLIENT_RFC_READ_MAX];
+    UNUSED(p_data);
+
+    memset(buf, 0, sizeof(buf));
+
+    /* read data from rfcomm; if bad status, we're done */
+    while (PORT_ReadData(bta_hf_client_cb.scb.conn_handle, buf, BTA_HF_CLIENT_RFC_READ_MAX, &len) == PORT_SUCCESS)
+    {
+        /* if no data, we're done */
+        if (len == 0)
+        {
+            break;
+        }
+
+        bta_hf_client_at_parse(buf, len);
+
+        /* no more data to read, we're done */
+        if (len < BTA_HF_CLIENT_RFC_READ_MAX)
+        {
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_svc_conn_open
+**
+** Description      Service level connection opened
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT evt;
+    UNUSED(p_data);
+
+    memset(&evt, 0, sizeof(evt));
+
+    if (!bta_hf_client_cb.scb.svc_conn)
+    {
+        /* set state variable */
+        bta_hf_client_cb.scb.svc_conn = TRUE;
+
+        /* call callback */
+        evt.conn.peer_feat = bta_hf_client_cb.scb.peer_features;
+        evt.conn.chld_feat = bta_hf_client_cb.scb.chld_features;
+
+        (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CONN_EVT, &evt);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_ind
+**
+** Description      Send indicator callback event to application.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.ind.type = type;
+    evt.ind.value = value;
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_IND_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_evt_val
+**
+** Description      Send event to application.
+**                  This is a generic helper for events with common data.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.val.value = value;
+
+    (*bta_hf_client_cb.p_cback)(type, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_operator_name
+**
+** Description      Send operator name event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_operator_name(char *name)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    strlcpy(evt.operator.name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
+    evt.operator.name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0';
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPERATOR_NAME_EVT, &evt);
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_clip
+**
+** Description      Send CLIP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_clip(char *number)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLIP_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_ccwa
+**
+** Description      Send CLIP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_ccwa(char *number)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CCWA_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_at_result
+**
+** Description      Send AT result event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.result.type = type;
+    evt.result.cme = cme;
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_AT_RESULT_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_clcc
+**
+** Description      Send clcc event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.clcc.idx = idx;
+    evt.clcc.inc = incoming;
+    evt.clcc.status = status;
+    evt.clcc.mpty = mpty;
+
+    if (number)
+    {
+        evt.clcc.number_present = TRUE;
+        strlcpy(evt.clcc.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+        evt.clcc.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+    }
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLCC_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cnum
+**
+** Description      Send cnum event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_cnum(char *number, UINT16 service)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    evt.cnum.service = service;
+    strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    evt.cnum.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CNUM_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_binp
+**
+** Description      Send BINP event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_binp(char *number)
+{
+    tBTA_HF_CLIENT evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_BINP_EVT, &evt);
+}
diff --git a/system/bta/hf_client/bta_hf_client_at.c b/system/bta/hf_client/bta_hf_client_at.c
new file mode 100644
index 0000000..4f061ba
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_at.c
@@ -0,0 +1,1816 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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 <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "port_api.h"
+
+/* Uncomment to enable AT traffic dumping */
+/* #define BTA_HF_CLIENT_AT_DUMP 1 */
+
+/* minimum length of AT event */
+#define BTA_HF_CLIENT_AT_EVENT_MIN_LEN 3
+
+/* timeout for AT response  */
+#define BTA_HF_CLIENT_AT_TIMEOUT 29989
+
+/* timeout for AT hold timer  */
+#define BTA_HF_CLIENT_AT_HOLD_TIMEOUT 41
+
+/******************************************************************************
+**
+**          DATA TYPES AND CONTAINERS
+**
+*******************************************************************************/
+/* BRSF: store received values here */
+extern tBTA_HF_CLIENT_CB  bta_hf_client_cb;
+
+/******************************************************************************
+**       SUPPORTED EVENT MESSAGES
+*******************************************************************************/
+
+/* CIND: supported indicator names                        */
+#define BTA_HF_CLIENT_INDICATOR_BATTERYCHG  "battchg"
+#define BTA_HF_CLIENT_INDICATOR_SIGNAL      "signal"
+#define BTA_HF_CLIENT_INDICATOR_SERVICE     "service"
+#define BTA_HF_CLIENT_INDICATOR_CALL        "call"
+#define BTA_HF_CLIENT_INDICATOR_ROAM        "roam"
+#define BTA_HF_CLIENT_INDICATOR_CALLSETUP   "callsetup"
+#define BTA_HF_CLIENT_INDICATOR_CALLHELD    "callheld"
+
+/* CIND: represents each indicators boundaries */
+typedef struct
+{
+    char* name;
+    UINT8 min;
+    UINT8 max;
+    UINT8 namelen;
+} tBTA_HF_CLIENT_INDICATOR;
+
+#define BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT 7
+
+/* CIND: storage room for indicators value range and their statuses */
+static const tBTA_HF_CLIENT_INDICATOR bta_hf_client_indicators[BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT] =
+{
+    /* name                                | min | max | name length - used by parser */
+     {BTA_HF_CLIENT_INDICATOR_BATTERYCHG,     0,   5,    sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
+     {BTA_HF_CLIENT_INDICATOR_SIGNAL,         0,   5,    sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
+     {BTA_HF_CLIENT_INDICATOR_SERVICE,        0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
+     {BTA_HF_CLIENT_INDICATOR_CALL,           0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_CALL)},
+     {BTA_HF_CLIENT_INDICATOR_ROAM,           0,   1,    sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
+     {BTA_HF_CLIENT_INDICATOR_CALLSETUP,      0,   3,    sizeof(BTA_HF_CLIENT_INDICATOR_CALLSETUP)},
+     {BTA_HF_CLIENT_INDICATOR_CALLHELD,       0,   2,    sizeof(BTA_HF_CLIENT_INDICATOR_CALLHELD)}
+};
+
+/* +VGM/+VGS - gain min/max values  */
+#define BTA_HF_CLIENT_VGS_MIN   0
+#define BTA_HF_CLIENT_VGS_MAX  15
+#define BTA_HF_CLIENT_VGM_MIN   0
+#define BTA_HF_CLIENT_VGM_MAX  15
+
+UINT32 service_index = 0;
+BOOLEAN service_availability = TRUE;
+/* helper functions for handling AT commands queueing */
+
+static void bta_hf_client_clear_queued_at(void)
+{
+    tBTA_HF_CLIENT_AT_QCMD *cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+    tBTA_HF_CLIENT_AT_QCMD *next;
+
+    while (cur != NULL) {
+        next = cur->next;
+        GKI_freebuf(cur);
+        cur = next;
+    }
+
+    bta_hf_client_cb.scb.at_cb.queued_cmd = NULL;
+}
+
+static void bta_hf_client_queue_at(tBTA_HF_CLIENT_AT_CMD cmd, const char *buf, UINT16 buf_len)
+{
+    tBTA_HF_CLIENT_AT_QCMD *new_cmd;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if ((new_cmd = (tBTA_HF_CLIENT_AT_QCMD *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_AT_QCMD))) != NULL)
+    {
+        new_cmd->cmd = cmd;
+        new_cmd->buf_len = buf_len;
+        new_cmd->next = NULL;
+        memcpy(new_cmd->buf, buf, buf_len);
+
+        if (bta_hf_client_cb.scb.at_cb.queued_cmd != NULL)
+        {
+            tBTA_HF_CLIENT_AT_QCMD *qcmd = bta_hf_client_cb.scb.at_cb.queued_cmd;
+
+            while (qcmd->next != NULL)
+                qcmd = qcmd->next;
+
+            qcmd->next = new_cmd;
+        }
+        else
+        {
+            bta_hf_client_cb.scb.at_cb.queued_cmd = new_cmd;
+        }
+    }
+}
+
+static void bta_hf_client_at_resp_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    if (p_tle)
+    {
+        bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
+
+        APPL_TRACE_ERROR0("HFPClient: AT response timeout, disconnecting");
+
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+    }
+}
+
+static void bta_hf_client_stop_at_resp_timer(void)
+{
+    if (bta_hf_client_cb.scb.at_cb.resp_timer_on)
+    {
+        bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.resp_timer);
+    }
+}
+
+static void bta_hf_client_start_at_resp_timer(void)
+{
+    if (bta_hf_client_cb.scb.at_cb.resp_timer_on)
+    {
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.resp_timer);
+    }
+
+    bta_hf_client_cb.scb.at_cb.resp_timer.p_cback = (TIMER_CBACK*)&bta_hf_client_at_resp_timer_cback;
+    bta_sys_start_timer(&bta_hf_client_cb.scb.at_cb.resp_timer, 0, BTA_HF_CLIENT_AT_TIMEOUT);
+    bta_hf_client_cb.scb.at_cb.resp_timer_on = TRUE;
+}
+
+static void bta_hf_client_send_at(tBTA_HF_CLIENT_AT_CMD cmd, char *buf, UINT16 buf_len)
+{
+    if ((bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
+            bta_hf_client_cb.scb.svc_conn == FALSE) &&
+            bta_hf_client_cb.scb.at_cb.hold_timer_on == FALSE)
+    {
+        UINT16  len;
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+        APPL_TRACE_DEBUG3("%s %.*s", __FUNCTION__, buf_len - 1, buf);
+#endif
+
+        bta_hf_client_cb.scb.at_cb.current_cmd = cmd;
+        PORT_WriteData(bta_hf_client_cb.scb.conn_handle, buf, buf_len, &len);
+
+        bta_hf_client_start_at_resp_timer();
+
+        return;
+    }
+
+    bta_hf_client_queue_at(cmd, buf, buf_len);
+}
+
+static void bta_hf_client_send_queued_at(void)
+{
+    tBTA_HF_CLIENT_AT_QCMD *cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+    tBTA_HF_CLIENT_AT_QCMD *next;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (cur != NULL)
+    {
+        next = cur->next;
+
+        bta_hf_client_send_at(cur->cmd, cur->buf, cur->buf_len);
+
+        GKI_freebuf(cur);
+
+        bta_hf_client_cb.scb.at_cb.queued_cmd = next;
+    }
+}
+
+static void bta_hf_client_at_hold_timer_cback(TIMER_LIST_ENT *p_tle)
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (p_tle)
+    {
+        bta_hf_client_cb.scb.at_cb.hold_timer_on = FALSE;
+        bta_hf_client_send_queued_at();
+    }
+}
+
+static void bta_hf_client_stop_at_hold_timer(void)
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.at_cb.hold_timer_on)
+    {
+        bta_hf_client_cb.scb.at_cb.hold_timer_on = FALSE;
+        bta_sys_stop_timer (&bta_hf_client_cb.scb.at_cb.hold_timer);
+    }
+}
+
+static void bta_hf_client_start_at_hold_timer(void)
+{
+    TIMER_LIST_ENT *timer = &bta_hf_client_cb.scb.at_cb.hold_timer;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.at_cb.hold_timer_on)
+    {
+        bta_sys_stop_timer (timer);
+    }
+
+    timer->p_cback = (TIMER_CBACK*)&bta_hf_client_at_hold_timer_cback;
+    bta_sys_start_timer(timer, 0, BTA_HF_CLIENT_AT_HOLD_TIMEOUT);
+    bta_hf_client_cb.scb.at_cb.hold_timer_on = TRUE;
+}
+
+/******************************************************************************
+**
+**          COMMON AT EVENT HANDLING FUNCTIONS
+**
+**   Receives data (strings, ints, etc.) from the parser and processes this data.
+**   No buffer parsing is being done here.
+*******************************************************************************/
+
+static void bta_hf_client_handle_ok()
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    bta_hf_client_stop_at_resp_timer();
+
+    if (!bta_hf_client_cb.scb.svc_conn)
+    {
+        bta_hf_client_slc_seq(FALSE);
+        return;
+    }
+
+    switch(bta_hf_client_cb.scb.at_cb.current_cmd)
+    {
+        case BTA_HF_CLIENT_AT_BIA:
+        case BTA_HF_CLIENT_AT_BCC:
+            break;
+        case BTA_HF_CLIENT_AT_BCS:
+            bta_hf_client_start_at_hold_timer();
+            bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+            return;
+        case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+            if (bta_hf_client_cb.scb.send_at_reply == FALSE)
+            {
+                bta_hf_client_cb.scb.send_at_reply = TRUE;
+            }
+            break;
+        case BTA_HF_CLIENT_AT_NONE:
+            bta_hf_client_stop_at_hold_timer();
+            break;
+        default:
+            if (bta_hf_client_cb.scb.send_at_reply)
+            {
+                bta_hf_client_at_result(BTA_HF_CLIENT_AT_RESULT_OK, 0);
+            }
+            break;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+    bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_error(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme)
+{
+    APPL_TRACE_DEBUG3("%s %u %u", __FUNCTION__, type, cme);
+
+    bta_hf_client_stop_at_resp_timer();
+
+    if (!bta_hf_client_cb.scb.svc_conn)
+    {
+        bta_hf_client_slc_seq(TRUE);
+        return;
+    }
+
+    switch(bta_hf_client_cb.scb.at_cb.current_cmd)
+    {
+        case BTA_HF_CLIENT_AT_BIA:
+            break;
+        case BTA_HF_CLIENT_AT_BCC:
+        case BTA_HF_CLIENT_AT_BCS:
+            bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+            break;
+        case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+            if (bta_hf_client_cb.scb.send_at_reply == FALSE)
+            {
+                bta_hf_client_cb.scb.send_at_reply = TRUE;
+            }
+            break;
+        default:
+            if (bta_hf_client_cb.scb.send_at_reply)
+            {
+                bta_hf_client_at_result(type, cme);
+            }
+            break;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+    bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_ring()
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+    bta_hf_client_evt_val(BTA_HF_CLIENT_RING_INDICATION,0);
+}
+
+static void bta_hf_client_handle_brsf(UINT32 value)
+{
+    APPL_TRACE_DEBUG2("%s 0x%x", __FUNCTION__, value);
+    bta_hf_client_cb.scb.peer_features = value;
+}
+
+/* handles a single indicator descriptor - registers it for value changing events */
+static void bta_hf_client_handle_cind_list_item(char *name, UINT32 min, UINT32 max, UINT32 index)
+{
+
+    UINT8 i = 0;
+
+    APPL_TRACE_DEBUG5("%s %lu.%s <%lu:%lu>", __FUNCTION__, index, name, min, max);
+
+    /* look for a matching indicator on list of supported ones */
+    for(i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++)
+    {
+        if (strcmp(name,BTA_HF_CLIENT_INDICATOR_SERVICE) == 0)
+        {
+            service_index = index;
+        }
+        /* look for a match - search one sign further than indicators name to check for string end */
+        /* It will distinguish 'callheld' which could be matched by strncmp as 'call'.               */
+        if (strncmp(name, bta_hf_client_indicators[i].name, bta_hf_client_indicators[i].namelen) != 0)
+            continue;
+
+        /* index - enumerates value position in the incoming sequence                      */
+        /* if name matches one of the known indicators, add its incoming position          */
+        /* to lookup table for easy value->indicator matching later, when only values come  */
+        bta_hf_client_cb.scb.at_cb.indicator_lookup[index] = i;
+
+        return;
+    }
+}
+
+static void bta_hf_client_handle_cind_value(UINT32 index, UINT32 value)
+{
+    APPL_TRACE_DEBUG3("%s index: %u value: %u", __FUNCTION__, index, value);
+
+    if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT)
+    {
+        return;
+    }
+
+    if (service_index == index)
+    {
+        if (value == 0)
+        {
+            service_availability = FALSE;
+        }
+        else
+        {
+            service_availability = TRUE;
+        }
+    }
+    if (bta_hf_client_cb.scb.at_cb.indicator_lookup[index] == -1)
+    {
+        return;
+    }
+
+    /* get the real array index from lookup table */
+    index = bta_hf_client_cb.scb.at_cb.indicator_lookup[index];
+
+    /* Ignore out of range values */
+    if(value > bta_hf_client_indicators[index].max ||
+       value < bta_hf_client_indicators[index].min)
+    {
+        return;
+    }
+
+    /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+    bta_hf_client_ind(index, value);
+}
+
+static void bta_hf_client_handle_chld(UINT32 mask)
+{
+    APPL_TRACE_DEBUG2("%s 0x%x", __FUNCTION__, mask);
+
+    bta_hf_client_cb.scb.chld_features |= mask;
+}
+
+static void bta_hf_client_handle_ciev(UINT32 index, UINT32 value)
+{
+    INT8 realind = -1;
+
+    APPL_TRACE_DEBUG3("%s index: %u value: %u", __FUNCTION__, index, value);
+
+    if(index == 0 || index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT)
+    {
+        return;
+    }
+
+    realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index - 1];
+
+    if(realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT)
+    {
+        /* get the real in-array index from lookup table by index it comes at */
+        /* if there is no bug it should automatically be correctly calculated    */
+        if(value > bta_hf_client_indicators[realind].max || value < bta_hf_client_indicators[realind].min)
+        {
+            return;
+        }
+
+        /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+        bta_hf_client_ind(realind, value);
+    }
+}
+
+static void bta_hf_client_handle_bcs(UINT32 codec)
+{
+    APPL_TRACE_DEBUG2("%s %u", __FUNCTION__, codec);
+
+    if (codec == BTM_SCO_CODEC_CVSD ||
+            (codec == BTM_SCO_CODEC_MSBC && bta_hf_client_cb.msbc_enabled == TRUE))
+    {
+        bta_hf_client_cb.scb.negotiated_codec = codec;
+        bta_hf_client_send_at_bcs(codec);
+    }
+    else
+    {
+        bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+        bta_hf_client_send_at_bac();
+    }
+}
+
+static void bta_hf_client_handle_bsir(UINT32 provided)
+{
+    APPL_TRACE_DEBUG2("%s %u", __FUNCTION__, provided);
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_BSIR_EVT, provided);
+}
+
+static void bta_hf_client_handle_cmeerror(UINT32 code)
+{
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_CME, code);
+}
+
+static void bta_hf_client_handle_vgm(UINT32 value)
+{
+    APPL_TRACE_DEBUG2("%s %lu", __FUNCTION__, value);
+
+    if(value <= BTA_HF_CLIENT_VGM_MAX)
+    {
+        bta_hf_client_evt_val(BTA_HF_CLIENT_MIC_EVT, value);
+    }
+}
+
+static void bta_hf_client_handle_vgs(UINT32 value)
+{
+    APPL_TRACE_DEBUG2("%s %lu", __FUNCTION__, value);
+
+    if(value <= BTA_HF_CLIENT_VGS_MAX)
+    {
+        bta_hf_client_evt_val(BTA_HF_CLIENT_SPK_EVT, value);
+    }
+}
+
+static void bta_hf_client_handle_bvra(UINT32 value)
+{
+    APPL_TRACE_DEBUG2("%s %lu", __FUNCTION__, value);
+
+    if (value > 1)
+    {
+        return;
+    }
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_VOICE_REC_EVT, value);
+}
+
+static void bta_hf_client_handle_clip(char *numstr, UINT32 type)
+{
+    APPL_TRACE_DEBUG3("%s %u %s", __FUNCTION__, type, numstr);
+
+    bta_hf_client_clip(numstr);
+}
+
+static void bta_hf_client_handle_ccwa(char *numstr, UINT32 type)
+{
+    APPL_TRACE_DEBUG3("%s %u %s", __FUNCTION__, type, numstr);
+
+    bta_hf_client_ccwa(numstr);
+}
+
+static void bta_hf_client_handle_cops(char *opstr, UINT32 mode)
+{
+    APPL_TRACE_DEBUG3("%s %u %s", __FUNCTION__, mode, opstr);
+
+    bta_hf_client_operator_name(opstr);
+}
+
+static void bta_hf_client_handle_binp(char *numstr)
+{
+    APPL_TRACE_DEBUG2("%s %s", __FUNCTION__, numstr);
+
+    bta_hf_client_binp(numstr);
+}
+
+static void bta_hf_client_handle_clcc(UINT16 idx, UINT16 dir, UINT16 status, UINT16 mode, UINT16 mpty, char *numstr, UINT16 type)
+{
+    APPL_TRACE_DEBUG6("%s idx: %u dir: %u status: %u mode: %u mpty: %u",
+                        __FUNCTION__, idx, dir, status, mode, mpty);
+
+    if (numstr)
+    {
+        APPL_TRACE_DEBUG3("%s number: %s  type: %u", __FUNCTION__, numstr, type);
+    }
+
+    bta_hf_client_clcc(idx, dir, status, mpty, numstr);
+}
+
+static void bta_hf_client_handle_cnum( char *numstr, UINT16 type, UINT16 service)
+{
+    APPL_TRACE_DEBUG4("%s number: %s type: %u service: %u", __FUNCTION__, numstr, type, service);
+
+    /* TODO: should number be modified according to type? */
+    bta_hf_client_cnum(numstr, service);
+}
+
+static void bta_hf_client_handle_btrh( UINT16 code)
+{
+    APPL_TRACE_DEBUG2("%s %lu", __FUNCTION__, code);
+
+    bta_hf_client_evt_val(BTA_HF_CLIENT_BTRH_EVT, code);
+}
+
+/******************************************************************************
+**
+**          COMMON AT EVENTS PARSING FUNCTIONS
+**
+*******************************************************************************/
+
+/* Check if prefix match and skip spaces if any */
+#define AT_CHECK_EVENT(buf, event) \
+    if (strncmp("\r\n"event, buf,sizeof("\r\n"event) - 1) != 0) return buf; \
+    buf += sizeof("\r\n"event) - 1; \
+    while (*buf == ' ') buf++;
+
+/* check for <cr><lf> and forward buffer if match */
+#define AT_CHECK_RN(buf) \
+    if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \
+        APPL_TRACE_DEBUG1("%s missing end <cr><lf>", __FUNCTION__); \
+        return NULL;} \
+    buf += sizeof("\r\n") - 1;
+
+/* skip rest of AT string up to <cr> */
+#define AT_SKIP_REST(buf) while(*buf != '\r') buf++;
+
+static char *bta_hf_client_parse_ok(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "OK");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ok();
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_error(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "ERROR");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_ERROR, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_ring(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "RING");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ring();
+
+    return buffer;
+}
+
+/* generic uint32 parser */
+static char *bta_hf_client_parse_uint32(char *buffer, void (*handler_callback)(UINT32))
+{
+    UINT32 value;
+    int res;
+    int offset;
+
+    res = sscanf(buffer, "%u%n", &value, &offset);
+    if (res < 1)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    handler_callback(value);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_brsf(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BRSF:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_brsf);
+}
+
+static char *bta_hf_client_parse_cind_values(char *buffer)
+{
+    /* value and its position */
+    UINT16 index = 0;
+    UINT32 value = 0;
+
+    int offset;
+    int res;
+
+    while((res = sscanf(buffer, "%u%n", &value, &offset)) > 0)
+    {
+        /* decides if its valid index and value, if yes stores it */
+        bta_hf_client_handle_cind_value(index, value);
+
+        buffer += offset;
+
+        /* check if more values are present */
+        if (*buffer != ',')
+        {
+            break;
+        }
+
+        index++;
+        buffer++;
+    }
+
+    if (res > 0)
+    {
+        AT_CHECK_RN(buffer);
+        return buffer;
+    }
+
+    return NULL;
+}
+
+static char *bta_hf_client_parse_cind_list(char *buffer)
+{
+    int offset;
+    char name[129];
+    UINT32 min, max;
+    UINT32 index = 0;
+    int res;
+
+    while ((res = sscanf(buffer, "(\"%128[^\"]\",(%u%*[-,]%u))%n", name, &min, &max, &offset)) > 2)
+    {
+        bta_hf_client_handle_cind_list_item(name, min, max, index);
+        buffer += offset;
+        index++;
+
+        if (*buffer != ',')
+        {
+            break;
+        }
+
+        buffer++;
+    }
+
+    if (res > 2)
+    {
+        AT_CHECK_RN(buffer);
+        return buffer;
+    }
+
+    return NULL;
+}
+
+static char *bta_hf_client_parse_cind(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CIND:");
+
+    if(*buffer == '(')
+        return bta_hf_client_parse_cind_list(buffer);
+
+    return bta_hf_client_parse_cind_values(buffer);
+}
+
+static char *bta_hf_client_parse_chld(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CHLD:");
+
+    if (*buffer != '(')
+    {
+        return NULL;
+    }
+
+    buffer++;
+
+    while(*buffer != '\0')
+    {
+        if(strncmp("0",buffer, 1) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL);
+            buffer++;
+        }
+        else if(strncmp("1x",buffer, 2) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_X);
+            buffer += 2;
+        }
+        else if(strncmp("1",buffer, 1) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_ACC);
+            buffer++;
+        }
+        else if(strncmp("2x",buffer, 2) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_PRIV_X);
+            buffer += 2;
+        }
+        else if(strncmp("2",buffer, 1) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_HOLD_ACC);
+            buffer++;
+        }
+        else if(strncmp("3",buffer, 1) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE);
+            buffer++;
+        }
+        else if(strncmp("4",buffer, 1) == 0)
+        {
+            bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE_DETACH);
+            buffer++;
+        }
+        else
+        {
+            return NULL;
+        }
+
+        if (*buffer == ',')
+        {
+            buffer++;
+            continue;
+        }
+
+        if (*buffer == ')')
+        {
+            buffer++;
+            break;
+        }
+
+        return NULL;
+    }
+
+    AT_CHECK_RN(buffer);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_ciev(char *buffer)
+{
+    UINT32 index, value;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CIEV:");
+
+    res = sscanf(buffer, "%u,%u%n", &index, &value, &offset);
+    if(res < 2)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ciev(index, value);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_bcs(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BCS:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bcs);
+}
+
+static char *bta_hf_client_parse_bsir(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BSIR:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bsir);
+}
+
+static char *bta_hf_client_parse_cmeerror(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+CME ERROR:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_cmeerror);
+}
+
+static char *bta_hf_client_parse_vgm(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGM:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char *bta_hf_client_parse_vgme(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGM=");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char *bta_hf_client_parse_vgs(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGS:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char *bta_hf_client_parse_vgse(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+VGS=");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char *bta_hf_client_parse_bvra(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "+BVRA:");
+
+    return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bvra);
+}
+
+static char *bta_hf_client_parse_clip(char *buffer)
+{
+    /* spec forces 32 chars, plus \0 here */
+    char number[33];
+    UINT32 type = 0;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CLIP:");
+
+    /* there might be something more after %lu but HFP doesn't care */
+    res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+    if(res < 2)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_clip(number, type);
+    return buffer;
+}
+
+/* in HFP context there is no difference between ccwa and clip */
+static char *bta_hf_client_parse_ccwa(char *buffer)
+{
+    /* ac to spec 32 chars max, plus \0 here */
+    char number[33];
+    UINT32 type = 0;
+    int res ;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CCWA:");
+
+    /* there might be something more after %lu but HFP doesn't care */
+    res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+    if(res < 2)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_ccwa(number, type);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_cops(char *buffer)
+{
+    UINT8 mode;
+    /* spec forces 16 chars max, plus \0 here */
+    char opstr[17];
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+COPS:");
+
+    /* TODO: Not sure if operator string actually can contain escaped " char inside */
+    res = sscanf(buffer, "%hhi,0,\"%16[^\"]\"%n", &mode, opstr, &offset);
+    if(res < 2)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_cops(opstr, mode);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_binp(char *buffer)
+{
+    /* HFP only supports phone number as BINP data */
+    /* phone number is 32 chars plus one for \0*/
+    char numstr[33];
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+BINP:");
+
+    res = sscanf(buffer, "\"%32[^\"]\"\r\n%n", numstr, &offset);
+    if(res < 1)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    /* some phones might sent type as well, just skip it */
+    AT_SKIP_REST(buffer);
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_binp(numstr);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_clcc(char *buffer)
+{
+    UINT16 idx, dir, status, mode, mpty;
+    char numstr[33];     /* spec forces 32 chars, plus one for \0*/
+    UINT16 type;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CLCC:");
+
+    res = sscanf(buffer, "%hu,%hu,%hu,%hu,%hu%n",
+                    &idx, &dir, &status, &mode, &mpty, &offset);
+    if (res < 5)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    /* check optional part */
+    if (*buffer == ',')
+    {
+        int res2;
+
+        res2 = sscanf(buffer, ",\"%32[^\"]\",%hu%n", numstr, &type, &offset);
+        if (res2 < 0)
+        {
+            return NULL;
+        }
+
+        if (res2 == 0)
+        {
+            res2 = sscanf(buffer, ",\"\",%hu%n", &type, &offset);
+            if (res < 0)
+            {
+                return NULL;
+            }
+
+            /* numstr is not matched in second attempt, correct this */
+            res2++;
+            numstr[0] = '\0';
+        }
+
+        if (res2 < 2)
+        {
+            return NULL;
+        }
+
+        res += res2;
+        buffer += offset;
+    }
+
+    AT_CHECK_RN(buffer);
+
+    if(res > 6)
+    {
+        /* we also have last two optional parameters */
+        bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, numstr, type);
+    }
+    else
+    {
+        /* we didn't get the last two parameters */
+        bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, NULL, 0);
+    }
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_cnum(char *buffer)
+{
+    char numstr[33];     /* spec forces 32 chars, plus one for \0*/
+    UINT16 type;
+    UINT16 service = 0; /* 0 in case this optional parameter is not being sent */
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+CNUM:");
+
+    res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service, &offset);
+    if(res < 0)
+    {
+        return NULL;
+    }
+
+    if (res == 0)
+    {
+        res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
+        if (res < 0)
+        {
+            return NULL;
+        }
+
+        /* numstr is not matched in second attempt, correct this */
+        res++;
+        numstr[0] = '\0';
+    }
+
+    if (res < 3)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    /* service is optional */
+    if(res == 2)
+    {
+        bta_hf_client_handle_cnum(numstr, type, service);
+        return buffer;
+    }
+
+    if (service != 4 && service != 5)
+    {
+        return NULL;
+    }
+
+    bta_hf_client_handle_cnum(numstr, type, service);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_btrh(char *buffer)
+{
+    UINT16 code = 0;
+    int res;
+    int offset;
+
+    AT_CHECK_EVENT(buffer, "+BTRH:");
+
+    res = sscanf(buffer, "%hu%n", &code, &offset);
+    if(res < 1)
+    {
+        return NULL;
+    }
+
+    buffer += offset;
+
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_btrh(code);
+    return buffer;
+}
+
+static char *bta_hf_client_parse_busy(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "BUSY");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BUSY, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_delayed(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "DELAYED");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_DELAY, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_no_carrier(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "NO CARRIER");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_CARRIER, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_no_answer(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "NO ANSWER");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_ANSWER, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_parse_blacklisted(char *buffer)
+{
+    AT_CHECK_EVENT(buffer, "BLACKLISTED");
+    AT_CHECK_RN(buffer);
+
+    bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BLACKLISTED, 0);
+
+    return buffer;
+}
+
+static char *bta_hf_client_skip_unknown(char *buffer)
+{
+    char *start;
+    char *tmp;
+
+    tmp = strstr(buffer, "\r\n");
+    if (tmp == NULL)
+    {
+        return NULL;
+    }
+
+    buffer += 2;
+    start = buffer;
+
+    tmp = strstr(buffer, "\r\n");
+    if (tmp == NULL)
+    {
+        return NULL;
+    }
+
+    buffer = tmp + 2;
+
+    APPL_TRACE_DEBUG3("%s %.*s", __FUNCTION__, buffer - start - 2, start);
+
+    return buffer;
+}
+
+
+/******************************************************************************
+**       SUPPORTED EVENT MESSAGES
+*******************************************************************************/
+
+/* returned values are as follow:
+ * != NULL && != buf  : match and parsed ok
+ * == NULL            : match but parse failed
+ * != NULL && == buf  : no match
+ */
+typedef char* (*tBTA_HF_CLIENT_PARSER_CALLBACK)(char*);
+
+static const tBTA_HF_CLIENT_PARSER_CALLBACK bta_hf_client_parser_cb[] =
+{
+    bta_hf_client_parse_ok,
+    bta_hf_client_parse_error,
+    bta_hf_client_parse_ring,
+    bta_hf_client_parse_brsf,
+    bta_hf_client_parse_cind,
+    bta_hf_client_parse_ciev,
+    bta_hf_client_parse_chld,
+    bta_hf_client_parse_bcs,
+    bta_hf_client_parse_bsir,
+    bta_hf_client_parse_cmeerror,
+    bta_hf_client_parse_vgm,
+    bta_hf_client_parse_vgme,
+    bta_hf_client_parse_vgs,
+    bta_hf_client_parse_vgse,
+    bta_hf_client_parse_bvra,
+    bta_hf_client_parse_clip,
+    bta_hf_client_parse_ccwa,
+    bta_hf_client_parse_cops,
+    bta_hf_client_parse_binp,
+    bta_hf_client_parse_clcc,
+    bta_hf_client_parse_cnum,
+    bta_hf_client_parse_btrh,
+    bta_hf_client_parse_busy,
+    bta_hf_client_parse_delayed,
+    bta_hf_client_parse_no_carrier,
+    bta_hf_client_parse_no_answer,
+    bta_hf_client_parse_blacklisted,
+    bta_hf_client_skip_unknown
+};
+
+/* calculate supported event list length */
+static const UINT16 bta_hf_client_psraser_cb_count =
+        sizeof(bta_hf_client_parser_cb) / sizeof(bta_hf_client_parser_cb[0]);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+static void bta_hf_client_dump_at(void)
+{
+    char dump[(4 * BTA_HF_CLIENT_AT_PARSER_MAX_LEN) + 1];
+    char *p1, *p2;
+
+    p1 = bta_hf_client_cb.scb.at_cb.buf;
+    p2 = dump;
+
+    while (*p1 != '\0')
+    {
+        if (*p1 == '\r')
+        {
+            strlcpy(p2, "<cr>", 4);
+            p2 += 4;
+        }
+        else if (*p1 == '\n')
+        {
+            strlcpy(p2, "<lf>", 4);
+            p2 += 4;
+        }
+        else
+        {
+            *p2 = *p1;
+            p2++;
+        }
+        p1++;
+    }
+
+    *p2 = '\0';
+
+    APPL_TRACE_DEBUG2("%s %s", __FUNCTION__, dump);
+}
+#endif
+
+static void bta_hf_client_at_parse_start(void)
+{
+    char *buf = bta_hf_client_cb.scb.at_cb.buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+    bta_hf_client_dump_at();
+#endif
+
+    while(*buf != '\0')
+    {
+        int i;
+        char *tmp = NULL;
+
+        for(i = 0; i < bta_hf_client_psraser_cb_count; i++)
+        {
+            tmp = bta_hf_client_parser_cb[i](buf);
+            if (tmp == NULL)
+            {
+                APPL_TRACE_ERROR0("HFPCient: AT event/reply parsing failed, skipping");
+                tmp = bta_hf_client_skip_unknown(buf);
+                break;
+            }
+
+            /* matched or unknown skipped, if unknown failed tmp is NULL so
+               this is also handled */
+            if (tmp != buf)
+            {
+                buf = tmp;
+                break;
+            }
+        }
+
+        /* could not skip unknown (received garbage?)... disconnect */
+        if (tmp == NULL)
+        {
+            APPL_TRACE_ERROR0("HFPCient: could not skip unknown AT event, disconnecting");
+            bta_hf_client_at_reset();
+            bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+            return;
+        }
+
+        buf = tmp;
+    }
+}
+
+static BOOLEAN bta_hf_client_check_at_complete(void)
+{
+    BOOLEAN ret = FALSE;
+    tBTA_HF_CLIENT_AT_CB *at_cb = &bta_hf_client_cb.scb.at_cb;
+
+    if (at_cb->offset >= BTA_HF_CLIENT_AT_EVENT_MIN_LEN)
+    {
+        if (at_cb->buf[at_cb->offset - 2] == '\r' && at_cb->buf[at_cb->offset - 1] == '\n')
+        {
+            ret = TRUE;
+        }
+    }
+
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, ret);
+
+    return ret;
+}
+
+static void bta_hf_client_at_clear_buf(void)
+{
+    memset(bta_hf_client_cb.scb.at_cb.buf, 0, sizeof(bta_hf_client_cb.scb.at_cb.buf));
+    bta_hf_client_cb.scb.at_cb.offset = 0;
+}
+
+/******************************************************************************
+**
+**          MAIN PARSING FUNCTION
+**
+**
+*******************************************************************************/
+void bta_hf_client_at_parse(char *buf, unsigned int len)
+{
+    APPL_TRACE_DEBUG3("%s offset: %u len: %u", __FUNCTION__, bta_hf_client_cb.scb.at_cb.offset, len);
+
+    if (len + bta_hf_client_cb.scb.at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN)
+    {
+        char tmp_buff[BTA_HF_CLIENT_AT_PARSER_MAX_LEN];
+        unsigned int tmp = bta_hf_client_cb.scb.at_cb.offset;
+        unsigned int space_left = BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset;
+
+        APPL_TRACE_DEBUG1("%s overrun, trying to recover", __FUNCTION__);
+
+        /* fill up parser buffer */
+        memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, space_left);
+        len -= space_left;
+        buf += space_left;
+        bta_hf_client_cb.scb.at_cb.offset += space_left;
+
+        /* find end of last complete command before proceeding */
+        while(bta_hf_client_check_at_complete() == FALSE)
+        {
+            if (bta_hf_client_cb.scb.at_cb.offset == 0) {
+                APPL_TRACE_ERROR0("HFPClient: AT parser buffer overrun, disconnecting");
+
+                bta_hf_client_at_reset();
+                bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+                return;
+            }
+
+            bta_hf_client_cb.scb.at_cb.offset--;
+        }
+
+        /* cut buffer to complete AT event and keep cut data */
+        tmp += space_left - bta_hf_client_cb.scb.at_cb.offset;
+        memcpy(tmp_buff, bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, tmp);
+        bta_hf_client_cb.scb.at_cb.buf[bta_hf_client_cb.scb.at_cb.offset] = '\0';
+
+        /* parse */
+        bta_hf_client_at_parse_start();
+        bta_hf_client_at_clear_buf();
+
+        /* recover cut data */
+        memcpy(bta_hf_client_cb.scb.at_cb.buf, tmp_buff, tmp);
+        bta_hf_client_cb.scb.at_cb.offset += tmp;
+    }
+
+    memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len);
+    bta_hf_client_cb.scb.at_cb.offset += len;
+
+    /* If last event is complete, parsing can be started */
+    if (bta_hf_client_check_at_complete() == TRUE)
+    {
+        bta_hf_client_at_parse_start();
+        bta_hf_client_at_clear_buf();
+    }
+}
+
+void bta_hf_client_send_at_brsf(void)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+BRSF=%u\r", bta_hf_client_cb.scb.features);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BRSF , buf, at_len);
+}
+
+void bta_hf_client_send_at_bac(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.msbc_enabled)
+    {
+        buf = "AT+BAC=1,2\r";
+    }
+    else
+    {
+        buf = "AT+BAC=1\r";
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BAC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bcs(UINT32 codec)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+BCS=%u\r", codec);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCS, buf, at_len);
+}
+
+void bta_hf_client_send_at_cind(BOOLEAN status)
+{
+    char *buf;
+    tBTA_HF_CLIENT_AT_CMD cmd;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (status)
+    {
+        buf = "AT+CIND?\r";
+        cmd = BTA_HF_CLIENT_AT_CIND_STATUS;
+    }
+    else
+    {
+        buf = "AT+CIND=?\r";
+        cmd = BTA_HF_CLIENT_AT_CIND;
+    }
+
+    bta_hf_client_send_at(cmd, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmer(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (activate)
+        buf = "AT+CMER=3,0,0,1\r";
+    else
+        buf = "AT+CMER=3,0,0,0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMER, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chld(char cmd, UINT32 idx)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (idx > 0)
+        at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c%u\r", cmd, idx);
+    else
+        at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c\r", cmd);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHLD, buf, at_len);
+}
+
+void bta_hf_client_send_at_clip(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (activate)
+        buf = "AT+CLIP=1\r";
+    else
+        buf = "AT+CLIP=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLIP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ccwa(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (activate)
+        buf = "AT+CCWA=1\r";
+    else
+        buf = "AT+CCWA=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CCWA, buf, strlen(buf));
+}
+
+
+void bta_hf_client_send_at_cmee(BOOLEAN activate)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (activate)
+        buf = "AT+CMEE=1\r";
+    else
+        buf = "AT+CMEE=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMEE, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cops(BOOLEAN query)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (!service_availability)
+    {
+        APPL_TRACE_DEBUG0("Skip AT+COPS no service");
+        return;
+    }
+    if (query)
+        buf = "AT+COPS?\r";
+    else
+        buf = "AT+COPS=3,0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_COPS, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_clcc(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    buf = "AT+CLCC\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bvra(BOOLEAN enable)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (enable)
+        buf = "AT+BVRA=1\r";
+    else
+        buf = "AT+BVRA=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BVRA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_vgs(UINT32 volume)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+VGS=%u\r", volume);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGS, buf, at_len);
+}
+
+void bta_hf_client_send_at_vgm(UINT32 volume)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+VGM=%u\r", volume);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGM, buf, at_len);
+}
+
+void bta_hf_client_send_at_atd(char *number, UINT32 memory)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (number[0] != '\0')
+    {
+        at_len = snprintf(buf, sizeof(buf), "ATD%s;\r", number);
+    }
+    else
+    {
+        at_len = snprintf(buf, sizeof(buf), "ATD>%u;\r", memory);
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATD, buf, at_len);
+}
+
+void bta_hf_client_send_at_bldn(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    buf = "AT+BLDN\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BLDN, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ata(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    buf = "ATA\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chup(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    buf = "AT+CHUP\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHUP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (query == TRUE)
+    {
+        at_len = snprintf(buf, sizeof(buf), "AT+BTRH?\r");
+    }
+    else
+    {
+        at_len = snprintf(buf, sizeof(buf), "AT+BTRH=%u\r", val);
+    }
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BTRH, buf, at_len);
+}
+
+void bta_hf_client_send_at_vts(char code)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+VTS=%c\r", code);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_VTS, buf, at_len);
+}
+
+void bta_hf_client_send_at_bcc(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    buf = "AT+BCC\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cnum(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (!service_availability)
+    {
+        APPL_TRACE_DEBUG0("Skip AT+CNUM no Service");
+        return;
+    }
+    buf = "AT+CNUM\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_CNUM, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_nrec(void)
+{
+    char *buf;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (!(bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR))
+    {
+        APPL_TRACE_DEBUG0("Remote does not support NREC.");
+        return;
+    }
+
+    buf = "AT+NREC=0\r";
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_NREC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_binp(UINT32 action)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    at_len = snprintf(buf, sizeof(buf), "AT+BINP=%u\r", action);
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BINP, buf, at_len);
+}
+
+void bta_hf_client_send_at_bia(void)
+{
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    int at_len;
+    int i;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+    if (bta_hf_client_cb.scb.peer_version < HFP_VERSION_1_6)
+    {
+        APPL_TRACE_DEBUG0("Remote does not Support AT+BIA");
+        return;
+    }
+
+    at_len = snprintf(buf, sizeof(buf), "AT+BIA=");
+
+    for(i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++)
+    {
+        int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1;
+
+        at_len += snprintf(buf + at_len, sizeof(buf) - at_len, "%u,", sup);
+    }
+
+    buf[at_len - 1] = '\r';
+
+    bta_hf_client_send_at(BTA_HF_CLIENT_AT_BIA, buf, at_len);
+}
+
+void bta_hf_client_at_init(void)
+{
+    memset(&bta_hf_client_cb.scb.at_cb, 0, sizeof(tBTA_HF_CLIENT_AT_CB));
+    bta_hf_client_at_reset();
+}
+
+void bta_hf_client_at_reset(void)
+{
+    int i;
+
+    bta_hf_client_stop_at_resp_timer();
+    bta_hf_client_stop_at_hold_timer();
+
+    bta_hf_client_clear_queued_at();
+
+    bta_hf_client_at_clear_buf();
+
+    for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++)
+    {
+        bta_hf_client_cb.scb.at_cb.indicator_lookup[i] = -1;
+    }
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+}
diff --git a/system/bta/hf_client/bta_hf_client_at.h b/system/bta/hf_client/bta_hf_client_at.h
new file mode 100644
index 0000000..917c605
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_at.h
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* ASCII character string of arguments to the AT command */
+#define BTA_HF_CLIENT_AT_MAX_LEN        512
+
+/* AT command table element */
+typedef struct
+{
+    const char  *p_cmd;         /* AT command string */
+    UINT8       arg_type;       /* allowable argument type syntax */
+    UINT8       fmt;            /* whether arg is int or string */
+    UINT8       min;            /* minimum value for int arg */
+    INT16       max;            /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
+                                    char *p_arg, INT16 int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
+
+enum
+{
+    BTA_HF_CLIENT_AT_NONE,
+    BTA_HF_CLIENT_AT_BRSF,
+    BTA_HF_CLIENT_AT_BAC,
+    BTA_HF_CLIENT_AT_CIND,
+    BTA_HF_CLIENT_AT_CIND_STATUS,
+    BTA_HF_CLIENT_AT_CMER,
+    BTA_HF_CLIENT_AT_CHLD,
+    BTA_HF_CLIENT_AT_CMEE,
+    BTA_HF_CLIENT_AT_BIA,
+    BTA_HF_CLIENT_AT_CLIP,
+    BTA_HF_CLIENT_AT_CCWA,
+    BTA_HF_CLIENT_AT_COPS,
+    BTA_HF_CLIENT_AT_CLCC,
+    BTA_HF_CLIENT_AT_BVRA,
+    BTA_HF_CLIENT_AT_VGS,
+    BTA_HF_CLIENT_AT_VGM,
+    BTA_HF_CLIENT_AT_ATD,
+    BTA_HF_CLIENT_AT_BLDN,
+    BTA_HF_CLIENT_AT_ATA,
+    BTA_HF_CLIENT_AT_CHUP,
+    BTA_HF_CLIENT_AT_BTRH,
+    BTA_HF_CLIENT_AT_VTS,
+    BTA_HF_CLIENT_AT_BCC,
+    BTA_HF_CLIENT_AT_BCS,
+    BTA_HF_CLIENT_AT_CNUM,
+    BTA_HF_CLIENT_AT_NREC,
+    BTA_HF_CLIENT_AT_BINP,
+};
+
+typedef UINT8 tBTA_HF_CLIENT_AT_CMD;
+
+/* Maximum combined buffer for received AT events string */
+#define BTA_HF_CLIENT_AT_PARSER_MAX_LEN        4096
+
+/* This structure holds prepared AT command queued for sending */
+struct queued_at_cmd{
+    tBTA_HF_CLIENT_AT_CMD cmd;
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+    UINT16 buf_len;
+    struct queued_at_cmd *next;
+};
+typedef struct queued_at_cmd tBTA_HF_CLIENT_AT_QCMD;
+
+/* Maximum number of indicators */
+#define BTA_HF_CLIENT_AT_INDICATOR_COUNT 20
+
+/* AT command parsing control block */
+typedef struct
+{
+    char                    buf[BTA_HF_CLIENT_AT_PARSER_MAX_LEN + 1]; /* extra byte to always have \0 at the end */
+    unsigned int            offset;
+    tBTA_HF_CLIENT_AT_CMD   current_cmd;
+    tBTA_HF_CLIENT_AT_QCMD  *queued_cmd;
+
+    TIMER_LIST_ENT          resp_timer;    /* AT response timer */
+    BOOLEAN                 resp_timer_on; /* TRUE if AT response timer is active */
+
+    TIMER_LIST_ENT          hold_timer;    /* AT hold timer */
+    BOOLEAN                 hold_timer_on; /* TRUE if AT hold timer is active */
+
+    /* CIND: lookup table to store the sequence of incoming indicators and their values
+       so when their values come later, we know which value in sequence match certain indicator */
+    int                     indicator_lookup[BTA_HF_CLIENT_AT_INDICATOR_COUNT];
+
+} tBTA_HF_CLIENT_AT_CB;
+
+/*****************************************************************************
+**  Functions
+*****************************************************************************/
+
+void bta_hf_client_at_init(void);
+void bta_hf_client_at_reset(void);
diff --git a/system/bta/hf_client/bta_hf_client_cmd.c b/system/bta/hf_client/bta_hf_client_cmd.c
new file mode 100644
index 0000000..f71fce7
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_cmd.c
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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 "bta_hf_client_int.h"
+#include "stdio.h"
+
+void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_DATA_VAL *p_val = (tBTA_HF_CLIENT_DATA_VAL *)p_data;
+    char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+
+    switch(p_val->uint8_val)
+    {
+        case BTA_HF_CLIENT_AT_CMD_VTS:
+            bta_hf_client_send_at_vts((char)p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_BTRH:
+            bta_hf_client_send_at_btrh(FALSE, p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_CHUP:
+            bta_hf_client_send_at_chup();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_CHLD:
+            /* expects ascii code for command */
+            bta_hf_client_send_at_chld('0' + p_val->uint32_val1, p_val->uint32_val2);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_BCC:
+            bta_hf_client_send_at_bcc();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_CNUM:
+            bta_hf_client_send_at_cnum();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_ATA:
+            bta_hf_client_send_at_ata();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_COPS:
+            bta_hf_client_send_at_cops(TRUE);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_ATD:
+            bta_hf_client_send_at_atd(p_val->str, p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_VGM:
+            bta_hf_client_send_at_vgm(p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_VGS:
+            bta_hf_client_send_at_vgs(p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_BVRA:
+            bta_hf_client_send_at_bvra(p_val->uint32_val1 == 0 ? FALSE : TRUE);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_CLCC:
+            bta_hf_client_send_at_clcc();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_BINP:
+            bta_hf_client_send_at_binp(p_val->uint32_val1);
+            break;
+        case BTA_HF_CLIENT_AT_CMD_BLDN:
+            bta_hf_client_send_at_bldn();
+            break;
+        case BTA_HF_CLIENT_AT_CMD_NREC:
+            bta_hf_client_send_at_nrec();
+            break;
+        default:
+            APPL_TRACE_ERROR0("Default case");
+            snprintf(buf,BTA_HF_CLIENT_AT_MAX_LEN,
+                "Cmd %d 1st arg %u 2nd arg %u string arg %s",
+                p_val->uint8_val, p_val->uint32_val1,
+                p_val->uint32_val2, p_val->str);
+            APPL_TRACE_ERROR1("%s ", buf);
+            break;
+    }
+}
diff --git a/system/bta/hf_client/bta_hf_client_int.h b/system/bta/hf_client/bta_hf_client_int.h
new file mode 100644
index 0000000..fbd5082
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_int.h
@@ -0,0 +1,294 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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 "bta_sys.h"
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_at.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1         0x0101
+#define HFP_VERSION_1_5         0x0105
+#define HFP_VERSION_1_6         0x0106
+
+/* RFCOMM MTU SIZE */
+#define BTA_HF_CLIENT_MTU       256
+
+/* profile role for connection */
+#define BTA_HF_CLIENT_ACP       0       /* accepted connection */
+#define BTA_HF_CLIENT_INT       1       /* initiating connection */
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_HF_CLIENT_COLLISION_TIMER
+#define BTA_HF_CLIENT_COLLISION_TIMER  2411
+#endif
+
+enum
+{
+    /* these events are handled by the state machine */
+    BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
+    BTA_HF_CLIENT_API_DEREGISTER_EVT,
+    BTA_HF_CLIENT_API_OPEN_EVT,
+    BTA_HF_CLIENT_API_CLOSE_EVT,
+    BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
+    BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_OPEN_EVT,
+    BTA_HF_CLIENT_RFC_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
+    BTA_HF_CLIENT_RFC_DATA_EVT,
+    BTA_HF_CLIENT_DISC_ACP_RES_EVT,
+    BTA_HF_CLIENT_DISC_INT_RES_EVT,
+    BTA_HF_CLIENT_DISC_OK_EVT,
+    BTA_HF_CLIENT_DISC_FAIL_EVT,
+    BTA_HF_CLIENT_SCO_OPEN_EVT,
+    BTA_HF_CLIENT_SCO_CLOSE_EVT,
+    BTA_HF_CLIENT_SEND_AT_CMD_EVT,
+    BTA_HF_CLIENT_MAX_EVT,
+
+    /* these events are handled outside of the state machine */
+    BTA_HF_CLIENT_API_ENABLE_EVT,
+    BTA_HF_CLIENT_API_DISABLE_EVT
+};
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* data type for BTA_HF_CLIENT_API_ENABLE_EVT */
+typedef struct
+{
+    BT_HDR                     hdr;
+    tBTA_HF_CLIENT_CBACK      *p_cback;
+} tBTA_HF_CLIENT_API_ENABLE;
+
+/* data type for BTA_HF_CLIENT_API_REGISTER_EVT */
+typedef struct
+{
+    BT_HDR                     hdr;
+    tBTA_HF_CLIENT_CBACK      *p_cback;
+    tBTA_SEC                   sec_mask;
+    tBTA_HF_CLIENT_FEAT        features;
+    char                       name[BTA_SERVICE_NAME_LEN+1];
+} tBTA_HF_CLIENT_API_REGISTER;
+
+/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    BD_ADDR             bd_addr;
+    tBTA_SEC            sec_mask;
+} tBTA_HF_CLIENT_API_OPEN;
+
+/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          status;
+} tBTA_HF_CLIENT_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          port_handle;
+} tBTA_HF_CLIENT_RFC;
+
+/* generic purpose data type for other events */
+typedef struct
+{
+    BT_HDR          hdr;
+    BOOLEAN         bool_val;
+    UINT8           uint8_val;
+    UINT32          uint32_val1;
+    UINT32          uint32_val2;
+    char            str[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_DATA_VAL;
+
+/* union of all event datatypes */
+typedef union
+{
+    BT_HDR                         hdr;
+    tBTA_HF_CLIENT_API_ENABLE      api_enable;
+    tBTA_HF_CLIENT_API_REGISTER    api_register;
+    tBTA_HF_CLIENT_API_OPEN        api_open;
+    tBTA_HF_CLIENT_DISC_RESULT     disc_result;
+    tBTA_HF_CLIENT_RFC             rfc;
+    tBTA_HF_CLIENT_DATA_VAL        val;
+
+} tBTA_HF_CLIENT_DATA;
+
+/* type for each service control block */
+typedef struct
+{
+    UINT16              serv_handle;    /* RFCOMM server handle */
+    BD_ADDR             peer_addr;      /* peer bd address */
+    tSDP_DISCOVERY_DB   *p_disc_db;     /* pointer to discovery database */
+    UINT16              conn_handle;    /* RFCOMM handle of connected service */
+    tBTA_SEC            serv_sec_mask;  /* server security mask */
+    tBTA_SEC            cli_sec_mask;   /* client security mask */
+    tBTA_HF_CLIENT_FEAT        features;       /* features registered by application */
+    tBTA_HF_CLIENT_PEER_FEAT   peer_features;  /* peer device features */
+    tBTA_HF_CLIENT_CHLD_FEAT   chld_features;  /* call handling features */
+    UINT16              peer_version;   /* profile version of peer device */
+    UINT8               peer_scn;       /* peer scn */
+    UINT8               role;           /* initiator/acceptor role */
+    UINT16              sco_idx;        /* SCO handle */
+    UINT8               sco_state;      /* SCO state variable */
+    BOOLEAN             sco_close_rfc;   /* TRUE if also close RFCOMM after SCO */
+    BOOLEAN             retry_with_sco_only;
+    BOOLEAN             deregister;     /* TRUE if service shutting down */
+    BOOLEAN             svc_conn;       /* set to TRUE when service level connection is up */
+    BOOLEAN             send_at_reply;  /* set to TRUE to notify framework about AT results */
+    tBTA_HF_CLIENT_AT_CB at_cb;         /* AT Parser control block */
+    UINT8               state;          /* state machine state */
+    tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
+    TIMER_LIST_ENT      colli_timer;    /* Collision timer */
+    BOOLEAN             colli_tmr_on;   /* TRUE if collision timer is active */
+} tBTA_HF_CLIENT_SCB;
+
+/* sco states */
+enum
+{
+    BTA_HF_CLIENT_SCO_SHUTDOWN_ST,  /* no listening, no connection */
+    BTA_HF_CLIENT_SCO_LISTEN_ST,    /* listening */
+    BTA_HF_CLIENT_SCO_OPENING_ST,   /* connection opening */
+    BTA_HF_CLIENT_SCO_OPEN_CL_ST,   /* opening connection being closed */
+    BTA_HF_CLIENT_SCO_OPEN_ST,      /* open */
+    BTA_HF_CLIENT_SCO_CLOSING_ST,   /* closing */
+    BTA_HF_CLIENT_SCO_CLOSE_OP_ST,  /* closing sco being opened */
+    BTA_HF_CLIENT_SCO_SHUTTING_ST   /* sco shutting down */
+};
+
+/* type for AG control block */
+typedef struct
+{
+    tBTA_HF_CLIENT_SCB         scb;             /* service control block */
+    UINT32                     sdp_handle;
+    UINT8                      scn;
+    tBTA_HF_CLIENT_CBACK       *p_cback;        /* application callback */
+    BOOLEAN                    msbc_enabled;
+} tBTA_HF_CLIENT_CB;
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+/* control block declaration */
+extern tBTA_HF_CLIENT_CB bta_hf_client_cb;
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_hf_client_scb_init(void);
+extern void bta_hf_client_scb_disable(void);
+extern BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg);
+extern void bta_hf_client_sm_execute(UINT16 event,
+                                        tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_slc_seq(BOOLEAN error);
+extern void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_hf_client_resume_open ();
+
+/* SDP functions */
+extern BOOLEAN bta_hf_client_add_record(char *p_service_name,
+                                        UINT8 scn, tBTA_HF_CLIENT_FEAT features,
+                                        UINT32 sdp_handle);
+extern void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data);
+extern BOOLEAN bta_hf_client_sdp_find_attr(void);
+extern void bta_hf_client_do_disc(void);
+extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_hf_client_setup_port(UINT16 handle);
+extern void bta_hf_client_start_server(void);
+extern void bta_hf_client_close_server(void);
+extern void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data);
+
+/* SCO functions */
+extern void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_cback_sco(UINT8 event);
+
+/* AT command functions */
+extern void bta_hf_client_at_parse(char *buf, unsigned int len);
+extern void bta_hf_client_send_at_brsf(void);
+extern void bta_hf_client_send_at_bac(void);
+extern void bta_hf_client_send_at_cind(BOOLEAN status);
+extern void bta_hf_client_send_at_cmer(BOOLEAN activate);
+extern void bta_hf_client_send_at_chld(char cmd, UINT32 idx);
+extern void bta_hf_client_send_at_clip(BOOLEAN activate);
+extern void bta_hf_client_send_at_ccwa(BOOLEAN activate);
+extern void bta_hf_client_send_at_cmee(BOOLEAN activate);
+extern void bta_hf_client_send_at_cops(BOOLEAN query);
+extern void bta_hf_client_send_at_clcc(void);
+extern void bta_hf_client_send_at_bvra(BOOLEAN enable);
+extern void bta_hf_client_send_at_vgs(UINT32 volume);
+extern void bta_hf_client_send_at_vgm(UINT32 volume);
+extern void bta_hf_client_send_at_atd(char *number, UINT32 memory);
+extern void bta_hf_client_send_at_bldn(void);
+extern void bta_hf_client_send_at_ata(void);
+extern void bta_hf_client_send_at_chup(void);
+extern void bta_hf_client_send_at_btrh(BOOLEAN query, UINT32 val);
+extern void bta_hf_client_send_at_vts(char code);
+extern void bta_hf_client_send_at_bcc(void);
+extern void bta_hf_client_send_at_bcs(UINT32 codec);
+extern void bta_hf_client_send_at_cnum(void);
+extern void bta_hf_client_send_at_nrec(void);
+extern void bta_hf_client_send_at_binp(UINT32 action);
+extern void bta_hf_client_send_at_bia(void);
+
+/* Action functions */
+extern void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, UINT16 value);
+extern void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, UINT16 value);
+extern void bta_hf_client_operator_name(char *name);
+extern void bta_hf_client_clip(char *number);
+extern void bta_hf_client_ccwa(char *number);
+extern void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme);
+extern void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number);
+extern void bta_hf_client_cnum(char *number, UINT16 service);
+extern void bta_hf_client_binp(char *number);
+
+/* Commands handling functions */
+extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data);
diff --git a/system/bta/hf_client/bta_hf_client_rfc.c b/system/bta/hf_client/bta_hf_client_rfc.c
new file mode 100644
index 0000000..b71f919
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_rfc.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions controlling the RFCOMM
+ *  connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_hf_client_int.h"
+#include "port_api.h"
+#include "bd.h"
+#include "bt_utils.h"
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_port_cback
+**
+** Description      RFCOMM Port callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle)
+{
+    BT_HDR      *p_buf;
+    UNUSED(code);
+
+    /* ignore port events for port handles other than connected handle */
+    if (port_handle != bta_hf_client_cb.scb.conn_handle)
+    {
+        APPL_TRACE_DEBUG2("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
+                          port_handle, bta_hf_client_cb.scb.conn_handle);
+        return;
+    }
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_mgmt_cback
+**
+** Description      RFCOMM management callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle)
+{
+    tBTA_HF_CLIENT_RFC     *p_buf;
+    UINT16                  event;
+
+    APPL_TRACE_DEBUG4("bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = %d, serv_handle = %d",
+                        code, port_handle, bta_hf_client_cb.scb.conn_handle, bta_hf_client_cb.scb.serv_handle);
+
+    /* ignore close event for port handles other than connected handle */
+    if ((code != PORT_SUCCESS) && (port_handle != bta_hf_client_cb.scb.conn_handle))
+    {
+        APPL_TRACE_DEBUG1("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle);
+        return;
+    }
+
+    if (code == PORT_SUCCESS)
+    {
+        if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
+                (port_handle == bta_hf_client_cb.scb.serv_handle))                       /* incoming connection */
+        {
+            event = BTA_HF_CLIENT_RFC_OPEN_EVT;
+        }
+        else
+        {
+            APPL_TRACE_ERROR1 ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+            return;
+        }
+    }
+    /* distinguish server close events */
+    else if (port_handle == bta_hf_client_cb.scb.conn_handle)
+    {
+        event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+    }
+    else
+    {
+        event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
+    }
+
+    if ((p_buf = (tBTA_HF_CLIENT_RFC *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_RFC))) != NULL)
+    {
+        p_buf->hdr.event = event;
+        p_buf->port_handle = port_handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_setup_port
+**
+** Description      Setup RFCOMM port for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_setup_port(UINT16 handle)
+{
+    PORT_SetEventMask(handle, PORT_EV_RXCHAR);
+    PORT_SetEventCallback(handle, bta_hf_client_port_cback);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_start_server
+**
+** Description      Setup RFCOMM server for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_start_server(void)
+{
+    int i;
+    int port_status;
+
+    if (bta_hf_client_cb.scb.serv_handle > 0)
+    {
+        APPL_TRACE_DEBUG2("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
+        return;
+    }
+
+    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask,
+        BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
+
+    port_status =  RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn,
+        TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle),
+        bta_hf_client_mgmt_cback);
+
+    if (port_status  == PORT_SUCCESS)
+    {
+        bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
+    }
+    else
+    {
+        /* TODO: can we handle this better? */
+        APPL_TRACE_DEBUG1("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status);
+    }
+
+    APPL_TRACE_DEBUG1("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_close_server
+**
+** Description      Close RFCOMM server port for use by HF Client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_close_server(void)
+{
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
+
+    if (bta_hf_client_cb.scb.serv_handle == 0)
+    {
+        APPL_TRACE_DEBUG1("%s already stopped", __FUNCTION__);
+        return;
+    }
+
+    RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
+    bta_hf_client_cb.scb.serv_handle = 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_do_open
+**
+** Description      Open an RFCOMM connection to the peer device.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+                            bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
+                            BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
+
+    if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn,
+            FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle),
+            bta_hf_client_mgmt_cback) == PORT_SUCCESS)
+    {
+        bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
+        APPL_TRACE_DEBUG1("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle);
+    }
+    /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+    else
+    {
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_rfc_do_close
+**
+** Description      Close RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    tBTA_HF_CLIENT_RFC     *p_buf;
+    UNUSED(p_data);
+
+    if (bta_hf_client_cb.scb.conn_handle)
+    {
+        RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
+    }
+    else
+    {
+        /* Close API was called while HF Client is in Opening state.        */
+        /* Need to trigger the state machine to send callback to the app    */
+        /* and move back to INIT state.                                     */
+        if ((p_buf = (tBTA_HF_CLIENT_RFC *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_RFC))) != NULL)
+        {
+            p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+            bta_sys_sendmsg(p_buf);
+        }
+
+        /* Cancel SDP if it had been started. */
+        if(bta_hf_client_cb.scb.p_disc_db)
+        {
+            (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
+            bta_hf_client_free_db(NULL);
+        }
+    }
+}
diff --git a/system/bta/hf_client/bta_hf_client_sco.c b/system/bta/hf_client/bta_hf_client_sco.c
new file mode 100644
index 0000000..224dcc6
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_sco.c
@@ -0,0 +1,734 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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 "bta_hf_client_int.h"
+#include <bt_trace.h>
+#include <bd.h>
+#include <string.h>
+#include "bt_utils.h"
+
+#define BTA_HF_CLIENT_NO_EDR_ESCO  (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
+                                    BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+                                    BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+                                    BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+static const tBTM_ESCO_PARAMS bta_hf_client_esco_params[] = {
+        /* SCO CVSD */
+        {
+                .rx_bw = BTM_64KBITS_RATE,
+                .tx_bw = BTM_64KBITS_RATE,
+                .max_latency = 10,
+                .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+                .packet_types = (BTM_SCO_LINK_ONLY_MASK          |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+                 .retrans_effort = BTM_ESCO_RETRANS_POWER,
+        },
+        /* ESCO CVSD */
+        {
+                .rx_bw = BTM_64KBITS_RATE,
+                .tx_bw = BTM_64KBITS_RATE,
+                .max_latency = 10,
+                .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+                /* Allow controller to use all types available except 5-slot EDR */
+                .packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+                .retrans_effort = BTM_ESCO_RETRANS_POWER,
+        },
+        /* ESCO mSBC */
+        {
+                .rx_bw = BTM_64KBITS_RATE,
+                .tx_bw = BTM_64KBITS_RATE,
+                .max_latency = 13,
+                .voice_contfmt = BTM_VOICE_SETTING_TRANS,
+                /* Packet Types : EV3 + 2-EV3               */
+                .packet_types = (BTM_SCO_PKT_TYPES_MASK_EV3  |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+                .retrans_effort = BTM_ESCO_RETRANS_QUALITY,
+        }
+};
+
+enum
+{
+    BTA_HF_CLIENT_SCO_LISTEN_E,
+    BTA_HF_CLIENT_SCO_OPEN_E,          /* open request */
+    BTA_HF_CLIENT_SCO_CLOSE_E,         /* close request */
+    BTA_HF_CLIENT_SCO_SHUTDOWN_E,      /* shutdown request */
+    BTA_HF_CLIENT_SCO_CONN_OPEN_E,     /* sco opened */
+    BTA_HF_CLIENT_SCO_CONN_CLOSE_E,    /* sco closed */
+};
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_remove_sco
+**
+** Description      Removes the specified SCO from the system.
+**                  If only_active is TRUE, then SCO is only removed if connected
+**
+** Returns          BOOLEAN   - TRUE if Sco removal was started
+**
+*******************************************************************************/
+static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
+{
+    BOOLEAN     removed_started = FALSE;
+    tBTM_STATUS status;
+
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, only_active);
+
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);
+
+        APPL_TRACE_DEBUG3("%s idx 0x%04x, status:0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx, status);
+
+        if (status == BTM_CMD_STARTED)
+        {
+            removed_started = TRUE;
+        }
+        /* If no connection reset the sco handle */
+        else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
+        {
+            bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+        }
+    }
+    return removed_started;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_cback_sco
+**
+** Description      Call application callback function with SCO event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_cback_sco(UINT8 event)
+{
+    tBTA_HF_CLIENT    evt;
+
+    memset(&evt, 0, sizeof(evt));
+
+    /* call app cback */
+    (*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT *) &evt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_rsp
+**
+** Description      Process the SCO connection request
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_conn_rsp(tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+    tBTM_ESCO_PARAMS    resp;
+    UINT8               hci_status = HCI_SUCCESS;
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST)
+    {
+        if (p_data->link_type == BTM_LINK_TYPE_SCO)
+        {
+            resp = bta_hf_client_esco_params[0];
+        }
+        else
+        {
+            resp = bta_hf_client_esco_params[bta_hf_client_cb.scb.negotiated_codec];
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+    }
+    else
+    {
+        hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+    }
+
+    BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_connreq_cback
+**
+** Description      BTM eSCO connection requests and eSCO change requests
+**                  Only the connection requests are processed by BTA.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, event);
+
+    if (event != BTM_ESCO_CONN_REQ_EVT)
+    {
+        return;
+    }
+
+    /* TODO check remote bdaddr, should allow connect only from device with
+     * active SLC  */
+
+    bta_hf_client_cb.scb.sco_idx = p_data->conn_evt.sco_inx;
+
+    bta_hf_client_sco_conn_rsp(&p_data->conn_evt);
+
+    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_cback
+**
+** Description      BTM SCO connection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_conn_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+    UINT8 *rem_bd;
+
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, sco_idx);
+
+    rem_bd = BTM_ReadScoBdAddr(sco_idx);
+
+    if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
+            bta_hf_client_cb.scb.svc_conn && bta_hf_client_cb.scb.sco_idx == sco_idx)
+    {
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
+            p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found; disconnect sco, init sco variables */
+    else
+    {
+        bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+        BTM_RemoveSco(sco_idx);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_disc_cback
+**
+** Description      BTM SCO disconnection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_disc_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, sco_idx);
+
+    if (bta_hf_client_cb.scb.sco_idx == sco_idx)
+    {
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
+            p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_create_sco
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_create(BOOLEAN is_orig)
+{
+    tBTM_STATUS       status;
+    UINT8            *p_bd_addr = NULL;
+    tBTM_ESCO_PARAMS params;
+
+    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, is_orig);
+
+    /* Make sure this sco handle is not already in use */
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        APPL_TRACE_WARNING2("%s: Index 0x%04x already in use", __FUNCTION__,
+                            bta_hf_client_cb.scb.sco_idx);
+        return;
+    }
+
+    params = bta_hf_client_esco_params[1];
+
+    /* if initiating set current scb and peer bd addr */
+    if (is_orig)
+    {
+        /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+        if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 && !bta_hf_client_cb.scb.retry_with_sco_only)
+        {
+            BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+            /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+            if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+               ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_HF_CLIENT_NO_EDR_ESCO))
+            {
+                bta_hf_client_cb.scb.retry_with_sco_only = TRUE;
+                APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+            }
+        }
+        else
+        {
+            if(bta_hf_client_cb.scb.retry_with_sco_only)
+                APPL_TRACE_API0("retrying with SCO only");
+            bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+    }
+    else
+    {
+        bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+    }
+
+    p_bd_addr = bta_hf_client_cb.scb.peer_addr;
+
+    status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+                           &bta_hf_client_cb.scb.sco_idx, bta_hf_client_sco_conn_cback,
+                           bta_hf_client_sco_disc_cback);
+    if (status == BTM_CMD_STARTED && !is_orig)
+    {
+        if(!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx, bta_hf_client_esco_connreq_cback))
+            APPL_TRACE_DEBUG1("%s SCO registration success", __FUNCTION__);
+    }
+
+    APPL_TRACE_API5("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+                      __FUNCTION__, is_orig, bta_hf_client_cb.scb.sco_idx,
+                      status, params.packet_types);
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_event
+**
+** Description      Handle SCO events
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sco_event(UINT8 event)
+{
+    APPL_TRACE_DEBUG3("%s state: %d event: %d", __FUNCTION__,
+                        bta_hf_client_cb.scb.sco_state, event);
+
+    switch (bta_hf_client_cb.scb.sco_state)
+    {
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_LISTEN_E:
+                    /* create sco listen connection */
+                    bta_hf_client_sco_create(FALSE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_LISTEN_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    bta_hf_client_sco_create(FALSE);
+                    break;
+
+                case BTA_HF_CLIENT_SCO_OPEN_E:
+                    /* remove listening connection */
+                    bta_hf_client_sco_remove(FALSE);
+
+                    /* create sco connection to peer */
+                    bta_hf_client_sco_create(TRUE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    /* remove listening connection */
+                    bta_hf_client_sco_remove(FALSE);
+
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CLOSE_E:
+                    /* remove listening connection */
+                    /* Ignore the event. We need to keep listening SCO for the active SLC */
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_hf_client_sco_create(FALSE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_OPENING_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_CLOSE_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_hf_client_sco_create(FALSE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_OPEN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+                    /* close sco connection */
+                    bta_hf_client_sco_remove(TRUE);
+
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_OPEN_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_CLOSE_E:
+                    /* close sco connection if active */
+                    if (bta_hf_client_sco_remove(TRUE))
+                    {
+                        bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+                    }
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    /* remove all listening connections */
+                    bta_hf_client_sco_remove(FALSE);
+
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_hf_client_sco_create(FALSE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_CLOSING_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_OPEN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_hf_client_sco_create(FALSE);
+
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_CLOSE_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    /* open sco connection */
+                    bta_hf_client_sco_create(TRUE);
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_HF_CLIENT_SCO_SHUTTING_ST:
+            switch (event)
+            {
+                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+                    /* close sco connection; wait for conn close event */
+                    bta_hf_client_sco_remove(TRUE);
+                    break;
+
+                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+                    break;
+
+                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_listen
+**
+** Description      Initialize SCO listener
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_shutdown
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_OPEN_E);
+
+    bta_sys_sco_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC)
+    {
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
+    }
+    else
+    {
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_OPEN_EVT);
+    }
+
+    bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_conn_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    /* clear current scb */
+    bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+
+    /* retry_with_sco_only, will be set only when initiator
+    ** and HFClient is first trying to establish an eSCO connection */
+    if (bta_hf_client_cb.scb.retry_with_sco_only && bta_hf_client_cb.scb.svc_conn)
+    {
+        bta_hf_client_sco_create(TRUE);
+    }
+    else
+    {
+        bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
+
+        bta_sys_sco_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+        bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+        /* call app callback */
+        bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+
+        if (bta_hf_client_cb.scb.sco_close_rfc == TRUE)
+        {
+            bta_hf_client_cb.scb.sco_close_rfc = FALSE;
+            bta_hf_client_rfc_do_close(p_data);
+        }
+    }
+    bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_OPEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sco_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG2("%s  0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx);
+
+    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CLOSE_E);
+    }
+}
diff --git a/system/bta/hf_client/bta_hf_client_sdp.c b/system/bta/hf_client/bta_hf_client_sdp.c
new file mode 100644
index 0000000..f967fbf
--- /dev/null
+++ b/system/bta/hf_client/bta_hf_client_sdp.c
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions performing SDP
+ *  operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bt_utils.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_HF_CLIENT_NUM_PROTO_ELEMS      2
+
+/* Number of elements in service class id list. */
+#define BTA_HF_CLIENT_NUM_SVC_ELEMS        2
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sdp_cback
+**
+** Description      SDP callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hf_client_sdp_cback(UINT16 status)
+{
+    tBTA_HF_CLIENT_DISC_RESULT *p_buf;
+    UINT16                     event;
+
+    APPL_TRACE_DEBUG1("bta_hf_client_sdp_cback status:0x%x", status);
+
+    /* set event according to int/acp */
+    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP)
+    {
+        event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
+    }
+    else
+    {
+        event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
+    }
+
+    if ((p_buf = (tBTA_HF_CLIENT_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_DISC_RESULT))) != NULL)
+    {
+        p_buf->hdr.event = event;
+        p_buf->status = status;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_hf_client_add_record
+**
+** Description      This function is called by a server application to add
+**                  HFP Client information to an SDP record.  Prior to
+**                  calling this function the application must call
+**                  SDP_CreateRecord() to create an SDP record.
+**
+** Returns          TRUE if function execution succeeded,
+**                  FALSE if function execution failed.
+**
+******************************************************************************/
+BOOLEAN bta_hf_client_add_record(char *p_service_name, UINT8 scn,
+                          tBTA_HF_CLIENT_FEAT features, UINT32 sdp_handle)
+{
+    tSDP_PROTOCOL_ELEM  proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
+    UINT16              svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
+    UINT16              browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+    UINT16              version;
+    UINT16              profile_uuid;
+    BOOLEAN             result = TRUE;
+    BOOLEAN             codec_supported = FALSE;
+    UINT8               buf[2];
+    UINT16              sdp_features = 0;
+
+    APPL_TRACE_DEBUG0("bta_hf_client_add_record");
+
+    memset( proto_elem_list, 0 , BTA_HF_CLIENT_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+    /* add the protocol element sequence */
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params = 0;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+    proto_elem_list[1].num_params = 1;
+    proto_elem_list[1].params[0] = scn;
+    result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list);
+
+    /* add service class id list */
+    svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
+    svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+    result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list);
+
+    /* add profile descriptor list */
+    profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+    version = HFP_VERSION_1_6;
+
+    result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+    /* add service name */
+    if (p_service_name != NULL && p_service_name[0] != 0)
+    {
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                    (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+    }
+
+    /* add features */
+    if (features & BTA_HF_CLIENT_FEAT_ECNR)
+       sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
+
+    if (features & BTA_HF_CLIENT_FEAT_3WAY)
+       sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
+
+    if (features & BTA_HF_CLIENT_FEAT_CLI)
+       sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
+
+    if (features & BTA_HF_CLIENT_FEAT_VREC)
+       sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
+
+    if (features & BTA_HF_CLIENT_FEAT_VOL)
+       sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
+
+    /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
+    if (features & BTA_HF_CLIENT_FEAT_CODEC)
+       sdp_features |= 0x0020;
+
+    UINT16_TO_BE_FIELD(buf, sdp_features);
+    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
+
+    /* add browse group list */
+    result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_create_record
+**
+** Description      Create SDP record for registered service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data)
+{
+    /* add sdp record if not already registered */
+    if (bta_hf_client_cb.sdp_handle == 0)
+    {
+        bta_hf_client_cb.sdp_handle = SDP_CreateRecord();
+        bta_hf_client_cb.scn = BTM_AllocateSCN();
+        bta_hf_client_add_record(p_data->api_register.name,
+                                 bta_hf_client_cb.scn,
+                                 p_data->api_register.features,
+                                 bta_hf_client_cb.sdp_handle);
+
+        bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_del_record
+**
+** Description      Delete SDP record for registered service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    APPL_TRACE_DEBUG0("bta_hf_client_del_record");
+
+    if (bta_hf_client_cb.sdp_handle != 0)
+    {
+        SDP_DeleteRecord(bta_hf_client_cb.sdp_handle);
+        bta_hf_client_cb.sdp_handle = 0;
+        BTM_FreeSCN(bta_hf_client_cb.scn);
+        BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE);
+        bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_sdp_find_attr
+**
+** Description      Process SDP discovery results to find requested attribute
+**
+**
+** Returns          TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_hf_client_sdp_find_attr(void)
+{
+    tSDP_DISC_REC       *p_rec = NULL;
+    tSDP_DISC_ATTR      *p_attr;
+    tSDP_PROTOCOL_ELEM  pe;
+    BOOLEAN             result = FALSE;
+
+    bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1;   /* Default version */
+
+    /* loop through all records we found */
+    while (TRUE)
+    {
+        /* get next record; if none found, we're done */
+        if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL)
+        {
+            break;
+        }
+
+        /* get scn from proto desc list if initiator */
+        if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
+        {
+            if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+            {
+                bta_hf_client_cb.scb.peer_scn = (UINT8) pe.params[0];
+            }
+            else
+            {
+                continue;
+            }
+        }
+
+        /* get profile version (if failure, version parameter is not updated) */
+        SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version);
+
+        /* get features */
+        if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+        {
+            /* Found attribute. Get value. */
+            /* There might be race condition between SDP and BRSF.  */
+            /* Do not update if we already received BRSF.           */
+            if (bta_hf_client_cb.scb.peer_features == 0)
+            {
+                bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16;
+
+                /* SDP and BRSF WBS bit are different, correct it if set */
+                if (bta_hf_client_cb.scb.peer_features & 0x0020)
+                {
+                    bta_hf_client_cb.scb.peer_features &= ~0x0020;
+                    bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC;
+                }
+
+                /* get network for ability to reject calls */
+                if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL)
+                {
+                    if (p_attr->attr_value.v.u16 == 0x01)
+                    {
+                        bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT;
+                    }
+                }
+            }
+        }
+
+        /* found what we needed */
+        result = TRUE;
+        break;
+    }
+
+    APPL_TRACE_DEBUG3("%s peer_version=0x%x peer_features=0x%x",
+                      __FUNCTION__, bta_hf_client_cb.scb.peer_version,
+                      bta_hf_client_cb.scb.peer_features);
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_do_disc
+**
+** Description      Do service discovery.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_do_disc(void)
+{
+    tSDP_UUID       uuid_list[2];
+    UINT16          num_uuid = 1;
+    UINT16          attr_list[4];
+    UINT8           num_attr;
+    BOOLEAN         db_inited = FALSE;
+
+    /* initiator; get proto list and features */
+    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 4;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+    }
+    /* acceptor; get features */
+    else
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 3;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+    }
+
+    /* allocate buffer for sdp database */
+    bta_hf_client_cb.scb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(GKI_MAX_BUF_SIZE);
+
+    if (bta_hf_client_cb.scb.p_disc_db)
+    {
+        /* set up service discovery database; attr happens to be attr_list len */
+        uuid_list[0].len = LEN_UUID_16;
+        uuid_list[1].len = LEN_UUID_16;
+        db_inited = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db, GKI_MAX_BUF_SIZE, num_uuid,
+                            uuid_list, num_attr, attr_list);
+    }
+
+    if (db_inited)
+    {
+        /*Service discovery not initiated */
+        db_inited = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
+                            bta_hf_client_cb.scb.p_disc_db, bta_hf_client_sdp_cback);
+    }
+
+    if (!db_inited)
+    {
+        /*free discover db */
+        bta_hf_client_free_db(NULL);
+        /* sent failed event */
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_hf_client_free_db
+**
+** Description      Free discovery database.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data)
+{
+    UNUSED(p_data);
+
+    if (bta_hf_client_cb.scb.p_disc_db != NULL)
+    {
+        GKI_freebuf(bta_hf_client_cb.scb.p_disc_db);
+        bta_hf_client_cb.scb.p_disc_db = NULL;
+    }
+}
diff --git a/system/bta/include/bta_hf_client_api.h b/system/bta/include/bta_hf_client_api.h
new file mode 100644
index 0000000..8ef42f4
--- /dev/null
+++ b/system/bta/include/bta_hf_client_api.h
@@ -0,0 +1,382 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the public interface file for the handsfree (HF role) subsystem
+ *
+ ******************************************************************************/
+#ifndef BTA_HF_CLIENT_API_H
+#define BTA_HF_CLIENT_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+**  Constants and data types
+*****************************************************************************/
+
+/* HFP peer (AG) features*/
+#define BTA_HF_CLIENT_PEER_FEAT_3WAY   0x00000001  /* Three-way calling */
+#define BTA_HF_CLIENT_PEER_FEAT_ECNR   0x00000002  /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_PEER_FEAT_VREC   0x00000004  /* Voice recognition */
+#define BTA_HF_CLIENT_PEER_INBAND      0x00000008  /* In-band ring tone */
+#define BTA_HF_CLIENT_PEER_VTAG        0x00000010  /* Attach a phone number to a voice tag */
+#define BTA_HF_CLIENT_PEER_REJECT      0x00000020  /* Ability to reject incoming call */
+#define BTA_HF_CLIENT_PEER_ECS         0x00000040  /* Enhanced Call Status */
+#define BTA_HF_CLIENT_PEER_ECC         0x00000080  /* Enhanced Call Control */
+#define BTA_HF_CLIENT_PEER_EXTERR      0x00000100  /* Extended error codes */
+#define BTA_HF_CLIENT_PEER_CODEC       0x00000200  /* Codec Negotiation */
+
+typedef UINT16 tBTA_HF_CLIENT_PEER_FEAT;
+
+/* HFP HF features */
+#define BTA_HF_CLIENT_FEAT_ECNR        0x00000001  /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_FEAT_3WAY        0x00000002  /* Call waiting and three-way calling */
+#define BTA_HF_CLIENT_FEAT_CLI         0x00000004  /* Caller ID presentation capability */
+#define BTA_HF_CLIENT_FEAT_VREC        0x00000008  /* Voice recognition activation */
+#define BTA_HF_CLIENT_FEAT_VOL         0x00000010  /* Remote volume control */
+#define BTA_HF_CLIENT_FEAT_ECS         0x00000020  /* Enhanced Call Status */
+#define BTA_HF_CLIENT_FEAT_ECC         0x00000040  /* Enhanced Call Control */
+#define BTA_HF_CLIENT_FEAT_CODEC       0x00000080  /* Codec Negotiation */
+
+/* HFP HF extended call handling - masks not related to any spec */
+#define BTA_HF_CLIENT_CHLD_REL          0x00000001  /* 0  Release waiting call or held calls */
+#define BTA_HF_CLIENT_CHLD_REL_ACC      0x00000002  /* 1  Release active calls and accept other (waiting or held) cal */
+#define BTA_HF_CLIENT_CHLD_REL_X        0x00000004  /* 1x Release x call*/
+#define BTA_HF_CLIENT_CHLD_HOLD_ACC     0x00000008  /* 2  Active calls on hold and accept other call */
+#define BTA_HF_CLIENT_CHLD_PRIV_X       0x00000010  /* 2x Active multiparty call on hold except call x */
+#define BTA_HF_CLIENT_CHLD_MERGE        0x00000020  /* 3  Add held call to multiparty */
+#define BTA_HF_CLIENT_CHLD_MERGE_DETACH 0x00000040  /* 4  Add held call to multiparty */
+
+typedef UINT16 tBTA_HF_CLIENT_CHLD_FEAT;
+
+/* HFP AG errors ot OK sent to HF Unit */
+#define BTA_HF_CLIENT_AT_RESULT_OK            0
+#define BTA_HF_CLIENT_AT_RESULT_ERROR         1
+#define BTA_HF_CLIENT_AT_RESULT_NO_CARRIER    2
+#define BTA_HF_CLIENT_AT_RESULT_BUSY          3
+#define BTA_HF_CLIENT_AT_RESULT_NO_ANSWER     4
+#define BTA_HF_CLIENT_AT_RESULT_DELAY         5
+#define BTA_HF_CLIENT_AT_RESULT_BLACKLISTED   6
+#define BTA_HF_CLIENT_AT_RESULT_CME           7
+
+typedef UINT8 tBTA_HF_CLIENT_AT_RESULT_TYPE;
+
+/* HF Client callback events */
+#define BTA_HF_CLIENT_ENABLE_EVT            0  /* HF Client enabled */
+#define BTA_HF_CLIENT_REGISTER_EVT          1  /* HF Client registered */
+#define BTA_HF_CLIENT_OPEN_EVT              2  /* HF Client connection open */
+#define BTA_HF_CLIENT_CLOSE_EVT             3  /* HF Client connection closed */
+#define BTA_HF_CLIENT_CONN_EVT              4  /* Service level connection opened */
+#define BTA_HF_CLIENT_AUDIO_OPEN_EVT        5  /* Audio connection open */
+#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT   6  /* Audio connection with mSBC codec open */
+#define BTA_HF_CLIENT_AUDIO_CLOSE_EVT       7  /* Audio connection closed */
+#define BTA_HF_CLIENT_SPK_EVT               8  /* Speaker volume changed */
+#define BTA_HF_CLIENT_MIC_EVT               9  /* Microphone volume changed */
+#define BTA_HF_CLIENT_IND_EVT               10 /* Indicator */
+#define BTA_HF_CLIENT_VOICE_REC_EVT         11 /* AG changed voice recognition setting */
+#define BTA_HF_CLIENT_OPERATOR_NAME_EVT     12 /* Operator name acquired */
+#define BTA_HF_CLIENT_CLIP_EVT              13 /* Calling line identification event */
+#define BTA_HF_CLIENT_CCWA_EVT              14 /* Call waiting notification */
+#define BTA_HF_CLIENT_AT_RESULT_EVT         15 /* Call waiting notification */
+#define BTA_HF_CLIENT_CLCC_EVT              16 /* current call event */
+#define BTA_HF_CLIENT_CNUM_EVT              17 /* subscriber information event */
+#define BTA_HF_CLIENT_BTRH_EVT              18 /* bluetooth response and hold event */
+#define BTA_HF_CLIENT_BSIR_EVT              19 /* in-band ring tone setting changed event */
+#define BTA_HF_CLIENT_BINP_EVT              20 /* binp number event */
+#define BTA_HF_CLIENT_RING_INDICATION       21 /* HF Client ring indication */
+#define BTA_HF_CLIENT_DISABLE_EVT           30 /* HF Client disabled */
+
+typedef UINT8 tBTA_HF_CLIENT_EVT;
+
+/* HF Client open status */
+#define BTA_HF_CLIENT_SUCCESS          0 /* Connection successfully opened */
+#define BTA_HF_CLIENT_FAIL_SDP         1 /* Open failed due to SDP */
+#define BTA_HF_CLIENT_FAIL_RFCOMM      2 /* Open failed due to RFCOMM */
+#define BTA_HF_CLIENT_FAIL_RESOURCES   3 /* out of resources failure  */
+
+typedef UINT8 tBTA_HF_CLIENT_STATUS;
+
+/* indicator type */
+#define BTA_HF_CLIENT_IND_BATTCH    0  /* Battery charge indicator */
+#define BTA_HF_CLIENT_IND_SIGNAL    1  /* Signal Strength indicator */
+#define BTA_HF_CLIENT_IND_SERVICE   2  /* Service availability indicator */
+#define BTA_HF_CLIENT_IND_CALL      3  /* Standard call status indicator*/
+#define BTA_HF_CLIENT_IND_ROAM      4  /* Roaming status indicator */
+#define BTA_HF_CLIENT_IND_CALLSETUP 5  /* Call setup status indicator */
+#define BTA_HF_CLIENT_IND_CALLHELD  6  /* Call hold status indicator */
+
+typedef UINT8 tBTA_HF_CLIENT_IND_TYPE;
+
+/* AT commands */
+#define BTA_HF_CLIENT_AT_CMD_VTS    0
+#define BTA_HF_CLIENT_AT_CMD_BTRH   1
+#define BTA_HF_CLIENT_AT_CMD_CHUP   2
+#define BTA_HF_CLIENT_AT_CMD_CHLD   3
+#define BTA_HF_CLIENT_AT_CMD_BCC    4
+#define BTA_HF_CLIENT_AT_CMD_CNUM   5
+#define BTA_HF_CLIENT_AT_CMD_ATA    6
+#define BTA_HF_CLIENT_AT_CMD_COPS   7
+#define BTA_HF_CLIENT_AT_CMD_ATD    8
+#define BTA_HF_CLIENT_AT_CMD_VGM    9
+#define BTA_HF_CLIENT_AT_CMD_VGS    10
+#define BTA_HF_CLIENT_AT_CMD_BVRA   11
+#define BTA_HF_CLIENT_AT_CMD_CLCC   12
+#define BTA_HF_CLIENT_AT_CMD_BINP   13
+#define BTA_HF_CLIENT_AT_CMD_BLDN   14
+#define BTA_HF_CLIENT_AT_CMD_NREC   15
+
+typedef UINT8 tBTA_HF_CLIENT_AT_CMD_TYPE;
+
+/* data associated with most non-AT events */
+/* placeholder, if not needed should be removed*/
+typedef struct
+{
+} tBTA_HF_CLIENT_HDR;
+
+/* data associated with BTA_HF_CLIENT_REGISTER_EVT */
+typedef struct
+{
+    tBTA_HF_CLIENT_HDR      hdr;
+    UINT16                  handle;
+    tBTA_HF_CLIENT_STATUS   status;
+} tBTA_HF_CLIENT_REGISTER;
+
+/* data associated with BTA_HF_CLIENT_OPEN_EVT */
+typedef struct
+{
+    tBTA_HF_CLIENT_HDR      hdr;
+    BD_ADDR                 bd_addr;
+    tBTA_HF_CLIENT_STATUS   status;
+} tBTA_HF_CLIENT_OPEN;
+
+/* data associated with BTA_HF_CLIENT_CONN_EVT */
+typedef struct
+{
+    tBTA_HF_CLIENT_HDR         hdr;
+    tBTA_HF_CLIENT_PEER_FEAT   peer_feat;
+    tBTA_HF_CLIENT_CHLD_FEAT   chld_feat;
+} tBTA_HF_CLIENT_CONN;
+
+/* data associated with BTA_HF_CLIENT_IND_EVT event */
+typedef struct
+{
+    tBTA_HF_CLIENT_HDR         hdr;
+    tBTA_HF_CLIENT_IND_TYPE    type;
+    UINT16                     value;
+} tBTA_HF_CLIENT_IND;
+
+/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */
+#define BTA_HF_CLIENT_OPERATOR_NAME_LEN 16
+typedef struct
+{
+    char                       name[BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1];
+} tBTA_HF_CLIENT_OPERATOR_NAME;
+
+/* data associated with BTA_HF_CLIENT_CLIP_EVT  and BTA_HF_CLIENT_CCWA_EVT*/
+#define BTA_HF_CLIENT_NUMBER_LEN 32
+typedef struct
+{
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_NUMBER;
+
+/* data associated with BTA_HF_CLIENT_AT_RESULT_EVT event */
+typedef struct
+{
+    tBTA_HF_CLIENT_AT_RESULT_TYPE    type;
+    UINT16                           cme;
+} tBTA_HF_CLIENT_AT_RESULT;
+
+/* data associated with BTA_HF_CLIENT_CLCC_EVT event */
+typedef struct
+{
+    UINT32                     idx;
+    BOOLEAN                    inc;
+    UINT8                      status;
+    BOOLEAN                    mpty;
+    BOOLEAN                    number_present;
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CLCC;
+
+/* data associated with BTA_HF_CLIENT_CNUM_EVT event */
+typedef struct
+{
+    UINT16                     service;
+    char                       number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CNUM;
+
+/* data associated with other events */
+typedef struct
+{
+    UINT16                     value;
+} tBTA_HF_CLIENT_VAL;
+
+/* union of data associated with AG callback */
+typedef union
+{
+    tBTA_HF_CLIENT_HDR              hdr;
+    tBTA_HF_CLIENT_REGISTER         reg;
+    tBTA_HF_CLIENT_OPEN             open;
+    tBTA_HF_CLIENT_CONN             conn;
+    tBTA_HF_CLIENT_IND              ind;
+    tBTA_HF_CLIENT_VAL              val;
+    tBTA_HF_CLIENT_OPERATOR_NAME    operator;
+    tBTA_HF_CLIENT_NUMBER           number;
+    tBTA_HF_CLIENT_AT_RESULT        result;
+    tBTA_HF_CLIENT_CLCC             clcc;
+    tBTA_HF_CLIENT_CNUM             cnum;
+} tBTA_HF_CLIENT;
+
+typedef UINT32 tBTA_HF_CLIENT_FEAT;
+
+/* HF Client callback */
+typedef void (tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event, tBTA_HF_CLIENT *p_data);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientEnable
+**
+** Description      Enable the HF CLient service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+**                  be called before other function in the HF CLient API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+BTA_API tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDisable
+**
+** Description      Disable the HF Client service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientDisable(void);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientRegister
+**
+** Description      Register an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features,
+                                                        char *p_service_name);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientDeregister
+**
+** Description      Deregister an HF Client service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientDeregister(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientOpen
+**
+** Description      Opens a connection to an audio gateway.
+**                  When connection is open callback function is called
+**                  with a BTA_HF_CLIENT_OPEN_EVT. Only the data connection is
+**                  opened. The audio connection is not opened.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientClose
+**
+** Description      Close the current connection to an audio gateway.
+**                  Any current audio connection will also be closed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfCllientAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                 audio gateway
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientAudioOpen(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientAudioClose
+**
+** Description      Close the currently active audio connection to an audio
+**                  gateway. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientAudioClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function         BTA_HfClientSendAT
+**
+** Description      send AT command
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val1, UINT32 val2, const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HF_CLIENT_API_H */
diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h
index f11b629..111b90c 100644
--- a/system/btif/include/btif_common.h
+++ b/system/btif/include/btif_common.h
@@ -1,5 +1,6 @@
 /******************************************************************************
  *
+ *  Copyright (c) 2014 The Android Open Source Project
  *  Copyright (C) 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,6 +50,7 @@
 #define BTIF_HFP            2
 #define BTIF_AV             3
 #define BTIF_PAN            4
+#define BTIF_HF_CLIENT      5
 
 extern bt_callbacks_t *bt_hal_cbacks;
 
@@ -116,6 +118,9 @@
 
     BTIF_PAN_CB_START = BTIF_SIG_CB_START(BTIF_PAN),
     BTIF_PAN_CB_DISCONNECTING, /* PAN Disconnect has been sent to BTA successfully */
+
+    BTIF_HF_CLIENT_CLIENT_CB_START  = BTIF_SIG_CB_START(BTIF_HF_CLIENT),
+    BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, /* AUDIO connect has been sent to BTA successfully */
 };
 
 /* Macro definitions for BD ADDR persistence */
diff --git a/system/btif/include/btif_util.h b/system/btif/include/btif_util.h
index 95969dd..4f1a9cc 100644
--- a/system/btif/include/btif_util.h
+++ b/system/btif/include/btif_util.h
@@ -1,5 +1,6 @@
 /******************************************************************************
  *
+ *  Copyright (c) 2014 The Android Open Source Project
  *  Copyright (C) 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,6 +51,7 @@
 const char* dump_dm_search_event(UINT16 event);
 const char* dump_dm_event(UINT16 event);
 const char* dump_hf_event(UINT16 event);
+const char* dump_hf_client_event(UINT16 event);
 const char* dump_hh_event(UINT16 event);
 const char* dump_hf_conn_state(UINT16 event);
 const char* dump_hf_call_state(bthf_call_state_t call_state);
diff --git a/system/btif/src/bluetooth.c b/system/btif/src/bluetooth.c
index 17da1d3..9e63d54 100644
--- a/system/btif/src/bluetooth.c
+++ b/system/btif/src/bluetooth.c
@@ -30,6 +30,7 @@
 
 #include <hardware/bluetooth.h>
 #include <hardware/bt_hf.h>
+#include <hardware/bt_hf_client.h>
 #include <hardware/bt_av.h>
 #include <hardware/bt_sock.h>
 #include <hardware/bt_hh.h>
@@ -75,6 +76,8 @@
 
 /* handsfree profile */
 extern bthf_interface_t *btif_hf_get_interface();
+/* handsfree profile - client */
+extern bthf_client_interface_t *btif_hf_client_get_interface();
 /* advanced audio profile */
 extern btav_interface_t *btif_av_get_interface();
 /*rfc l2cap*/
@@ -315,6 +318,9 @@
     if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
         return btif_hf_get_interface();
 
+    if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
+        return btif_hf_client_get_interface();
+
     if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
         return btif_sock_get_interface();
 
diff --git a/system/btif/src/btif_dm.c b/system/btif/src/btif_dm.c
index 874aaeb..8a06e18 100644
--- a/system/btif/src/btif_dm.c
+++ b/system/btif/src/btif_dm.c
@@ -158,6 +158,7 @@
 extern bt_status_t btif_hf_execute_service(BOOLEAN b_enable);
 extern bt_status_t btif_av_execute_service(BOOLEAN b_enable);
 extern bt_status_t btif_hh_execute_service(BOOLEAN b_enable);
+extern bt_status_t btif_hf_client_execute_service(BOOLEAN b_enable);
 extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
 extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
 
@@ -185,7 +186,10 @@
          {
               btif_hh_execute_service(b_enable);
          }break;
-
+         case BTA_HFP_HS_SERVICE_ID:
+         {
+             btif_hf_client_execute_service(b_enable);
+         }break;
          default:
               BTIF_TRACE_ERROR1("%s: Unknown service being enabled", __FUNCTION__);
               return BT_STATUS_FAIL;
diff --git a/system/btif/src/btif_hf_client.c b/system/btif/src/btif_hf_client.c
new file mode 100644
index 0000000..f1eb374
--- /dev/null
+++ b/system/btif/src/btif_hf_client.c
@@ -0,0 +1,985 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hf_client.c
+ *
+ *  Description:   Handsfree Profile (HF role) Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf_client.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+
+#define LOG_TAG "BTIF_HF_CLIENT"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+#include "bt_utils.h"
+#include "bd.h"
+#include "bta_hf_client_api.h"
+
+/************************************************************************************
+**  Constants & Macros
+************************************************************************************/
+
+#ifndef BTIF_HF_CLIENT_SERVICE_NAME
+#define BTIF_HF_CLIENT_SERVICE_NAME ("Handsfree")
+#endif
+
+#ifndef BTIF_HF_CLIENT_SECURITY
+#define BTIF_HF_CLIENT_SECURITY    (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_CLIENT_FEATURES
+#define BTIF_HF_CLIENT_FEATURES   ( BTA_HF_CLIENT_FEAT_ECNR  | \
+                                    BTA_HF_CLIENT_FEAT_3WAY  | \
+                                    BTA_HF_CLIENT_FEAT_CLI   | \
+                                    BTA_HF_CLIENT_FEAT_VREC  | \
+                                    BTA_HF_CLIENT_FEAT_VOL   | \
+                                    BTA_HF_CLIENT_FEAT_ECS   | \
+                                    BTA_HF_CLIENT_FEAT_ECC   | \
+                                    BTA_HF_CLIENT_FEAT_CODEC)
+#endif
+
+/************************************************************************************
+**  Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+**  Static variables
+************************************************************************************/
+static bthf_client_callbacks_t *bt_hf_client_callbacks = NULL;
+char   btif_hf_client_version[PROPERTY_VALUE_MAX];
+static UINT32 btif_hf_client_features = 0;
+
+
+#define CHECK_BTHF_CLIENT_INIT() if (bt_hf_client_callbacks == NULL)\
+    {\
+        BTIF_TRACE_WARNING1("BTHF CLIENT: %s: not initialized", __FUNCTION__);\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else\
+    {\
+        BTIF_TRACE_EVENT1("BTHF CLIENT: %s", __FUNCTION__);\
+    }
+
+#define CHECK_BTHF_CLIENT_SLC_CONNECTED() if (bt_hf_client_callbacks == NULL)\
+    {\
+        BTIF_TRACE_WARNING1("BTHF CLIENT: %s: not initialized", __FUNCTION__);\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else if (btif_hf_client_cb.state != BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED)\
+    {\
+        BTIF_TRACE_WARNING2("BTHF CLIENT: %s: SLC connection not up. state=%s",\
+                           __FUNCTION__, \
+                           dump_hf_conn_state(btif_hf_client_cb.state));\
+        return BT_STATUS_NOT_READY;\
+    }\
+    else\
+    {\
+        BTIF_TRACE_EVENT1("BTHF CLIENT: %s", __FUNCTION__);\
+    }
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct
+{
+    UINT16                          handle;
+    bt_bdaddr_t                     connected_bda;
+    bthf_client_connection_state_t  state;
+    bthf_client_vr_state_t          vr_state;
+    tBTA_HF_CLIENT_PEER_FEAT        peer_feat;
+    tBTA_HF_CLIENT_CHLD_FEAT        chld_feat;
+} btif_hf_client_cb_t;
+
+static btif_hf_client_cb_t btif_hf_client_cb;
+
+
+/************************************************************************************
+**  Static functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function        btif_in_hf_client_generic_evt
+**
+** Description     Processes generic events to be sent to JNI that are not triggered from the BTA.
+**                 Always runs in BTIF context
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btif_in_hf_client_generic_evt(UINT16 event, char *p_param)
+{
+    UNUSED(p_param);
+
+    BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+    switch (event) {
+        case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING:
+        {
+            HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
+                      &btif_hf_client_cb.connected_bda);
+        } break;
+        default:
+        {
+            BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+        }
+        break;
+    }
+}
+
+/************************************************************************************
+**  Externs
+************************************************************************************/
+
+/************************************************************************************
+**  Functions
+************************************************************************************/
+
+static void clear_state(void)
+{
+    memset(&btif_hf_client_cb, 0, sizeof(btif_hf_client_cb_t));
+}
+
+static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
+{
+    if (((btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_CONNECTED) ||
+            (btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED))&&
+        ((bd_addr == NULL) || (bdcmp(bd_addr->address, btif_hf_client_cb.connected_bda.address) == 0)))
+        return TRUE;
+    return FALSE;
+}
+
+/*****************************************************************************
+**   Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+**   btif hf api functions (no context switch)
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         btif_hf_client_init
+**
+** Description     initializes the hf interface
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthf_client_callbacks_t* callbacks )
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+    bt_hf_client_callbacks = callbacks;
+
+    btif_enable_service(BTA_HFP_HS_SERVICE_ID);
+
+    clear_state();
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         connect
+**
+** Description     connect to audio gateway
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_int( bt_bdaddr_t *bd_addr )
+{
+    if (is_connected(bd_addr))
+        return BT_STATUS_BUSY;
+
+    btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTING;
+    bdcpy(btif_hf_client_cb.connected_bda.address, bd_addr->address);
+
+    BTA_HfClientOpen(btif_hf_client_cb.handle, btif_hf_client_cb.connected_bda.address,
+               BTIF_HF_CLIENT_SECURITY);
+
+    return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t connect( bt_bdaddr_t *bd_addr )
+{
+    BTIF_TRACE_EVENT1("HFP Client version is  %s", btif_hf_client_version);
+    CHECK_BTHF_CLIENT_INIT();
+    return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
+
+}
+
+/*******************************************************************************
+**
+** Function         disconnect
+**
+** Description      disconnect from audio gateway
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_CLIENT_INIT();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_HfClientClose(btif_hf_client_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         connect_audio
+**
+** Description     create an audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (is_connected(bd_addr))
+    {
+        if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
+        }
+        else
+        {
+            BTA_HfClientAudioOpen(btif_hf_client_cb.handle);
+        }
+
+        /* Inform the application that the audio connection has been initiated successfully */
+        btif_transfer_context(btif_in_hf_client_generic_evt, BTIF_HF_CLIENT_CB_AUDIO_CONNECTING,
+                              (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         disconnect_audio
+**
+** Description      close the audio connection
+**
+** Returns         bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (is_connected(bd_addr))
+    {
+        BTA_HfClientAudioClose(btif_hf_client_cb.handle);
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function         start_voice_recognition
+**
+** Description      start voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t start_voice_recognition()
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC)
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         stop_voice_recognition
+**
+** Description      stop voice recognition
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t stop_voice_recognition()
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC)
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         volume_control
+**
+** Description      volume control
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t volume_control(bthf_client_volume_type_t type, int volume)
+{
+    BOOLEAN speaker;
+
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    switch (type)
+    {
+        case BTHF_CLIENT_VOLUME_TYPE_SPK:
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS, volume, 0, NULL);
+            break;
+        case BTHF_CLIENT_VOLUME_TYPE_MIC:
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM, volume, 0, NULL);
+            break;
+        default:
+            return BT_STATUS_UNSUPPORTED;
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         dial
+**
+** Description      place a call
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t dial(const char *number)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (number)
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number);
+    }
+    else
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0, 0, NULL);
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         dial_memory
+**
+** Description      place a call with number specified by location (speed dial)
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t dial_memory(int location)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, location, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         handle_call_action
+**
+** Description      handle specified call related action
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t handle_call_action(bthf_client_call_action_t action, int idx)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    switch (action)
+    {
+    case BTHF_CLIENT_CALL_ACTION_CHLD_0:
+        if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 0, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_1:
+        // CHLD 1 is mandatory for 3 way calling
+        if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_2:
+        // CHLD 2 is mandatory for 3 way calling
+        if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_3:
+        if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 3, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_4:
+        if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH)
+        {
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 4, 0, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_1x:
+        if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC)
+        {
+            if (idx < 1)
+            {
+                return BT_STATUS_FAIL;
+            }
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, idx, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_2x:
+        if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC)
+        {
+            if (idx < 1)
+            {
+                return BT_STATUS_FAIL;
+            }
+            BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, idx, NULL);
+            break;
+        }
+        return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_ATA:
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0, 0, NULL);
+        break;
+    case BTHF_CLIENT_CALL_ACTION_CHUP:
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0, 0, NULL);
+        break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_0:
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0, 0, NULL);
+        break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_1:
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1, 0, NULL);
+        break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_2:
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2, 0, NULL);
+        break;
+    default:
+        return BT_STATUS_FAIL;
+
+    }
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         query_current_calls
+**
+** Description      query list of current calls
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t query_current_calls(void)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS)
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         query_current_operator_name
+**
+** Description      query current selected operator name
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t query_current_operator_name(void)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         retieve_subscriber_info
+**
+** Description      retrieve subscriber number information
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t retrieve_subscriber_info(void)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         send_dtmf
+**
+** Description      send dtmf
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t send_dtmf(char code)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code, 0, NULL);
+
+    return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         request_last_voice_tag_number
+**
+** Description      Request number from AG for VR purposes
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t request_last_voice_tag_number(void)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+    if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG)
+    {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1, 0, NULL);
+
+        return BT_STATUS_SUCCESS;
+    }
+
+    return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+**
+** Function         cleanup
+**
+** Description      Closes the HF interface
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static void  cleanup( void )
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+    if (bt_hf_client_callbacks)
+    {
+        btif_disable_service(BTA_HFP_HS_SERVICE_ID);
+        bt_hf_client_callbacks = NULL;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         send_at_cmd
+**
+** Description      Send requested AT command to rempte device.
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+static bt_status_t send_at_cmd(int cmd,int val1,int val2,const char *arg)
+{
+    CHECK_BTHF_CLIENT_SLC_CONNECTED();
+    BTIF_TRACE_EVENT5("%s Cmd %d val1 %d val2 %d arg %s",
+            __FUNCTION__,cmd,val1,val2,arg);
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, cmd, val1, val2, arg);
+
+    return BT_STATUS_SUCCESS;
+}
+
+static const bthf_client_interface_t bthfClientInterface = {
+    sizeof(bthf_client_interface_t),
+    .init = init,
+    .connect = connect,
+    .disconnect = disconnect,
+    .connect_audio = connect_audio,
+    .disconnect_audio = disconnect_audio,
+    .start_voice_recognition = start_voice_recognition,
+    .stop_voice_recognition = stop_voice_recognition,
+    .volume_control = volume_control,
+    .dial = dial,
+    .dial_memory = dial_memory,
+    .handle_call_action = handle_call_action,
+    .query_current_calls = query_current_calls,
+    .query_current_operator_name = query_current_operator_name,
+    .retrieve_subscriber_info = retrieve_subscriber_info,
+    .send_dtmf = send_dtmf,
+    .request_last_voice_tag_number = request_last_voice_tag_number,
+    .cleanup = cleanup,
+    .send_at_cmd = send_at_cmd,
+};
+
+static void process_ind_evt(tBTA_HF_CLIENT_IND *ind)
+{
+    switch (ind->type)
+    {
+        case BTA_HF_CLIENT_IND_CALL:
+            HAL_CBACK(bt_hf_client_callbacks, call_cb, ind->value);
+            break;
+
+        case BTA_HF_CLIENT_IND_CALLSETUP:
+            HAL_CBACK(bt_hf_client_callbacks, callsetup_cb, ind->value);
+            break;
+        case BTA_HF_CLIENT_IND_CALLHELD:
+            HAL_CBACK(bt_hf_client_callbacks, callheld_cb, ind->value);
+            break;
+
+        case BTA_HF_CLIENT_IND_SERVICE:
+            HAL_CBACK(bt_hf_client_callbacks, network_state_cb, ind->value);
+            break;
+
+        case BTA_HF_CLIENT_IND_SIGNAL:
+            HAL_CBACK(bt_hf_client_callbacks, network_signal_cb, ind->value);
+            break;
+
+        case BTA_HF_CLIENT_IND_ROAM:
+            HAL_CBACK(bt_hf_client_callbacks, network_roaming_cb, ind->value);
+            break;
+
+        case BTA_HF_CLIENT_IND_BATTCH:
+            HAL_CBACK(bt_hf_client_callbacks, battery_level_cb, ind->value);
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btif_hf_client_upstreams_evt
+**
+** Description      Executes HF CLIENT UPSTREAMS events in btif context
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btif_hf_client_upstreams_evt(UINT16 event, char* p_param)
+{
+    tBTA_HF_CLIENT *p_data = (tBTA_HF_CLIENT *)p_param;
+    bdstr_t bdstr;
+
+    BTIF_TRACE_DEBUG3("%s: event=%s (%u)", __FUNCTION__, dump_hf_client_event(event), event);
+
+    switch (event)
+    {
+        case BTA_HF_CLIENT_ENABLE_EVT:
+        case BTA_HF_CLIENT_DISABLE_EVT:
+            break;
+
+        case BTA_HF_CLIENT_REGISTER_EVT:
+            btif_hf_client_cb.handle = p_data->reg.handle;
+            break;
+
+        case BTA_HF_CLIENT_OPEN_EVT:
+            if (p_data->open.status == BTA_HF_CLIENT_SUCCESS)
+            {
+                bdcpy(btif_hf_client_cb.connected_bda.address, p_data->open.bd_addr);
+                btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
+                btif_hf_client_cb.peer_feat = 0;
+                btif_hf_client_cb.chld_feat = 0;
+                //clear_phone_state();
+            }
+            else if (btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_CONNECTING)
+            {
+                btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+            }
+            else
+            {
+                BTIF_TRACE_WARNING4("%s: HF CLient open failed, but another device connected. status=%d state=%d connected device=%s",
+                        __FUNCTION__, p_data->open.status, btif_hf_client_cb.state, bd2str(&btif_hf_client_cb.connected_bda, &bdstr));
+                break;
+            }
+
+            HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, btif_hf_client_cb.state,
+                        0, 0, &btif_hf_client_cb.connected_bda);
+
+            if (btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED)
+                bdsetany(btif_hf_client_cb.connected_bda.address);
+
+            if (p_data->open.status != BTA_HF_CLIENT_SUCCESS)
+                btif_queue_advance();
+            break;
+
+        case BTA_HF_CLIENT_CONN_EVT:
+            btif_hf_client_cb.peer_feat = p_data->conn.peer_feat;
+            btif_hf_client_cb.chld_feat = p_data->conn.chld_feat;
+            btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
+
+            HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, btif_hf_client_cb.state,
+                        btif_hf_client_cb.peer_feat, btif_hf_client_cb.chld_feat,
+                        &btif_hf_client_cb.connected_bda);
+
+            /* Inform the application about in-band ringtone */
+            if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND)
+            {
+                HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+            }
+
+            btif_queue_advance();
+            break;
+
+        case BTA_HF_CLIENT_CLOSE_EVT:
+            btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+            HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,  btif_hf_client_cb.state,
+                        0, 0, &btif_hf_client_cb.connected_bda);
+            bdsetany(btif_hf_client_cb.connected_bda.address);
+            btif_hf_client_cb.peer_feat = 0;
+            btif_hf_client_cb.chld_feat = 0;
+            btif_queue_advance();
+            break;
+
+        case BTA_HF_CLIENT_IND_EVT:
+            process_ind_evt(&p_data->ind);
+            break;
+
+        case BTA_HF_CLIENT_MIC_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, volume_change_cb, BTHF_CLIENT_VOLUME_TYPE_MIC, p_data->val.value);
+            break;
+
+        case BTA_HF_CLIENT_SPK_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, volume_change_cb, BTHF_CLIENT_VOLUME_TYPE_SPK, p_data->val.value);
+            break;
+
+        case BTA_HF_CLIENT_VOICE_REC_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, vr_cmd_cb, p_data->val.value);
+            break;
+
+        case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, current_operator_cb, p_data->operator.name);
+            break;
+
+        case BTA_HF_CLIENT_CLIP_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, clip_cb, p_data->number.number);
+            break;
+
+        case BTA_HF_CLIENT_BINP_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, last_voice_tag_number_callback, p_data->number.number);
+            break;
+
+        case BTA_HF_CLIENT_CCWA_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, call_waiting_cb, p_data->number.number);
+            break;
+
+        case BTA_HF_CLIENT_AT_RESULT_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, cmd_complete_cb, p_data->result.type, p_data->result.cme);
+            break;
+
+        case BTA_HF_CLIENT_CLCC_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, current_calls_cb, p_data->clcc.idx,
+                        p_data->clcc.inc ? BTHF_CLIENT_CALL_DIRECTION_INCOMING : BTHF_CLIENT_CALL_DIRECTION_OUTGOING,
+                        p_data->clcc.status,
+                        p_data->clcc.mpty ? BTHF_CLIENT_CALL_MPTY_TYPE_MULTI : BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE,
+                        p_data->clcc.number_present ? p_data->clcc.number : NULL);
+            break;
+
+        case BTA_HF_CLIENT_CNUM_EVT:
+            if (p_data->cnum.service == 4)
+            {
+                HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, p_data->cnum.number, BTHF_CLIENT_SERVICE_VOICE);
+            }
+            else if (p_data->cnum.service == 5)
+            {
+                HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, p_data->cnum.number, BTHF_CLIENT_SERVICE_FAX);
+            }
+            else
+            {
+                HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, p_data->cnum.number, BTHF_CLIENT_SERVICE_UNKNOWN);
+            }
+            break;
+
+        case BTA_HF_CLIENT_BTRH_EVT:
+            if (p_data->val.value <= BTRH_CLIENT_RESP_AND_HOLD_REJECT)
+            {
+                HAL_CBACK(bt_hf_client_callbacks, resp_and_hold_cb, p_data->val.value);
+            }
+            break;
+
+        case BTA_HF_CLIENT_BSIR_EVT:
+            if (p_data->val.value != 0)
+            {
+                HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+            }
+            else
+            {
+                HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED);
+            }
+            break;
+
+        case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, BTHF_CLIENT_AUDIO_STATE_CONNECTED, &btif_hf_client_cb.connected_bda);
+            break;
+
+        case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC, &btif_hf_client_cb.connected_bda);
+            break;
+
+        case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
+            HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, BTHF_CLIENT_AUDIO_STATE_DISCONNECTED, &btif_hf_client_cb.connected_bda);
+            break;
+        case BTA_HF_CLIENT_RING_INDICATION:
+            HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb);
+            break;
+        default:
+            BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bte_hf_client_evt
+**
+** Description      Switches context from BTE to BTIF for all HF Client events
+**
+** Returns          void
+**
+*******************************************************************************/
+
+static void bte_hf_client_evt(tBTA_HF_CLIENT_EVT event, tBTA_HF_CLIENT *p_data)
+{
+    bt_status_t status;
+
+    /* switch context to btif task context (copy full union size for convenience) */
+    status = btif_transfer_context(btif_hf_client_upstreams_evt, (uint16_t)event, (void*)p_data, sizeof(*p_data), NULL);
+
+    /* catch any failed context transfers */
+    ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function         btif_hf_client_execute_service
+**
+** Description      Initializes/Shuts down the service
+**
+** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_hf_client_execute_service(BOOLEAN b_enable)
+{
+    BTIF_TRACE_EVENT2("%s enable:%d", __FUNCTION__, b_enable);
+
+    property_get("ro.bluetooth.hfp.ver", btif_hf_client_version, "1.5");
+
+     if (b_enable)
+     {
+          /* Enable and register with BTA-HFClient */
+          BTA_HfClientEnable(bte_hf_client_evt);
+          if (strcmp(btif_hf_client_version, "1.6") == 0)
+          {
+              BTIF_TRACE_EVENT1("Support Codec Nego. %d ", BTIF_HF_CLIENT_FEATURES);
+              BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, BTIF_HF_CLIENT_FEATURES,
+                      BTIF_HF_CLIENT_SERVICE_NAME);
+          }
+          else
+          {
+              BTIF_TRACE_EVENT0("No Codec Nego Supported");
+              btif_hf_client_features = BTIF_HF_CLIENT_FEATURES;
+              btif_hf_client_features = btif_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC);
+              BTIF_TRACE_EVENT1("btif_hf_client_features is   %d", btif_hf_client_features);
+              BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, btif_hf_client_features,
+                      BTIF_HF_CLIENT_SERVICE_NAME);
+          }
+
+     }
+     else
+     {
+         BTA_HfClientDeregister(btif_hf_client_cb.handle);
+         BTA_HfClientDisable();
+     }
+     return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btif_hf_get_interface
+**
+** Description      Get the hf callback interface
+**
+** Returns          bthf_interface_t
+**
+*******************************************************************************/
+const bthf_client_interface_t *btif_hf_client_get_interface(void)
+{
+    BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+    return &bthfClientInterface;
+}
diff --git a/system/btif/src/btif_storage.c b/system/btif/src/btif_storage.c
index 9f74935..b0c2826 100644
--- a/system/btif/src/btif_storage.c
+++ b/system/btif/src/btif_storage.c
@@ -1,5 +1,6 @@
 /******************************************************************************
  *
+ *  Copyright (c) 2014 The Android Open Source Project
  *  Copyright (C) 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -601,6 +602,12 @@
                                               p_uuid+num_uuids);
                             num_uuids++;
                         }break;
+                    case BTA_HFP_HS_SERVICE_ID:
+                        {
+                            uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE,
+                                              p_uuid+num_uuids);
+                            num_uuids++;
+                        }break;
                 }
             }
         }
diff --git a/system/btif/src/btif_util.c b/system/btif/src/btif_util.c
index 12aa7a9..2a86e12 100644
--- a/system/btif/src/btif_util.c
+++ b/system/btif/src/btif_util.c
@@ -1,5 +1,6 @@
 /******************************************************************************
  *
+ *  Copyright (c) 2014 The Android Open Source Project
  *  Copyright (C) 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,6 +48,7 @@
 #include "bta_ag_api.h"
 #include "bta_av_api.h"
 #include "bta_hh_api.h"
+#include "bta_hf_client_api.h"
 #include "avrc_defs.h"
 
 
@@ -326,6 +328,38 @@
      }
 }
 
+const char* dump_hf_client_event(UINT16 event)
+{
+    switch(event)
+    {
+        CASE_RETURN_STR(BTA_HF_CLIENT_ENABLE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_REGISTER_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CONN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_CLOSE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_SPK_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_MIC_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_DISABLE_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_IND_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_VOICE_REC_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_OPERATOR_NAME_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CLIP_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CCWA_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_AT_RESULT_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CLCC_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_CNUM_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_BTRH_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_BSIR_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_BINP_EVT)
+        CASE_RETURN_STR(BTA_HF_CLIENT_RING_INDICATION)
+        default:
+            return "UNKNOWN MSG ID";
+     }
+}
+
 const char* dump_hh_event(UINT16 event)
 {
     switch(event)
diff --git a/system/include/bt_target.h b/system/include/bt_target.h
index 0ad112b..7cccf36 100644
--- a/system/include/bt_target.h
+++ b/system/include/bt_target.h
@@ -1,5 +1,6 @@
 /******************************************************************************
  *
+ *  Copyright (c) 2014 The Android Open Source Project
  *  Copyright (C) 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,6 +34,9 @@
 #define BTIF_HFAG_SERVICE_NAME  ("Handsfree Gateway")
 #endif
 
+#ifndef BTIF_HF_CLIENT_SERVICE_NAME
+#define BTIF_HF_CLIENT_SERVICE_NAME  ("Handsfree")
+#endif
 
 #ifdef BUILDCFG
 
diff --git a/system/main/Android.mk b/system/main/Android.mk
index fb218a9..07afe1b 100644
--- a/system/main/Android.mk
+++ b/system/main/Android.mk
@@ -26,6 +26,7 @@
     ../btif/src/btif_util.c \
     ../btif/src/btif_sm.c \
     ../btif/src/btif_hf.c \
+    ../btif/src/btif_hf_client.c \
     ../btif/src/btif_av.c \
     ../btif/src/btif_rc.c \
     ../btif/src/btif_media_task.c \