Merge dbfdf08be44659ad9d3f90085c59b8314361110a on remote branch

Change-Id: I21bb018f97b8fb2c6d23deaf341532e8d6717263
diff --git a/BATestApp/Android.mk b/BATestApp/Android.mk
index ba23089..df6c8b2 100644
--- a/BATestApp/Android.mk
+++ b/BATestApp/Android.mk
@@ -3,22 +3,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
-LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
 
 LOCAL_AAPT_FLAGS := --auto-add-overlay
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += src/org/codeaurora/bluetooth/batestapp/IGattBroadcastServiceCallback.aidl
-LOCAL_SRC_FILES += src/org/codeaurora/bluetooth/batestapp/IGattBroadcastService.aidl
 
 LOCAL_AIDL_INCLUDES += system/bt/binder
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-v4 \
-    android-support-v7-recyclerview \
-    android-support-v7-appcompat
-
 LOCAL_PACKAGE_NAME := BATestApp
 LOCAL_PRIVILEGED_MODULE := true
 LOCAL_CERTIFICATE := platform
diff --git a/BATestApp/AndroidManifest.xml b/BATestApp/AndroidManifest.xml
index 5685cff..aeb161a 100644
--- a/BATestApp/AndroidManifest.xml
+++ b/BATestApp/AndroidManifest.xml
@@ -38,7 +38,6 @@
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
@@ -67,15 +66,6 @@
         <service
             android:name=".GattBroadcastService"
             android:exported="true" />
-
-        <receiver
-            android:name=".BroadcastAudioAppReceiver"
-            android:enabled="true"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
-            </intent-filter>
-        </receiver>
     </application>
 
 </manifest>
diff --git a/BATestApp/res/layout/layout_devices.xml b/BATestApp/res/layout/layout_devices.xml
index 557795a..8ee4351 100644
--- a/BATestApp/res/layout/layout_devices.xml
+++ b/BATestApp/res/layout/layout_devices.xml
@@ -50,7 +50,7 @@
         android:layout_alignParentBottom="true"
         android:text="@string/go_previous" />
 
-    <android.support.v7.widget.RecyclerView
+    <ListView
         android:id="@+id/id_lv_deviceslist"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/BATestApp/res/values/styles.xml b/BATestApp/res/values/styles.xml
index ae8c7d2..00ada2e 100644
--- a/BATestApp/res/values/styles.xml
+++ b/BATestApp/res/values/styles.xml
@@ -31,14 +31,10 @@
 
 <resources>
 
-    <!-- Base application theme. -->
-    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
-        <!-- Customize your theme here. -->
-        <item name="colorPrimary">@color/colorPrimary</item>
-        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-        <item name="colorAccent">@color/colorAccent</item>
+    <style name="AppTheme" parent="android:Theme.Holo.Light">
+        <item name="android:windowNoTitle">true</item>
     </style>
-
+    <!-- Base application theme. -->
     <style name="style_view_app">
         <item name="android:textColor">@android:color/black</item>
         <item name="android:layout_width">match_parent</item>
@@ -47,8 +43,4 @@
         <item name="android:fontFamily">sans-serif-condensed</item>
     </style>
 
-    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
-
-    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
-
 </resources>
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/AdapterDevice.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/AdapterDevice.java
index deaa64c..99641e1 100644
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/AdapterDevice.java
+++ b/BATestApp/src/org/codeaurora/bluetooth/batestapp/AdapterDevice.java
@@ -29,31 +29,25 @@
 
 package org.codeaurora.bluetooth.batestapp;
 
-import android.bluetooth.BluetoothDevice;
-import android.support.v7.widget.RecyclerView;
+import java.util.ArrayList;
+import java.util.List;
+
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.BaseAdapter;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.List;
-
-public class AdapterDevice extends RecyclerView.Adapter<AdapterDevice.ViewHolder> {
+public class AdapterDevice extends BaseAdapter {
 
     private List<BroadcastAudioDevice> mList;
     private LayoutInflater mInflater;
-    private RecyclerViewListener mListener;
-    private static final String TAG=Utils.TAG +"AdapterDevice";
+    private static final String TAG=BAAudio.TAG +" AdapterDevice";
 
-    public AdapterDevice(List<BroadcastAudioDevice> list, LayoutInflater inflater,
-            RecyclerViewListener listener) {
+    public AdapterDevice(List<BroadcastAudioDevice> list, LayoutInflater inflater) {
         mList = list;
         mInflater = inflater;
-        mListener = listener;
-        Log.v(TAG," AdapterDevice ");
     }
 
     public void refreshDevices(List<BroadcastAudioDevice> list) {
@@ -62,53 +56,49 @@
         } else {
             mList = list;
         }
-        Log.v(TAG," refreshDevices mList :"+mList.size());
+        Log.i(TAG," refreshDevices mList :"+mList.size());
         notifyDataSetChanged();
     }
 
     @Override
-    public void onBindViewHolder(ViewHolder holder, final int position) {
-
-        BroadcastAudioDevice device = mList.get(position);
-        if (device != null && device.getName() != null){
-            holder.textViewName.setText(device.getName());
-        }
-
-        if (device != null && device.getBluetoothDevice() != null){
-            holder.textViewAddress.setText(device.getBluetoothDevice()
-                                                 .getAddress());
-        }
-        holder.mLayout.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                Log.v(TAG," onClick position  :" + position);
-                mListener.onRecylerViewItemClicked(position);
-            }
-        });
-    }
-
-    @Override
-    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        View view = mInflater.inflate(R.layout.layout_row_device, parent, false);
-        return new ViewHolder(view);
-    }
-
-    @Override
-    public int getItemCount() {
+    public int getCount() {
         return mList.size();
     }
 
-    static class ViewHolder extends RecyclerView.ViewHolder {
-
-        private TextView textViewName, textViewAddress;
-        private LinearLayout mLayout;
-
-        public ViewHolder(View v) {
-            super(v);
-            textViewName = (TextView) v.findViewById(R.id.id_tv_devicename);
-            textViewAddress = (TextView) v.findViewById(R.id.id_tv_devieaddress);
-            mLayout = (LinearLayout) v.findViewById(R.id.id_linearlayout_row);
-        }
+    @Override
+    public BroadcastAudioDevice getItem(int arg0) {
+        return mList.get(arg0);
     }
-}
 
+    @Override
+    public long getItemId(int arg0) {
+        return arg0;
+    }
+
+    @Override
+    public View getView(int arg0, View view, ViewGroup arg2) {
+        ViewHolder holder;
+        if(view == null) {
+            view = mInflater.inflate(R.layout.layout_row_device, null);
+            holder = new ViewHolder();
+            holder.textViewName = (TextView) view.findViewById(R.id.id_tv_devicename);
+            holder.textViewAddress = (TextView) view.findViewById(R.id.id_tv_devieaddress);
+            view.setTag(holder);
+        } else {
+            holder = (ViewHolder) view.getTag();
+        }
+        BroadcastAudioDevice device = getItem(arg0);
+        if (device.getName() != null){
+            holder.textViewName.setText(device.getName());
+        }
+        if (device.getBluetoothDevice() != null){
+            holder.textViewAddress.setText(device.getBluetoothDevice()
+                    .getAddress());
+        }
+        return view;
+    }
+
+    static class ViewHolder {
+        private TextView textViewName, textViewAddress;
+    }
+}
\ No newline at end of file
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BAAudio.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BAAudio.java
index 3ea2f5f..eab8b63 100644
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BAAudio.java
+++ b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BAAudio.java
@@ -29,51 +29,36 @@
 
 package org.codeaurora.bluetooth.batestapp;
 
-import android.app.Service;
-import android.media.AudioFocusRequest;
-import android.media.AudioAttributes;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothBATransmitter;
-import android.bluetooth.BluetoothBAEncryptionKey;
-import android.bluetooth.BluetoothBAStreamServiceRecord;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.bluetooth.BluetoothProfile;
-import android.util.Log;
-import android.os.IBinder;
-import android.content.Context;
-import java.util.Map;
-import java.util.HashMap;
-
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
 import android.media.AudioFormat;
 import android.media.AudioManager;
-import android.media.AudioTrack;
+import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.AudioRecord;
+import android.media.AudioTrack;
+import android.media.MediaRecorder;
+import android.media.audiofx.AcousticEchoCanceler;
+import android.media.audiofx.AutomaticGainControl;
+import android.media.audiofx.NoiseSuppressor;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
 
-import java.io.IOException;
-
-import android.media.MediaRecorder;
-import android.media.AudioManager;
-import android.media.AudioManager.OnAudioFocusChangeListener;
-
-import android.media.audiofx.AcousticEchoCanceler;
-import android.media.audiofx.AutomaticGainControl;
-import android.media.audiofx.NoiseSuppressor;
-
-// class to handle all interactions with Audio part of Broadcast Audio Transmitter.
+// Class to handle all interactions with Audio part of Broadcast Audio Transmitter.
 public class BAAudio {
 
+    static final String TAG = "BAAPP   ";
     public static final String BASERVICE_STATE_CHANGED = "android.bluetooth.bat.service";
     public static final String EXTRA_BA_STATE = "android.bluetooth.extra.ba.state";
     public static final String EXTRA_CONN_STATE = "android.bluetooth.extra.conn.state";
-    private static final String TAG = Utils.TAG + "BAAudio";
     private static final int SAMPLE_RATE = 16000;
     /* CHANNEL_CONFIGURATION_MONO @deprecated Use {@link #CHANNEL_OUT_MONO} or {@link #CHANNEL_IN_MONO} instead.  */
     private static final int CHANNEL_CONFIG_RECORD = AudioFormat.CHANNEL_IN_MONO;
@@ -86,17 +71,12 @@
     private final static int MSG_STOP_RECORD_PLAY = 1;
     private final static int MSG_START_RECORD_PLAY = 2;
     private final static int MSG_AUDIO_FOCUS_CHANGE = 3;
-    private static BluetoothBATransmitter sBATprofile = null;
     private static boolean sIsBAReady = false;
-    private static BluetoothBAStreamServiceRecord mServiceRecord;
     private static boolean sIsPlaying = false;
     private BluetoothAdapter mAdapter;
     private BAAudioReceiver mReceiver;
     private Context mContext;
     private int mCurrBATState;
-    private BluetoothBAEncryptionKey mCurrEncKey;
-    private int mCurrDiv;
-    private int mCurrStreamId;
     private AudioRecord mAudioRecord = null;
     private AudioTrack mAudioTrack = null;
     private int mCurrAudioFocusState = AudioManager.AUDIOFOCUS_LOSS;
@@ -105,6 +85,9 @@
     private StreamingThread mStrThread;
     // This is returned when requesting focus from AudioManager
     private AudioFocusRequest mfocusRequest;
+    private int BAT_State = BroadcastAudioAppActivity.STATE_DISABLED;
+    static int BA_TRANSMITTER = 23;
+
     private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
         public void onAudioFocusChange(int focusVal) {
             Log.d(TAG, "focusChangs val = " + focusVal);
@@ -114,39 +97,34 @@
     };
 
     public BAAudio(Context context) {
+
         Log.d(TAG, " BAAudio constructor");
         mContext = context;
         mReceiver = new BAAudioReceiver();
         mAdapter = BluetoothAdapter.getDefaultAdapter();
-        IntentFilter filter = new IntentFilter(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_ENCRYPTION_KEY_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_STREAMING_ID_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-        if (mAdapter != null) {
-            mAdapter.getProfileProxy(mContext, new BATServiceListener(),
-                    BluetoothProfile.BA_TRANSMITTER);
-        }
-        mCurrEncKey = null;
-        mServiceRecord = null;
-        mCurrDiv = BluetoothBATransmitter.INVALID_DIV;
-        mCurrStreamId = 0;
-        mCurrBATState = BluetoothBATransmitter.STATE_DISABLED;
 
+        IntentFilter filter = new IntentFilter(
+                BroadcastAudioAppActivity.ACTION_BAT_STATE_CHANGED);
+        filter.addAction(BroadcastAudioAppActivity.ACTION_BAT_ENCRYPTION_KEY_CHANGED);
+        filter.addAction(BroadcastAudioAppActivity.ACTION_BAT_STATE_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+
+        mCurrBATState = BroadcastAudioAppActivity.STATE_DISABLED;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
         HandlerThread thread = new HandlerThread("BAaudioHandler");
         thread.start();
         Looper looper = thread.getLooper();
         mHandler = new BAMsgHandler(looper);
-        AudioAttributes streamAttributes =
-             new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA)
-                                          .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
-                                          .build();
-        mfocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
-                                      .setAudioAttributes(streamAttributes)
-                                      .setOnAudioFocusChangeListener(mAudioFocusListener)
-                                      .build();
 
+        AudioAttributes streamAttributes =
+                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA)
+                        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+                                .build();
+        mfocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioAttributes(streamAttributes)
+                        .setOnAudioFocusChangeListener(mAudioFocusListener)
+                                .build();
     }
 
     public void broadcastServiceConnection(boolean isConnected, int state) {
@@ -167,107 +145,13 @@
             mContext.unregisterReceiver(mReceiver);
         }
     }
-
-    public boolean enableBA() {
-        Log.d(TAG, " enableBA currState = " + mCurrBATState);
-        if (sBATprofile == null) {
-            Log.d(TAG, " profile null, return");
-            return false;
-        }
-        if ((mCurrBATState == BluetoothBATransmitter.STATE_PAUSED) ||
-                (mCurrBATState == BluetoothBATransmitter.STATE_PLAYING)) {
-            return false;
-        }
-        return sBATprofile.setBATState(BluetoothBATransmitter.ENABLE_BA_TRANSMITTER);
-    }
-
-    public boolean disableBA() {
-        Log.d(TAG, " disableBA currState = " + mCurrBATState);
-        if (sBATprofile == null) {
-            Log.d(TAG, " profile null, return");
-            return false;
-        }
-        if (mCurrBATState == BluetoothBATransmitter.STATE_DISABLED) {
-            return false;
-        }
-        return sBATprofile.setBATState(BluetoothBATransmitter.DISABLE_BA_TRANSMITTER);
-    }
-
-    public int getBATState() {
-        Log.d(TAG, " getBATState currState = " + mCurrBATState);
-        if (sBATprofile != null) {
-            mCurrBATState = sBATprofile.getBATState();
-        }
-        Log.d(TAG, " getBATState returning  = " + mCurrBATState);
-        return mCurrBATState;
-    }
-
-    public BluetoothBAEncryptionKey getEncKey() {
-        Log.d(TAG, " getEncKey currState = " + mCurrBATState);
-        if (sBATprofile != null) {
-            mCurrEncKey = sBATprofile.getEncryptionKey();
-        }
-        for (int i = 0; i < BluetoothBAEncryptionKey.ENCRYPTION_KEY_LENGTH; i++) {
-            if (mCurrEncKey != null)
-                Log.d(TAG, " EncrycptionKey[ " + i + "] = " + mCurrEncKey.getEncryptionKey()[i]);
-        }
-        return mCurrEncKey;
-    }
-
-    public int getStreamId() {
-        Log.d(TAG, " getStreamId mCurrStreamId = " + mCurrStreamId);
-        if (sBATprofile != null) {
-            mCurrStreamId = (int) sBATprofile.getStreamId();
-        }
-        Log.d(TAG, " getStreamid returning  = " + mCurrStreamId);
-        return mCurrStreamId;
-    }
-
-    public int getDIV() {
-        Log.d(TAG, " getDIV mCurrDiv = " + mCurrDiv);
-        if (sBATprofile != null) {
-            mCurrDiv = sBATprofile.getDIV();
-        }
-        Log.d(TAG, " getDIV returning  = " + mCurrDiv);
-        return mCurrDiv;
-    }
-
-    public boolean refreshEncryptionKey() {
-        Log.d(TAG, " refreshEncryptionKey mCurrBATState = " + mCurrBATState);
-        if (sBATprofile == null) {
-            return false;
-        }
-        return sBATprofile.refreshEncryptionKey();
-    }
-
-    public BluetoothBAStreamServiceRecord getBAServiceRecord() {
-        Log.d(TAG, " getBAServiceRecord mCurrBATState = " + mCurrBATState);
-        if (sBATprofile == null) {
-            Log.d(TAG, " Profile not up, return null ");
-            return null;
-        }
-        try {
-            mServiceRecord = sBATprofile.getBAServiceRecord();
-            Long[] streamIDs = mServiceRecord.getStreamIds();
-            Log.d(TAG, " streamIDs =  " + streamIDs.length + "streamId = " + streamIDs[0]);
-            Map<Integer, Long> mServiceRecordData = mServiceRecord.getServiceRecord(streamIDs[0]);
-            for (Map.Entry<Integer, Long> entry : mServiceRecordData.entrySet()) {
-                Log.d(TAG, " Key< " + entry.getKey() + " >" + " value <" + entry.getValue() + ">");
-            }
-        } catch (Exception e) {
-            Log.d(TAG, " Exception occured ");
-            return null;
-        }
-        return mServiceRecord;
-    }
-
     private synchronized void initAudioRecordSink() {
-        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_RATE,
-                CHANNEL_CONFIG_RECORD, AUDIO_FORMAT, RECORD_BUF_SIZE);
+        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
+                SAMPLE_RATE, CHANNEL_CONFIG_RECORD, AUDIO_FORMAT, RECORD_BUF_SIZE);
         Log.d(TAG," mAudioRecord initialized = " + mAudioRecord.getState());
         if (AutomaticGainControl.isAvailable()) {
-            AutomaticGainControl agc = AutomaticGainControl.create(mAudioRecord.getAudioSessionId
-                    ());
+            AutomaticGainControl agc = AutomaticGainControl.create(
+                    mAudioRecord.getAudioSessionId());
             if (agc != null) {
                 Log.d(TAG, "AGC is " + (agc.getEnabled() ? "enabled" : "disabled"));
                 agc.setEnabled(true);
@@ -296,8 +180,8 @@
             if (aec != null) {
                 Log.d(TAG, "AEC is " + (aec.getEnabled() ? "enabled" : "disabled"));
                 aec.setEnabled(true);
-                Log.d(TAG, "AEC is " + (aec.getEnabled() ? "enabled" : "disabled" + " after trying to" +
-                        " disable"));
+                Log.d(TAG, "AEC is " + (aec.getEnabled() ? "enabled" : "disabled"
+                        + " after trying to" + " disable"));
             }
         } else {
             Log.d(TAG, "aec is unavailable");
@@ -341,34 +225,18 @@
         }
     }
 
-    class BATServiceListener implements BluetoothProfile.ServiceListener {
-        @Override
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG, " onServiceConnected profile = " + profile);
-            sBATprofile = (BluetoothBATransmitter) proxy;
-            sIsBAReady = true;
-            mCurrBATState = sBATprofile.getBATState();
-            broadcastServiceConnection(true, mCurrBATState);
-        }
-
-        @Override
-        public void onServiceDisconnected(int profile) {
-            Log.d(TAG, " onServiceDisconnected profile = " + profile);
-            sIsBAReady = false;
-            mCurrBATState = BluetoothBATransmitter.STATE_DISABLED;
-            sBATprofile = null;
-            broadcastServiceConnection(false, mCurrBATState);
-        }
-    }
-
     private class BAAudioReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
+
             String action = intent.getAction();
-            int extraVal = 0;
             Log.d(TAG, action);
-            if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                extraVal = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE,
+            int extraVal = 0;
+
+            if(action == null)
+                return;
+            if (action.equals(BroadcastAudioAppActivity.ACTION_BAT_STATE_CHANGED)) {
+                extraVal = intent.getIntExtra(BroadcastAudioAppActivity.EXTRA_STATE,
                         -1);
                 if (extraVal != -1)
                     mCurrBATState = extraVal;
@@ -376,26 +244,10 @@
                         "extraVal = "
                         + extraVal);
             }
-            if (action.equals(BluetoothBATransmitter.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
-                mCurrEncKey = (BluetoothBAEncryptionKey) intent.getParcelableExtra
-                        (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
-                Log.d(TAG, " ACTION_BAT_ENCRYPTION_KEY_CHANGED ");
-            }
-            if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                extraVal = intent.getIntExtra(BluetoothBATransmitter.EXTRA_DIV_VALUE,
-                        -1);
-                if (extraVal != -1)
-                    mCurrDiv = extraVal;
-                Log.d(TAG, " ACTION_BAT_DIV_CHANGED mCurrDiv = " + mCurrDiv + "extraVal = " +
-                        extraVal);
-            }
-            if (action.equals(BluetoothBATransmitter.ACTION_BAT_STREAMING_ID_CHANGED)) {
-                extraVal = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STREAM_ID,
-                        -1);
-                if (extraVal != -1)
-                    mCurrStreamId = extraVal;
-                Log.d(TAG, " ACTION_BAT_STREAMING_ID_CHANGED mCurrStreamId = "
-                        + mCurrStreamId + " extraVal = " + extraVal);
+            // Need to get BAT State for above class.
+            if (action.equals(BroadcastAudioAppActivity.ACTION_BAT_STATE_CHANGED)) {
+                final int state = intent.getIntExtra(BroadcastAudioAppActivity.EXTRA_STATE, -1);
+                BAT_State = state;
             }
         }
     }
@@ -445,9 +297,9 @@
                 case MSG_START_RECORD_PLAY:
                     Log.d(TAG, " Current Audio Focus = " + mCurrAudioFocusState);
                     if (mCurrAudioFocusState == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)
-                        Log.d(TAG, " Transient Loss occused, call must be in progress, don't " +
-                                "start now ");
-                    //requestAudioFocus (AudioManager.OnAudioFocusChangeListener l, int, int)
+                        Log.d(TAG, " Transient Loss occurred, call must be in progress, don't "
+                            + "start now ");
+                    // requestAudioFocus (AudioManager.OnAudioFocusChangeListener l, int, int)
                     // method was deprecated in API level 26. use requestAudioFocus(AudioFocusRequest)
                     int focusGranted = mAudioManager.requestAudioFocus(mfocusRequest);
                     Log.d(TAG, " Focus Granted = " + focusGranted);
@@ -516,4 +368,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppActivity.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppActivity.java
index 48cd457..7c9ae4c 100644
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppActivity.java
+++ b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppActivity.java
@@ -29,79 +29,128 @@
 
 package org.codeaurora.bluetooth.batestapp;
 
-import android.Manifest;
+import android.app.Activity;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Message;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ActivityCompat;
 import android.util.Log;
-
 import android.view.View;
 import android.widget.Button;
 import android.widget.CompoundButton;
 import android.widget.ToggleButton;
-import android.app.Activity;
-import org.codeaurora.bluetooth.batestapp.BAAudio;
-import android.bluetooth.BluetoothBATransmitter;
-
+import android.widget.Toast;
 
 public class BroadcastAudioAppActivity extends Activity implements
-        CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+    CompoundButton.OnCheckedChangeListener, View.OnClickListener {
 
-    //private ToggleButton mBtnBtEnable;
-    private ToggleButton mBAEnable;
-    private ToggleButton mMegaPhoneEnable;
+    public static final String ACTION_BAT_BA_ENABLE =
+            "com.android.bluetooth.bat.profile.action.BA_ENABLE";
+    public static final String ACTION_BAT_BA_DISABLE =
+            "com.android.bluetooth.bat.profile.action.BA_DISABLE";
+    public static final String ACTION_BAT_BRA_ENABLE =
+            "com.android.bluetooth.bat.profile.action.BRA_ENABLE";
+    public static final String ACTION_BAT_BRA_DISABLE =
+            "com.android.bluetooth.bat.profile.action.BRA_DISABLE";
+    public static final String ACTION_BAT_ENCRYPTION_KEY_REFRESH =
+            "com.android.bluetooth.bat.profile.action.ENCRYPTION_KEY_REFRESH";
+    public static final String ACTION_BAT_ASSOCIATE_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ASSOCIATE_BCA_RECEIVER";
+    public static final String ACTION_BAT_STATE_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_STATE_CHANGED";
+    public static final String EXTRA_STATE =
+            "com.android.bluetooth.bat.profile.extra.STATE";
+    public static final String EXTRA_PREVIOUS_STATE =
+            "com.android.bluetooth.bat.profile.extra.PREV_STATE";
+    public static final String ACTION_BAT_ONFOUND_ONLOST_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ONFOUND_ONLOST_BCA_RECEIVER";
+    public static final String EXTRA_SCAN_RESULT =
+            "com.android.bluetooth.bat.profile.extra.EXTRA_SCAN_RESULT";
+    public static final String EXTRA_ONFOUND =
+            "com.android.bluetooth.bat.profile.extra.EXTRA_ONFOUND";
+    public static final String ACTION_BAT_BRA_STATE_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BRA_STATE_CHANGED";
+    public static final String EXTRA_STATUS =
+            "com.android.bluetooth.bat.profile.extra.STATUS";
+    public static final String ACTION_BAT_ON_ASSOCIATED_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ON_ASSOCIATED_BCA_RECEIVER";
+    public static final String ACTION_BAT_ENCRYPTION_KEY_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_ENC_KEY_CHANGED";
+    public static final String EXTRA_ECNRYPTION_KEY =
+            "com.android.bluetooth.bat.profile.extra.ENC_KEY";
+
+    public static final int STATE_DISABLED = 0;
+    public static final int STATE_PAUSED = 1;
+    public static final int STATE_PLAYING = 2;
+
+    private static final String TAG = BAAudio.TAG + "BAAppActivity";
+    BAAudio mBAAudiobj = null;
+    private ToggleButton mBAEnable, mMegaPhoneEnable;
     private BluetoothAdapter mBtAdapter;
-    private String mMsg;
-    private static final String TAG = Utils.TAG +"BroadcastAudioAppActivity";
-    private final int REQUEST_ENABLE_BT = 1001;
-    private final int PERMISSIONS_REQUEST_BLUETOOTH = 1002;
-    private Button mBtnBRAEnable;
-    private Button mBtnChangeEnc;
-    BAAudio mBAAudiobj =  null;
+    private Button mBtnBRAEnable, mBtnChangeEnc;
     private boolean isStateChangePending = false;
-    private int expectedState = BluetoothBATransmitter.STATE_DISABLED;
+    private int expectedState = STATE_DISABLED;
+    private int BATState = STATE_DISABLED;
+
+    // Implementation of 30 sec Timeout for BT
+    private static final int BA_ENABLE_TIMEOUT = 0;
+    private static final int BA_ENABLE_TIMEOUT_VALUE = 30000;
+
+    private void onTimeout() {
+        mTimeoutHandler.sendMessageDelayed(mTimeoutHandler.obtainMessage(BA_ENABLE_TIMEOUT),
+                BA_ENABLE_TIMEOUT_VALUE);
+    }
+
+    private final Handler mTimeoutHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case BA_ENABLE_TIMEOUT:
+                    Context context = getApplicationContext();
+                    Toast toast = Toast.makeText(context, "BA Not enabled properly", Toast.LENGTH_SHORT);
+                    toast.show();
+                    Log.d(TAG, "BA not enabled properly");
+                    isStateChangePending = false;
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Log.d(TAG, "onCreate ");
         super.onCreate(savedInstanceState);
+
         setContentView(R.layout.layout_main);
         mBAEnable = (ToggleButton) findViewById(R.id.id_switch_bt_enable);
         mBAEnable.setOnCheckedChangeListener(this);
-        mMegaPhoneEnable =  (ToggleButton) findViewById(R.id.id_switch_mp);
+        mMegaPhoneEnable = (ToggleButton) findViewById(R.id.id_switch_mp);
         mMegaPhoneEnable.setOnCheckedChangeListener(this);
         mBtnChangeEnc = (Button) findViewById(R.id.id_btn_enc_change);
         mBtnChangeEnc.setOnClickListener(this);
-
         mBtnBRAEnable = (Button) findViewById(R.id.id_btn_enable_bra);
         mBtnBRAEnable.setOnClickListener(this);
         mBtnBRAEnable.setEnabled(false);
-
         mBtAdapter = BluetoothAdapter.getDefaultAdapter();
+
         if (mBtAdapter == null) {
             Log.d(TAG, " Device does not support Bluetooth");
             return;
         }
-
         boolean isBtEnabled = mBtAdapter.isEnabled();
-        if (isBtEnabled) {
-            startService(new Intent(BroadcastAudioAppActivity.this, GattBroadcastService.class));
-        }
 
         IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED);
+        filter.addAction(ACTION_BAT_STATE_CHANGED);
         filter.addAction(BAAudio.BASERVICE_STATE_CHANGED);
         registerReceiver(mReceiver, filter);
 
-        Log.d(TAG, " Creating BAAudio ");
         mBAAudiobj = new BAAudio(getApplicationContext());
-        Log.d(TAG, " LauncherActivity  constructor - ");
     }
 
     @Override
@@ -116,51 +165,53 @@
 
     @Override
     public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
-        Log.d(TAG, " onCheckChanged isChecked = " + isChecked + " button = " + compoundButton
-                                                 +" stateChangePending " + isStateChangePending);
-            if(mBtAdapter == null) return;
-            if (!mBtAdapter.isEnabled()) return;
-            if (mBAAudiobj == null) return;
 
-            if (compoundButton == mBAEnable) {
-                if (isStateChangePending) return;
-                if (isChecked) {
-                    if(mBAAudiobj.getBATState() == BluetoothBATransmitter.STATE_DISABLED) {
-                        isStateChangePending = true;
-                        expectedState = BluetoothBATransmitter.STATE_PAUSED;
-                        mBAEnable.setEnabled(false);
-                        mBAAudiobj.enableBA();
-                    }
-                } else {
-                   if(mBAAudiobj.getBATState() != BluetoothBATransmitter.STATE_DISABLED) {
-                       isStateChangePending = true;
-                       expectedState = BluetoothBATransmitter.STATE_DISABLED;
-                       mBAEnable.setEnabled(false);
-                       mBAAudiobj.disableBA();
-                   }
+        Log.d(TAG, " onCheckChanged isChecked = " + isChecked + " button = " +
+                compoundButton + " stateChangePending " + isStateChangePending);
+
+        if (mBtAdapter == null || !mBtAdapter.isEnabled() || mBAAudiobj == null)
+            return;
+
+        if (compoundButton == mBAEnable) {
+            if (isStateChangePending)
+                return;
+            if (isChecked) {
+                if(BATState == STATE_DISABLED) {
+                    isStateChangePending = true;
+                    expectedState = STATE_PAUSED;
+                    mBAEnable.setEnabled(false);
+                    Intent intent_to_enable_BA = new Intent(ACTION_BAT_BA_ENABLE);
+                    sendBroadcast(intent_to_enable_BA);
+                    onTimeout();
                 }
+            } else {
+               if(BATState != STATE_DISABLED) {
+                   isStateChangePending = true;
+                   expectedState = STATE_DISABLED;
+                   mBAEnable.setEnabled(false);
+                   Intent intent_to_disable_BA = new Intent(ACTION_BAT_BA_DISABLE);
+                   sendBroadcast(intent_to_disable_BA);
+               }
             }
-            if (compoundButton == mMegaPhoneEnable) {
-                if (isChecked) {
-                    boolean started = mBAAudiobj.startRecordAndPlay();
-                    setMPButtonText(started);
-                } else {
-                   mBAAudiobj.stopRecordAndPlay();
-                   setMPButtonText(false);
-                }
+        } else if (compoundButton == mMegaPhoneEnable) {
+            if (isChecked) {
+                boolean started = mBAAudiobj.startRecordAndPlay();
+                setMPButtonText(started);
+            } else {
+               mBAAudiobj.stopRecordAndPlay();
+               setMPButtonText(false);
             }
+        }
     }
 
     @Override
     public void onClick(View view) {
-        Log.d(TAG, " onClick  view :"+view);
         if (view == mBtnBRAEnable) {
             startActivity(new Intent(BroadcastAudioAppActivity.this,
                     BroadcastAudioDeviceListActivity.class));
-        }
-        if (view == mBtnChangeEnc) {
-            if (mBAAudiobj == null) return;
-            mBAAudiobj.refreshEncryptionKey();
+        } else if (view == mBtnChangeEnc) {
+            Intent intent_to_refresh_EncKey = new Intent(ACTION_BAT_ENCRYPTION_KEY_REFRESH);
+            sendBroadcast(intent_to_refresh_EncKey);
         }
     }
 
@@ -173,22 +224,20 @@
             if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter
                         .ERROR);
-                int prevState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE,
-                        BluetoothAdapter.ERROR);
-                //setButtonText(state);
                 if (state == BluetoothAdapter.STATE_TURNING_OFF
                     || state == BluetoothAdapter.STATE_OFF) {
-                    setBRAButtonState(BluetoothBATransmitter.STATE_DISABLED);
+                    setBRAButtonState(STATE_DISABLED);
                 }
             }
 
-            if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                final int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE,
-                        -1);
+            if (action.equals(ACTION_BAT_STATE_CHANGED)) {
+                final int state = intent.getIntExtra(EXTRA_STATE, -1);
+                BATState = state;
                 if(state != -1) {
                     setBRAButtonState(state);
+                    mTimeoutHandler.removeCallbacksAndMessages(null);
                     Log.d(TAG, " stateChangePending " + isStateChangePending + " expectedState = "
-                            +expectedState + " state " + state);
+                            + expectedState + " state " + state);
                     if (isStateChangePending) {
                         isStateChangePending = false;
                         mBAEnable.setEnabled(true);
@@ -202,9 +251,10 @@
                 }
             }
             if (action.equals(BAAudio.BASERVICE_STATE_CHANGED)) {
-                final boolean serviceState = intent.getBooleanExtra(BAAudio.EXTRA_CONN_STATE, false);
+                final boolean serviceState = intent.getBooleanExtra(BAAudio.EXTRA_CONN_STATE,
+                        false);
                 final int baState = intent.getIntExtra(BAAudio.EXTRA_BA_STATE, -1);
-                Log.d(TAG, " Service state changed servicState = "
+                Log.d(TAG, " Service state changed serviceState = "
                         + serviceState + " baState = " + baState);
                 setBAButtonText(baState);
             }
@@ -223,14 +273,13 @@
     private void setBAButtonText(int state) {
         boolean currentCheckStatus = mBAEnable.isChecked();
         Log.d(TAG," setBAButtonText state = " + state + " isChecked() = " + currentCheckStatus);
-        if(state == BluetoothBATransmitter.STATE_DISABLED) {
+        if(state == STATE_DISABLED) {
             if (currentCheckStatus) {
-                // button was cheked and we are making it false, need to set it
+                // button was checked and we are making it false, need to set it
                 Log.d(TAG, " setting button false ");
                 mBAEnable.setChecked(false);
             }
-        }
-        else {
+        } else {
             if (!currentCheckStatus) {
                Log.d(TAG, " setting button true ");
                mBAEnable.setChecked(true);
@@ -240,10 +289,10 @@
 
     private void setBRAButtonState(int state) {
         Log.d(TAG, "setBRAButtonState state : "+state);
-        if(state == BluetoothBATransmitter.STATE_DISABLED) {
+        if(state == STATE_DISABLED) {
             mBtnBRAEnable.setEnabled(false);
         } else {
             mBtnBRAEnable.setEnabled(true);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppReceiver.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppReceiver.java
deleted file mode 100644
index aaa1a47..0000000
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioAppReceiver.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *    * Neither the name of The Linux Foundation nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.codeaurora.bluetooth.batestapp;
-
-import android.util.Log;
-import android.content.BroadcastReceiver;
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.content.Intent;
-
-
-public class BroadcastAudioAppReceiver extends BroadcastReceiver {
-
-    private static final String TAG = Utils.TAG +"BroadcastAudioAppReceiver";
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        Log.d(TAG, " Action :" + action);
-
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            int prevState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE,
-                    BluetoothAdapter.ERROR);
-            if (state == BluetoothAdapter.STATE_ON) {
-                Log.d(TAG, "state == BluetoothAdapter.STATE_ON");
-                try {
-                    context.startService(new Intent(context, GattBroadcastService.class));
-                } catch (IllegalStateException e) {
-                    Log.e(TAG, " GattBroadcastService start failed " + e.toString());
-                }
-            }
-        }
-    }
-}
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioDeviceListActivity.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioDeviceListActivity.java
index 5f1eb51..e31deed 100644
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioDeviceListActivity.java
+++ b/BATestApp/src/org/codeaurora/bluetooth/batestapp/BroadcastAudioDeviceListActivity.java
@@ -29,109 +29,118 @@
 
 package org.codeaurora.bluetooth.batestapp;
 
-import android.Manifest;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import android.app.Activity;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanRecord;
-
+import android.bluetooth.le.ScanResult;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.ServiceConnection;
-
 import android.os.Bundle;
-import android.os.Message;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-
+import android.os.Message;
 import android.util.Log;
-import android.support.annotation.NonNull;
-import android.app.Activity;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
 import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.Button;
+import android.widget.ListView;
 
-import org.codeaurora.bluetooth.batestapp.IGattBroadcastService;
-import org.codeaurora.bluetooth.batestapp.IGattBroadcastServiceCallback;
-import org.codeaurora.bluetooth.batestapp.BroadcastAudioDevice;
+public class BroadcastAudioDeviceListActivity extends Activity
+    implements View.OnClickListener, OnItemClickListener {
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.Collections;
-
-public class BroadcastAudioDeviceListActivity extends Activity implements View.OnClickListener,
-        RecyclerViewListener {
-
-    private static final String TAG = Utils.TAG + "BroadcastAudioDeviceListActivity";
+    private static final String TAG = BAAudio.TAG + " BAListActivity";
     GattBroadcastServiceClientHandler mGattBroadcastServiceClientHandler;
-    boolean mIsCountdownLatchEnabled = false;
     boolean mIsAssociationInProgress = false;
     boolean mIsBRAEnabled = false;
-    private RecyclerView mRvDevices;
-    private AdapterDevice mAdapterDevice;
     BroadcastAudioDevice mDevice;
+
+    private ListView mLvDevices;
+    private AdapterDevice mAdapterDevice;
     private List<BroadcastAudioDevice> mList;
-    private BluetoothAdapter mBtAdapter;
-    private Context mCtx;
     private Button mBtnBack;
-    private CountDownLatch mDeinitSignal = new CountDownLatch(1);
     private boolean mIsCleanupCompleted = false;
 
+    public static final int BRA_ENABLED_SUCCESS = 0;
+    public static final int BRA_ENABLED_FAILED = 1;
+    public static final int BRA_DISABLED_SUCCESS = 2;
+    public static final int BRA_DISABLED_FAILED = 3;
+    public static final int ASSOCIATE_BCA_RECEIVER_SUCCESS = 4;
+    public static final int ASSOCIATE_BCA_RECEIVER_FAILED = 5;
+    private static final int CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION = 2;
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
 
             final String action = intent.getAction();
-            Log.d(TAG, " Action " + action);
+            Log.d(TAG, " action " + action);
+
+            if(action == null)
+                return;
             if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter
                         .ERROR);
-                int prevState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE,
-                        BluetoothAdapter.ERROR);
                 if (state == BluetoothAdapter.STATE_TURNING_OFF) {
                     cleanup();
                     finish();
                 }
+            } else if (action.equals(
+                    BroadcastAudioAppActivity.ACTION_BAT_ONFOUND_ONLOST_BCA_RECEIVER)) {
+                ScanResult result = (ScanResult) intent.getParcelableExtra(
+                        BroadcastAudioAppActivity.EXTRA_SCAN_RESULT);
+                boolean isFound = intent.getBooleanExtra(BroadcastAudioAppActivity.EXTRA_ONFOUND,
+                        false);
+                onFoundOnLostBCAReceiver(result, isFound);
+            } else if (action.equals(
+                    BroadcastAudioAppActivity.ACTION_BAT_ON_ASSOCIATED_BCA_RECEIVER)) {
+                int status = intent.getIntExtra(BroadcastAudioAppActivity.EXTRA_STATUS, -1);
+                BluetoothDevice dev = (BluetoothDevice) intent.getParcelableExtra(
+                        BluetoothDevice.EXTRA_DEVICE);
+                onAssociatedBCAReceiver(dev, status);
+            } else if (action.equals(BroadcastAudioAppActivity.ACTION_BAT_BRA_STATE_CHANGED)) {
+                int status = intent.getIntExtra(BroadcastAudioAppActivity.EXTRA_STATUS, -1);
+                onConfiguredBroadcastReceiverAssociation(status);
             }
         }
     };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        Log.d(TAG, " oncreate:");
+
         super.onCreate(savedInstanceState);
         setContentView(R.layout.layout_devices);
-        mRvDevices = (RecyclerView) findViewById(R.id.id_lv_deviceslist);
-        mRvDevices.setLayoutManager(new LinearLayoutManager(this));
+
+        mLvDevices = (ListView) findViewById(R.id.id_lv_deviceslist);
         mList = Collections.synchronizedList(new ArrayList<BroadcastAudioDevice>());
-        mAdapterDevice = new AdapterDevice(mList, getLayoutInflater(), this);
-        mRvDevices.setAdapter(mAdapterDevice);
+        mAdapterDevice = new AdapterDevice(mList, getLayoutInflater());
+        mLvDevices.setAdapter(mAdapterDevice);
+        mLvDevices.setOnItemClickListener(this);
         mBtnBack = (Button) findViewById(R.id.id_btn_back);
         mBtnBack.setOnClickListener(this);
         mBtnBack.setEnabled(true);
-        mCtx = getApplicationContext();
-        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
+
         IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BroadcastAudioAppActivity.ACTION_BAT_BRA_STATE_CHANGED);
+        filter.addAction(BroadcastAudioAppActivity.ACTION_BAT_ONFOUND_ONLOST_BCA_RECEIVER);
+        filter.addAction(BroadcastAudioAppActivity.ACTION_BAT_ON_ASSOCIATED_BCA_RECEIVER);
         registerReceiver(mReceiver, filter);
 
         HandlerThread thread = new HandlerThread("GattBroadcastServiceClientHandler");
         thread.start();
         Looper looper = thread.getLooper();
 
-        mGattBroadcastServiceClientHandler = new GattBroadcastServiceClientHandler(this, looper);
-
-
+        mGattBroadcastServiceClientHandler = new GattBroadcastServiceClientHandler(looper);
+        mGattBroadcastServiceClientHandler.sendMessage(
+                mGattBroadcastServiceClientHandler.obtainMessage(
+                        CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION, true));
     }
 
     @Override
@@ -155,21 +164,9 @@
                 mBtnBack.setEnabled(false);
                 mGattBroadcastServiceClientHandler.sendMessage(
                         mGattBroadcastServiceClientHandler.obtainMessage(
-                                GattBroadcastServiceClientHandler
-                                        .CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION,
+                                CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION,
                                 false));
             }
-            mGattBroadcastServiceClientHandler.sendMessage(
-                    mGattBroadcastServiceClientHandler.obtainMessage(
-                            GattBroadcastServiceClientHandler.UNREGISTER_CALLBACK));
-            mIsCountdownLatchEnabled = true;
-            Log.i(TAG, "Waiting for deinit to complete");
-            try {
-                mDeinitSignal.await();
-            } catch (InterruptedException e) {
-                Log.e(TAG, "Interrupt received while waitinf for de-init to complete", e);
-            }
-
             mGattBroadcastServiceClientHandler.close();
             mGattBroadcastServiceClientHandler.removeCallbacksAndMessages(null);
             Looper looper = mGattBroadcastServiceClientHandler.getLooper();
@@ -191,19 +188,14 @@
     }
 
     @Override
-    public void onRecylerViewItemClicked(int clickedPos) {
-        Log.v(TAG, "onRecylerViewItemClicked position : " + clickedPos);
-        BroadcastAudioDevice device = mList.get(clickedPos);
+    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+        BroadcastAudioDevice device = mList.get(arg2);
         String msg = getString(R.string.msg_association_initiated, device.getName());
-        Log.v(TAG, "onRecylerViewItemClicked device name  : " + msg);
-
         if (mIsAssociationInProgress) {
             Log.d(TAG, "Association is in progress ignore click");
             return;
         }
-
         if (mGattBroadcastServiceClientHandler != null) {
-            Utils.toast(mCtx, msg);
             Log.d(TAG, " sendMessage ASSOCIATE_BCA_RECEIVER" );
             mGattBroadcastServiceClientHandler.sendMessage(
                     mGattBroadcastServiceClientHandler.obtainMessage(
@@ -214,12 +206,10 @@
         } else {
             Log.e(TAG, "mGattBroadcastServiceClientHandler is null");
         }
-        Log.v(TAG, "onRecylerViewItemClicked position end ");
     }
 
-    private synchronized void  addOrRemoveBCAReceiverDevice(BroadcastAudioDevice device,
+    private synchronized void addOrRemoveBCAReceiverDevice(BroadcastAudioDevice device,
             boolean isAdd) {
-
         boolean isFound = false;
         BluetoothDevice bDevice = device.getBluetoothDevice();
         Log.d(TAG, " addOrRemoveBCAReceiverDevice: isAdd: " + isAdd);
@@ -234,7 +224,6 @@
                 break;
             }
         }
-
         if (isAdd && !isFound) {
             Log.d(TAG, " New Device Added :" + device.getName());
             mList.add(device);
@@ -249,101 +238,62 @@
                 mAdapterDevice.refreshDevices(mList);
             }
         });
-
     }
 
-    public class GattBroadcastServiceClientHandler extends Handler {
-        public static final int REGISTER_CALLBACK = 0;
-        public static final int UNREGISTER_CALLBACK = 1;
-        public static final int CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION = 2;
+    public void onFoundOnLostBCAReceiver(ScanResult result, boolean isFound) {
+        ScanRecord record = result.getScanRecord();
+        String mac = result.getDevice().getAddress();
+        Log.d(TAG, "onFoundOnLostBCAReceiver: " + isFound + " mac :" + mac + "record :" + record);
+        BroadcastAudioDevice device = new BroadcastAudioDevice(result.getDevice(),
+                result.getScanRecord());
+        addOrRemoveBCAReceiverDevice(device, isFound);
+        refreshDevices();
+    }
+
+    public void onConfiguredBroadcastReceiverAssociation(int status) {
+        Log.d(TAG, "onConfiguredBroadcastReceiverAssociation status: " + status);
+        if (status == BRA_ENABLED_SUCCESS) {
+            mIsBRAEnabled = true;
+        } else if (status == BRA_DISABLED_SUCCESS) {
+            mIsBRAEnabled = false;
+        } else if (status == BRA_ENABLED_FAILED) {
+            finish();
+        } else if (status == BRA_DISABLED_FAILED) {
+            mIsBRAEnabled = false;
+        }
+    }
+
+    public void onAssociatedBCAReceiver(BluetoothDevice device, int status) {
+        Log.d(TAG, "onAssociatedBCAReceiver: status " + status);
+        if (mDevice == null){
+            Log.d(TAG, "onAssociatedBCAReceiver: Nothing to show on UI, mDevice is null");
+            return;
+        }
+
+        if (status == ASSOCIATE_BCA_RECEIVER_SUCCESS) {
+            String msg = getString(R.string.msg_association_success, mDevice.getName());
+            List<BroadcastAudioDevice> tempList =
+                    new ArrayList<BroadcastAudioDevice>(mList);
+            for (BroadcastAudioDevice BADev : tempList) {
+                if (device.equals(BADev.getBluetoothDevice())) {
+                    addOrRemoveBCAReceiverDevice(BADev, false);
+                }
+            }
+            refreshDevices();
+        } else if (status == ASSOCIATE_BCA_RECEIVER_FAILED) {
+            String msg = getString(R.string.msg_association_failed, mDevice.getName());
+        }
+        mIsAssociationInProgress = false;
+    }
+
+    private class GattBroadcastServiceClientHandler extends Handler {
         public static final int ASSOCIATE_BCA_RECEIVER = 3;
-        private Context mContext;
-        private IGattBroadcastService mService = null;
-
-        private final ServiceConnection mConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                Log.d(TAG, "gatt Broadcast Proxy object connected");
-                mService = IGattBroadcastService.Stub.asInterface(Binder.allowBlocking(service));
-                mGattBroadcastServiceClientHandler.sendMessage(
-                        mGattBroadcastServiceClientHandler.obtainMessage(
-                                REGISTER_CALLBACK));
-                mGattBroadcastServiceClientHandler.sendMessage(
-                        mGattBroadcastServiceClientHandler.obtainMessage(
-                                CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION, true));
-            }
-
-            public void onServiceDisconnected(ComponentName className) {
-                Log.d(TAG, "gatt Broadcast  Proxy object disconnected");
-                mIsBRAEnabled = false;
-                mIsAssociationInProgress = false;
-                mService = null;
-            }
-        };
-
-        private IGattBroadcastServiceCallback.Stub mServiceCallbacks =
-                new IGattBroadcastServiceCallback.Stub() {
-            public void onFoundOnLostBCAReceiver(ScanResult result, boolean isFound) {
-                ScanRecord record = result.getScanRecord();
-                String mac = result.getDevice().getAddress();
-
-                Log.d(TAG, "onFoundOnLostBCAReceiver: " + isFound);
-                Log.d(TAG, "onFoundOnLostBCAReceiver device address: " + mac);
-                Log.d(TAG, "onFoundOnLostBCAReceiver: scanRecord: " + record);
-
-                BroadcastAudioDevice device = new BroadcastAudioDevice(result.getDevice(),
-                        result.getScanRecord());
-
-                addOrRemoveBCAReceiverDevice(device, isFound);
-                refreshDevices();
-            }
-
-            public void onConfiguredBroadcastReceiverAssociation(int status) {
-                Log.d(TAG, "onConfiguredBroadcastReceiverAssociation status: " + status);
-                if (status == GattBroadcastService.BRA_ENABLED_SUCESSS) {
-                    mIsBRAEnabled = true;
-                } else if (status == GattBroadcastService.BRA_DISABLED_SUCESSS) {
-                    mIsBRAEnabled = false;
-                } else if (status == GattBroadcastService.BRA_ENABLED_FAILED) {
-                    finish();
-                } else if (status == GattBroadcastService.BRA_DISABLED_FAILED) {
-                    mIsBRAEnabled = false;
-                }
-            }
-
-            public void onAssociatedBCAReceiver(BluetoothDevice device, int status) {
-                Log.d(TAG, "onAssociatedBCAReceiver: status " + status);
-                if (mDevice == null){
-                    Log.d(TAG, "onAssociatedBCAReceiver: Nothing to show on UI, mDevice is null");
-                    return;
-                }
-
-                if (status == GattBroadcastService.ASSOCIATE_BCA_RECEIVER_SUCCESS) {
-                    String msg = getString(R.string.msg_association_success, mDevice.getName());
-                    Utils.toast(mCtx, msg);
-                    List<BroadcastAudioDevice> tempList =
-                            new ArrayList<BroadcastAudioDevice>(mList);
-                    for (BroadcastAudioDevice BADev : tempList) {
-                        if (device.equals(BADev.getBluetoothDevice())) {
-                            addOrRemoveBCAReceiverDevice(BADev, false);
-                        }
-                    }
-                    refreshDevices();
-                } else if (status == GattBroadcastService.ASSOCIATE_BCA_RECEIVER_FAILED) {
-                    String msg = getString(R.string.msg_association_failed, mDevice.getName());
-                    Utils.toast(mCtx, msg);
-                }
-                mIsAssociationInProgress = false;
-            }
-        };
-
         /**
          * Create a GattBroadcastService proxy object for interacting with the local
          * Bluetooth Service which handles the GattBroadcastService Profile
          */
-        private GattBroadcastServiceClientHandler(Context context, Looper looper) {
+        private GattBroadcastServiceClientHandler(Looper looper) {
             super(looper);
-            mContext = context;
-            doBind();
         }
 
         @Override
@@ -351,106 +301,33 @@
             Log.d(TAG, "Handler(): got msg=" + msg.what);
 
             switch (msg.what) {
-                case REGISTER_CALLBACK:
-                    registerCallbacks();
-                    break;
-                case UNREGISTER_CALLBACK:
-                    deRegisterCallbacks();
-                    if (mIsCountdownLatchEnabled) {
-                        mDeinitSignal.countDown();
-                        mIsCountdownLatchEnabled = false;
-                    }
-                    break;
                 case CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION:
-                    boolean enable = (boolean) msg.obj;
-                    configureBroadcastReceiverAssociation(enable);
+                    Boolean enable = (Boolean) msg.obj;
+                    if(enable) {
+                        Intent intent_to_configure_BRA = new Intent(
+                                BroadcastAudioAppActivity.ACTION_BAT_BRA_ENABLE);
+                        sendBroadcast(intent_to_configure_BRA);
+                    } else {
+                        Intent intent_to_configure_BRA = new Intent(
+                                BroadcastAudioAppActivity.ACTION_BAT_BRA_DISABLE);
+                        sendBroadcast(intent_to_configure_BRA);
+                    }
                     break;
                 case ASSOCIATE_BCA_RECEIVER:
                     BluetoothDevice device = (BluetoothDevice) msg.obj;
-                    associateBCAReceiver(device);
+                    Intent intent_to_associate_BCA_Receiver = new Intent(
+                            BroadcastAudioAppActivity.ACTION_BAT_ASSOCIATE_BCA_RECEIVER);
+                    intent_to_associate_BCA_Receiver.putExtra(
+                            BluetoothDevice.EXTRA_DEVICE, device);
+                    sendBroadcast(intent_to_associate_BCA_Receiver);
                     break;
                 default:
                     break;
             }
         }
 
-        boolean doBind() {
-            Log.v(TAG, " doBind ");
-            Intent intent = new Intent().setClass(mContext, GattBroadcastService.class);
-            if (!mContext.bindServiceAsUser(intent, mConnection, 0,
-                    android.os.Process.myUserHandle())) {
-                Log.e(TAG, "Could not bind to Bluetooth gatt Service with intent" + intent);
-                return false;
-            }
-            return true;
-        }
-
         void close() {
             Log.v(TAG, " close ");
-            synchronized (mConnection) {
-                if (mService != null) {
-                    try {
-                        mContext.unbindService(mConnection);
-                        mService = null;
-                    } catch (Exception re) {
-                        Log.e(TAG, "", re);
-                    }
-                }
-            }
-        }
-
-        private boolean associateBCAReceiver(BluetoothDevice device) {
-            Log.v(TAG, " associateBCAReceiver ");
-            try {
-                if (mService != null) {
-                    mService.associateBCAReceiver(device);
-                    return true;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to associate BCA Receiver " + e);
-            }
-            return false;
-        }
-
-        private boolean registerCallbacks() {
-            Log.v(TAG, " registerCallbacks ");
-            try {
-                if (mService != null) {
-                    mService.registerCallbacks(mServiceCallbacks);
-                    return true;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to register Callbacks" + e);
-            }
-            return false;
-        }
-
-        private boolean deRegisterCallbacks() {
-            Log.v(TAG, " deRegisterCallbacks ");
-            try {
-                if (mService != null) {
-                    mService.deRegisterCallbacks(mServiceCallbacks);
-                    return true;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to deRegister Callbacks" + e);
-                return false;
-            }
-            return false;
-        }
-
-        private boolean configureBroadcastReceiverAssociation(boolean enable) {
-            Log.v(TAG, " configureBroadcastReceiverAssociation ");
-
-            try {
-                if (mService != null) {
-                    mService.configureBroadcastReceiverAssociation(enable);
-                    return true;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to configure Broadcast Receiver Association" + e);
-            }
-            return false;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastService.aidl b/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastService.aidl
deleted file mode 100644
index c75dd09..0000000
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastService.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *    * Neither the name of The Linux Foundation nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.codeaurora.bluetooth.batestapp;
-
-import android.bluetooth.BluetoothDevice;
-import org.codeaurora.bluetooth.batestapp.IGattBroadcastServiceCallback;
-
-/**
- * API for interacting with GattBroadcastService
- * @hide
- */
-
-interface IGattBroadcastService
-{
-    void registerCallbacks(in IGattBroadcastServiceCallback cb);
-    void deRegisterCallbacks(in IGattBroadcastServiceCallback cb);
-    void configureBroadcastReceiverAssociation(in boolean enable);
-    void associateBCAReceiver(in BluetoothDevice device);
-}
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastServiceCallback.aidl b/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastServiceCallback.aidl
deleted file mode 100644
index 00bc22c..0000000
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/IGattBroadcastServiceCallback.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *    * Neither the name of The Linux Foundation nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.codeaurora.bluetooth.batestapp;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.ScanResult;
-
-/**
- * Callback definitions for interacting with GattBroadcastService
- * @hide
- */
-
-interface IGattBroadcastServiceCallback {
-    void onFoundOnLostBCAReceiver(in ScanResult result, in boolean onfound);
-    void onConfiguredBroadcastReceiverAssociation(in int status);
-    void onAssociatedBCAReceiver(in BluetoothDevice device, in int status);
-}
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/RecyclerViewListener.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/RecyclerViewListener.java
deleted file mode 100644
index 44ec03d..0000000
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/RecyclerViewListener.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *    * Neither the name of The Linux Foundation nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.codeaurora.bluetooth.batestapp;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.support.v4.content.ContextCompat;
-import android.util.Log;
-import android.widget.Toast;
-
-public interface RecyclerViewListener {
-    void onRecylerViewItemClicked(int clickedPos);
-}
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/Utils.java b/BATestApp/src/org/codeaurora/bluetooth/batestapp/Utils.java
deleted file mode 100644
index 58918b0..0000000
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/Utils.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *    * Neither the name of The Linux Foundation nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.codeaurora.bluetooth.batestapp;
-
-import android.content.Context;
-import android.widget.Toast;
-
-public class Utils {
-
-    static final String TAG="BAAPP ";
-    public static void toast(Context ctx, String msg) {
-        Toast.makeText(ctx, msg, Toast.LENGTH_SHORT).show();
-    }
-}
diff --git a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
index 0a05b7d..f3acfc5 100644
--- a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
+++ b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
@@ -65,6 +65,7 @@
 
 static jmethodID method_onBredrCleanup;
 static jmethodID method_iotDeviceBroadcast;
+static jmethodID method_bqrDeliver;
 static jmethodID method_devicePropertyChangedCallback;
 static jmethodID method_adapterPropertyChangedCallback;
 static jmethodID method_ssrCleanupCallback;
@@ -159,6 +160,34 @@
                     (jint)glitch_count);
 }
 
+static void bqr_delivery_callback(RawAddress* bd_addr, uint8_t lmp_ver, uint16_t lmp_subver,
+        uint16_t manufacturer_id, std::vector<uint8_t> bqr_raw_data) {
+  ALOGI("%s", __func__);
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid()) return;
+
+  ScopedLocalRef<jbyteArray> addr(
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
+  if (!addr.get()) {
+    ALOGE("Error while allocation byte array for addr in %s", __func__);
+    return;
+  }
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
+      (jbyte*)bd_addr->address);
+
+  ScopedLocalRef<jbyteArray> raw_data(
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(bqr_raw_data.size()));
+  if (!raw_data.get()) {
+    ALOGE("Error while allocation byte array for bqr raw data in %s", __func__);
+    return;
+  }
+  sCallbackEnv->SetByteArrayRegion(raw_data.get(), 0, bqr_raw_data.size(),
+      (jbyte*)bqr_raw_data.data());
+
+  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_bqrDeliver, addr.get(),
+      (jint)lmp_ver, (jint)lmp_subver, (jint)manufacturer_id, raw_data.get());
+}
+
 static void adapter_vendor_properties_callback(bt_status_t status,
                           int num_properties,
                           bt_vendor_property_t *properties) {
@@ -255,6 +284,7 @@
     sizeof(sBluetoothVendorCallbacks),
     bredr_cleanup_callback,
     iot_device_broadcast_callback,
+    bqr_delivery_callback,
     remote_device_properties_callback,
     NULL,
     adapter_vendor_properties_callback,
@@ -265,6 +295,7 @@
 
     method_onBredrCleanup = env->GetMethodID(clazz, "onBredrCleanup", "(Z)V");
     method_iotDeviceBroadcast = env->GetMethodID(clazz, "iotDeviceBroadcast", "([BIIIIIIIIII)V");
+    method_bqrDeliver = env->GetMethodID(clazz, "bqrDeliver", "([BIII[B)V");
     method_devicePropertyChangedCallback = env->GetMethodID(
       clazz, "devicePropertyChangedCallback", "([B[I[[B)V");
     method_adapterPropertyChangedCallback = env->GetMethodID(
diff --git a/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java b/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
index a650069..4dd8e2e 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
@@ -506,10 +506,11 @@
                     break;
 
                 case AvrcpConstants_ext.ATTRID_COVER_ART:
-                    if (mAvrcp != null) {
+                    if (mAvrcp != null && mAvrcp.isCoverArtFeatureSupported(bdaddr)) {
                         attrValue = mAvrcp.getImgHandleFromTitle(bdaddr,
                                 desc.getTitle().toString());
                     } else {
+                        attrValue = null;
                         if (DEBUG) Log.d(TAG, " mAvrcp null ");
                     }
                     break;
diff --git a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
index 4bdfea4..bef8fa9 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
@@ -168,6 +168,7 @@
     private boolean avrcp_playstatus_blacklist = false;
     private static final String [] BlacklistDeviceAddrToMediaAttr = {"00:17:53"/*Toyota Etios*/};
     private boolean ignore_play;
+    private BluetoothDevice disconnectedActiveDevice;
     private byte changePathFolderType;
     private FolderItemsRsp_ext saveRspObj;
     private int changePathDepth;
@@ -177,6 +178,8 @@
     private boolean isShoActive = false;
 
     private boolean twsShoEnabled = false;
+    byte[] dummyaddr = {(byte)0xFA, (byte)0xCE, (byte)0xFA,
+                        (byte)0xCE, (byte)0xFA, (byte)0xCE};
     private static final String playerStateUpdateBlackListedAddr[] = {
          "BC:30:7E", //bc-30-7e-5e-f6-27, Name: Porsche BT 0310; bc-30-7e-8c-22-cb, Name: Audi MMI 1193
          "00:1E:43", //00-1e-43-14-f0-68, Name: Audi MMI 4365
@@ -197,7 +200,8 @@
     public static final int BTRC_FEAT_METADATA = 0x01;
     public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
     public static final int BTRC_FEAT_BROWSE = 0x04;
-    public static final int BTRC_FEAT_AVRC_UI_UPDATE = 0x08;
+    public static final int BTRC_FEAT_COVER_ART = 0x08;
+    public static final int BTRC_FEAT_AVRC_UI_UPDATE = 0x10;
 
     /* AVRC response codes, from avrc_defs */
     private static final int AVRC_RSP_NOT_IMPL = 8;
@@ -238,6 +242,7 @@
     private final static int MESSAGE_UPDATE_ABS_VOLUME_STATUS = 31;
     private static final int MSG_PLAY_STATUS_CMD_TIMEOUT = 33;
     private final static int MESSAGE_START_SHO = 34;
+    private static final int MSG_SET_ACTIVE_DEVICE = 35;
 
     private static final int STACK_CLEANUP = 0;
     private static final int APP_CLEANUP = 1;
@@ -363,7 +368,7 @@
         private int mBlackListVolume;
         private int mLastPassthroughcmd;
         private int mReportedPlayerID;
-
+        private boolean mTwsPairDisconnected;
         public DeviceDependentFeature(Context context) {
             mContext = context;
             mCurrentDevice = null;
@@ -406,6 +411,7 @@
             mLastRspPlayStatus = -1;
             mLastPassthroughcmd = KeyEvent.KEYCODE_UNKNOWN;
             mReportedPlayerID = NO_PLAYER_ID;
+            mTwsPairDisconnected = false;
         }
     };
     DeviceDependentFeature[] deviceFeatures;
@@ -413,6 +419,7 @@
     private static class SHOQueue {
         static BluetoothDevice device;
         static boolean PlayReq;
+        static boolean isRetry;
     }
 
     static {
@@ -602,6 +609,7 @@
         changePathDepth = 0;
         changePathFolderType = 0;
         changePathDirection = 0;
+        disconnectedActiveDevice = null;
         Avrcp_extVolumeManager();
         Log.v(TAG, "Exit start");
     }
@@ -669,6 +677,7 @@
         changePathDepth = 0;
         changePathFolderType = 0;
         changePathDirection = 0;
+        disconnectedActiveDevice = null;
         Log.d(TAG, "Exit doQuit");
     }
 
@@ -689,6 +698,30 @@
         Log.d(TAG, "Exit cleanup()");
     }
 
+    public boolean isCoverArtFeatureSupported(byte[] bdaddr) {
+        Log.w(TAG, "isCoverArtFeatureSupported");
+        String address = Utils.getAddressStringFromByte((byte[]) bdaddr);
+        BluetoothDevice device = mAdapter.getRemoteDevice(address);
+        if (device == null)
+            return false;
+        MediaPlayerInfo_ext player = mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null);
+        int index = getIndexForDevice(device);
+        if ((index == INVALID_DEVICE_INDEX) || (player == null))
+            return false;
+
+        short[] featureBits = player.getFeatureBitMask();
+        boolean playerSupportsCA = false;
+        for (int i = 0; i < featureBits.length; i++) {
+            if (featureBits[i] == AvrcpConstants_ext.AVRC_PF_COVER_ART_BIT_NO) {
+                playerSupportsCA = true;
+                break;
+            }
+        }
+        boolean peerSupprtsCA = ((deviceFeatures[index].mFeatures & BTRC_FEAT_COVER_ART) != 0);
+        Log.w(TAG, "playersupportCA " + playerSupportsCA + " peersupportCA " + peerSupprtsCA);
+        return (peerSupprtsCA && playerSupportsCA);
+    }
+
     private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
         @Override
         public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
@@ -807,11 +840,11 @@
                 mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),
                                                           isAbsoluteVolumeSupported(deviceIndex));
                 if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax &&
-                        vol > mAbsVolThreshold) {
-                        if (DEBUG) Log.v(TAG, "remote inital volume too high " + vol + ">" +
-                            mAbsVolThreshold);
-                        vol = mAbsVolThreshold;
-                        notifyVolumeChanged(vol, false);
+                    vol > mAbsVolThreshold) {
+                    if (DEBUG) Log.v(TAG, "remote inital volume too high " + vol + ">" +
+                       mAbsVolThreshold);
+                    vol = mAbsVolThreshold;
+                    notifyVolumeChanged(vol, false);
                 }
                 if (vol >= 0) {
                     int volume = convertToAvrcpVolume(vol);
@@ -1092,15 +1125,18 @@
                     Log.e(TAG,"invalid index for device");
                     break;
                 }
+                byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD
                 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE addr: " + address);
 
                 if (((!(deviceFeatures[deviceIndex].isActiveDevice)) &&
                     (deviceFeatures[deviceIndex].mInitialRemoteVolume != -1)) ||
                     (!deviceFeatures[deviceIndex].isAbsoluteVolumeSupportingDevice)) {
+                        if (deviceFeatures[deviceIndex].isAbsoluteVolumeSupportingDevice) {
+                           deviceFeatures[deviceIndex].mRemoteVolume = absVol;
+                        }
                         if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE ignored");
                         break;
                 }
-                byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD
                 int absolutevol = absVol;
                 if (DEBUG)
                     Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE: volume=" + absVol + " ctype="
@@ -1137,6 +1173,12 @@
                 if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
                     if ((deviceFeatures[deviceIndex].mVolCmdAdjustInProgress == false) &&
                         (deviceFeatures[deviceIndex].mVolCmdSetInProgress == false)) {
+                        if (deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice()) {
+                            Log.e(TAG,"Store volume for TWS+ pair for volume relays");
+                            deviceFeatures[deviceIndex].mRemoteVolume = absVol;
+                            deviceFeatures[deviceIndex].mLocalVolume = convertToAudioStreamVolume(absVol);
+                            break;
+                        }
                         Log.e(TAG, "Unsolicited response, ignored");
                         break;
                     }
@@ -1156,11 +1198,19 @@
                         if (i != deviceIndex && deviceFeatures[i].mCurrentDevice != null &&
                             deviceFeatures[i].mInitialRemoteVolume != -1 &&
                             isTwsPlusPair(conn_dev, device)) {
-                            Log.v(TAG,"volume already set for tws pair");
-                            deviceFeatures[deviceIndex].mInitialRemoteVolume = absVol;
-                            deviceFeatures[deviceIndex].mRemoteVolume = absVol;
-                            deviceFeatures[deviceIndex].mLocalVolume = convertToAudioStreamVolume(absVol);
-                            break;
+                            Log.v(TAG,"TWS+ pair found at index " + i +
+                               "mTwsPairDisconnected = " + deviceFeatures[i].mTwsPairDisconnected);
+                            if (deviceFeatures[i].mTwsPairDisconnected) {
+                                Log.v(TAG,"TWS+ pair was disconnected earlier");
+                                Log.v(TAG,"TWS+ store this volume");
+                                deviceFeatures[i].mTwsPairDisconnected = false;
+                            } else {
+                                Log.v(TAG,"volume already set for tws pair");
+                                deviceFeatures[deviceIndex].mInitialRemoteVolume = absVol;
+                                deviceFeatures[deviceIndex].mRemoteVolume = absVol;
+                                deviceFeatures[deviceIndex].mLocalVolume = convertToAudioStreamVolume(absVol);
+                                break;
+                            }
                         }
                     }
                 }
@@ -1389,7 +1439,7 @@
                             Log.e(TAG, "1: SHO complete");
                         }
 
-                        if(mHandler.hasMessages(MESSAGE_START_SHO)) {
+                        if(mHandler.hasMessages(MESSAGE_START_SHO) && (!SHOQueue.isRetry)) {
                             mHandler.removeMessages(MESSAGE_START_SHO);
                             triggerSHO(SHOQueue.device, SHOQueue.PlayReq, false);
                         }
@@ -1591,7 +1641,7 @@
                     synchronized (Avrcp_ext.this) {
                         isShoActive = false;
                         Log.d(TAG, "3: SHO complete");
-                        if (mHandler.hasMessages(MESSAGE_START_SHO)) {
+                        if (mHandler.hasMessages(MESSAGE_START_SHO) && (!SHOQueue.isRetry)) {
                             mHandler.removeMessages(MESSAGE_START_SHO);
                             triggerSHO(SHOQueue.device, SHOQueue.PlayReq, false);
                         }
@@ -1600,6 +1650,114 @@
                 }
                 break;
 
+            case MSG_SET_ACTIVE_DEVICE:
+                boolean tws_switch = false;
+                Log.d(TAG, "MSG_SET_ACTIVE_DEVICE");
+                BluetoothDevice bt_device = (BluetoothDevice) msg.obj;
+                if (bt_device == null) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        deviceFeatures[i].isActiveDevice = false;
+                    }
+                    break;
+                }
+                if (bt_device != null && bt_device.isTwsPlusDevice()) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        if (deviceFeatures[i].mCurrentDevice != null &&
+                                deviceFeatures[i].isActiveDevice &&
+                                deviceFeatures[i].mCurrentDevice.isTwsPlusDevice()) {
+                            tws_switch = true;
+                        }
+                    }
+                }
+                deviceIndex = getIndexForDevice(bt_device);
+                if (deviceIndex == INVALID_DEVICE_INDEX) {
+                    Log.e(TAG,"Invalid device index for setActiveDevice");
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        deviceFeatures[i].isActiveDevice = false;
+                    }
+                    break;
+                }
+                deviceFeatures[deviceIndex].isActiveDevice = true;
+
+                Log.w(TAG, "Active device Calling SetBrowsePackage for " + mCachedBrowsePlayer);
+                if (mCachedBrowsePlayer != null && is_player_updated_for_browse == false) {
+                    SetBrowsePackage(mCachedBrowsePlayer);
+                }
+
+                if (deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice() &&
+                        updateAbsVolume == true) {
+                    Log.d(TAG,"setting absVolume flag for TWS+ device");
+                    mAudioManager.avrcpSupportsAbsoluteVolume(bt_device.getAddress(),true);
+                    AdapterService mAdapterService = AdapterService.getAdapterService();
+                    BluetoothDevice peer_device = mAdapterService.
+                            getTwsPlusPeerDevice(deviceFeatures[deviceIndex].mCurrentDevice);
+                    if (peer_device != null &&
+                            getIndexForDevice(peer_device) == INVALID_DEVICE_INDEX) {
+                        Log.d(TAG,"Other TWS+ earbud not connected, reset updateAbsVolume flag");
+                        updateAbsVolume = false;
+                    }
+                }
+                if (bt_device.isTwsPlusDevice() && !tws_switch) {
+                    Log.d(TAG,"Restting mTwsPairDisconnected at index " + deviceIndex);
+                    deviceFeatures[deviceIndex].mTwsPairDisconnected = false;
+                }
+                if (maxAvrcpConnections > 1) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        if (deviceIndex != i && deviceFeatures[i].mCurrentDevice != null &&
+                                deviceFeatures[i].mCurrentDevice.isTwsPlusDevice() &&
+                                isTwsPlusPair(deviceFeatures[i].mCurrentDevice, bt_device)) {
+                            Log.d(TAG,"TWS+ pair connected, keep both devices active");
+                            deviceFeatures[i].isActiveDevice = true;
+                            if (updateAbsVolume == true) {
+                                Log.d(TAG,"Setting absVolume flag to TWS+ pair");
+                                mAudioManager.avrcpSupportsAbsoluteVolume(
+                                        bt_device.getAddress(), true);
+                                updateAbsVolume = false;
+                            }
+                        } else {
+                            if (deviceIndex != i)
+                                deviceFeatures[i].isActiveDevice = false;
+                        }
+                    }
+                }
+                Log.e(TAG, "AVRCP isActive device index " + deviceIndex + " setActive addr " +
+                            deviceFeatures[deviceIndex].mCurrentDevice.getAddress());
+
+                //to keep volume copy for setting volume
+                deviceFeatures[deviceIndex].mLocalVolume = getVolume(bt_device);
+                if((maxAvrcpConnections > 1) && (deviceFeatures[deviceIndex].mCurrentDevice != null)
+                        && (deviceFeatures[deviceIndex].mReportedPlayerID != mCurrAddrPlayerID)) {
+                    Log.d(TAG,"Update cache browsing event to last active device, deviceFeatures[" +
+                            deviceIndex + "].mReportedPlayerID: " +
+                            deviceFeatures[deviceIndex].mReportedPlayerID +
+                            ", mCurrAddrPlayerID: " + mCurrAddrPlayerID);
+                    if (deviceFeatures[deviceIndex].mAvailablePlayersChangedNT ==
+                            AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
+                        registerNotificationRspAvalPlayerChangedNative(
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED,
+                                getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+                        mAvailablePlayerViewChanged = false;
+                        deviceFeatures[deviceIndex].mAvailablePlayersChangedNT =
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
+                    }
+                    if (deviceFeatures[deviceIndex].mAddrPlayerChangedNT ==
+                            AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
+                        registerNotificationRspAddrPlayerChangedNative(
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED,
+                                mCurrAddrPlayerID, sUIDCounter,
+                                getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+                        deviceFeatures[deviceIndex].mAddrPlayerChangedNT =
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
+                        // send track change event becasue some carkits will refresh metadata
+                        // while receive addressed player change event. Track change event to
+                        // make remote get metadata correctly.
+                        sendTrackChangedRsp(false, deviceFeatures[deviceIndex].mCurrentDevice);
+                    }
+
+                    deviceFeatures[deviceIndex].mReportedPlayerID = mCurrAddrPlayerID;
+                    break;
+                }
+
             default:
                 Log.e(TAG, "unknown message! msg.what=" + msg.what);
                 break;
@@ -2638,10 +2796,19 @@
         if (requested || ((deviceFeatures[i].mLastReportedPosition != playPositionMs) &&
              ((playPositionMs >= deviceFeatures[i].mNextPosMs) ||
              (playPositionMs <= deviceFeatures[i].mPrevPosMs))) && deviceFeatures[i].isActiveDevice) {
-            if (!requested) deviceFeatures[i].mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
-            if (deviceFeatures[i].mCurrentDevice != null)
-                registerNotificationRspPlayPosNative(deviceFeatures[i].mPlayPosChangedNT,
-                   (int)playPositionMs, getByteAddress(deviceFeatures[i].mCurrentDevice));
+            if (!requested)
+                deviceFeatures[i].mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
+            if (deviceFeatures[i].mCurrentDevice != null) {
+                if (!registerNotificationRspPlayPosNative(deviceFeatures[i].mPlayPosChangedNT,
+                        (int)playPositionMs, getByteAddress(deviceFeatures[i].mCurrentDevice))) {
+                    Log.w(TAG,"Fail to send rsp to remote, restore to interim if change rsp fail");
+                    if (!requested) {
+                        deviceFeatures[i].mPlayPosChangedNT =
+                                AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
+                        return;
+                    }
+                }
+            }
             deviceFeatures[i].mLastReportedPosition = playPositionMs;
             if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                 deviceFeatures[i].mNextPosMs = playPositionMs + deviceFeatures[i].mPlaybackIntervalMs;
@@ -2745,23 +2912,23 @@
                     if (deviceFeatures[i].mCurrentDevice != null) {
                         Log.d(TAG, "SendPassThruPlay command sent for = "
                                 + deviceFeatures[i].mCurrentDevice);
-                        /*if (volume > mLocalVolume) {
+                        if (volume > mLocalVolume) {
                             Log.d(TAG, "Vol Passthrough Up");
-                            avrcpCtrlService.sendPassThroughCmd(
-                                deviceFeatures[i].mCurrentDevice, AVRC_ID_VOL_UP,
-                                AvrcpConstants_ext.KEY_STATE_PRESS);
-                            avrcpCtrlService.sendPassThroughCmd(
-                                deviceFeatures[i].mCurrentDevice, AVRC_ID_VOL_UP,
-                                AvrcpConstants_ext.KEY_STATE_RELEASE);
+                            avrcpCtrlService.sendPassThroughCommandNative(
+                                Utils.getByteAddress(deviceFeatures[i].mCurrentDevice),
+                                AVRC_ID_VOL_UP, AvrcpConstants_ext.KEY_STATE_PRESS);
+                            avrcpCtrlService.sendPassThroughCommandNative(
+                                Utils.getByteAddress(deviceFeatures[i].mCurrentDevice),
+                                AVRC_ID_VOL_UP, AvrcpConstants_ext.KEY_STATE_RELEASE);
                         } else if (volume < mLocalVolume) {
                            Log.d(TAG, "Vol Passthrough Down");
-                           avrcpCtrlService.sendPassThroughCmd(
-                                deviceFeatures[i].mCurrentDevice, AVRC_ID_VOL_DOWN,
-                                AvrcpConstants_ext.KEY_STATE_PRESS);
-                           avrcpCtrlService.sendPassThroughCmd(
-                                deviceFeatures[i].mCurrentDevice, AVRC_ID_VOL_DOWN,
-                                AvrcpConstants_ext.KEY_STATE_RELEASE);
-                         }*/
+                           avrcpCtrlService.sendPassThroughCommandNative(
+                                Utils.getByteAddress(deviceFeatures[i].mCurrentDevice),
+                                AVRC_ID_VOL_DOWN, AvrcpConstants_ext.KEY_STATE_PRESS);
+                            avrcpCtrlService.sendPassThroughCommandNative(
+                                Utils.getByteAddress(deviceFeatures[i].mCurrentDevice),
+                                AVRC_ID_VOL_DOWN, AvrcpConstants_ext.KEY_STATE_RELEASE);
+                        }
                         mLocalVolume = volume;
                     }
                 }
@@ -3278,6 +3445,11 @@
         for (int i = 0; i < maxAvrcpConnections; i++ ) {
             if (deviceFeatures[i].mCurrentDevice !=null &&
                     deviceFeatures[i].mCurrentDevice.equals(device)) {
+                if (deviceFeatures[i].isActiveDevice &&
+                      deviceFeatures[i].isAbsoluteVolumeSupportingDevice) {
+                    storeVolumeForDevice(device);
+                    disconnectedActiveDevice = device;
+                 }
                 // initiate cleanup for all variables;
                 Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_RC_CLEANUP, STACK_CLEANUP,
                        0, device);
@@ -3307,6 +3479,8 @@
                     isTwsPlusPair(device,deviceFeatures[i].mCurrentDevice )) {
                     Log.i(TAG,"TWS+ pair got disconnected,update absVolume");
                     updateAbsVolume = true;
+                    Log.i(TAG,"TWS+ pair disconnected, set mTwsPairDisconnected for index " + i);
+                    deviceFeatures[i].mTwsPairDisconnected = true;
                 }
             }
         }
@@ -3325,7 +3499,11 @@
         if ((mCurrentBrowsingDevice != null) &&
             (mCurrentBrowsingDevice.equals(device))) {
             Log.v(TAG,"BT device is matched with browsing device:");
-            mAvrcpBrowseManager.cleanup();
+            BrowsedMediaPlayer_ext player =
+                    mAvrcpBrowseManager.getBrowsedMediaPlayer(getByteAddress(device));
+            if (player != null)
+               player.disconnect();
+            mAvrcpBrowseManager.clearBrowsedMediaPlayer(getByteAddress(device));
             mCurrentBrowsingDevice = null;
             changePathDepth = 0;
             changePathFolderType = 0;
@@ -3713,6 +3891,11 @@
         synchronized (this) {
             synchronized (mBrowsePlayerInfoList) {
                 mBrowsePlayerInfoList.clear();
+                BrowsedMediaPlayer_ext player =
+                        mAvrcpBrowseManager.getBrowsedMediaPlayer(dummyaddr);
+                if (player != null)
+                    player.start();
+                Log.d(TAG, "buildBrowsablePlayerList " + player);
                 Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE);
                 List<ResolveInfo> playerList =
                         mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
@@ -3723,8 +3906,10 @@
                             (displayName != null) ? displayName.toString():new String();
                     String serviceName = info.serviceInfo.name;
                     String packageName = info.serviceInfo.packageName;
-
-                    if (DEBUG) Log.d(TAG, "Adding " + serviceName + " to list of browsable players");
+                    Log.d(TAG, "svc " + serviceName + " and pkg = " + packageName);
+                    if ((player != null) && (serviceName != null)) {
+                        player.CheckMBSConnection(packageName, serviceName);
+                    }
                     BrowsePlayerInfo_ext currentPlayer =
                             new BrowsePlayerInfo_ext(packageName, displayableName, serviceName);
                     mBrowsePlayerInfoList.add(currentPlayer);
@@ -4097,13 +4282,25 @@
                     playStatusValues[idx] = info.getPlayStatus();
 
                     short[] featureBits = info.getFeatureBitMask();
-                    for (int numBit = 0; numBit < featureBits.length; numBit++) {
-                        /* gives which octet this belongs to */
-                        byte octet = (byte) (featureBits[numBit] / 8);
-                        /* gives the bit position within the octet */
-                        byte bit = (byte) (featureBits[numBit] % 8);
-                        featureBitMaskValues[(idx * AvrcpConstants_ext.AVRC_FEATURE_MASK_SIZE) + octet] |=
-                                (1 << bit);
+                    short[] featureBitsArray = {0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x01, 0x04,
+                                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+                    String browsedPackage = getPackageName(mCurrAddrPlayerID);
+                    BrowsedMediaPlayer_ext player =
+                            mAvrcpBrowseManager.getBrowsedMediaPlayer(dummyaddr);
+                    if ((player != null) && (!browsedPackage.isEmpty()) &&
+                            player.isPackageInMBSList(browsedPackage)) {
+                        for (int numBit = 0; numBit < featureBits.length; numBit++) {
+                            /* gives which octet this belongs to */
+                            byte octet = (byte) (featureBits[numBit] / 8);
+                            /* gives the bit position within the octet */
+                            byte bit = (byte) (featureBits[numBit] % 8);
+                            featureBitMaskValues[(idx * AvrcpConstants_ext.AVRC_FEATURE_MASK_SIZE) + octet] |=
+                                    (1 << bit);
+                        }
+                    } else {
+                         featureBitMaskValues =
+                                 Arrays.copyOf(featureBitsArray, featureBitsArray.length);
+                         Log.w(TAG, "sending bit mask for non Browsable Player");
                     }
 
                     /* printLogs */
@@ -4562,7 +4759,7 @@
             if (connList.containsKey(bdaddrStr)) {
                 mediaPlayer = connList.get(bdaddrStr);
             } else {
-                mediaPlayer = new BrowsedMediaPlayer_ext(bdaddr, mContext, mMediaInterface);
+                mediaPlayer = new BrowsedMediaPlayer_ext(bdaddr, mContext, mMediaInterface, mAvrcp);
                 connList.put(bdaddrStr, mediaPlayer);
             }
             return mediaPlayer;
@@ -4921,6 +5118,19 @@
         int storeVolume =  mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
         Log.i(TAG, "storeVolume: Storing stream volume level for device " + device
                 + " : " + storeVolume);
+        if (index != INVALID_DEVICE_INDEX && deviceFeatures[index].isAbsoluteVolumeSupportingDevice &&
+           (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax &&
+           storeVolume > mAbsVolThreshold)) {
+            if (DEBUG) Log.v(TAG, "remote store volume too high" + storeVolume + ">" +
+               mAbsVolThreshold);
+                storeVolume = mAbsVolThreshold;
+        }
+        if (index == INVALID_DEVICE_INDEX && disconnectedActiveDevice != null &&
+            disconnectedActiveDevice.equals(device)) {
+            Log.v(TAG, "No need to store volume again during avrcp disconnect volume is stored");
+            disconnectedActiveDevice = null;
+            return;
+        }
         mVolumeMap.put(device, storeVolume);
         pref.putInt(device.getAddress(), storeVolume);
         if (device != null && device.isTwsPlusDevice()) {
@@ -4952,6 +5162,7 @@
                 Message msg = mHandler.obtainMessage(MESSAGE_START_SHO, PlayReq?1:0, 0, device);
                 SHOQueue.device = device;
                 SHOQueue.PlayReq = PlayReq;
+                SHOQueue.isRetry = false;
                 mHandler.sendMessageDelayed(msg, 3000);
                 Log.d(TAG, "4: SHO Queued");
                 return true;
@@ -4974,6 +5185,7 @@
             }
             mHandler.removeMessages(MESSAGE_START_SHO);
             triggerSHO(device, PlayReq, true);
+            return ret;
         }
         synchronized (Avrcp_ext.this) {
             if (!PlayReq || isInCall || isFMActive) {
@@ -4993,9 +5205,13 @@
     private void triggerSHO(BluetoothDevice device, boolean PlayReq, boolean isRetry) {
         Message msg = mHandler.obtainMessage(MESSAGE_START_SHO, PlayReq?1:0, isRetry?1:0, device);
         if(isRetry) {
+            SHOQueue.device = device;
+            SHOQueue.PlayReq = PlayReq;
+            SHOQueue.isRetry = true;
             mHandler.sendMessageDelayed(msg, 2000);
             Log.e(TAG, "Retry SHO after delay");
         } else {
+            SHOQueue.isRetry = false;
             mHandler.sendMessage(msg);
         }
     }
@@ -5005,92 +5221,9 @@
     }
 
     public void setActiveDevice(BluetoothDevice device) {
-        if (device == null) {
-          for (int i = 0; i < maxAvrcpConnections; i++) {
-              deviceFeatures[i].isActiveDevice = false;
-          }
-          return;
-        }
-        int deviceIndex = getIndexForDevice(device);
-        if (deviceIndex == INVALID_DEVICE_INDEX) {
-            Log.e(TAG,"Invalid device index for setActiveDevice");
-            for (int i = 0; i < maxAvrcpConnections; i++) {
-                deviceFeatures[i].isActiveDevice = false;
-            }
-            return;
-        }
-        deviceFeatures[deviceIndex].isActiveDevice = true;
-
-        Log.w(TAG, "Active device Calling SetBrowsePackage for " + mCachedBrowsePlayer);
-        if (mCachedBrowsePlayer != null && is_player_updated_for_browse == false) {
-            SetBrowsePackage(mCachedBrowsePlayer);
-        }
-
-        if (updateAbsVolume == true && deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice()) {
-            Log.d(TAG,"setting absVolume flag for TWS+ device");
-            mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),true);
-            AdapterService mAdapterService = AdapterService.getAdapterService();
-            BluetoothDevice peer_device =
-                 mAdapterService.getTwsPlusPeerDevice(deviceFeatures[deviceIndex].mCurrentDevice);
-            if (peer_device != null &&
-                getIndexForDevice(peer_device) == INVALID_DEVICE_INDEX) {
-                Log.d(TAG,"Other TWS+ earbud not connected, reset updateAbsVolume flag");
-                updateAbsVolume = false;
-            }
-        }
-        if (maxAvrcpConnections > 1) {
-            for (int i = 0; i < maxAvrcpConnections; i++) {
-                if (deviceIndex != i && deviceFeatures[i].mCurrentDevice != null &&
-                    deviceFeatures[i].mCurrentDevice.isTwsPlusDevice() &&
-                    isTwsPlusPair(deviceFeatures[i].mCurrentDevice, device)) {
-                    Log.d(TAG,"TWS+ pair connected, keep both devices active");
-                    deviceFeatures[i].isActiveDevice = true;
-                    if (updateAbsVolume == true) {
-                        Log.d(TAG,"Setting absVolume flag to TWS+ pair");
-                        mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),true);
-                        updateAbsVolume = false;
-                    }
-                } else {
-                    if(deviceIndex != i)
-                        deviceFeatures[i].isActiveDevice = false;
-                }
-            }
-        }
-        Log.e(TAG,"AVRCP setActive  addr " + deviceFeatures[deviceIndex].mCurrentDevice.getAddress() +
-                    " isActive device index " + deviceIndex);
-
-        //to keep volume copy for setting volume
-        deviceFeatures[deviceIndex].mLocalVolume = getVolume(device);
-        if ((maxAvrcpConnections > 1) && (deviceFeatures[deviceIndex].mCurrentDevice != null) &&
-                (deviceFeatures[deviceIndex].mReportedPlayerID != mCurrAddrPlayerID)) {
-            Log.d(TAG,"Update cached browsing events to latest active device, deviceFeatures[" +
-                    deviceIndex + "].mReportedPlayerID: " +
-                    deviceFeatures[deviceIndex].mReportedPlayerID +
-                    ", mCurrAddrPlayerID: " + mCurrAddrPlayerID);
-            if (deviceFeatures[deviceIndex].mAvailablePlayersChangedNT ==
-                    AvrcpConstants_ext.NOTIFICATION_TYPE_INTERIM) {
-                registerNotificationRspAvalPlayerChangedNative(
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED,
-                        getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
-                mAvailablePlayerViewChanged = false;
-                deviceFeatures[deviceIndex].mAvailablePlayersChangedNT =
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED;
-            }
-            if (deviceFeatures[deviceIndex].mAddrPlayerChangedNT ==
-                    AvrcpConstants_ext.NOTIFICATION_TYPE_INTERIM) {
-                registerNotificationRspAddrPlayerChangedNative(
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID,
-                        sUIDCounter, getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
-                deviceFeatures[deviceIndex].mAddrPlayerChangedNT =
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED;
-                // send track change event becasue some carkits will refresh metadata
-                // while receive addressed player change event. Track change event to
-                // make remote get metadata correctly.
-                sendTrackChangedRsp(false, deviceFeatures[deviceIndex].mCurrentDevice);
-            }
-
-            deviceFeatures[deviceIndex].mReportedPlayerID = mCurrAddrPlayerID;
-        }
+        Log.w(TAG, "setActiveDevice call for device " + device);
+        Message msg = mHandler.obtainMessage(MSG_SET_ACTIVE_DEVICE, 0, 0, device);
+        mHandler.sendMessage(msg);
     }
 
     private SharedPreferences getVolumeMap() {
diff --git a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
index 8f1801d..1327a4a 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
@@ -26,6 +26,10 @@
 import android.media.session.MediaSession;
 import android.os.Bundle;
 import android.util.Log;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -48,6 +52,11 @@
     private static final int CONNECTED = 1;
     private static final int SUSPENDED = 2;
 
+    private static final int MSG_CONNECT_PLAYER = 1;
+    private static final int MSG_DISCONNECT_PLAYER = 2;
+    private static final int MSG_TIMEOUT = 3;
+
+    private static final int TIMEOUT = 3000;
     private static final int BROWSED_ITEM_ID_INDEX = 2;
     private static final int BROWSED_FOLDER_ID_INDEX = 4;
     private static final String[] ROOT_FOLDER = {"root"};
@@ -59,10 +68,14 @@
     private Context mContext;
     private AvrcpMediaRspInterface_ext mMediaInterface;
     private byte[] mBDAddr;
+    private Avrcp_ext mAvrcp = null;
 
     private String mCurrentBrowsePackage;
     private String mCurrentBrowseClass;
 
+    private BrowseMediaHandler mHandler = null;
+    private HandlerThread mHandlerThread;
+
     /* Object used to connect to MediaBrowseService of Media Player */
     private MediaBrowser mMediaBrowser = null;
     private MediaController mMediaController = null;
@@ -89,6 +102,44 @@
 
     /* store result of getfolderitems with scope="vfs" */
     private List<MediaBrowser.MediaItem> mFolderItems = null;
+    private List<String> mBrowsablePlayerList = new ArrayList<String>();
+
+    class BrowseMediaHandler extends Handler {
+        BrowseMediaHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            Log.w(TAG, "handleMessage " + msg.what + " obj " + msg.obj);
+            switch (msg.what) {
+                case MSG_CONNECT_PLAYER:
+                    Bundle data = msg.getData();
+                    String packageName = data.getCharSequence("package").toString();
+                    String cls = data.getCharSequence("class").toString();
+                    Log.w(TAG, "package = " + packageName + " svc class " + cls);
+                    MediaConnectionCallback callback = new MediaConnectionCallback(packageName);
+                    MediaBrowser tempBrowser = new MediaBrowser(
+                            mContext, new ComponentName(packageName, cls), callback, null);
+                    callback.setBrowser(tempBrowser);
+                    tempBrowser.connect();
+                    Log.w(TAG, "TryconnectMBS with Browser service");
+                    Message m = mHandler.obtainMessage(MSG_TIMEOUT, 0, 0, packageName);
+                    mHandler.sendMessageDelayed(m, TIMEOUT);
+                    break;
+                case MSG_DISCONNECT_PLAYER:
+                    MediaBrowser mb = (MediaBrowser)msg.obj;
+                    mb.disconnect();
+                    Log.w(TAG, "Trigger disconnect for MediaBrowser " + mb);
+                    break;
+                case MSG_TIMEOUT:
+                    Log.w(TAG, "MSG_TIMEOUT");
+                    break;
+                default:
+                    break;
+           }
+       }
+    };
 
     /* Connection state callback handler */
     class MediaConnectionCallback extends MediaBrowser.ConnectionCallback {
@@ -100,15 +151,21 @@
         }
 
         public void setBrowser(MediaBrowser b) {
+            Log.d(TAG, "setBrowser " + b);
             mBrowser = b;
         }
 
         @Override
         public void onConnected() {
-            mConnState = CONNECTED;
-            if (DEBUG) {
-                Log.d(TAG, "mediaBrowser CONNECTED to " + mPackageName);
+            if ((mHandler != null) && !mBrowsablePlayerList.contains(mCallbackPackageName)) {
+                Log.d(TAG, "Add " + mCallbackPackageName + " to MBS List " + mBrowser);
+                mBrowsablePlayerList.add(mCallbackPackageName);
+                mHandler.removeMessages(MSG_TIMEOUT, mCallbackPackageName);
+                Message msg = mHandler.obtainMessage(MSG_DISCONNECT_PLAYER, 0, 0, mBrowser);
+                mHandler.sendMessage(msg);
             }
+            mConnState = CONNECTED;
+            Log.d(TAG, "mediaBrowser CONNECTED to " + mPackageName);
             /* perform init tasks and set player as browsed player on successful connection */
             onBrowseConnect(mCallbackPackageName, mBrowser);
 
@@ -118,17 +175,23 @@
 
         @Override
         public void onConnectionFailed() {
+            if ((mHandler != null) && !mBrowsablePlayerList.contains(mCallbackPackageName)) {
+                mHandler.removeMessages(MSG_TIMEOUT, mCallbackPackageName);
+            }
             mConnState = DISCONNECTED;
             // Remove what could be a circular dependency causing GC to never happen on this object
             mBrowser = null;
             Log.e(TAG, "mediaBrowser Connection failed with " + mPackageName
                     + ", Sending fail response!");
-            mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR,
+            mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_PLAY_NOT_BROW,
                     (byte) 0x00, 0, null);
         }
 
         @Override
         public void onConnectionSuspended() {
+            if ((mHandler != null) && !mBrowsablePlayerList.contains(mCallbackPackageName)) {
+                mHandler.removeMessages(MSG_TIMEOUT, mCallbackPackageName);
+            }
             mBrowser = null;
             mConnState = SUSPENDED;
             Log.e(TAG, "mediaBrowser SUSPENDED connection with " + mPackageName);
@@ -281,10 +344,11 @@
 
     /* Constructor */
     BrowsedMediaPlayer_ext(byte[] address, Context context,
-            AvrcpMediaRspInterface_ext mAvrcpMediaRspInterface) {
+            AvrcpMediaRspInterface_ext mAvrcpMediaRspInterface, Avrcp_ext mAvrcp_ext) {
         mContext = context;
         mMediaInterface = mAvrcpMediaRspInterface;
         mBDAddr = address;
+        mAvrcp = mAvrcp_ext;
     }
 
     /* initialize mediacontroller in order to communicate with media player. */
@@ -478,18 +542,80 @@
         Log.w(TAG, "Reconnected with Browser service");
     }
 
+    public void CheckMBSConnection(String packageName, String cls) {
+        Log.w(TAG, "TryconnectMBS with Browser service for package = " + packageName);
+        Message msg = mHandler.obtainMessage(MSG_CONNECT_PLAYER);
+        Bundle data = new Bundle();
+        data.putCharSequence("package", packageName);
+        data.putCharSequence("class", cls);
+        msg.setData(data);
+        mHandler.sendMessage(msg);
+        Log.w(TAG, "Exit MSG_CONNECT_PLAYER for package = " + packageName);
+    }
+
+    public boolean isPackageInMBSList(String packageName) {
+        if (packageName == null || packageName.isEmpty())
+            return false;
+        Log.w(TAG, "isPlayerConnectedMBS for package = " + packageName);
+
+        // Wait while pending messages are in queue
+        while ((mHandler != null) && (mHandler.hasMessages(MSG_CONNECT_PLAYER)
+                || mHandler.hasMessages(MSG_TIMEOUT))) {
+            try {
+                Log.d(TAG, "Connection with MBS ongoing, sleep for 200 ms and recheck");
+                Thread.sleep(200);
+            } catch (InterruptedException e) {
+                Log.w(TAG, "Interrupt sleep caught Exception");
+            }
+        }
+
+        Log.w(TAG, "List of Browse supported players = " + mBrowsablePlayerList);
+        for (String pkg : mBrowsablePlayerList) {
+            if (packageName.equals(pkg))
+                return true;
+        }
+        return false;
+    }
+
     public void setCurrentPackage(String packageName, String cls) {
         Log.w(TAG, "Set current Browse based on Addr Player as " + packageName);
         mCurrentBrowsePackage = packageName;
         mCurrentBrowseClass = cls;
     }
 
+    public void start() {
+        if (mHandler == null) {
+            Log.w(TAG, "start");
+            mHandlerThread = new HandlerThread("BrowseMediaHandler");
+            mHandlerThread.start();
+            mHandler = new BrowseMediaHandler(mHandlerThread.getLooper());
+        }
+        Log.w(TAG, "start exit");
+    }
+
     /* called when connection to media player is closed */
     public void cleanup() {
+        disconnect();
         if (DEBUG) {
             Log.d(TAG, "cleanup");
         }
+        mBrowsablePlayerList.clear();
+        if (mHandler != null) {
+            Log.d(TAG, "cleanup handlers");
+            mHandler.removeCallbacksAndMessages(null);
+            Looper looper = mHandler.getLooper();
+            if (looper != null)
+                looper.quit();
+        }
+        if (mHandlerThread != null) {
+            mHandlerThread.quitSafely();
+        }
+    }
 
+    public void disconnect() {
+        if (DEBUG) {
+            Log.d(TAG, "disconnect");
+        }
         if (mConnState != DISCONNECTED) {
             if (mMediaBrowser != null) mMediaBrowser.disconnect();
         }
@@ -852,7 +978,7 @@
         mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants_ext.RSP_NO_ERROR, rspObj);
     }
 
-    public String getAttrValue(byte []bdaddr, int attr, MediaBrowser.MediaItem item) {
+    public String getAttrValue(byte[] bdaddr, int attr, MediaBrowser.MediaItem item) {
         String attrValue = null;
         try {
             MediaDescription desc = item.getDescription();
@@ -888,8 +1014,12 @@
                     break;
 
                 case AvrcpConstants_ext.ATTRID_COVER_ART:
-                    attrValue = Avrcp_ext.getImgHandleFromTitle(bdaddr,
-                            desc.getTitle().toString());
+                    if (mAvrcp != null && mAvrcp.isCoverArtFeatureSupported(bdaddr)) {
+                        attrValue = Avrcp_ext.getImgHandleFromTitle(bdaddr,
+                                desc.getTitle().toString());
+                    } else {
+                        attrValue = null;
+                    }
                     break;
 
                 default:
diff --git a/packages_apps_bluetooth_ext/src/ba/BATService.java b/packages_apps_bluetooth_ext/src/ba/BATService.java
index b658a67..5f6a01b 100644
--- a/packages_apps_bluetooth_ext/src/ba/BATService.java
+++ b/packages_apps_bluetooth_ext/src/ba/BATService.java
@@ -30,38 +30,37 @@
 package com.android.bluetooth.ba;
 
 import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothBATransmitter;
-import android.bluetooth.BluetoothBAStreamServiceRecord;
-import android.bluetooth.BluetoothBAEncryptionKey;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothA2dp;
 
-import android.bluetooth.IBluetoothBATransmitter;
+import com.android.bluetooth.ba.BluetoothBAStreamServiceRecord;
+import com.android.bluetooth.ba.BluetoothBAEncryptionKey;
+import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.Utils;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.media.AudioManager;
 import android.os.Bundle;
-import android.provider.Settings;
+import android.os.Binder;
 import android.os.SystemProperties;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
-import com.android.bluetooth.btservice.ProfileService;
-import com.android.bluetooth.a2dp.A2dpService;
-import com.android.bluetooth.hfp.HeadsetService;
-import com.android.bluetooth.Utils;
+import android.provider.Settings;
+import android.media.AudioManager;
 
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.nio.ByteBuffer;
 
 /**
  * Provides Bluetooth Broadcast Audio profile, as a service in
@@ -69,41 +68,217 @@
  * @hide
  */
 public class BATService extends ProfileService {
+
     private static final boolean DBG = true;
-    private static final String TAG="BATService";
+    private static final String TAG = "BATService";
 
     private static final int NUM_SERIVCE_RECORD = 1;
     private static final long STREAM_ID_48 = 1;
     // currently we are using 512(fr_samples),186(frame_size),frequency.
     // check GattService specification for more details
-    //private static final long   CODEC_CONFIG_CELT = (long)0x020000BA0100;
+    //private static final long  CODEC_CONFIG_CELT = (long)0x020000BA0100;
     // Messages
-    public static final int MESSAGE_BAT_STATE_CHANGE_REQ = 1;
-    public static final int MESSAGE_BAT_REFRESH_ENC_KEY_REQ = 2;
-    public static final int MESSAGE_BAT_VOL_CHANGE_REQ = 3;
+    private final int MESSAGE_BAT_STATE_CHANGE_REQ = 1;
+    private final int MESSAGE_BAT_REFRESH_ENC_KEY_REQ = 2;
+    private final int MESSAGE_BAT_VOL_CHANGE_REQ = 3;
 
-    public static final int MESSAGE_BAT_STATE_CHANGE_EVT = 101;
-    public static final int MESSAGE_BAT_ENC_CHANGE_EVT = 102;
-    public static final int MESSAGE_BAT_DIV_CHANGE_EVT = 103;
-    public static final int MESSAGE_BAT_STREAMING_ID_EVT = 104;
+    private final int MESSAGE_BAT_STATE_CHANGE_EVT = 101;
+    private final int MESSAGE_BAT_ENC_CHANGE_EVT = 102;
+    private final int MESSAGE_BAT_DIV_CHANGE_EVT = 103;
+    private final int MESSAGE_BAT_STREAMING_ID_EVT = 104;
 
-    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
-    public static final String mBAAddress = "CE:FA:CE:FA:CE:FA";
-    public static BluetoothDevice mBADevice;
+    private final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+    static final String BLUETOOTH_PERM_ADMIN = android.Manifest.permission.BLUETOOTH_ADMIN;
+    public static final String mBAAddress = "FA:CE:FA:CE:FA:CE";
+    private BluetoothDevice mBADevice;
     // we will listen for vol change intent from audio manager.
     // this intent is called in all following 3 cases
     // 1 - Local vol changing when there is no abs vol
     // 2 - Local vol changes if abs vol not supported
     // 3 - Vol changed from remote if abs vol is supported
+
+    /**
+     * Intent used to update state change of Broadcast Audio Transmitter.
+     *
+     * This intent will have 2 extras:
+     * #EXTRA_STATE - The current state of the profile.
+     * #EXTRA_PREVIOUS_STATE - The previous state of the profile.
+     *
+     * value of states can be any of
+     * STATE_DISABLED: Broadcast Audio is disabled.
+     * STATE_PAUSED:   Broadcast Audio is enabled but streaming is paused.
+     * STATE_PLAYING:  Broadcast Audio is enabled but streaming is ongoing.
+     *
+     */
+    protected static final String ACTION_BAT_STATE_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_STATE_CHANGED";
+    protected static final String EXTRA_STATE =
+            "com.android.bluetooth.bat.profile.extra.STATE";
+    protected static final String EXTRA_PREVIOUS_STATE =
+            "com.android.bluetooth.bat.profile.extra.PREV_STATE";
+
+     /**
+     * Intent is used to update state change of Broadcast Receiver Association.
+     *
+     * This intent will have 1 extra:
+     * #EXTRA_STATUS – status code
+     *
+     * value of states can be any of
+     *
+     * BRA_ENABLED_SUCESSS (0)
+     * BRA_ENABLED_FAILED (1)
+     * BRA_DISABLED_SUCESSS (2)
+     * BRA_DISABLED_FAILED(3)
+     */
+    protected static final String ACTION_BAT_BRA_STATE_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BRA_STATE_CHANGED";
+    protected static final String EXTRA_STATUS =
+            "com.android.bluetooth.bat.profile.extra.STATUS";
+
+    /**
+     * Intent is used to for updating  Broadcast Audio Receiver info, after Broadcast audio receiver is Lost or Found.
+     *
+     * This intent will have 2 extras:
+     * #EXTRA_SCAN_RESULT – Scan Result for particular device.
+     * #EXTRA_ONFOUND –  true if device found, false if device lost.
+     *
+     */
+    protected static final String ACTION_BAT_ONFOUND_ONLOST_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ONFOUND_ONLOST_BCA_RECEIVER";
+    protected static final String EXTRA_SCAN_RESULT =
+            "com.android.bluetooth.bat.profile.extra.EXTRA_SCAN_RESULT";
+    protected static final String EXTRA_ONFOUND =
+            "com.android.bluetooth.bat.profile.extra.EXTRA_ONFOUND";
+
+    /**
+     * Intent is used to for updating Broadcast Audio Aeceiver info, after a Broadcast audio receiver is associated.
+     *
+     * This intent will have 2 extras:
+     * #EXTRA_DEVICE–  BluetoothDevice info
+     * #EXTRA_STATUS – Status code
+     *
+     *  value of status code can be any of
+     *
+     *  ASSOCIATE_BCA_RECEIVER_SUCCESS(4)
+     *  ASSOCIATE_BCA_RECEIVER_FAILED(5)
+     */
+    protected static final String ACTION_BAT_ON_ASSOCIATED_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ON_ASSOCIATED_BCA_RECEIVER";
+
+    /**
+     * Intent is used, when Broadcast Audio Encryption Key is refreshed.
+     *
+     */
+    private final String ACTION_BAT_ENCRYPTION_KEY_REFRESHED =
+            "com.android.bluetooth.bat.profile.action.ENCRYPTION_KEY_REFRESHED";
+    private final String ACTION_BAT_ENCRYPTION_KEY_REFRESH =
+            "com.android.bluetooth.bat.profile.action.ENCRYPTION_KEY_REFRESH";
+
+    /**
+     * Intents are used to enable/disable Broadcast audio
+     */
+    private final String ACTION_BAT_BA_ENABLE =
+            "com.android.bluetooth.bat.profile.action.BA_ENABLE";
+    private final String ACTION_BAT_BA_DISABLE =
+            "com.android.bluetooth.bat.profile.action.BA_DISABLE";
+
+    /**
+     * Intent used to update encryption key .
+     *
+     * This intent will have 1 extra:
+     * #EXTRA_ENCRYPTION_KEY - The current value of encryption key.
+     *
+     * value of EncyptionKey would be 128-bit value. This value would change
+     * on every new BA session. We will send BluetoothBAEncryptionKey object.
+     *
+     */
+    protected static final String ACTION_BAT_ENCRYPTION_KEY_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_ENC_KEY_CHANGED";
+    protected static final String EXTRA_ECNRYPTION_KEY =
+            "com.android.bluetooth.bat.profile.extra.ENC_KEY";
+
+    /**
+     * Intent used to update DIV value .
+     *
+     * This intent will have 1 extras:
+     * #EXTRA_DIV_VALUE - The current value of DIV.
+     *
+     * value of DIV would be 2 byte value. This value would change
+     * on every new BA session. We will send integer value.
+     *
+     */
+    protected static final String ACTION_BAT_DIV_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_DIV_CHANGED";
+    protected static final String EXTRA_DIV_VALUE =
+            "com.android.bluetooth.bat.profile.extra.DIV";
+
+    /**
+     * Intent used to update  active stream id for Broadcast Audio Transmitter.
+     *
+     * This intent will have 1 extra:
+     * #EXTRA_STREAM_ID - The active streaming id.
+     *
+     * value of states can be any of
+     * 0: Broadcast Audio is not in STATE_PLAYING.
+     * valid streaming id:   Valid streaming id if BA is in STATE_PLAYING.
+     */
+    protected static final String ACTION_BAT_STREAMING_ID_CHANGED =
+            "com.android.bluetooth.bat.profile.action.BA_STR_ID_CHANGED";
+    protected static final String EXTRA_STREAM_ID =
+            "com.android.bluetooth.bat.profile.extra.STR_ID";
+
+    /**
+     * Intent used to update  Vendor Specific AVRCP Command.
+     *
+     * This intent will be sent whenever there is Vendor Specific AVRCP command
+     * received from primary headset.
+     *
+     * This intent will have 2 extra:
+     * #EXTRA_AVRCP_VS_ENABLE_BA - value describing enable/disable of BA.
+     * #EXTRA_AVRCP_VS_ENABLE_RA - value describing enable/disable of receiver
+     *                              association mode.
+     *
+     * value of states can be any of
+     * 0: Disable  BA/RA.
+     * 1: ENABLE  BA/RA.
+     */
+    private final String ACTION_BAT_AVRCP_VS_CMD =
+            "com.android.bluetooth.bat.profile.action.BA_AVRCP_VS_CMD";
+    private final String EXTRA_AVRCP_VS_ENABLE_BA =
+            "com.android.bluetooth.bat.profile.extra.ENABLE_BA";
+    private final String EXTRA_AVRCP_VS_ENABLE_RA =
+            "com.android.bluetooth.bat.profile.extra.ENABLE_RA";
+    protected static final String ACTION_BAT_BRA_ENABLE =
+            "com.android.bluetooth.bat.profile.action.BRA_ENABLE";
+    public static final String ACTION_BAT_BRA_DISABLE =
+            "com.android.bluetooth.bat.profile.action.BRA_DISABLE";
+    protected static final String ACTION_BAT_ASSOCIATE_BCA_RECEIVER =
+            "com.android.bluetooth.bat.profile.action.ASSOCIATE_BCA_RECEIVER";
+
+    protected static final int STATE_DISABLED = 0;
+    protected static final int STATE_PAUSED = 1;
+    protected static final int STATE_PLAYING = 2;
+    private final int ENABLE_BA_TRANSMITTER = 0;
+    private final int DISABLE_BA_TRANSMITTER = 1;
+    private final int INVALID_DIV = 0xFFFF;
+    public static int BA_TRANSMITTER = 23;      // Added to access in Config.java
+
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+
+            String action = intent.getAction();
+            Log.d(TAG," action: " + action);
+
+            if(action == null)
+                return;
+            if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
                 Log.d(TAG," onReceive  AudioManager Vol Changed");
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                 Log.d(TAG," streamType = " + streamType);
                 if (streamType == AudioManager.STREAM_MUSIC) {
-                    int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
+                    int streamValue = intent.getIntExtra(
+                            AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
                     int streamPrevValue = intent.getIntExtra(
                             AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
                     Log.d(TAG," prevVol = " + streamPrevValue + " streamVol = " + streamValue);
@@ -113,6 +288,22 @@
                     mMsgHandler.obtainMessage(MESSAGE_BAT_VOL_CHANGE_REQ,
                             streamValue,streamValue).sendToTarget();
                 }
+            } else if (action.equals(ACTION_BAT_BA_ENABLE)) {
+                setBATState(ENABLE_BA_TRANSMITTER);
+            } else if (action.equals(ACTION_BAT_BA_DISABLE)) {
+                setBATState(DISABLE_BA_TRANSMITTER);
+            } else if (action.equals(ACTION_BAT_ENCRYPTION_KEY_REFRESH)) {
+               refreshEncryptionKey();
+            } else if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                        BluetoothAdapter.ERROR);
+                int prevState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE,
+                        BluetoothAdapter.ERROR);
+                if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_ON) {
+                    Log.d(TAG,"ACTION_BLE_STATE_CHANGED state: " + state);
+                    mGattBroadcastService = new GattBroadcastService();
+                    mGattBroadcastService.start(getApplicationContext());
+                }
             }
         }
     };
@@ -128,6 +319,8 @@
     private BATMessageHandler mMsgHandler;
     private static BATService sBATService;
     private BluetoothAdapter mAdapter;
+    private GattBroadcastService mGattBroadcastService;
+
     // we need pending state only during transition from enable/disable.
     // no need for statemachine, at this point. Can be manager with a variable.
 
@@ -139,6 +332,15 @@
         return new BluetoothBATBinder(this);
     }
 
+    private static class BluetoothBATBinder extends Binder implements IProfileServiceBinder {
+
+        BluetoothBATBinder(BATService service) {}
+
+        @Override
+        public void cleanup() {
+        }
+    }
+
     @Override
     protected boolean start() {
         Log.d(TAG, "BATService :: start + ");
@@ -156,7 +358,7 @@
         mMsgHandler = new BATMessageHandler(looper);
         Log.d(TAG," mMsgHandler = " + mMsgHandler);
         // initialize with default value.
-        mCurrDIV = BluetoothBATransmitter.INVALID_DIV;
+        mCurrDIV = INVALID_DIV;
         byte[] mEncryptionKey = new byte[BluetoothBAEncryptionKey.ENCRYPTION_KEY_LENGTH];
         mCurrEncryptionKey = new BluetoothBAEncryptionKey(mEncryptionKey,
                 BluetoothBAEncryptionKey.SECURITY_KEY_TYPE_PRIVATE);
@@ -183,21 +385,26 @@
                 BluetoothBAStreamServiceRecord.BSSR_SAMPLE_SIZE_16_BIT);
         mServiceRecord.addServiceRecordValue(STREAM_ID_48,
                 BluetoothBAStreamServiceRecord.BSSR_TYPE_AFH_UPDATE_METHOD_ID,
-                BluetoothBAStreamServiceRecord.BSSR_AFH_CHANNEL_MAP_UPDATE_METHOD_TRIGGERED_SYNC_TRAIN);
+                BluetoothBAStreamServiceRecord
+                .BSSR_AFH_CHANNEL_MAP_UPDATE_METHOD_TRIGGERED_SYNC_TRAIN);
         mServiceRecord.addServiceRecordValue(STREAM_ID_48,
                 BluetoothBAStreamServiceRecord.BSSR_TYPE_CODEC_CONFIG_CELT_FREQ_ID,
                 BluetoothBAStreamServiceRecord.BSSR_CODEC_FREQ_48KHZ);
         mServiceRecord.addServiceRecordValue(STREAM_ID_48,
                 BluetoothBAStreamServiceRecord.BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SIZE_ID,(long)186);
         mServiceRecord.addServiceRecordValue(STREAM_ID_48,
-                BluetoothBAStreamServiceRecord.BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SAMPLES_ID, (long)512);
+                BluetoothBAStreamServiceRecord
+                .BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SAMPLES_ID, (long)512);
 
         IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
+        filter.addAction(ACTION_BAT_BA_ENABLE);
+        filter.addAction(ACTION_BAT_BA_DISABLE);
+        filter.addAction(ACTION_BAT_ENCRYPTION_KEY_REFRESH);
+        filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
         registerReceiver(mBroadcastReceiver, filter);
         mMsgHandler.obtainMessage(MESSAGE_BAT_VOL_CHANGE_REQ,
                 mCurrVolLevel,mCurrVolLevel).sendToTarget();
         mBADevice = mAdapter.getRemoteDevice(mBAAddress);
-        Log.d(TAG, "BATService :: start - ");
         return true;
     }
 
@@ -210,6 +417,10 @@
             if(looper != null)
                 looper.quit();
         }
+
+        if(mGattBroadcastService != null) {
+            mGattBroadcastService.stop();
+        }
         Log.d(TAG, "BATService :: stop - ");
         return true;
     }
@@ -257,8 +468,6 @@
             if (DBG)  {
                 if (instance == null) {
                     Log.d(TAG, "sBATService(): service not available");
-                } else if (!instance.isAvailable()) {
-                    Log.d(TAG,"sBATService(): service is cleaning up");
                 }
             }
         }
@@ -268,7 +477,7 @@
         sBATService = null;
     }
 
-    public static String dumpMessageString(int message) {
+    private String dumpMessageString(int message) {
         String str = "UNKNOWN";
         switch (message) {
             case MESSAGE_BAT_STATE_CHANGE_REQ: str = "REQ_STATE_CHANGE"; break;
@@ -283,7 +492,7 @@
         return str;
     }
 
-    public static String dumpStateString ( int state) {
+    private String dumpStateString ( int state) {
         String str = "UNKNOWN";
         switch (state) {
             case BA_STACK_STATE_IDLE: str = "BT_STACK_STATE_IDLE"; break;
@@ -304,7 +513,8 @@
         // when state changes from PENDING to IDLE, send A2DP Connected -> Disconnected
         if((mPrevStackBATState == BA_STACK_STATE_PENDING) &&
                 (mCurrStackBATState == BA_STACK_STATE_IDLE)) {
-            intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED);
+            intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE,
+                    BluetoothProfile.STATE_CONNECTED);
             intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
             updateConnectionState = true;
         }
@@ -382,43 +592,44 @@
         int broadcastSate;
         switch (mCurrStackBATState) {
             case BA_STACK_STATE_IDLE:
-                broadcastSate = BluetoothBATransmitter.STATE_DISABLED;
+                broadcastSate = STATE_DISABLED;
                 break;
             case BA_STACK_STATE_PAUSED:
-                broadcastSate = BluetoothBATransmitter.STATE_PAUSED;
+                broadcastSate = STATE_PAUSED;
                 break;
             case BA_STACK_STATE_STREAMING:
-                broadcastSate = BluetoothBATransmitter.STATE_PLAYING;
+                broadcastSate = STATE_PLAYING;
                 break;
             default:
                 // we don't want to send intent for other states.
                 return;
         }
         Log.d(TAG," broadcasting state = " + broadcastSate);
-        Intent intent = new Intent(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED);
-        intent.putExtra(BluetoothBATransmitter.EXTRA_STATE, broadcastSate);
-        sendBroadcast(intent);
+        Intent intent = new Intent(ACTION_BAT_STATE_CHANGED);
+        intent.putExtra(EXTRA_STATE, broadcastSate);
+        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, mPrevStackBATState);
+        sendBroadcast(intent, BLUETOOTH_PERM_ADMIN);
     }
 
     private void broadcastEncKeyUpdate(BluetoothBAEncryptionKey encKey) {
         Log.d(TAG," broadcastEncKeyUpdate ");
-        Intent intent = new Intent(BluetoothBATransmitter.ACTION_BAT_ENCRYPTION_KEY_CHANGED);
-        intent.putExtra(BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY, encKey);
-        sendBroadcast(intent);
+        Intent intent = new Intent(ACTION_BAT_ENCRYPTION_KEY_CHANGED);
+        intent.putExtra(EXTRA_ECNRYPTION_KEY, encKey);
+        sendBroadcast(intent, BLUETOOTH_PERM_ADMIN);
     }
 
     private void broadcastDIVUpdate(int div) {
         Log.d(TAG," broadcastDIVUpdate div =  "+ div);
-        Intent intent = new Intent(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED);
-        intent.putExtra(BluetoothBATransmitter.EXTRA_DIV_VALUE, div);
-        sendBroadcast(intent);
+        Intent intent = new Intent(ACTION_BAT_DIV_CHANGED);
+        intent.putExtra(EXTRA_DIV_VALUE, div);
+        sendBroadcast(intent, BLUETOOTH_PERM_ADMIN);
     }
 
     private void broadcastStramIdpdate(int streamID) {
-        Log.d(TAG," broadcastStramIdpdate streamID =  "+ streamID);
-        Intent intent = new Intent(BluetoothBATransmitter.ACTION_BAT_STREAMING_ID_CHANGED);
-        intent.putExtra(BluetoothBATransmitter.EXTRA_STREAM_ID, streamID);
-        sendBroadcast(intent);
+        Log.d(TAG," broadcastStramIdpdate streamID =  " + streamID);
+        Intent intent = new Intent(ACTION_BAT_STREAMING_ID_CHANGED);
+        intent.putExtra(EXTRA_STREAM_ID, streamID);
+        sendBroadcast(intent, BLUETOOTH_PERM_ADMIN);
     }
 
     // this api checks if abs vol is supported by AVRCP with any of the connected devices
@@ -453,7 +664,7 @@
         if((mPrevStackBATState == BA_STACK_STATE_PENDING) &&
                 (mCurrStackBATState == BA_STACK_STATE_PAUSED)) {
             Log.d(TAG," updating AudioManager: Connected for BA ");
-            mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+            mAudioManager.handleBluetoothA2dpActiveDeviceChange(
                 mBADevice, BluetoothProfile.STATE_CONNECTED,BluetoothProfile.A2DP, true, -1);
             //BA audio works on the principal of absVol
             //Currently mm-audio tracks value of last updated absVol support,
@@ -471,13 +682,13 @@
                 // as a2dp has to be updated as well. Switching should happen to
                 // A2DP in this case.
                 Log.d(TAG," updating AudioManager: Connected for A2DP ");
-                mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+                mAudioManager.handleBluetoothA2dpActiveDeviceChange(
                     a2dpActiveDevice, BluetoothProfile.STATE_CONNECTED,BluetoothProfile.A2DP,
                     true, -1);
             } else {// a2dp active device is null.
                 // inform BA device as disconnected. we have to send noisy intent
                 // because BA seems to be last device.
-                mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+                mAudioManager.handleBluetoothA2dpActiveDeviceChange(
                         mBADevice, BluetoothProfile.STATE_DISCONNECTED,BluetoothProfile.A2DP,
                         false, -1);
             }
@@ -497,12 +708,12 @@
     }
 
     // service level apis to be called from native callbacks
-    public void processBAStateUpdate(int newState) {
+    private void processBAStateUpdate(int newState) {
         Log.d(TAG," processBAStateUpdate newState = " + dumpStateString(newState));
         mMsgHandler.obtainMessage(MESSAGE_BAT_STATE_CHANGE_EVT, newState,0).sendToTarget();
     }
 
-    public void processEncryptionKeyUpdate(int size, byte[] enc_key) {
+    private void processEncryptionKeyUpdate(int size, byte[] enc_key) {
         Log.d(TAG," processEncryptionKeyUpdate size = " + size);
         Bundle data =  new Bundle();
         data.putByteArray("encKey", enc_key);
@@ -511,18 +722,18 @@
         mMsgHandler.sendMessage(msg);
     }
 
-    public void processDivUpdate(int size, byte[] div_key) {
+    private void processDivUpdate(int size, byte[] div_key) {
         Log.d(TAG," processDivUpdate size = " + size);
         ByteBuffer bb = ByteBuffer.wrap(div_key);
         Message msg = mMsgHandler.obtainMessage(MESSAGE_BAT_DIV_CHANGE_EVT, (int)bb.getShort(), 0);
         mMsgHandler.sendMessage(msg);
     }
 
-   public void processStreamIdUpdate(int streamId) {
+    private void processStreamIdUpdate(int streamId) {
        Log.d(TAG," processStreamIdUpdate streamID = " + streamId);
        Message msg = mMsgHandler.obtainMessage(MESSAGE_BAT_STREAMING_ID_EVT, (int)streamId, 0);
        mMsgHandler.sendMessage(msg);
-   }
+    }
 
     public boolean isBATActive() {
         Log.d(TAG," isBATActive  mCurrStackState = " + dumpStateString(mCurrStackBATState));
@@ -531,16 +742,6 @@
                 (mCurrStackBATState == BA_STACK_STATE_STREAMING));
     }
 
-    public boolean isBATPlaying() {
-        Log.d(TAG," isBATPlaying  mCurrStackState = " + dumpStateString(mCurrStackBATState));
-        return (mCurrStackBATState == BA_STACK_STATE_STREAMING);
-    }
-
-    public boolean isBATPaused() {
-        Log.d(TAG," isBATPaused  mCurrStackState = " + dumpStateString(mCurrStackBATState));
-        return (mCurrStackBATState == BA_STACK_STATE_PAUSED);
-    }
-
     public boolean isA2dpSuspendFromBA() {
         Log.d(TAG," isA2dpSuspendFromBA  mCurrStackState = "+
                         dumpStateString(mCurrStackBATState)
@@ -548,7 +749,7 @@
         return isCodecReconfigRequired;
     }
 
-    public boolean isA2dpPlaying() {
+    private boolean isA2dpPlaying() {
         A2dpService a2dpService = A2dpService.getA2dpService();
         if (a2dpService == null) {
             Log.d(TAG," isA2dpPlaying = false a2dpService null");
@@ -569,7 +770,7 @@
         return false;
     }
 
-    public boolean isCallActive() {
+    private boolean isCallActive() {
         HeadsetService headsetService = HeadsetService.getHeadsetService();
         if (headsetService == null) {
             Log.d(TAG," isCallActive = false HeadsetService null");
@@ -626,7 +827,7 @@
             switch(msg.what) {
                 case MESSAGE_BAT_STATE_CHANGE_REQ:
                     int newState = msg.arg1;
-                    if (newState == BluetoothBATransmitter.ENABLE_BA_TRANSMITTER) {
+                    if (newState == ENABLE_BA_TRANSMITTER) {
                         if (isCallActive()) {
                             Log.d(TAG," Call active, can't initilze BA ");
                             return;
@@ -637,8 +838,7 @@
                             //mAudioManager.setParameters("A2dpSuspended=true");
                         }
                         setBAStateNative(1);
-                    }
-                    if (newState == BluetoothBATransmitter.DISABLE_BA_TRANSMITTER) {
+                    } else if (newState == DISABLE_BA_TRANSMITTER) {
                         isCodecReconfigRequired = false;
                         setBAStateNative(0);
                     }
@@ -686,12 +886,12 @@
     public boolean setBATState(int newState) {
         Log.d(TAG," setBATState ( " + newState + ") currState = "
               + dumpStateString(mCurrStackBATState));
-        if((newState == BluetoothBATransmitter.ENABLE_BA_TRANSMITTER) &&
+        if((newState == ENABLE_BA_TRANSMITTER) &&
              (mCurrStackBATState != BA_STACK_STATE_IDLE)) {
             // we are already enabled, or in process of getting enabled
             return false;
         }
-        if((newState == BluetoothBATransmitter.DISABLE_BA_TRANSMITTER) &&
+        if((newState == DISABLE_BA_TRANSMITTER) &&
            (mCurrStackBATState == BA_STACK_STATE_IDLE)) {
             // we are already disabled
             return false;
@@ -701,7 +901,7 @@
             return false;
         if (mMsgHandler.hasMessages(MESSAGE_BAT_STATE_CHANGE_REQ))
             return false;
-        if (isCallActive() && (newState == BluetoothBATransmitter.ENABLE_BA_TRANSMITTER)) {
+        if (isCallActive() && (newState == ENABLE_BA_TRANSMITTER)) {
             Log.d(TAG," setBATState Call active, can't initilze BA ");
             return false;
         }
@@ -709,26 +909,26 @@
         return true;
     }
 
-    public int getBATState() {
-        int state = BluetoothBATransmitter.STATE_DISABLED;
+    protected int getBATState() {
+        int state = STATE_DISABLED;
         Log.d(TAG," getBATState = " + dumpStateString(mCurrStackBATState));
         switch (mCurrStackBATState) {
             case BA_STACK_STATE_IDLE:
             case BA_STACK_STATE_PENDING:
-                state = BluetoothBATransmitter.STATE_DISABLED;
+                state = STATE_DISABLED;
                 break;
             case BA_STACK_STATE_PAUSED:
             case BA_STACK_STATE_AUDIO_PENDING:
-                state = BluetoothBATransmitter.STATE_PAUSED;
+                state = STATE_PAUSED;
                 break;
             case BA_STACK_STATE_STREAMING:
-                state = BluetoothBATransmitter.STATE_PLAYING;
+                state = STATE_PLAYING;
                 break;
         }
         return state;
     }
 
-    public int getDIV() {
+    protected int getDIV() {
         Log.d(TAG," getDIV = " + mCurrDIV);
         if ((mCurrStackBATState == BA_STACK_STATE_IDLE) ||
             (mCurrStackBATState == BA_STACK_STATE_PENDING))
@@ -736,13 +936,13 @@
         return mCurrDIV;
     }
 
-    public long getStreamId() {
+    protected long getStreamId() {
         Log.d(TAG," getStreamId state = " + dumpStateString(mCurrStackBATState));
         // send same ID every time.
         return STREAM_ID_48;
     }
 
-    public BluetoothBAEncryptionKey getEncryptionKey() {
+    protected BluetoothBAEncryptionKey getEncryptionKey() {
         Log.d(TAG," getEncryptionKey state = " + dumpStateString(mCurrStackBATState));
         if ((mCurrStackBATState == BA_STACK_STATE_IDLE) ||
                 (mCurrStackBATState == BA_STACK_STATE_PENDING) )
@@ -750,7 +950,7 @@
         return mCurrEncryptionKey;
     }
 
-    public boolean refreshEncryptionKey() {
+    private boolean refreshEncryptionKey() {
         Log.d(TAG," refreshEncryptionKey state = " + dumpStateString(mCurrStackBATState));
         if (mCurrStackBATState == BA_STACK_STATE_IDLE)
             return false;
@@ -758,91 +958,10 @@
         return true;
     }
 
-    public BluetoothBAStreamServiceRecord getBAServiceRecord() {
+    protected BluetoothBAStreamServiceRecord getBAServiceRecord() {
         Log.d(TAG," getBAServiceRecord state = " + dumpStateString(mCurrStackBATState));
         return mServiceRecord;
     }
-    //Binder object: Must be static class or memory leak may occur
-    private static class BluetoothBATBinder extends IBluetoothBATransmitter.Stub
-        implements IProfileServiceBinder {
-        private BATService mService;
-
-        private BATService getService() {
-            if (!Utils.checkCaller()) {
-                Log.w(TAG,"A2dp call not allowed for non-active user");
-                return null;
-            }
-
-            if (mService != null && mService.isAvailable()) {
-                return mService;
-            }
-            return null;
-        }
-
-        BluetoothBATBinder(BATService svc) {
-            mService = svc;
-        }
-
-        public boolean setBATState(int state) {
-            BATService service = getService();
-            if(service == null) return false;
-            return service.setBATState(state);
-        }
-
-        public int getBATState() {
-            BATService service = getService();
-            if(service == null) return BluetoothBATransmitter.STATE_DISABLED;
-            return service.getBATState();
-        }
-
-        public int getDIV() {
-            BATService service = getService();
-            if(service == null) return 0;
-            return service.getDIV();
-        }
-
-        public long getStreamId() {
-            BATService service = getService();
-            if(service == null) return (long)0;
-            return service.getStreamId();
-        }
-
-        public BluetoothBAEncryptionKey getEncryptionKey() {
-            BATService service = getService();
-            if(service == null) return null;
-            return service.getEncryptionKey();
-        }
-
-        public boolean refreshEncryptionKey() {
-            BATService service = getService();
-            if(service == null) return false;
-            return service.refreshEncryptionKey();
-        }
-
-        public BluetoothBAStreamServiceRecord getBAServiceRecord() {
-            BATService service = getService();
-            if(service == null) return null;
-            return service.getBAServiceRecord();
-        }
-
-        public List<BluetoothDevice> getConnectedDevices() {
-            return new ArrayList<BluetoothDevice>();
-        }
-
-        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-            return new ArrayList<BluetoothDevice>();
-        }
-
-        public int getConnectionState(BluetoothDevice device) {
-            return BluetoothProfile.STATE_DISCONNECTED;
-        }
-
-        @Override
-        public void cleanup() {
-            mService = null;
-        }
-
-    };
 
     private void onBATStateChanged(int newState) {
         Log.d(TAG," onBATStateChanged ( " + newState + " )");
@@ -873,11 +992,11 @@
     }
 
     // make these states in sync with values in hal
-    final static int BA_STACK_STATE_IDLE = 0;
-    final static int BA_STACK_STATE_PENDING = 1;// transitioining between IDLE and non-idle state.
-    final static int BA_STACK_STATE_PAUSED = 2;
-    final static int BA_STACK_STATE_STREAMING = 3;
-    final static int BA_STACK_STATE_AUDIO_PENDING = 4;// transitioning between Pu and Str
+    private final int BA_STACK_STATE_IDLE = 0;
+    private final int BA_STACK_STATE_PENDING = 1;// transitioining between IDLE and non-idle state.
+    private final int BA_STACK_STATE_PAUSED = 2;
+    private final int BA_STACK_STATE_STREAMING = 3;
+    private final int BA_STACK_STATE_AUDIO_PENDING = 4;// transitioning between Pu and Str
 
     private native static void classInitNative();
     private native static void initNative();
diff --git a/packages_apps_bluetooth_ext/src/ba/BluetoothBAEncryptionKey.java b/packages_apps_bluetooth_ext/src/ba/BluetoothBAEncryptionKey.java
new file mode 100644
index 0000000..2c42c23
--- /dev/null
+++ b/packages_apps_bluetooth_ext/src/ba/BluetoothBAEncryptionKey.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.bluetooth.ba;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Class used to identify 128 bit Encryption Key for BA.
+ *
+ * {@hide}
+ */
+public final class BluetoothBAEncryptionKey implements Parcelable {
+    public static final String TAG = "BluetoothBAEncryptionKey";
+
+    private int mFlagType;
+    public static int ENCRYPTION_KEY_LENGTH = 16;// key len in bytes
+    public static int SECURITY_KEY_TYPE_PRIVATE = 0x0001;
+    public static int SECURITY_KEY_TYPE_TEMP    = 0x0002;
+    public static int SECURITY_KEY_FORWARD_ENABLED     = 0x0080;
+    private byte[] mEncryptionKey = new byte[ENCRYPTION_KEY_LENGTH];
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        for (int k =0; k < ENCRYPTION_KEY_LENGTH; k++) {
+            out.writeByte(mEncryptionKey[k]);
+        }
+        out.writeInt(mFlagType);
+    }
+
+    public static final Parcelable.Creator<BluetoothBAEncryptionKey> CREATOR
+            = new Parcelable.Creator<BluetoothBAEncryptionKey>() {
+        public BluetoothBAEncryptionKey createFromParcel(Parcel in) {
+            return new BluetoothBAEncryptionKey(in);
+        }
+
+        public BluetoothBAEncryptionKey[] newArray(int size) {
+            return new BluetoothBAEncryptionKey[size];
+        }
+    };
+
+    private BluetoothBAEncryptionKey(Parcel in) {
+        for (int i = 0; i < ENCRYPTION_KEY_LENGTH; i++) {
+            mEncryptionKey[i] = in.readByte();
+        }
+        mFlagType = in.readInt();
+    }
+
+    /**
+     * Create a new BluetoothBAEncryptionKey object.
+     *
+     * @param byte array contianing encryption key
+     */
+    public BluetoothBAEncryptionKey(byte[] mEncKey, int flagType) {
+        for (int i = 0; i < ENCRYPTION_KEY_LENGTH; i++) {
+            mEncryptionKey[i] = mEncKey[i];
+        }
+        mFlagType = flagType;
+    }
+
+    /**
+     * Get the encryption key.
+     *
+     * @return byte array containing encryption key.
+     */
+    public byte[] getEncryptionKey() {
+        return mEncryptionKey;
+    }
+
+    public int getFlagType() {
+        return mFlagType;
+    }
+}
\ No newline at end of file
diff --git a/packages_apps_bluetooth_ext/src/ba/BluetoothBAStreamServiceRecord.java b/packages_apps_bluetooth_ext/src/ba/BluetoothBAStreamServiceRecord.java
new file mode 100644
index 0000000..173c532
--- /dev/null
+++ b/packages_apps_bluetooth_ext/src/ba/BluetoothBAStreamServiceRecord.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.bluetooth.ba;
+
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+
+/**
+ * Class used to send Broadcast Audio Stream Service Records.
+ */
+public final class BluetoothBAStreamServiceRecord {
+    public static final String TAG = "BluetoothBAStreamServiceRecord";
+
+    public static final int BSSR_TYPE_STREAM_ID       = 0;
+    public static final int BSSR_TYPE_STREAM_ID_LEN   = 1;
+    // actual values would be returned
+
+    // security fields
+    public static final int BSSR_TYPE_SECURITY_ID     = 1;
+    public static final int BSSR_TYPE_SECURITY_ID_LEN = 2;
+    //This stream uses the private key
+    public static final long BSSR_SECURITY_KEY_TYPE_PRIVATE    = 0x0001;
+    //This stream uses the temporary key
+    public static final long BSSR_SECURITY_KEY_TYPE_TEMP       = 0x0002;
+    //This stream does not use encryption
+    public static final long BSSR_SECURITY_ENCRYPT_TYPE_NONE   = 0x0100;
+    //This stream uses AESCCM encryption
+    public static final long BSSR_SECURITY_ENCRYPT_TYPE_AESCCM = 0x0200;
+
+    // codec type fields
+    public static final int BSSR_TYPE_CODEC_TYPE_ID            = 2;
+    public static final int BSSR_TYPE_CODEC_TYPE_ID_LEN        = 1;
+    public static final long BSSR_CODEC_TYPE_CELT              = 0x01;       // CELT CODEC
+
+    // CELT config values, defined below.
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_ID     = 3;// these values are further divided
+    // into 3 values freq, frame_size and frame_samples.
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_ID_LEN = 6;
+
+    public static final int BSSR_TYPE_SCMST_SUPPORT_ID         = 5;
+    public static final int BSSR_TYPE_SCMST_SUPPORT_ID_LEN     = 1;
+    //The recipient must not copy the data in this stream
+    public static final long BSSR_SCMST_SUPPORT_COPY           = 0x01;
+    //The recipient must not forward the data in this stream.
+    public static final long BSSR_SCMST_SUPPORT_FORWARD        = 0x02;
+
+    // Erasure Coding values
+    public static final int BSSR_TYPE_ERASURE_CODE_ID     = 6;
+    public static final int BSSR_TYPE_ERASURE_CODE_ID_LEN = 1;
+    public static final long BSSR_ERASURE_CODE_NONE       = 0x00;//No erasure coding in this stream
+    public static final long BSSR_ERASURE_CODE_2_5        = 0x01;//The stream has a 2,5 coding scheme
+    public static final long BSSR_ERASURE_CODE_3_7        = 0x02;//The stream has a 3,7 coding scheme
+    public static final long BSSR_ERASURE_CODE_3_8        = 0x03;//The stream has a 3,8 coding scheme
+    public static final long BSSR_ERASURE_CODE_3_9        = 0x04;//The stream has a 3,9 coding scheme
+
+    public static final int BSSR_TYPE_CHANNELS_ID         = 7;
+    public static final int BSSR_TYPE_CHANNELS_ID_LEN     = 2;
+    public static final long BSSR_CHANNELS_MONO           = 0x0001;//This stream is mono
+    public static final long BSSR_CHANNELS_STEREO         = 0x0004;//This stream is stereo
+
+    public static final int BSSR_TYPE_SAMPLE_SIZE_ID      = 8;
+    public static final int BSSR_TYPE_SAMPLE_SIZE_ID_LEN  = 1;
+    public static final long BSSR_SAMPLE_SIZE_8_BIT       = 0x01;//This stream is 8-bit samples
+    public static final long BSSR_SAMPLE_SIZE_16_BIT      = 0x02;//This stream is 16-bit samples
+    public static final long BSSR_SAMPLE_SIZE_24_BIT      = 0x04;//This stream id 24-bit samples
+
+    public static final int BSSR_TYPE_AFH_UPDATE_METHOD_ID           = 9;
+    public static final int BSSR_TYPE_AFH_UPDATE_METHOD_ID_LEN       = 1;
+    //This stream does not support AFH channel map updates
+    public static final long BSSR_AFH_CHANNEL_MAP_UPDATE_METHOD_NONE = 0x00;
+    //This stream uses SCM to transport AFH channel map updates from broadcaster to receivers.
+    public static final long BSSR_AFH_CHANNEL_MAP_UPDATE_METHOD_SCM  = 0x01;
+    //This stream uses the triggered CSB sync train method to transport AFH channel map
+    // updates from broadcaster to receivers.
+    public static final long BSSR_AFH_CHANNEL_MAP_UPDATE_METHOD_TRIGGERED_SYNC_TRAIN = 0x02;
+
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FREQ_ID     = 10;
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FREQ_ID_LEN = 2;
+    public static final long BSSR_CODEC_FREQ_8KHZ                   = 0x0001;
+    public static final long BSSR_CODEC_FREQ_11025HZ                = 0x0002;
+    public static final long BSSR_CODEC_FREQ_12KHZ                  = 0x0004;
+    public static final long BSSR_CODEC_FREQ_16KHZ                  = 0x0008;
+    public static final long BSSR_CODEC_FREQ_22050HZ                = 0x0010;
+    public static final long BSSR_CODEC_FREQ_24KHZ                  = 0x0020;
+    public static final long BSSR_CODEC_FREQ_32KHZ                  = 0x0040;
+    public static final long BSSR_CODEC_FREQ_44100HZ                = 0x0080;
+    public static final long BSSR_CODEC_FREQ_48KHZ                  = 0x0100;
+    public static final long BSSR_CODEC_FREQ_64KHZ                  = 0x0200;
+    public static final long BSSR_CODEC_FREQ_88200HZ                = 0x0400;
+    public static final long BSSR_CODEC_FREQ_96KHZ                  = 0x0800;
+    public static final long BSSR_CODEC_FREQ_128KHZ                 = 0x1000;
+    public static final long BSSR_CODEC_FREQ_176400HZ               = 0x2000;
+    public static final long BSSR_CODEC_FREQ_192KHZ                 = 0x4000;
+
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SIZE_ID        = 11;
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SIZE_ID_LEN    = 2;
+    // actual values would be returned
+
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SAMPLES_ID     = 12;
+    public static final int BSSR_TYPE_CODEC_CONFIG_CELT_FRAME_SAMPLES_ID_LEN = 2;
+    // actual values would be returned
+
+    /*
+    * Every single record will be a HashMap of a number of record.
+    * We will have a List of HashMap to send all possible values of stream records.
+    */
+    //private Map<Integer, Long> mServiceRecord = new HashMap<Integer, Long>();
+    int mNumRecords;
+    private List<Map<Integer, Long>> mServiceRecordList = new ArrayList<Map<Integer, Long>>();
+
+    /**
+     * Create a new BA Service Record Object.
+     *
+     * @param number of records
+     */
+    public BluetoothBAStreamServiceRecord(int numRec) {
+        mNumRecords = numRec;
+    }
+
+    /**
+     * Get number of records.
+     *
+     * @return number of records
+     */
+    public int getNumRecords() {
+        return mNumRecords;
+    }
+
+    /**
+     * Add a record value.
+     *
+     * @param streamId: streamId of the record.
+     * @param recordAttribId: one of the record attribute as mentioned above.
+     * @param recordAttribVal: one of the record attribute values as mentioned above.
+     */
+    public void addServiceRecordValue(Long streamId, int recordAttribId, Long recordAttribVal) {
+        // find streamId in the list.
+        if (!mServiceRecordList.isEmpty()) {
+            for (Map<Integer, Long> mServiceRecord: mServiceRecordList) {
+                if (mServiceRecord.containsKey(BSSR_TYPE_STREAM_ID) &&
+                        mServiceRecord.get(BSSR_TYPE_STREAM_ID).equals(streamId)) {
+                    mServiceRecord.put(recordAttribId, recordAttribVal);
+                    return;
+                }
+            }
+        }
+        // either list is empty or matching record not found.
+        Map<Integer, Long> mServiceRecord = new HashMap<Integer, Long>();
+        mServiceRecord.put(BSSR_TYPE_STREAM_ID, streamId);
+        mServiceRecord.put(recordAttribId, recordAttribVal);
+        mServiceRecordList.add(mServiceRecord);
+    }
+
+    /**
+     * Add a record .
+     *
+     * @param serviceRecord: a Map of service attribute id and attribute values.
+     */
+    public void addServiceRecord(Map<Integer, Long> mServiceRecord) {
+        // if a record with same stream_id is existing, we will remove old record and add new one.
+        // We are not going to change this record.
+        if(mServiceRecordList.isEmpty()) {
+            mServiceRecordList.add(mServiceRecord);
+            return;
+        }
+        // check if we have record with same stream id
+        for (Map<Integer, Long> mRecord: mServiceRecordList) {
+            if (mRecord.containsKey(BSSR_TYPE_STREAM_ID) &&
+                mRecord.get(BSSR_TYPE_STREAM_ID).equals(mServiceRecord.get(BSSR_TYPE_STREAM_ID))) {
+                // delete this record from List
+                mServiceRecordList.remove(mRecord);
+            }
+        }
+        // either record is not found, or removed.
+        mServiceRecordList.add(mServiceRecord);
+    }
+
+    /**
+     * Get record values.
+     *
+     * @param streamId: streamId of the record.
+     * @param recordAttribId: one of the record attribute as mentioned above.
+     * @return one of the record attribute values as mentioned above, 0 otherwise
+     */
+    public Long getServiceRecordValue(Long streamId, int recordAttribId) {
+        // find streamId in the list.
+        if (!mServiceRecordList.isEmpty()) {
+            for (Map<Integer, Long> mServiceRecord: mServiceRecordList) {
+                if (mServiceRecord.containsKey(BSSR_TYPE_STREAM_ID) &&
+                        mServiceRecord.get(BSSR_TYPE_STREAM_ID).equals(streamId)) {
+                    return mServiceRecord.get(recordAttribId);
+                }
+            }
+        }
+        // either list is empty or matching record not found.
+        return new Long(0);
+    }
+
+    /**
+     * Get record .
+     *
+     * @param streamId: streamId of the Record to be fetched.
+     * @return servicerecord if streamId matches, empty record otherwise;
+     */
+    public Map<Integer, Long> getServiceRecord( Long streamId) {
+        if(mServiceRecordList.isEmpty())
+            return null;
+        for (Map<Integer, Long> mServiceRecord: mServiceRecordList) {
+            if (mServiceRecord.containsKey(BSSR_TYPE_STREAM_ID) &&
+                    mServiceRecord.get(BSSR_TYPE_STREAM_ID).equals(streamId)) {
+                return mServiceRecord;
+            }
+        }
+        // can't find record, return empty record
+        return null;
+    }
+
+    /**
+     * Get all stored streamIds .
+     *
+     * @return array of all streamIds
+     */
+    public Long[] getStreamIds() {
+        if(mServiceRecordList.isEmpty())
+            return null;
+        Long[] streamIdList = new Long[mServiceRecordList.size()];
+        int k = 0;
+        for (Map<Integer, Long> mServiceRecord: mServiceRecordList) {
+            if (mServiceRecord.containsKey(BSSR_TYPE_STREAM_ID))
+                streamIdList[k++] = mServiceRecord.get(BSSR_TYPE_STREAM_ID);
+        }
+        return streamIdList;
+    }
+}
\ No newline at end of file
diff --git a/BATestApp/src/org/codeaurora/bluetooth/batestapp/GattBroadcastService.java b/packages_apps_bluetooth_ext/src/ba/GattBroadcastService.java
similarity index 77%
rename from BATestApp/src/org/codeaurora/bluetooth/batestapp/GattBroadcastService.java
rename to packages_apps_bluetooth_ext/src/ba/GattBroadcastService.java
index 71052ea..cef1810 100644
--- a/BATestApp/src/org/codeaurora/bluetooth/batestapp/GattBroadcastService.java
+++ b/packages_apps_bluetooth_ext/src/ba/GattBroadcastService.java
@@ -27,7 +27,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-package org.codeaurora.bluetooth.batestapp;
+package com.android.bluetooth.ba;
 
 import android.app.Service;
 
@@ -35,7 +35,6 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothManager;
-
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.BluetoothGattCallback;
 import android.bluetooth.BluetoothGattCharacteristic;
@@ -57,9 +56,8 @@
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
 
-import android.bluetooth.BluetoothBAEncryptionKey;
-import android.bluetooth.BluetoothBAStreamServiceRecord;
-import android.bluetooth.BluetoothBATransmitter;
+import com.android.bluetooth.ba.BluetoothBAEncryptionKey;
+import com.android.bluetooth.ba.BluetoothBAStreamServiceRecord;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -70,20 +68,16 @@
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.Message;
-import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.RemoteException;
-
+import android.os.Binder;
 import android.util.Log;
 
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-
-import org.codeaurora.bluetooth.batestapp.IGattBroadcastService;
-import org.codeaurora.bluetooth.batestapp.IGattBroadcastServiceCallback;
-import org.codeaurora.bluetooth.batestapp.BAAudio;
+import com.android.bluetooth.btservice.ProfileService;
 
 import java.util.List;
 import java.util.UUID;
@@ -92,156 +86,119 @@
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
-public class GattBroadcastService extends Service {
-    private static final String TAG = Utils.TAG + "GattBroadcastService";
+public class GattBroadcastService  {
+    private static final String TAG = "GattBroadcastService";
 
-    public static final UUID GATT_BROADCAST_SERVICE_UUID = UUID.fromString
+    private final UUID GATT_BROADCAST_SERVICE_UUID = UUID.fromString
             ("0000FE06-0000-1000-8000-00805F9B34FB");
-    public static final UUID BROADCAST_VERSION_UUID = UUID.fromString
+    private final UUID BROADCAST_VERSION_UUID = UUID.fromString
             ("0000BCA4-d102-11e1-9b23-00025b00a5a5");
-    public static final UUID BROADCAST_ADDRESS_UUID = UUID.fromString
+    private final UUID BROADCAST_ADDRESS_UUID = UUID.fromString
             ("0000BCA7-d102-11e1-9b23-00025b00a5a5");
-    public static final UUID BROADCAST_STATUS_UUID = UUID.fromString
+    private final UUID BROADCAST_STATUS_UUID = UUID.fromString
             ("0000BCA5-d102-11e1-9b23-00025b00a5a5");
-    public static final UUID BROADCAST_SECKEY_UUID = UUID.fromString
+    private final UUID BROADCAST_SECKEY_UUID = UUID.fromString
             ("0000BCAC-d102-11e1-9b23-00025b00a5a5");
-    public static final UUID BROADCAST_STREAM_SERVICE_RECORDS_UUID = UUID.fromString
+    private final UUID BROADCAST_STREAM_SERVICE_RECORDS_UUID = UUID.fromString
             ("0000BCA6-d102-11e1-9b23-00025b00a5a5");
-    public static final UUID BROADCAST_IDENTIFIER_UUID = UUID.fromString
+    private final UUID BROADCAST_IDENTIFIER_UUID = UUID.fromString
             ("0000BCA8-d102-11e1-9b23-00025b00a5a5");
-    //status codes
-    public static final int BRA_ENABLED_SUCESSS = 0;
-    public static final int BRA_ENABLED_FAILED = 1;
-    public static final int BRA_DISABLED_SUCESSS = 2;
-    public static final int BRA_DISABLED_FAILED = 3;
-    public static final int ASSOCIATE_BCA_RECEIVER_SUCCESS = 4;
-    public static final int ASSOCIATE_BCA_RECEIVER_FAILED = 5;
 
+    // Status Codes
+    private final int BRA_ENABLED_SUCCESS = 0;
+    private final int BRA_ENABLED_FAILED = 1;
+    private final int BRA_DISABLED_SUCCESS = 2;
+    private final int BRA_DISABLED_FAILED = 3;
+    private final int ASSOCIATE_BCA_RECEIVER_SUCCESS = 4;
+    private final int ASSOCIATE_BCA_RECEIVER_FAILED = 5;
 
-    private static final int FETCH_OWN_RANDOM_ADDRESS = 0;
-    private static final int NOTIFY_CB_ASSOCIATE_BCA_RECEIVER = 1;
-    private static final int NOTIFY_CB_CONFIGURE_BRA = 2;
-    private static final int NOTIFY_CB_ONLOST_ONFOUND_RECEIVER = 3;
-    private static final int HANDLER_ARG_NOT_USED = -1;
+    private final int FETCH_OWN_RANDOM_ADDRESS = 0;
+    private final int NOTIFY_CB_ASSOCIATE_BCA_RECEIVER = 1;
+    private final int NOTIFY_CB_CONFIGURE_BRA = 2;
+    private final int NOTIFY_CB_ONLOST_ONFOUND_RECEIVER = 3;
+    private final int HANDLER_ARG_NOT_USED = -1;
+    private final int LE_DEVICE_NAME_MAX_LENGTH = 15;
 
-    private static final int LE_DEVICE_NAME_MAX_LENGTH = 15;
-
-    public BluetoothManager mBluetoothManager;
-    public BAAudio mBAAudio;
-    public BleScanner mBleScanner;
-    public BleAdvertiser mBleAdvertiser;
+    private BluetoothManager mBluetoothManager;
+    private BATService mBATService;
+    private BleScanner mBleScanner;
+    private BleAdvertiser mBleAdvertiser;
     private BluetoothAdapter mBluetoothAdapter;
     private GattBroadcastServiceReceiver mReceiver;
     private GattBroadcastServiceStateMachine mStateMachine;
     private boolean mIsBAPairing = false;
     private BluetoothDevice mDevice = null;
-    private IGattBroadcastServiceCallback mGattBroadcastServiceCallback = null;
     private Context mContext;
     private GattBroadcastServiceMessageHandler mSessionHandler = null;
 
-    private final IGattBroadcastService.Stub mBinder = new IGattBroadcastService.Stub() {
-
-        public void registerCallbacks(IGattBroadcastServiceCallback cb) {
-            Log.i(TAG, "registerCallbacks");
-            if (mGattBroadcastServiceCallback == null)
-                mGattBroadcastServiceCallback = cb;
+    private void configureBroadcastReceiverAssociation(boolean enable) {
+        Log.i(TAG, "configureBroadcastReceiverAssociation :" + enable);
+        //Do not forward BRA Enable/Disable request to state machine, if BT is not on.
+        if (isBluetoothLeOn() && mStateMachine != null) {
+            mStateMachine.sendMessage(GattBroadcastServiceStateMachine
+                    .CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION, enable);
+        } else if (mSessionHandler != null) {
+            int status = enable ? BRA_ENABLED_FAILED: BRA_DISABLED_SUCCESS;
+            mSessionHandler.sendMessage(
+                    mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA, status));
+        } else {
+            Log.i(TAG, "mSessionHandler is null");
         }
+    }
 
-        public void deRegisterCallbacks(IGattBroadcastServiceCallback cb) {
-            Log.i(TAG, "deRegisterCallbacks");
-            if (mGattBroadcastServiceCallback == cb)
-                mGattBroadcastServiceCallback = null;
+    private void associateBCAReceiver(BluetoothDevice device) {
+        Log.i(TAG, "associateBCAReceiver :" + device);
+         //Do not forward associate BCA Receiver request to state machine, if BT is not on.
+        if (isBluetoothLeOn() && mStateMachine != null) {
+            mStateMachine.sendMessage(GattBroadcastServiceStateMachine
+                    .ASSOCIATE_BCA_RECEIVER, device);
+        } else if (mSessionHandler != null) {
+            mSessionHandler.sendMessage(
+                    mSessionHandler.obtainMessage(NOTIFY_CB_ASSOCIATE_BCA_RECEIVER,
+                            ASSOCIATE_BCA_RECEIVER_FAILED, HANDLER_ARG_NOT_USED, device));
+        } else {
+            Log.i(TAG, "mSessionHandler is null");
         }
+    }
 
-        public void configureBroadcastReceiverAssociation(boolean enable) {
-            Log.i(TAG, "configureBroadcastReceiverAssociation :"+enable);
-            //Do not forward BRA Enable/Disable request to state machine, if BT is not on.
-            if (isBluetoothLeOn() && mStateMachine != null) {
-                mStateMachine.sendMessage(GattBroadcastServiceStateMachine
-                        .CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION, enable);
-            } else if (mSessionHandler != null) {
-                int status = enable ? BRA_ENABLED_FAILED: BRA_DISABLED_SUCESSS;
-                mSessionHandler.sendMessage(
-                        mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA, status));
-            } else {
-                Log.i(TAG, "mSessionHandler is null");
-            }
-        }
+    public void start(Context context) {
 
-        public void associateBCAReceiver(BluetoothDevice device) {
-            Log.i(TAG, "associateBCAReceiver :"+device);
-             //Do not forward associate BCA Receiver request to state machine, if BT is not on.
-            if (isBluetoothLeOn() && mStateMachine != null) {
-                mStateMachine.sendMessage(GattBroadcastServiceStateMachine
-                        .ASSOCIATE_BCA_RECEIVER, device);
-            } else if (mSessionHandler != null) {
-                mSessionHandler.sendMessage(
-                        mSessionHandler.obtainMessage(NOTIFY_CB_ASSOCIATE_BCA_RECEIVER,
-                        ASSOCIATE_BCA_RECEIVER_FAILED, HANDLER_ARG_NOT_USED, device));
-            } else {
-                Log.i(TAG, "mSessionHandler is null");
-            }
-        }
-
-    };
-
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        Log.i(TAG, "onCreate");
-
-        mContext = getApplicationContext();
-        if (!initAdapter()) {
-            Log.e(TAG, "onCreate: Unexpected error");
-            stopSelf();
-            return;
-        }
-
-        mBAAudio = new BAAudio(mContext);
-        mBleScanner = new BleScanner(this, mContext);
-        mBleAdvertiser = new BleAdvertiser(this, mContext);
+        mContext = context;
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+        mBleScanner = new BleScanner();
+        mBleAdvertiser = new BleAdvertiser();
 
         HandlerThread thread = new HandlerThread("BluetoothGattBroadcastServiceHandler");
         thread.start();
         Looper looper = thread.getLooper();
 
-        mSessionHandler = new GattBroadcastServiceMessageHandler(this, looper);
-
-        mStateMachine = new GattBroadcastServiceStateMachine(this, mContext);
-        Log.i("GattBroadcastServiceStateMachine", "make");
+        mSessionHandler = new GattBroadcastServiceMessageHandler(looper);
+        mBATService = BATService.getBATService();
+        mStateMachine = new GattBroadcastServiceStateMachine();
         mStateMachine.start();
         mReceiver = new GattBroadcastServiceReceiver();
 
-        IntentFilter filter = new IntentFilter();
-
-        filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_ENCRYPTION_KEY_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED);
-        filter.addAction(BluetoothBATransmitter.ACTION_BAT_STREAMING_ID_CHANGED);
+        IntentFilter filter = new IntentFilter(BATService.ACTION_BAT_STATE_CHANGED);
+        filter.addAction(BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED);
+        filter.addAction(BATService.ACTION_BAT_DIV_CHANGED);
+        filter.addAction(BATService.ACTION_BAT_STREAMING_ID_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
-        registerReceiver(mReceiver, filter);
+        filter.addAction(BATService.ACTION_BAT_BRA_ENABLE);
+        filter.addAction(BATService.ACTION_BAT_BRA_DISABLE);
+        filter.addAction(BATService.ACTION_BAT_ASSOCIATE_BCA_RECEIVER);
+        mContext.registerReceiver(mReceiver, filter);
     }
 
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.i(TAG, " onStartCommand");
-        return START_NOT_STICKY;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        Log.i(TAG, "onDestroy");
-
+    public void stop() {
+        Log.i(TAG, "Stop");
         if (mStateMachine != null) {
             mStateMachine.doQuit();
         }
 
         if (mSessionHandler != null) {
-            //Perform cleanup in Handler running on worker Thread
+            // Perform cleanup in Handler running on Worker Thread
             mSessionHandler.removeCallbacksAndMessages(null);
             Looper looper = mSessionHandler.getLooper();
             if (looper != null) {
@@ -253,46 +210,17 @@
         }
 
         if (mReceiver != null) {
-            unregisterReceiver(mReceiver);
+            mContext.unregisterReceiver(mReceiver);
         }
     }
 
-    @Override
-    public IBinder onBind(Intent intent) {
-        // Return the interface
-        return mBinder;
-    }
-
-    private boolean initAdapter() {
-        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
-        if (mBluetoothManager == null)
-        {
-            Log.e(TAG, "mBluetoothManager is null");
-            return false;
-        }
-
-        mBluetoothAdapter = mBluetoothManager.getAdapter();
-        if (mBluetoothAdapter == null) {
-            Log.e(TAG, "mBluetoothAdapter is null");
-            return false;
-        }
-
-        boolean isBtEnabled = mBluetoothAdapter.isEnabled();
-        if (!isBtEnabled) {
-           Log.e(TAG, "bt is not enabled");
-           return false;
-        }
-
-        return true;
-    }
-
     private boolean isBluetoothLeOn() {
         if (mBluetoothAdapter != null) {
             if (mBluetoothAdapter.isLeEnabled()) {
                 Log.i(TAG, "isBluetoothLeOn: true");
                 return true;
             } else {
-                Log.i(TAG, "bluetooth le state " + mBluetoothAdapter.getLeState());
+                Log.i(TAG, "Bluetooth LE state " + mBluetoothAdapter.getLeState());
             }
         } else {
             Log.i(TAG, " mBluetoothAdapter is null");
@@ -302,12 +230,10 @@
 
 
     private final class GattBroadcastServiceMessageHandler extends Handler {
-        Context mContxt;
-        private static final String TAG = Utils.TAG + "GattBroadcastServiceMessageHandler";
+        private static final String TAG = "GattBroadcastServiceMessageHandler";
 
-        private GattBroadcastServiceMessageHandler(Context contxt, Looper looper) {
+        private GattBroadcastServiceMessageHandler(Looper looper) {
             super(looper);
-            mContxt = contxt;
             Log.i(TAG, "GattBroadcastServiceMessageHandler ");
         }
 
@@ -325,25 +251,20 @@
                 case NOTIFY_CB_ASSOCIATE_BCA_RECEIVER:
                     status = msg.arg1;
                     dev = (BluetoothDevice) msg.obj;
-                    try {
-                        if (mGattBroadcastServiceCallback != null) {
-                            mGattBroadcastServiceCallback
-                                    .onAssociatedBCAReceiver(dev, status);
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "remote exception:  ", e);
-                    }
+                    Intent notify_on_associated_BCA_Receiver = new Intent(
+                            BATService.ACTION_BAT_ON_ASSOCIATED_BCA_RECEIVER);
+                    notify_on_associated_BCA_Receiver.putExtra(BATService.EXTRA_STATUS, status);
+                    notify_on_associated_BCA_Receiver.putExtra(BluetoothDevice.EXTRA_DEVICE, dev);
+                    mContext.sendBroadcast(notify_on_associated_BCA_Receiver,
+                            BATService.BLUETOOTH_PERM_ADMIN);
                     break;
                 case NOTIFY_CB_CONFIGURE_BRA:
                     status = msg.arg1;
-                    try {
-                        if (mGattBroadcastServiceCallback != null) {
-                            mGattBroadcastServiceCallback
-                                    .onConfiguredBroadcastReceiverAssociation(status);
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "remote exception:  ", e);
-                    }
+                    Intent notify_configure_bra = new Intent(
+                            BATService.ACTION_BAT_BRA_STATE_CHANGED);
+                    notify_configure_bra.putExtra(BATService.EXTRA_STATUS, status);
+                    mContext.sendBroadcast(notify_configure_bra,
+                            BATService.BLUETOOTH_PERM_ADMIN);
                     break;
                 case NOTIFY_CB_ONLOST_ONFOUND_RECEIVER:
                     boolean isFound;
@@ -357,12 +278,14 @@
                     } else {
                         return;
                     }
-                    try {
-                        if (mGattBroadcastServiceCallback != null)
-                            mGattBroadcastServiceCallback.onFoundOnLostBCAReceiver(result, isFound);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "remote exception:  ", e);
-                    }
+
+                    Intent notify_onlost_onfound_receiver = new Intent(
+                            BATService.ACTION_BAT_ONFOUND_ONLOST_BCA_RECEIVER);
+                    notify_onlost_onfound_receiver.putExtra(BATService.EXTRA_SCAN_RESULT,
+                            result);
+                    notify_onlost_onfound_receiver.putExtra(BATService.EXTRA_ONFOUND, isFound);
+                    mContext.sendBroadcast(notify_onlost_onfound_receiver,
+                            BATService.BLUETOOTH_PERM_ADMIN);
                     break;
                 default:
                     break;
@@ -370,20 +293,14 @@
         }
     };
 
-    public class BleScanner {
-        private static final String TAG = Utils.TAG + "GattBroadcastService: BleScanner";
+    private class BleScanner {
+        private static final String TAG = "GattBroadcastService: BleScanner";
         private BluetoothLeScanner mScanner;
         private ScanCallback mCallback;
-        private GattBroadcastService mService;
-        private Context mContext;
-        private BluetoothGatt mBluetoothGatt = null;
-        private String mOwnAddress = null;
         private boolean mScanning = false;
 
-        private BleScanner(GattBroadcastService svc, Context context) {
-            Log.i(TAG, "BleScanner ");
-            mService = svc;
-            mContext = context;
+        private BleScanner() {
+            Log.d(TAG, "BleScanner ");
             mCallback = new GattBroadcastReceiverScanCallback();
             mScanner = mBluetoothAdapter.getBluetoothLeScanner();
         }
@@ -397,8 +314,8 @@
                         List<ScanFilter> filters = new ArrayList<ScanFilter>();
                         ScanSettings.Builder settingBuilder = new ScanSettings.Builder();
                         filters.add(new ScanFilter.Builder()
-                                .setServiceSolicitationUuid(new ParcelUuid(GattBroadcastService
-                                        .GATT_BROADCAST_SERVICE_UUID))
+                                .setServiceSolicitationUuid(new ParcelUuid(
+                                        GATT_BROADCAST_SERVICE_UUID))
                                 .build());
                         settingBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
                         settingBuilder.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH |
@@ -436,9 +353,9 @@
     }
 
 
-    public class BleAdvertiser {
+    private class BleAdvertiser {
 
-        private static final String TAG = Utils.TAG + "GattBroadcastService: BleAdvertiser";
+        private static final String TAG = "GattBroadcastService: BleAdvertiser";
         private final int DIV_LENGTH = 2;
         public static final int BRA_ENABLED_STREAMING_PAUSED_ADV_INTERVAL = 160;// 100ms
         public static final int BRA_ENABLED_STREAMING_ACTIVE_ADV_INTERVAL = 160;// 100ms
@@ -447,8 +364,6 @@
         private BluetoothLeAdvertiser mAdvertiser;
         private BluetoothGattServer mGattServer;
         private AdvertisingSetCallback mCallback;
-        private GattBroadcastService mService;
-        private Context mContext;
         private int mState;
 
         //characterstic related object
@@ -469,7 +384,8 @@
          * GATT callbacks
          */
         private final BluetoothGattServerCallback mGattCallbacks = new
-                BluetoothGattServerCallback() {
+            BluetoothGattServerCallback() {
+
             @Override
             public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
 
@@ -532,8 +448,8 @@
 
             @Override
             public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
-                                                    int offset, BluetoothGattCharacteristic
-                                                            characteristic) {
+                    int offset, BluetoothGattCharacteristic characteristic) {
+
                 if (mState == BluetoothProfile.STATE_CONNECTED) {
                     UUID uuid = characteristic.getUuid();
                     byte[] value = {0};
@@ -572,10 +488,8 @@
             }
         };
 
-        private BleAdvertiser(GattBroadcastService svc, Context context) {
+        private BleAdvertiser() {
             Log.i(TAG, "BleAdvertiser");
-            mService = svc;
-            mContext = context;
             mCallback = new GattBroadcastAdvertiseCallback();
             mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
 
@@ -603,8 +517,7 @@
             Log.i(TAG, "startAdvertising:");
             if (isBluetoothLeOn() == false) return;
 
-            AdvertiseData data = generateAdvertiseData(GattBroadcastService
-                    .GATT_BROADCAST_SERVICE_UUID,
+            AdvertiseData data = generateAdvertiseData(GATT_BROADCAST_SERVICE_UUID,
                     getDiv());
 
             AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
@@ -822,9 +735,6 @@
         }
 
         private class BroadcastAddress {
-            public static final int LAP_OFFSET = 0;
-            public static final int UAP_OFFSET = 3;
-            public static final int NAP_OFFSET = 4;
             public static final int BROADCAST_ADDRESS_LENGTH = 7;
             private byte[] mAddress;
 
@@ -1018,8 +928,10 @@
                             Map<Integer, Long> mServiceRecordData = record.getServiceRecord
                                     (streamIDs[i]);
                             for (Map.Entry<Integer, Long> entry : mServiceRecordData.entrySet()) {
+
                                 Log.i(TAG, " Key< " + entry.getKey() + " >" + " value <"
                                         + entry.getValue() + ">");
+
                                 if (entry.getKey() == BluetoothBAStreamServiceRecord
                                         .BSSR_TYPE_SECURITY_ID) {
                                     long entryValue = entry.getValue().longValue();
@@ -1330,6 +1242,14 @@
                     }
                     mDevice = null;
                 }
+            } else if (action.equals(BATService.ACTION_BAT_BRA_ENABLE)) {
+                configureBroadcastReceiverAssociation(true);
+            } else if (action.equals(BATService.ACTION_BAT_BRA_DISABLE)) {
+                configureBroadcastReceiverAssociation(false);
+            } else if (action.equals(BATService.ACTION_BAT_ASSOCIATE_BCA_RECEIVER)) {
+                BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(
+                    BluetoothDevice.EXTRA_DEVICE);
+                associateBCAReceiver(device);
             } else {
                 if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)
                     || isBluetoothLeOn()) {
@@ -1341,7 +1261,7 @@
         }
     }
 
-    public class GattBroadcastServiceStateMachine extends StateMachine {
+    class GattBroadcastServiceStateMachine extends StateMachine {
 
         public static final int INTENT = 1;
         public static final int CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION = 2;
@@ -1353,14 +1273,10 @@
         private BRADisabledStreamingActive mBRADisabledStreamingActive;
         private BRAEnabledStreamingPaused mBRAEnabledStreamingPaused;
         private BRAEnabledStreamingActive mBRAEnabledStreamingActive;
-        private GattBroadcastService mService;
-        private Context mContext;
         private BluetoothAdapter mAdapter;
 
-        private GattBroadcastServiceStateMachine(GattBroadcastService svc, Context context) {
+        private GattBroadcastServiceStateMachine() {
             super("GattBroadcastServiceStateMachine");
-            mService = svc;
-            mContext = context;
             mAdapter = BluetoothAdapter.getDefaultAdapter();
 
             mBRADisabledStreamingDisabled = new BRADisabledStreamingDisabled();
@@ -1375,10 +1291,9 @@
             addState(mBRAEnabledStreamingPaused);
             addState(mBRAEnabledStreamingActive);
 
-            if ( mBAAudio.getBATState() ==
-            BluetoothBATransmitter.STATE_PLAYING) {
+            if (mBATService.getBATState() == BATService.STATE_PLAYING) {
                 setInitialState(mBRADisabledStreamingActive);
-                int div = mBAAudio.getDIV();
+                int div = mBATService.getDIV();
                 Log.d("GattBroadcastServiceStateMachine:", "div = " + div);
                 if (div != -1) {
                     mBleAdvertiser.setDiv(div);
@@ -1390,7 +1305,7 @@
                         BleAdvertiser.BRA_DISABLED_STREAMING_ACTIVE_ADV_INTERVAL);
                 }
             }
-            else if (mBAAudio.getBATState() == BluetoothBATransmitter.STATE_PAUSED)
+            else if (mBATService.getBATState() == BATService.STATE_PAUSED)
                 setInitialState(mBRADisabledStreamingPaused);
             else
                 setInitialState(mBRADisabledStreamingDisabled);
@@ -1430,36 +1345,28 @@
                         String action = intent.getAction();
                         Log.i(TAG, action);
 
-                        if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                    BluetoothAdapter.ERROR);
-                            int prevState = intent.getIntExtra(BluetoothAdapter
-                                    .EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
-                            processBTStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE, -1);
-                            int prevState = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_PREVIOUS_STATE, -1);
+                        if (action.equals(BATService.ACTION_BAT_STATE_CHANGED)) {
+                            int state = intent.getIntExtra(BATService.EXTRA_STATE, -1);
+                            int prevState = intent.getIntExtra(
+                                    BATService.EXTRA_PREVIOUS_STATE, -1);
                             processBATStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
+                        } else if (action.equals(
+                                    BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
                             BluetoothBAEncryptionKey encKey = intent.getParcelableExtra
-                                    (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
+                                    (BATService.EXTRA_ECNRYPTION_KEY);
                             processBATEncryptionKeyChangedEvent(encKey);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                            int div = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_DIV_VALUE, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_DIV_CHANGED)) {
+                            int div = intent.getIntExtra(BATService.EXTRA_DIV_VALUE, -1);
                             processBATDivChangedEvent(div);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_STREAMING_ID_CHANGED)) {
-                            int streamingId = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_STREAM_ID, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_STREAMING_ID_CHANGED)) {
+                            int streamingId = intent.getIntExtra(
+                                    BATService.EXTRA_STREAM_ID, -1);
                             processBATStreamingIdChangedEvent(streamingId);
                         }
                         break;
 
                     case CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION:
-                        boolean enable = (boolean) message.obj;
+                        boolean enable = (Boolean) message.obj;
                         processConfigureBroadcastReceiverAssociation(enable);
                         break;
 
@@ -1481,19 +1388,19 @@
                     return;
                 }
                 switch (state) {
-                    case BluetoothBATransmitter.STATE_PAUSED:
-                        if (mBAAudio != null && mBleAdvertiser != null) {
+                    case BATService.STATE_PAUSED:
+                        if (mBATService != null && mBleAdvertiser != null) {
                             mBleAdvertiser.mBroadcastStreamServiceRecords
-                                .setBroadcastStreamServiceRecords(mBAAudio.getBAServiceRecord());
+                                .setBroadcastStreamServiceRecords(mBATService.getBAServiceRecord());
 
-                            processBATDivChangedEvent(mBAAudio.getDIV());
+                            processBATDivChangedEvent(mBATService.getDIV());
 
                             mBleAdvertiser.startAdvertising(false,
                                 BleAdvertiser.BRA_DISABLED_STREAMING_PAUSED_ADV_INTERVAL);
 
                             transitionTo(mBRADisabledStreamingPaused);
                         } else {
-                            Log.e(TAG, "mBAAudio: " + mBAAudio + " mBleAdvertiser: "
+                            Log.e(TAG, "mBATService: " + mBATService + " mBleAdvertiser: "
                                     + mBleAdvertiser);
                         }
                         break;
@@ -1503,22 +1410,6 @@
                 }
             }
 
-            private void processBTStateChangedEvent(int state, int prevState) {
-                Log.i(TAG, "processBTStateChangedEvent prevState " + prevState
-                        + " state: " + state);
-                if (prevState == state) {
-                    return;
-                }
-                switch (state) {
-                    case BluetoothAdapter.STATE_BLE_TURNING_OFF:
-                        stopSelf();
-                        break;
-                    default:
-                        Log.w(TAG, "state " + state + " not handled");
-                        break;
-                }
-            }
-
             private void processBATEncryptionKeyChangedEvent(BluetoothBAEncryptionKey encKey) {
                 Log.i(TAG, "processBATEncryptionKeyChangedEvent encKey:" + encKey);
                 if (encKey != null) {
@@ -1579,30 +1470,20 @@
                         String action = intent.getAction();
                         Log.i(TAG, action);
 
-                        if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                    BluetoothAdapter.ERROR);
-                            int prevState = intent.getIntExtra(BluetoothAdapter
-                                    .EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
-                            processBTStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE, -1);
-                            int prevState = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_PREVIOUS_STATE, -1);
+                        if (action.equals(BATService.ACTION_BAT_STATE_CHANGED)) {
+                            int state = intent.getIntExtra(BATService.EXTRA_STATE, -1);
+                            int prevState = intent.getIntExtra(
+                                BATService.EXTRA_PREVIOUS_STATE, -1);
                             processBATStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
+                        } else if (action.equals(BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
                             BluetoothBAEncryptionKey encKey = intent.getParcelableExtra
-                                    (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
+                                    (BATService.EXTRA_ECNRYPTION_KEY);
                             processBATEncryptionKeyChangedEvent(encKey);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                            int div = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_DIV_VALUE, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_DIV_CHANGED)) {
+                            int div = intent.getIntExtra(BATService.EXTRA_DIV_VALUE, -1);
                             processBATDivChangedEvent(div);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_STREAMING_ID_CHANGED)) {
-                            int streamingId = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_STREAM_ID, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_STREAMING_ID_CHANGED)) {
+                            int streamingId = intent.getIntExtra(BATService.EXTRA_STREAM_ID, -1);
                             processBATStreamingIdChangedEvent(streamingId);
                         }
                         break;
@@ -1628,7 +1509,7 @@
                     return;
                 }
                 switch (state) {
-                    case BluetoothBATransmitter.STATE_DISABLED:
+                    case BATService.STATE_DISABLED:
                         if (mBleAdvertiser != null) {
                             mBleAdvertiser.stopAdvertising();
                             transitionTo(mBRADisabledStreamingDisabled);
@@ -1636,7 +1517,7 @@
                             Log.e(TAG, "mBleAdvertiser is null");
                         }
                         break;
-                    case BluetoothBATransmitter.STATE_PLAYING:
+                    case BATService.STATE_PLAYING:
                         if (mBleAdvertiser != null) {
                             mBleAdvertiser.stopAdvertising();
 
@@ -1656,27 +1537,6 @@
                 }
             }
 
-            private void processBTStateChangedEvent(int state, int prevState) {
-                Log.i(TAG, "processBTStateChangedEvent prevState: " + prevState
-                        + " state: " + state);
-                if (prevState == state) {
-                    return;
-                }
-                switch (state) {
-                    case BluetoothAdapter.STATE_BLE_ON:
-                        if (mBleAdvertiser != null) {
-                            mBleAdvertiser.stopAdvertising();
-                            transitionTo(mBRADisabledStreamingDisabled);
-                        } else {
-                            Log.e(TAG, "mBleAdvertiser is null");
-                        }
-                        break;
-                    default:
-                        Log.w(TAG, "state " + state + " not handled");
-                        break;
-                }
-            }
-
             private void processBATEncryptionKeyChangedEvent(BluetoothBAEncryptionKey encKey) {
                 Log.i(TAG, "processBATEncryptionKeyChangedEvent encKey:" + encKey);
                 if (encKey != null) {
@@ -1694,7 +1554,7 @@
                 }
             }
 
-            private void processBATStreamingIdChangedEvent(int streamingId) {
+            private void processBATStreamingIdChangedEvent(long streamingId) {
                 Log.i(TAG, "processBATStreamingIdChangedEvent streamingId:" + streamingId);
                 if (streamingId != -1) {
                     mBleAdvertiser.mBroadcastStatus.setActiveStreamId((byte) streamingId);
@@ -1704,14 +1564,14 @@
             private void processConfigureBroadcastReceiverAssociation(boolean enable) {
                 Log.i(TAG, "processConfigureBroadcastReceiverAssociation enable:" + enable);
                 if (enable) {
-                    if (mBAAudio != null && mSessionHandler != null
+                    if (mBATService != null && mSessionHandler != null
                         && mBleScanner != null && mBleAdvertiser != null) {
 
                         mBleAdvertiser.stopAdvertising();
 
-                        processBATDivChangedEvent(mBAAudio.getDIV());
-                        processBATStreamingIdChangedEvent(mBAAudio.getStreamId());
-                        processBATEncryptionKeyChangedEvent(mBAAudio.getEncKey());
+                        processBATDivChangedEvent(mBATService.getDIV());
+                        processBATStreamingIdChangedEvent(mBATService.getStreamId());
+                        processBATEncryptionKeyChangedEvent(mBATService.getEncryptionKey());
 
                         mBleAdvertiser.startAdvertising(true,
                                 BleAdvertiser.BRA_ENABLED_STREAMING_PAUSED_ADV_INTERVAL);
@@ -1722,12 +1582,12 @@
 
                         mSessionHandler.sendMessage(
                                 mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA,
-                                BRA_ENABLED_SUCESSS));
+                                BRA_ENABLED_SUCCESS));
 
                     } else {
                         Log.e(TAG, "mSessionHandler: " + mSessionHandler
-                                + " mBAAudio: " + mBAAudio + " mBleScanner: " + mBleScanner
-                                + " mBleAdvertiser: " + mBleAdvertiser);
+                                + " mBATService: " + mBATService + " mBleScanner: "
+                                + mBleScanner + " mBleAdvertiser: " + mBleAdvertiser);
                         mSessionHandler.sendMessage(
                                 mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA,
                                 BRA_ENABLED_FAILED));
@@ -1769,36 +1629,26 @@
                         String action = intent.getAction();
                         Log.i(TAG, action);
 
-                        if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                    BluetoothAdapter.ERROR);
-                            int prevState = intent.getIntExtra(BluetoothAdapter
-                                    .EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
-                            processBTStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE, -1);
-                            int prevState = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_PREVIOUS_STATE, -1);
+                        if (action.equals(BATService.ACTION_BAT_STATE_CHANGED)) {
+                            int state = intent.getIntExtra(BATService.EXTRA_STATE, -1);
+                            int prevState = intent.getIntExtra(
+                                    BATService.EXTRA_PREVIOUS_STATE, -1);
                             processBATStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
+                        } else if (action.equals(BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
                             BluetoothBAEncryptionKey encKey = intent.getParcelableExtra
-                                    (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
+                                    (BATService.EXTRA_ECNRYPTION_KEY);
                             processBATEncryptionKeyChangedEvent(encKey);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                            int div = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_DIV_VALUE, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_DIV_CHANGED)) {
+                            int div = intent.getIntExtra(BATService.EXTRA_DIV_VALUE, -1);
                             processBATDivChangedEvent(div);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_STREAMING_ID_CHANGED)) {
-                            int streamingId = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_STREAM_ID, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_STREAMING_ID_CHANGED)) {
+                            int streamingId = intent.getIntExtra(BATService.EXTRA_STREAM_ID, -1);
                             processBATStreamingIdChangedEvent(streamingId);
                         }
                         break;
 
                     case CONFIGURE_BROADCAST_RECEIVER_ASSOCIATION:
-                        boolean enable = (boolean) message.obj;
+                        boolean enable = (Boolean) message.obj;
                         processConfigureBroadcastReceiverAssociation(enable);
                         break;
 
@@ -1820,7 +1670,7 @@
                     return;
                 }
                 switch (state) {
-                    case BluetoothBATransmitter.STATE_DISABLED:
+                    case BATService.STATE_DISABLED:
                         if (mBleAdvertiser != null) {
                             mBleAdvertiser.stopAdvertising();
                             transitionTo(mBRADisabledStreamingDisabled);
@@ -1828,7 +1678,7 @@
                             Log.e(TAG, "mBleAdvertiser is null");
                         }
                         break;
-                    case BluetoothBATransmitter.STATE_PAUSED:
+                    case BATService.STATE_PAUSED:
                         if (mBleAdvertiser != null) {
                             mBleAdvertiser.stopAdvertising();
 
@@ -1848,27 +1698,6 @@
                 }
             }
 
-            private void processBTStateChangedEvent(int state, int prevState) {
-                Log.i(TAG, "processBTStateChangedEvent prevState: " + prevState
-                        + " state: " + state);
-                if (prevState == state) {
-                    return;
-                }
-                switch (state) {
-                    case BluetoothAdapter.STATE_BLE_ON:
-                        if (mBleAdvertiser != null) {
-                            mBleAdvertiser.stopAdvertising();
-                            transitionTo(mBRADisabledStreamingDisabled);
-                        } else {
-                            Log.i(TAG, "mBleAdvertiser is null");
-                        }
-                        break;
-                    default:
-                        Log.w(TAG, "state " + state + " not handled");;
-                        break;
-                }
-            }
-
             private void processBATEncryptionKeyChangedEvent(BluetoothBAEncryptionKey encKey) {
                 Log.i(TAG, "processBATEncryptionKeyChangedEvent encKey:" + encKey);
                 if (encKey != null) {
@@ -1886,7 +1715,7 @@
                 }
             }
 
-            private void processBATStreamingIdChangedEvent(int streamingId) {
+            private void processBATStreamingIdChangedEvent(long streamingId) {
                 Log.i(TAG, "processBATStreamingIdChangedEvent streamingId:" + streamingId);
                 if (streamingId != -1) {
                     mBleAdvertiser.mBroadcastStatus.setActiveStreamId((byte) streamingId);
@@ -1896,14 +1725,14 @@
             private void processConfigureBroadcastReceiverAssociation(boolean enable) {
                 Log.i(TAG, "processConfigureBroadcastReceiverAssociation enable:" + enable);
                 if (enable) {
-                    if (mBAAudio != null && mSessionHandler != null
+                    if (mBATService != null && mSessionHandler != null
                         && mBleScanner != null && mBleAdvertiser != null) {
 
                         mBleAdvertiser.stopAdvertising();
 
-                        processBATDivChangedEvent(mBAAudio.getDIV());
-                        processBATStreamingIdChangedEvent(mBAAudio.getStreamId());
-                        processBATEncryptionKeyChangedEvent(mBAAudio.getEncKey());
+                        processBATDivChangedEvent(mBATService.getDIV());
+                        processBATStreamingIdChangedEvent(mBATService.getStreamId());
+                        processBATEncryptionKeyChangedEvent(mBATService.getEncryptionKey());
 
                         mBleAdvertiser.startAdvertising(true,
                                 BleAdvertiser.BRA_ENABLED_STREAMING_ACTIVE_ADV_INTERVAL);
@@ -1914,12 +1743,12 @@
 
                         mSessionHandler.sendMessage(
                                 mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA,
-                                BRA_ENABLED_SUCESSS));
+                                BRA_ENABLED_SUCCESS));
 
                     } else {
                         Log.e(TAG, "mSessionHandler: " + mSessionHandler
-                                + " mBAAudio: " + mBAAudio + " mBleScanner: " + mBleScanner
-                                + " mBleAdvertiser: " + mBleAdvertiser);
+                                + " mBATService: " + mBATService + " mBleScanner: "
+                                + mBleScanner + " mBleAdvertiser: " + mBleAdvertiser);
                         mSessionHandler.sendMessage(
                                 mSessionHandler.obtainMessage(NOTIFY_CB_CONFIGURE_BRA,
                                 BRA_ENABLED_FAILED));
@@ -1959,30 +1788,20 @@
                         String action = intent.getAction();
                         Log.i(TAG, action);
 
-                        if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                    BluetoothAdapter.ERROR);
-                            int prevState = intent.getIntExtra(BluetoothAdapter
-                                    .EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
-                            processBTStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE, -1);
-                            int prevState = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_PREVIOUS_STATE, -1);
+                        if (action.equals(BATService.ACTION_BAT_STATE_CHANGED)) {
+                            int state = intent.getIntExtra(BATService.EXTRA_STATE, -1);
+                            int prevState = intent.getIntExtra(
+                                    BATService.EXTRA_PREVIOUS_STATE, -1);
                             processBATStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
+                        } else if (action.equals(BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
                             BluetoothBAEncryptionKey encKey = intent.getParcelableExtra
-                                    (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
+                                    (BATService.EXTRA_ECNRYPTION_KEY);
                             processBATEncryptionKeyChangedEvent(encKey);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                            int div = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_DIV_VALUE, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_DIV_CHANGED)) {
+                            int div = intent.getIntExtra(BATService.EXTRA_DIV_VALUE, -1);
                             processBATDivChangedEvent(div);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_STREAMING_ID_CHANGED)) {
-                            int streamingId = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_STREAM_ID, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_STREAMING_ID_CHANGED)) {
+                            int streamingId = intent.getIntExtra(BATService.EXTRA_STREAM_ID, -1);
                             processBATStreamingIdChangedEvent(streamingId);
                         }
                         break;
@@ -2010,7 +1829,7 @@
                     return;
                 }
                 switch (state) {
-                    case BluetoothBATransmitter.STATE_DISABLED:
+                    case BATService.STATE_DISABLED:
                         if (mBleScanner != null) {
                             mBleScanner.discoverBroadcastAudioReceiver(false);
                         } else {
@@ -2026,7 +1845,7 @@
 
                         transitionTo(mBRADisabledStreamingDisabled);
                         break;
-                    case BluetoothBATransmitter.STATE_PLAYING:
+                    case BATService.STATE_PLAYING:
                         transitionTo(mBRAEnabledStreamingActive);
                         break;
                     default:
@@ -2035,35 +1854,6 @@
                 }
             }
 
-            private void processBTStateChangedEvent(int state, int prevState) {
-                Log.i(TAG, "processBTStateChangedEvent prevState: " + prevState
-                        + " state: " + state);
-                if (prevState == state) {
-                    return;
-                }
-                switch (state) {
-                    case BluetoothAdapter.STATE_BLE_ON:
-                        if (mBleScanner != null) {
-                            mBleScanner.discoverBroadcastAudioReceiver(false);
-                        } else {
-                            Log.i(TAG, "mBleScanner is null");
-                        }
-
-                        if (mBleAdvertiser != null) {
-                            mBleAdvertiser.closeServer();
-                            mBleAdvertiser.stopAdvertising();
-                        } else {
-                            Log.i(TAG, "mBleAdvertiser is null");
-                        }
-
-                        transitionTo(mBRADisabledStreamingDisabled);
-                        break;
-                    default:
-                        Log.w(TAG, "state " + state + " not handled");
-                        break;
-                }
-            }
-
             private void processBATEncryptionKeyChangedEvent(BluetoothBAEncryptionKey encKey) {
                 Log.i(TAG, "processBATEncryptionKeyChangedEvent encKey:" + encKey);
                 if (encKey != null) {
@@ -2081,7 +1871,7 @@
                 }
             }
 
-            private void processBATStreamingIdChangedEvent(int streamingId) {
+            private void processBATStreamingIdChangedEvent(long streamingId) {
                 Log.i(TAG, "processBATStreamingIdChangedEvent streamingId:" + streamingId);
                 if (streamingId != -1) {
                     mBleAdvertiser.mBroadcastStatus.setActiveStreamId((byte) streamingId);
@@ -2093,7 +1883,7 @@
                 if (enable) {
                     Log.i(TAG, "Unexpected, Ignoring BRA enable");
                 } else {
-                    int status = BRA_DISABLED_SUCESSS;
+                    int status = BRA_DISABLED_SUCCESS;
                     if (mBleScanner != null) {
                         mBleScanner.discoverBroadcastAudioReceiver(false);
                     } else {
@@ -2156,30 +1946,20 @@
                         String action = intent.getAction();
                         Log.i(TAG, action);
 
-                        if (action.equals(BluetoothAdapter.ACTION_BLE_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                    BluetoothAdapter.ERROR);
-                            int prevState = intent.getIntExtra(BluetoothAdapter
-                                    .EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
-                            processBTStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_STATE_CHANGED)) {
-                            int state = intent.getIntExtra(BluetoothBATransmitter.EXTRA_STATE, -1);
-                            int prevState = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_PREVIOUS_STATE, -1);
+                        if (action.equals(BATService.ACTION_BAT_STATE_CHANGED)) {
+                            int state = intent.getIntExtra(BATService.EXTRA_STATE, -1);
+                            int prevState = intent.getIntExtra(
+                                    BATService.EXTRA_PREVIOUS_STATE, -1);
                             processBATStateChangedEvent(state, prevState);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
+                        } else if (action.equals(BATService.ACTION_BAT_ENCRYPTION_KEY_CHANGED)) {
                             BluetoothBAEncryptionKey encKey = intent.getParcelableExtra
-                                    (BluetoothBATransmitter.EXTRA_ECNRYPTION_KEY);
+                                    (BATService.EXTRA_ECNRYPTION_KEY);
                             processBATEncryptionKeyChangedEvent(encKey);
-                        } else if (action.equals(BluetoothBATransmitter.ACTION_BAT_DIV_CHANGED)) {
-                            int div = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_DIV_VALUE, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_DIV_CHANGED)) {
+                            int div = intent.getIntExtra(BATService.EXTRA_DIV_VALUE, -1);
                             processBATDivChangedEvent(div);
-                        } else if (action.equals(BluetoothBATransmitter
-                                .ACTION_BAT_STREAMING_ID_CHANGED)) {
-                            int streamingId = intent.getIntExtra(BluetoothBATransmitter
-                                    .EXTRA_STREAM_ID, -1);
+                        } else if (action.equals(BATService.ACTION_BAT_STREAMING_ID_CHANGED)) {
+                            int streamingId = intent.getIntExtra(BATService.EXTRA_STREAM_ID, -1);
                             processBATStreamingIdChangedEvent(streamingId);
                         }
                         break;
@@ -2205,7 +1985,7 @@
                     return;
                 }
                 switch (state) {
-                    case BluetoothBATransmitter.STATE_DISABLED:
+                    case BATService.STATE_DISABLED:
                         if (mBleScanner != null) {
                             mBleScanner.discoverBroadcastAudioReceiver(false);
                         } else {
@@ -2221,7 +2001,7 @@
 
                         transitionTo(mBRADisabledStreamingDisabled);
                         break;
-                    case BluetoothBATransmitter.STATE_PAUSED:
+                    case BATService.STATE_PAUSED:
                         transitionTo(mBRAEnabledStreamingPaused);
                         break;
                     default:
@@ -2230,35 +2010,6 @@
                 }
             }
 
-            private void processBTStateChangedEvent(int state, int prevState) {
-                Log.i(TAG, "processBTStateChangedEvent prevState: " + prevState
-                        + " state: " + state);
-                if (prevState == state) {
-                    return;
-                }
-                switch (state) {
-                    case BluetoothAdapter.STATE_BLE_ON:
-                        if (mBleScanner != null) {
-                            mBleScanner.discoverBroadcastAudioReceiver(false);
-                        } else {
-                            Log.i(TAG, "mBleScanner is null");
-                        }
-
-                        if (mBleAdvertiser != null) {
-                            mBleAdvertiser.closeServer();
-                            mBleAdvertiser.stopAdvertising();
-                        } else {
-                            Log.i(TAG, "mBleAdvertiser is null");
-                        }
-
-                        transitionTo(mBRADisabledStreamingDisabled);
-                        break;
-                    default:
-                        Log.w(TAG, "state " + state + " not handled");
-                        break;
-                }
-            }
-
             private void processBATEncryptionKeyChangedEvent(BluetoothBAEncryptionKey encKey) {
                 Log.i(TAG, "processBATEncryptionKeyChangedEvent encKey:" + encKey);
                 if (encKey != null) {
@@ -2276,7 +2027,7 @@
                 }
             }
 
-            private void processBATStreamingIdChangedEvent(int streamingId) {
+            private void processBATStreamingIdChangedEvent(long streamingId) {
                 Log.i(TAG, "processBATStreamingIdChangedEvent streamingId:" + streamingId);
                 if (streamingId != -1) {
                     mBleAdvertiser.mBroadcastStatus.setActiveStreamId((byte) streamingId);
@@ -2288,7 +2039,7 @@
                 if (enable) {
                     Log.i(TAG, "Unexpected, Ignoring BRA enable");
                 } else {
-                    int status = BRA_DISABLED_SUCESSS;
+                    int status = BRA_DISABLED_SUCCESS;
                     if (mBleScanner != null) {
                         mBleScanner.discoverBroadcastAudioReceiver(false);
                     } else {
@@ -2315,7 +2066,6 @@
                     } else {
                         Log.e(TAG, "mSessionHandler is null");
                     }
-
                 }
             }
 
@@ -2323,7 +2073,6 @@
                 Log.i(TAG, "processAssociateBCAReceiver BD address:" + device.getAddress());
                 mBleAdvertiser.connectDevice(device);
             }
-
         }
     }
-}
+}
\ No newline at end of file
diff --git a/packages_apps_bluetooth_ext/src/btservice/Vendor.java b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
index 685807a..31338db 100644
--- a/packages_apps_bluetooth_ext/src/btservice/Vendor.java
+++ b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
@@ -56,6 +56,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothQualityReport;
 import com.android.bluetooth.Utils;
 
 import android.content.Intent;
@@ -184,6 +185,31 @@
         mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
     }
 
+    private void bqrDeliver(byte[] remoteAddr,
+            int lmpVer, int lmpSubVer, int manufacturerId, byte[] bqrRawData) {
+        String remoteName = "";
+        int remoteCoD = 0;
+        String addr = Utils.getAddressStringFromByte(remoteAddr);
+        if (addr != null) {
+            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(addr);
+            remoteName = mService.getRemoteName(device);
+            remoteCoD = mService.getRemoteClass(device);
+        }
+
+        BluetoothQualityReport bqr;
+        try {
+            bqr = new BluetoothQualityReport(addr, lmpVer, lmpSubVer,
+                    manufacturerId, remoteName, remoteCoD, bqrRawData);
+        } catch (Exception e) {
+            Log.e(TAG, "bqrDeliver: failed to create bqr", e);
+            return;
+        }
+        Log.d(TAG, "" + bqr);
+        Intent intent = new Intent(BluetoothDevice.ACTION_REMOTE_ISSUE_OCCURRED);
+        intent.putExtra(BluetoothDevice.EXTRA_BQR, bqr);
+        mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
+    }
+
     void ssr_cleanup_callback() {
         Log.e(TAG,"ssr_cleanup_callback");
         mService.ssrCleanupCallback();
diff --git a/packages_apps_bluetooth_ext/src/hfp/vendorhfservice.java b/packages_apps_bluetooth_ext/src/hfp/vendorhfservice.java
index aab40ef..2309ee1 100644
--- a/packages_apps_bluetooth_ext/src/hfp/vendorhfservice.java
+++ b/packages_apps_bluetooth_ext/src/hfp/vendorhfservice.java
@@ -74,10 +74,10 @@
     }
 
     private void onTwsBatteryStateCallback(String atString, byte[] address) {
-        /*HeadsetStackEvent event = new HeadsetStackEvent(
-                HeadsetStackEvent.EVENT_TYPE_TWSP_BATTERY_STATE, atString,
-                getDevice(address));
-        sendMessageToService(event);*/
+        HeadsetStackEvent event =
+                new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_TWSP_BATTERY_STATE, atString,
+                                    getDevice(address));
+        sendMessageToService(event);
     }
 
     private void sendMessageToService(HeadsetStackEvent event) {
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
index 443cfb1..c91e380 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapFixes.java
@@ -273,4 +273,10 @@
         }
         return !ismap14Enabled;
     }
+
+    static boolean isRebonded(BluetoothDevice remoteDevice) {
+        String isRebonded = mapSdpResponse.get(
+            remoteDevice.getAddress().substring(0,8));
+        return ((isRebonded != null) && isRebonded.equalsIgnoreCase("Y"));
+    }
 }
diff --git a/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java b/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
index a4b647b..b1307a0 100644
--- a/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
+++ b/packages_apps_bluetooth_ext/src/pbap/BluetoothPbapFixes.java
@@ -521,4 +521,11 @@
                 mNotificationManager.cancelAll();
         }
     }
+
+    static boolean isRebonded(BluetoothDevice remoteDevice) {
+        String isRebonded = PbapSdpResponse.get(
+                remoteDevice.getAddress().substring(0,8));
+        return ((isRebonded != null) && isRebonded.equalsIgnoreCase("Y"));
+    }
+
 }
diff --git a/system_bt_ext/bta/include/bta_ag_swb.h b/system_bt_ext/bta/include/bta_ag_swb.h
index a65f3c3..3fb096e 100644
--- a/system_bt_ext/bta/include/bta_ag_swb.h
+++ b/system_bt_ext/bta/include/bta_ag_swb.h
@@ -46,7 +46,7 @@
 #define  BTA_AG_LOCAL_RES_QCS 0x109
 
 #define LEGACY_CODECS 2
-#define SWB_ESCO_NUM_CODECS 1
+#define SWB_ESCO_NUM_CODECS 4
 
 void bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd, int16_t int_arg, tBTA_AG_VAL val);
 void bta_ag_send_qac(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
@@ -54,6 +54,7 @@
 tBTA_AG_PEER_CODEC bta_ag_parse_qac(tBTA_AG_SCB* p_scb, char* p_s);
 
 const enh_esco_params_t default_esco_swb_parameters[SWB_ESCO_NUM_CODECS] = {
+     // ESCO_CODEC_SWB_Q0
      {.transmit_bandwidth = TXRX_64KBITS_RATE,
      .receive_bandwidth = TXRX_64KBITS_RATE,
      .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
@@ -84,6 +85,103 @@
      .output_transport_unit_size = 0x00,
      .max_latency_ms = 14,
      .packet_types = 0x0380,
-     .retransmission_effort = ESCO_RETRANSMISSION_QUALITY}};
+     .retransmission_effort = ESCO_RETRANSMISSION_QUALITY},
+     // ESCO_CODEC_SWB_Q1
+     {.transmit_bandwidth = TXRX_64KBITS_RATE,
+     .receive_bandwidth = TXRX_64KBITS_RATE,
+     .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                                .company_id = 0x000A,
+                                .vendor_specific_codec_id = 0x0000},
+     .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                               .company_id = 0x000A,
+                               .vendor_specific_codec_id = 0x0000},
+     .transmit_codec_frame_size = 60,
+     .receive_codec_frame_size = 60,
+     .input_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .output_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                             .company_id = 0x0000,
+                             .vendor_specific_codec_id = 0x0000},
+     .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                              .company_id = 0x0000,
+                              .vendor_specific_codec_id = 0x0000},
+     .input_coded_data_size = 16,
+     .output_coded_data_size = 16,
+     .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .input_pcm_payload_msb_position = 0,
+     .output_pcm_payload_msb_position = 0,
+     .input_data_path = ESCO_DATA_PATH_PCM,
+     .output_data_path = ESCO_DATA_PATH_PCM,
+     .input_transport_unit_size = 0x00,
+     .output_transport_unit_size = 0x00,
+     .max_latency_ms = 14,
+     .packet_types = 0x0380,
+     .retransmission_effort = ESCO_RETRANSMISSION_QUALITY},
+     // ESCO_CODEC_SWB_Q2
+     {.transmit_bandwidth = TXRX_64KBITS_RATE,
+     .receive_bandwidth = TXRX_64KBITS_RATE,
+     .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                                .company_id = 0x000A,
+                                .vendor_specific_codec_id = 0x0000},
+     .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                               .company_id = 0x000A,
+                               .vendor_specific_codec_id = 0x0000},
+     .transmit_codec_frame_size = 60,
+     .receive_codec_frame_size = 60,
+     .input_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .output_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                             .company_id = 0x0000,
+                             .vendor_specific_codec_id = 0x0000},
+     .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                              .company_id = 0x0000,
+                              .vendor_specific_codec_id = 0x0000},
+     .input_coded_data_size = 16,
+     .output_coded_data_size = 16,
+     .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .input_pcm_payload_msb_position = 0,
+     .output_pcm_payload_msb_position = 0,
+     .input_data_path = ESCO_DATA_PATH_PCM,
+     .output_data_path = ESCO_DATA_PATH_PCM,
+     .input_transport_unit_size = 0x00,
+     .output_transport_unit_size = 0x00,
+     .max_latency_ms = 14,
+     .packet_types = 0x0380,
+     .retransmission_effort = ESCO_RETRANSMISSION_QUALITY},
+     // ESCO_CODEC_SWB_Q3
+     {.transmit_bandwidth = TXRX_64KBITS_RATE,
+     .receive_bandwidth = TXRX_64KBITS_RATE,
+     .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                                .company_id = 0x000A,
+                                .vendor_specific_codec_id = 0x0000},
+     .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS,
+                               .company_id = 0x000A,
+                               .vendor_specific_codec_id = 0x0000},
+     .transmit_codec_frame_size = 60,
+     .receive_codec_frame_size = 60,
+     .input_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .output_bandwidth = INPUT_OUTPUT_128K_RATE,
+     .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                             .company_id = 0x0000,
+                             .vendor_specific_codec_id = 0x0000},
+     .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+                              .company_id = 0x0000,
+                              .vendor_specific_codec_id = 0x0000},
+     .input_coded_data_size = 16,
+     .output_coded_data_size = 16,
+     .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+     .input_pcm_payload_msb_position = 0,
+     .output_pcm_payload_msb_position = 0,
+     .input_data_path = ESCO_DATA_PATH_PCM,
+     .output_data_path = ESCO_DATA_PATH_PCM,
+     .input_transport_unit_size = 0x00,
+     .output_transport_unit_size = 0x00,
+     .max_latency_ms = 14,
+     .packet_types = 0x0380,
+     .retransmission_effort = ESCO_RETRANSMISSION_QUALITY}
+};
 
 #endif//_BTA_AG_SWB_H_
diff --git a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
index d2c25c4..7068c15 100644
--- a/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
+++ b/system_bt_ext/bta/tws_plus/ag/bta_ag_twsp_dev.cc
@@ -596,6 +596,11 @@
     int i;
     char* p;
 
+    if (p_s == NULL) {
+        APPL_TRACE_ERROR("%s: Invalid Argument", __func__);
+        return false;
+    }
+
     for (i = 0; i < 2; i++) {
         /* skip to comma delimiter */
         for (p = p_s; *p != ',' && *p != 0; p++)
diff --git a/system_bt_ext/btconfigstore/bt_configstore.cc b/system_bt_ext/btconfigstore/bt_configstore.cc
index 4f91bbf..0e05453 100644
--- a/system_bt_ext/btconfigstore/bt_configstore.cc
+++ b/system_bt_ext/btconfigstore/bt_configstore.cc
@@ -49,12 +49,15 @@
 
 #include <hwbinder/ProcessState.h>
 #include <string.h>
+#include <hwbinder/IPCThreadState.h>
+#include <cutils/properties.h>
 
 /* max platform record must be equal to the predefined max num
    of platform in bt_configstore.conf */
 #define MAX_PLATFORM_PROP_RECORD 12
 #define BT_CONFIG_STORE_PATH "/etc/bluetooth/bt_configstore.conf"
 
+using android::hardware::IPCThreadState;
 using ::vendor::qti::hardware::btconfigstore::V1_0::IBTConfigStore;
 using ::vendor::qti::hardware::btconfigstore::V1_0::VendorProperty;
 using ::vendor::qti::hardware::btconfigstore::V1_0::AddOnFeaturesList;
@@ -79,6 +82,7 @@
 static bt_soc_type_t convertSocNameToBTSocType(const char * name);
 static const char * convertPropTypeToStringFormat(uint32_t propType);
 
+const bool IsLazyHalSupported(property_get_bool("ro.vendor.bt.enablelazyhal", false));
 
 EXPORT_SYMBOL bt_configstore_interface_t btConfigStoreInterface = {
     sizeof(btConfigStoreInterface),
@@ -89,6 +93,7 @@
     convertPropTypeToStringFormat,
 };
 
+
 /*******************************************************************************
 **
 ** Function         getVendorProperties
@@ -104,6 +109,8 @@
 *******************************************************************************/
 static bool getVendorProperties(uint32_t vPropType, std::vector<vendor_property_t> &vPropList)
 {
+  bool status = false;
+
   LOG_INFO(LOG_TAG, "%s ", __func__);
 
   if (btConfigStore == nullptr)
@@ -131,18 +138,23 @@
         LOG_INFO(LOG_TAG, "prop type: %s, prop_value: %s",
             convertPropTypeToStringFormat(vProp.type), vProp.value);
       }
-      return true;
+      status = true;
     }
   } else {
     LOG_WARN(LOG_TAG,"%s btConfigStore hal interface is null", __func__);
     if (btConfigStoreLoadProperties(vPropType, vPropList)){
       LOG_INFO(LOG_TAG, "Properties are successfully read from %s",
           BT_CONFIG_STORE_PATH);
-      return true;
+
+      status = true;
     }
   }
 
-  return false;
+  if (IsLazyHalSupported && btConfigStore != nullptr)
+    IPCThreadState::self()->flushCommands();
+
+  btConfigStore = nullptr;
+  return status;
 }
 
 /*******************************************************************************
@@ -160,6 +172,8 @@
 *******************************************************************************/
 static bool setVendorProperty(uint32_t type, const char * value)
 {
+  bool status = false;
+
   LOG_INFO(LOG_TAG, "%s ", __func__);
 
   if (btConfigStore == nullptr)
@@ -173,12 +187,17 @@
     LOG_INFO(LOG_TAG, "%s:: halResult = %d", __func__, halResult);
 
     if (halResult == Result::SUCCESS){
-      return true;
+      status = true;
     }
   } else {
     LOG_WARN(LOG_TAG, "%s btConfigStore is null", __func__);
   }
-  return false;
+
+  if (IsLazyHalSupported && btConfigStore != nullptr)
+    IPCThreadState::self()->flushCommands();
+
+  btConfigStore = nullptr;
+  return status;
 }
 
 /*******************************************************************************
@@ -196,6 +215,8 @@
 *******************************************************************************/
 static bool getAddOnFeatures(add_on_features_list_t *features_list)
 {
+  bool status = false;
+
   LOG_INFO(LOG_TAG, "%s ", __func__);
 
   if (btConfigStore == nullptr)
@@ -232,13 +253,17 @@
           "%s:: product_id = %d, version = %d, feat_mask_len = %d features data: %s",
           __func__, features_list->product_id, features_list->rsp_version,
           features_list->feat_mask_len, features);
-      return true;
+      status = true;
     }
   } else {
     LOG_WARN(LOG_TAG, "%s add feature is not avaliable", __func__);
   }
 
-  return false;
+  if (IsLazyHalSupported && btConfigStore != nullptr)
+    IPCThreadState::self()->flushCommands();
+
+  btConfigStore = nullptr;
+  return status;
 }
 
 /*******************************************************************************
@@ -348,6 +373,22 @@
         LOG_INFO(LOG_TAG, "%s:: prop type: %s, prop value: %s", __func__,
                 convertPropTypeToStringFormat(vProp.type), vProp.value);
         vPropList.push_back(vProp);
+
+        vProp.type = BT_PROP_A2DP_MCAST_TEST;
+        strlcpy(vProp.value,
+                config_get_string(config, section_name, "a2dpMcastSupported", "null"),
+                sizeof(vProp.value));
+        LOG_INFO(LOG_TAG, "%s:: prop type: %s, prop value: %s", __func__,
+                convertPropTypeToStringFormat(vProp.type), vProp.value);
+        vPropList.push_back(vProp);
+
+        vProp.type = BT_PROP_TWSP_STATE;
+        strlcpy(vProp.value,
+                config_get_string(config, section_name, "twspStateSupported", "null"),
+                sizeof(vProp.value));
+        LOG_INFO(LOG_TAG, "%s:: prop type: %s, prop value: %s", __func__,
+                convertPropTypeToStringFormat(vProp.type), vProp.value);
+        vPropList.push_back(vProp);
         break;
 
       case BT_PROP_SOC_TYPE:
@@ -399,6 +440,25 @@
                 convertPropTypeToStringFormat(vProp.type), vProp.value);
         vPropList.push_back(vProp);
         break;
+      case BT_PROP_A2DP_MCAST_TEST:
+        vProp.type = BT_PROP_A2DP_MCAST_TEST;
+        strlcpy(vProp.value,
+                config_get_string(config, section_name, "a2dpMcastSupported", "null"),
+                sizeof(vProp.value));
+        LOG_INFO(LOG_TAG, "%s:: prop type: %s, prop value: %s", __func__,
+                convertPropTypeToStringFormat(vProp.type), vProp.value);
+        vPropList.push_back(vProp);
+        break;
+
+      case BT_PROP_TWSP_STATE:
+        vProp.type = BT_PROP_TWSP_STATE;
+        strlcpy(vProp.value,
+                config_get_string(config, section_name, "twspStateSupported", "null"),
+                sizeof(vProp.value));
+        LOG_INFO(LOG_TAG, "%s:: prop type: %s, prop value: %s", __func__,
+                convertPropTypeToStringFormat(vProp.type), vProp.value);
+        vPropList.push_back(vProp);
+        break;
 
       default:
         LOG_INFO(LOG_TAG, "%s:: prop type not handled %d", __func__, vPropType);
diff --git a/system_bt_ext/btconfigstore/bt_configstore.conf b/system_bt_ext/btconfigstore/bt_configstore.conf
index 346cbd3..b52fb64 100644
--- a/system_bt_ext/btconfigstore/bt_configstore.conf
+++ b/system_bt_ext/btconfigstore/bt_configstore.conf
@@ -19,6 +19,8 @@
 # Wipower Support  - true(default) or false
 wiPowerSupported = true
 
+# TWS+ state processing
+twspStateSupported = false;
 #=================================================================================================#
 # platform configuration
 [platform2]
@@ -41,6 +43,8 @@
 # Wipower Support  - true(default) or false
 wiPowerSupported = true
 
+# TWS+ state processing
+twspStateSupported = false;
 #=================================================================================================#
 # platform configuration
 [platform3]
@@ -63,6 +67,8 @@
 # Wipower Support  - true(default) or false
 wiPowerSupported = true
 
+# TWS+ state processing
+twspStateSupported = false;
 #=================================================================================================#
 # platform configuration
 [platform4]
@@ -85,6 +91,8 @@
 # Wipower Support  - true(default) or false
 wiPowerSupported = true
 
+# TWS+ state processing
+twspStateSupported = false;
 #=================================================================================================#
 # platform configuration
 [platform5]
@@ -129,6 +137,11 @@
 # Wipower Support  - true(default) or false
 wiPowerSupported = true
 
+#A2dp Multicast support
+a2dpMcastSupported = false;
+
+# TWS+ state processing
+twspStateSupported = false;
 #=================================================================================================#
 # platform configuration
 [platform7]
@@ -247,4 +260,4 @@
 aacFrameCtlEnabled = false
 
 # Wipower Support  - true or false (default)
-wiPowerSupported = false
\ No newline at end of file
+wiPowerSupported = false
diff --git a/system_bt_ext/btif/include/btif_twsp_hf.h b/system_bt_ext/btif/include/btif_twsp_hf.h
index 0b11ca9..2c9c7c4 100644
--- a/system_bt_ext/btif/include/btif_twsp_hf.h
+++ b/system_bt_ext/btif/include/btif_twsp_hf.h
@@ -47,5 +47,7 @@
 
 int btif_hf_get_other_connected_twsp_index(int idx);
 
+void btif_hf_twsp_send_bvra_update(int idx, tBTA_AG_RES_DATA* ag_res);
+
 }  // namespace headset
 }  // namespace bluetooth
diff --git a/system_bt_ext/btif/src/btif_twsp_hf.cc b/system_bt_ext/btif/src/btif_twsp_hf.cc
index 52ab07d..029df6d 100644
--- a/system_bt_ext/btif/src/btif_twsp_hf.cc
+++ b/system_bt_ext/btif/src/btif_twsp_hf.cc
@@ -123,6 +123,24 @@
     return btif_max_hf_clients;
 }
 
+/*******************************************************************************
+**
+** Function         btif_hf_twsp_send_bvra_update
+**
+** Description      Send BVRA update for connected TWS+ peer earbud
+**
+** Returns          void
+**
+*******************************************************************************/
+
+void btif_hf_twsp_send_bvra_update(int current_index, tBTA_AG_RES_DATA* ag_res) {
+    int peer_eb_idx = btif_hf_get_other_connected_twsp_index(current_index);
+    if ((peer_eb_idx >= 0) && (peer_eb_idx < BTA_AG_MAX_NUM_CLIENTS) &&
+        (btif_hf_cb[peer_eb_idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) {
+        BTIF_TRACE_DEBUG("%s: Send BVRA update for peer earbud, idx: %d", __func__, peer_eb_idx);
+        BTA_AgResult(btif_hf_cb[peer_eb_idx].handle, BTA_AG_BVRA_RES, ag_res);
+    }
+}
 
 }  // namespace headset
 }  // namespace bluetooth
diff --git a/system_bt_ext/btif/src/btif_vendor.cc b/system_bt_ext/btif/src/btif_vendor.cc
index b5d0172..b8dbcf8 100644
--- a/system_bt_ext/btif/src/btif_vendor.cc
+++ b/system_bt_ext/btif/src/btif_vendor.cc
@@ -62,10 +62,14 @@
 #include <hardware/vendor.h>
 #include <stdlib.h>
 #include <string.h>
+#include <vector>
 
 #define LOG_TAG "bt_btif_vendor"
 
 #include <cutils/properties.h>
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/location.h>
 #include "bt_utils.h"
 #include "btif_common.h"
 #include "btif_util.h"
@@ -297,6 +301,43 @@
             manufacturer_id, power_level, rssi, link_quality,
             glitch_count);
 }
+
+void btif_vendor_bqr_delivery_event(const RawAddress* bd_addr, const uint8_t* bqr_raw_data,
+        uint32_t bqr_raw_data_len)
+{
+    if (bd_addr == NULL) {
+        LOG_ERROR(LOG_TAG, "%s: addr is null", __func__);
+        return;
+    }
+
+    if (bqr_raw_data == NULL) {
+        LOG_ERROR(LOG_TAG, "%s: bqr data is null", __func__);
+        return;
+    }
+
+    std::vector<uint8_t> raw_data;
+    raw_data.insert(raw_data.begin(), bqr_raw_data, bqr_raw_data + bqr_raw_data_len);
+
+    uint8_t lmp_ver = 0;
+    uint16_t lmp_subver = 0;
+    uint16_t manufacturer_id = 0;
+    btif_vendor_get_remote_version(bd_addr, &lmp_ver, &manufacturer_id, &lmp_subver);
+
+    LOG_INFO(LOG_TAG, "%s: len: %d, addr: %s, lmp_ver: %d, manufacturer_id: %d, lmp_subver: %d",
+            __func__, bqr_raw_data_len, bd_addr->ToString().c_str(), lmp_ver,
+            manufacturer_id, lmp_subver);
+
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(
+            [](RawAddress addr, uint8_t lmp_ver, uint16_t lmp_subver, uint16_t manufacturer_id,
+                std::vector<uint8_t> raw_data) {
+                HAL_CBACK(bt_vendor_callbacks, bqr_delivery_cb, &addr,
+                    lmp_ver, lmp_subver, manufacturer_id, std::move(raw_data));
+            },
+            *bd_addr, lmp_ver, lmp_subver, manufacturer_id, std::move(raw_data)));
+}
+
 static void bredrstartup(void)
 {
     LOG_INFO(LOG_TAG,"bredrstartup");
diff --git a/system_bt_ext/conf/bt_profile.conf b/system_bt_ext/conf/bt_profile.conf
index 8082534..d3fd677 100644
--- a/system_bt_ext/conf/bt_profile.conf
+++ b/system_bt_ext/conf/bt_profile.conf
@@ -7,7 +7,7 @@
 #   1.AVRCP
 #   2.PBAP
 #   3.MAP
-#   4.MAX_PWR
+#   4.MAX_POW
 #
 # ******************************* Start of config Database *******************
 #AVRCP profile and its configurable features
@@ -32,14 +32,14 @@
 map_email_support = true
 map_0104_support = true
 
-#Configurable BT MAX_PWR based on BT Technology
+#Configurable BT MAX_POW based on BT Technology
 #Host can specify different max. power for different Technology/packet type
 #Currently BR,EDR and BLE packet type are supported
-#Power value 0XFF is meant to disable the max power restriction for particular technology
-# BR_max_pow_support default value 0xFF
-# EDR_max_pow_support default value 0xFF
-# BLE_max_pow_support default value 0xFF
+#Power value 0x80 is meant to disable the max power restriction for particular technology
+# BR_max_pow_support default value 0x80
+# EDR_max_pow_support default value 0x80
+# BLE_max_pow_support default value 0x80
 [MAX_POW]
-#BR_max_pow_support = 0xFF
-#EDR_max_pow_support = 0xFF
+#BR_max_pow_support = 0x80
+#EDR_max_pow_support = 0x80
 BLE_max_pow_support = 0x18
diff --git a/system_bt_ext/conf/interop_database.conf b/system_bt_ext/conf/interop_database.conf
index 1edf231..eb8afac 100644
--- a/system_bt_ext/conf/interop_database.conf
+++ b/system_bt_ext/conf/interop_database.conf
@@ -79,6 +79,7 @@
 00:18:91 = Address_Based
 00:24:1C = Address_Based
 00:08:8b = Address_Based
+94:16:25 = Address_Based
 
 # Disable automatic pairing with headsets/car-kits
 # Some car kits do not react kindly to a failed pairing attempt and
@@ -345,6 +346,27 @@
 XAV-AX100 = Name_Based
 00:18:6b = Address_Based
 LG HBS730 = Name_Based
+8C:57:9B = Address_Based
+h.ear go (SRS-HG1) = Name_Based
+40:ED:98 = Address_Based
+FiiO BTR1K = Name_Based
+0C:A6:94 = Address_Based
+HK Soho Wireless = Name_Based
+00:09:A7 = Address_Based
+Beoplay H4 = Name_Based
+70:26:05 = Address_Based
+WF-SP700N = Name_Based
+48:D6:D5 = Address_Based
+Pixel Buds = Name_Based
+00:09:a7 = Address_Based
+Beoplay E8 = Name_Based
+2C:41:A1 = Address_Based
+Bose SoundWear = Name_Based
+2C:41:A1 = Address_Based
+Bose Free SoundSport = Name_Based
+00:18:09 = Address_Based
+Samsung Level On = Name_Based
+
 
 #E0:D1:E6 = Address_Based
 #00:18:6b = Address_Based
@@ -400,7 +422,7 @@
 [INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS]
 00:09:93 = Address_Based
 74:6f:f7 = Address_Based
-A0:56:B2 = Address_Based
+A0:56:B2:4F = Address_Based
 00:54:AF = Address_Based
 
 [INTEROP_DISABLE_CONNECTION_AFTER_COLLISION]
@@ -470,3 +492,8 @@
 #Leviathan Mini :: 10:b7:f6:03:38:b0
 [INTEROP_DISABLE_SNIFF_DURING_CALL]
 10:b7:f6 = Address_Based
+
+#Nintendo Switch Pro Controller - does not set sniff interval dynamically.
+#Requires custom HID report command to change mode.
+[INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL]
+98:B6:E9 = Address_Based
diff --git a/system_bt_ext/device/src/interop.cc b/system_bt_ext/device/src/interop.cc
index 2381669..22cdab3 100644
--- a/system_bt_ext/device/src/interop.cc
+++ b/system_bt_ext/device/src/interop.cc
@@ -255,6 +255,7 @@
     CASE_RETURN_STR(INTEROP_ADV_PBAP_VER_1_2)
     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_LINK_DURING_SCO)
     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_DURING_CALL)
+    CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
   }
   return "UNKNOWN";
 }
diff --git a/system_bt_ext/device/src/profile_config.cc b/system_bt_ext/device/src/profile_config.cc
index a206fc8..39c95d7 100644
--- a/system_bt_ext/device/src/profile_config.cc
+++ b/system_bt_ext/device/src/profile_config.cc
@@ -283,7 +283,7 @@
 
 max_pow_feature_t  max_radiated_power_fetch(const profile_t profile, profile_info_t feature_name)
 {
-  static max_pow_feature_t Tech_max_power = {0xFF, 0xFF, 0xFF, false, false, false};
+  static max_pow_feature_t Tech_max_power = {0x80, 0x80, 0x80, false, false, false};
   assert(profile);
   LOG_WARN(LOG_TAG, "max_radiated_power_fetch:profile %d", profile);
 
diff --git a/vhal/include/hardware/vendor.h b/vhal/include/hardware/vendor.h
index ccddf2d..32668ab 100644
--- a/vhal/include/hardware/vendor.h
+++ b/vhal/include/hardware/vendor.h
@@ -53,6 +53,7 @@
 #define ANDROID_INCLUDE_BT_VENDOR_H
 
 #include <hardware/bluetooth.h>
+#include <vector>
 
 __BEGIN_DECLS
 
@@ -120,6 +121,9 @@
                         uint16_t error_info, uint32_t event_mask, uint8_t lmp_ver, uint16_t lmp_subver,
                         uint16_t manufacturer_id, uint8_t power_level, int8_t rssi, uint8_t link_quality,
                         uint16_t glitch_count );
+typedef void (* btvendor_bqr_delivery_callback)(RawAddress* remote_bd_addr,
+                        uint8_t lmp_ver, uint16_t lmp_subver, uint16_t manufacturer_id,
+                        std::vector<uint8_t> bqr_raw_data);
 typedef void (* btvendor_bredr_cleanup_callback)(bool status);
 
 /** Callback to notify the remote device vendor properties.
@@ -147,6 +151,7 @@
     size_t      size;
     btvendor_bredr_cleanup_callback  bredr_cleanup_cb;
     btvendor_iot_device_broadcast_callback iot_device_broadcast_cb;
+    btvendor_bqr_delivery_callback bqr_delivery_cb;
     remote_dev_prop_callback         rmt_dev_prop_cb;
     hci_event_recv_callback  hci_event_recv_cb;
     adapter_vendor_prop_callback     adapter_vendor_prop_cb;