Merge "AVRCP_Browse: Don't peek/pop elements from empty stack" into p-keystone-qcom
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 7f36fce..c8b882e 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -34,7 +34,7 @@
     <string name="incoming_file_confirm_content" msgid="2752605552743148036">"Eingehende Datei annehmen?"</string>
     <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Ablehnen"</string>
     <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Akzeptieren"</string>
-    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Ok"</string>
     <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"Die Zeit zum Empfang der eingehenden Datei von \"<xliff:g id="SENDER">%1$s</xliff:g>\" ist abgelaufen."</string>
     <string name="incoming_file_confirm_Notification_title" msgid="5573329005298936903">"Eingehende Datei"</string>
     <string name="incoming_file_confirm_Notification_content" msgid="3359694069319644738">"<xliff:g id="SENDER">%1$s</xliff:g> kann jetzt <xliff:g id="FILE">%2$s</xliff:g> senden."</string>
@@ -59,19 +59,19 @@
     <string name="download_fail_line1" msgid="3846450148862894552">"Datei nicht empfangen"</string>
     <string name="download_fail_line2" msgid="8950394574689971071">"Datei: <xliff:g id="FILE">%1$s</xliff:g>"</string>
     <string name="download_fail_line3" msgid="3451040656154861722">"Grund: <xliff:g id="REASON">%1$s</xliff:g>"</string>
-    <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+    <string name="download_fail_ok" msgid="1521733664438320300">"Ok"</string>
     <string name="download_succ_line5" msgid="4509944688281573595">"Datei empfangen"</string>
     <string name="download_succ_ok" msgid="7053688246357050216">"Öffnen"</string>
     <string name="upload_line1" msgid="2055952074059709052">"An: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
     <string name="upload_line3" msgid="4920689672457037437">"Dateityp: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
     <string name="upload_line5" msgid="7759322537674229752">"Datei wird gesendet..."</string>
     <string name="upload_succ_line5" msgid="5687317197463383601">"Die Datei wurde gesendet."</string>
-    <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+    <string name="upload_succ_ok" msgid="7705428476405478828">"Ok"</string>
     <string name="upload_fail_line1" msgid="7899394672421491701">"Die Datei wurde nicht an \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" gesendet."</string>
     <string name="upload_fail_line1_2" msgid="2108129204050841798">"Datei: <xliff:g id="FILE">%1$s</xliff:g>"</string>
     <string name="upload_fail_ok" msgid="5807702461606714296">"Wiederholen"</string>
     <string name="upload_fail_cancel" msgid="9118496285835687125">"Schließen"</string>
-    <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+    <string name="bt_error_btn_ok" msgid="5965151173011534240">"Ok"</string>
     <string name="unknown_file" msgid="6092727753965095366">"Unbekannte Datei"</string>
     <string name="unknown_file_desc" msgid="480434281415453287">"Dieser Dateityp kann von keiner App verarbeitet werden. \n"</string>
     <string name="not_exist_file" msgid="3489434189599716133">"Keine Datei"</string>
diff --git a/res/values-de/test_strings.xml b/res/values-de/test_strings.xml
index 0ce94ff..3e07229 100644
--- a/res/values-de/test_strings.xml
+++ b/res/values-de/test_strings.xml
@@ -6,7 +6,7 @@
     <string name="update_record" msgid="2480425402384910635">"Aufnahme bestätigen"</string>
     <string name="ack_record" msgid="6716152390978472184">"Aufnahme bestätigen"</string>
     <string name="deleteAll_record" msgid="4383349788485210582">"Gesamte Aufnahme löschen"</string>
-    <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+    <string name="ok_button" msgid="6519033415223065454">"Ok"</string>
     <string name="delete_record" msgid="4645040331967533724">"Aufnahme löschen"</string>
     <string name="start_server" msgid="9034821924409165795">"TCP-Server starten"</string>
     <string name="notify_server" msgid="4369106744022969655">"TCP-Server benachrichtigen"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 6436c7f..af1fc3f 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -20,7 +20,7 @@
     <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Bluetooth bidezko partekatzeen kudeatzailea atzitzea eta fitxategiak transferitzeko erabiltzea baimentzen die aplikazioei."</string>
     <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Sartu sarbidedunen zerrendan Bluetooth gailua."</string>
     <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Bluetooth gailu bat aldi baterako sarbidedunen zerrendan sartzea baimentzen die aplikazioei, gailu honetara fitxategiak bidaltzeko baimena izan dezan, baina gailu honen erabiltzaileari berrespena eskatu beharrik gabe."</string>
-    <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+    <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth-a"</string>
     <string name="unknown_device" msgid="9221903979877041009">"Gailu ezezaguna"</string>
     <string name="unknownNumber" msgid="4994750948072751566">"Ezezaguna"</string>
     <string name="airplane_error_title" msgid="2683839635115739939">"Hegaldi modua"</string>
diff --git a/res/values-eu/test_strings.xml b/res/values-eu/test_strings.xml
index 2497be5..e7236e7 100644
--- a/res/values-eu/test_strings.xml
+++ b/res/values-eu/test_strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="6006644116867509664">"Bluetooth konexioa"</string>
+    <string name="app_name" msgid="6006644116867509664">"Bluetooth-a"</string>
     <string name="insert_record" msgid="1450997173838378132">"Sartu erregistroa"</string>
     <string name="update_record" msgid="2480425402384910635">"Berretsi erregistroa"</string>
     <string name="ack_record" msgid="6716152390978472184">"ACK erregistroa"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 6c52e73..54396de 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -23,8 +23,8 @@
     <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
     <string name="unknown_device" msgid="9221903979877041009">"Անհայտ սարք"</string>
     <string name="unknownNumber" msgid="4994750948072751566">"Անհայտ"</string>
-    <string name="airplane_error_title" msgid="2683839635115739939">"Ինքնաթիռի ռեժիմ"</string>
-    <string name="airplane_error_msg" msgid="8698965595254137230">"Դուք չեք կարող օգտվել Bluetooth-ից Ինքնաթիռի ռեժիմում:"</string>
+    <string name="airplane_error_title" msgid="2683839635115739939">"Ավիառեժիմ"</string>
+    <string name="airplane_error_msg" msgid="8698965595254137230">"Դուք չեք կարող օգտվել Bluetooth-ից Ավիառեժիմում:"</string>
     <string name="bt_enable_title" msgid="8657832550503456572"></string>
     <string name="bt_enable_line1" msgid="7203551583048149">"Bluetooth ծառայություններից օգտվելու համար նախ պետք է միացնեք Bluetooth-ը:"</string>
     <string name="bt_enable_line2" msgid="4341936569415937994">"Միացնե՞լ Bluetooth-ը հիմա:"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index b8cfee6..e4bff90 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"ダウンロードマネージャーにアクセスします。"</string>
     <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"BluetoothShareマネージャーへのアクセスとそれを利用したファイル転送をアプリに許可します。"</string>
-    <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Bluetooth端末によるアクセスを許可します。"</string>
-    <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Bluetooth端末によるアクセスを一時的に許可して、ユーザーの確認を受けずにその端末からこの端末にファイルを送信することをアプリに許可します。"</string>
+    <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Bluetoothデバイスによるアクセスを許可します。"</string>
+    <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Bluetoothデバイスによるアクセスを一時的に許可して、ユーザーの確認を受けずにそのデバイスからこのデバイスにファイルを送信することをアプリに許可します。"</string>
     <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
-    <string name="unknown_device" msgid="9221903979877041009">"不明なモバイル端末"</string>
+    <string name="unknown_device" msgid="9221903979877041009">"不明なモバイルデバイス"</string>
     <string name="unknownNumber" msgid="4994750948072751566">"不明"</string>
     <string name="airplane_error_title" msgid="2683839635115739939">"機内モード"</string>
     <string name="airplane_error_msg" msgid="8698965595254137230">"機内モードではBluetoothを使用できません。"</string>
@@ -92,7 +92,7 @@
     <string name="status_running" msgid="6562808920311008696">"ファイルを転送中です。"</string>
     <string name="status_success" msgid="239573225847565868">"ファイル転送が完了しました。"</string>
     <string name="status_not_accept" msgid="1695082417193780738">"コンテンツはサポートされていません。"</string>
-    <string name="status_forbidden" msgid="613956401054050725">"転送先の端末で転送が禁止されています。"</string>
+    <string name="status_forbidden" msgid="613956401054050725">"転送先のデバイスで転送が禁止されています。"</string>
     <string name="status_canceled" msgid="6664490318773098285">"ユーザーが転送をキャンセルしました。"</string>
     <string name="status_file_error" msgid="3671917770630165299">"ストレージのエラーです。"</string>
     <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"USBストレージがありません。"</string>
diff --git a/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java b/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
index b8c897b..b5fc3a1 100644
--- a/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
+++ b/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
@@ -34,7 +34,6 @@
     private Context mContext;
     private A2dpNativeInterface mA2dpNativeInterface;
 
-    private static String BT_SOC;
     private BluetoothCodecConfig[] mCodecConfigPriorities;
     private int mA2dpSourceCodecPrioritySbc = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
     private int mA2dpSourceCodecPriorityAac = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
@@ -102,8 +101,8 @@
             return null;
         }
 
-        BT_SOC = SystemProperties.get("vendor.bluetooth.soc");
         int value;
+        AdapterService mAdapterService = AdapterService.getAdapterService();
         try {
             value = resources.getInteger(R.integer.a2dp_source_codec_priority_sbc);
         } catch (NotFoundException e) {
@@ -133,17 +132,21 @@
                 < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) {
             mA2dpSourceCodecPriorityAptx = value;
         }
-        try {
-            value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_adaptive);
-        } catch (NotFoundException e) {
-            value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
-        }
-        if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value
-                < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) {
-            mA2dpSourceCodecPriorityAptxAdaptive = value;
+        if(mAdapterService.isSplitA2DPSourceAPTXADAPTIVE()) {
+            try {
+                value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_adaptive);
+            } catch (NotFoundException e) {
+                value = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
+            }
+            if ((value >= BluetoothCodecConfig.CODEC_PRIORITY_DISABLED) && (value
+                    < BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)) {
+                mA2dpSourceCodecPriorityAptxAdaptive = value;
+            }
+        } else {
+            mA2dpSourceCodecPriorityAptxAdaptive = BluetoothCodecConfig.CODEC_PRIORITY_DISABLED;
         }
 
-        if(BT_SOC.equals("cherokee")) {
+        if(mAdapterService.isSplitA2DPSourceAPTXHD()) {
             try {
                 value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_hd);
             } catch (NotFoundException e) {
@@ -158,7 +161,7 @@
         }
 
 
-        if(BT_SOC.equals("cherokee")) {
+        if(mAdapterService.isSplitA2DPSourceLDAC()) {
             try {
                 value = resources.getInteger(R.integer.a2dp_source_codec_priority_ldac);
             } catch (NotFoundException e) {
@@ -171,7 +174,6 @@
         } else {
             mA2dpSourceCodecPriorityLdac = BluetoothCodecConfig.CODEC_PRIORITY_DISABLED;
         }
-        AdapterService mAdapterService = AdapterService.getAdapterService();
         if (mAdapterService.isVendorIntfEnabled()) {
             try {
                 value = resources.getInteger(R.integer.a2dp_source_codec_priority_aptx_tws);
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 75b88c2..f0ede44 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
 import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothCodecStatus;
 import android.bluetooth.BluetoothDevice;
@@ -65,6 +66,8 @@
     private static final String TAG = "A2dpService";
 
     private static A2dpService sA2dpService;
+    private static A2dpSinkService sA2dpSinkService;
+    private static boolean mA2dpSrcSnkConcurrency;
 
     private BluetoothAdapter mAdapter;
     private AdapterService mAdapterService;
@@ -211,6 +214,11 @@
         if (DBG) {
             Log.d(TAG, "A2DP offload flag set to " + mA2dpOffloadEnabled);
         }
+        mA2dpSrcSnkConcurrency= SystemProperties.getBoolean(
+                                "persist.vendor.service.bt.a2dp_concurrency", false);
+        if (DBG) {
+            Log.d(TAG, "A2DP concurrency set to " + mA2dpSrcSnkConcurrency);
+        }
 
         // Step 8: Setup broadcast receivers
         IntentFilter filter = new IntentFilter();
@@ -372,12 +380,21 @@
                 Log.e(TAG, "Cannot connect to " + device + " : no state machine");
                 return false;
             }
+            if (mA2dpSrcSnkConcurrency) {
+                sA2dpSinkService = A2dpSinkService.getA2dpSinkService();
+                List<BluetoothDevice> srcDevs = sA2dpSinkService.getConnectedDevices();
+                for ( BluetoothDevice src : srcDevs ) {
+                    Log.d(TAG, "calling sink disconnect to " + src);
+                    sA2dpSinkService.disconnect(src);
+                }
+            }
+
             smConnect.sendMessage(A2dpStateMachine.CONNECT);
             return true;
         }
     }
 
-    boolean disconnect(BluetoothDevice device) {
+    public boolean disconnect(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
         if (DBG) {
             Log.d(TAG, "disconnect(): " + device);
@@ -416,7 +433,9 @@
 
         List <BluetoothDevice> connectingConnectedDevices =
                   getDevicesMatchingConnectionStates(CONNECTING_CONNECTED_STATES);
-        BluetoothDevice mConnDev = connectingConnectedDevices.get(0);
+        BluetoothDevice mConnDev = null;
+        if(!connectingConnectedDevices.isEmpty())
+            mConnDev = connectingConnectedDevices.get(0);
         if (mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTING ||
             mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTED) {
             if ((!mAdapterService.isTwsPlusDevice(device) && tws_connected) ||
@@ -442,7 +461,7 @@
             if (num_connected > 1) {
                 Log.d(TAG,"isConnectionAllowed: Max TWS connected, disconnect first");
                 return false;
-            } else if(mAdapterService.getTwsPlusPeerAddress(mConnDev).equals(device.getAddress())) {
+            } else if(mConnDev != null && mAdapterService.getTwsPlusPeerAddress(mConnDev).equals(device.getAddress())) {
                 Log.d(TAG,"isConnectionAllowed: Peer earbud pair allow connection");
                 return true;
             } else {
@@ -1121,6 +1140,16 @@
                 Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
                 return;
             }
+            if (mA2dpSrcSnkConcurrency &&
+                ( A2dpStackEvent.CONNECTION_STATE_CONNECTING == stackEvent.valueInt ||
+                  A2dpStackEvent.CONNECTION_STATE_CONNECTED == stackEvent.valueInt )) {
+                sA2dpSinkService = A2dpSinkService.getA2dpSinkService();
+                List<BluetoothDevice> srcDevs = sA2dpSinkService.getConnectedDevices();
+                for ( BluetoothDevice src : srcDevs ) {
+                    Log.d(TAG, "calling sink disconnect to " + src);
+                    sA2dpSinkService.disconnect(src);
+                }
+            }
             sm.sendMessage(A2dpStateMachine.STACK_EVENT, stackEvent);
         }
     }
@@ -1302,7 +1331,7 @@
         }
     }
 
-    private void updateOptionalCodecsSupport(BluetoothDevice device) {
+    public void updateOptionalCodecsSupport(BluetoothDevice device) {
         int previousSupport = getSupportsOptionalCodecs(device);
         boolean supportsOptional = false;
 
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 56faad4..fdc9a33 100644
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -632,6 +632,7 @@
     // NOTE: This event is processed in any state
     private void processCodecConfigEvent(BluetoothCodecStatus newCodecStatus) {
         BluetoothCodecConfig prevCodecConfig = null;
+        BluetoothCodecStatus prevCodecStatus = mCodecStatus;
         int new_codec_type = newCodecStatus.getCodecConfig().getCodecType();
         String offloadSupported =
                 SystemProperties.get("persist.vendor.btstack.enable.splita2dp");
@@ -670,6 +671,14 @@
             }
         }
 
+        if (isConnected() && !sameSelectableCodec(prevCodecStatus, mCodecStatus)) {
+             // Remote selectable codec could be changed if codec config changed
+             // in connected state, we need to re-check optional codec status
+             // for this codec change event.
+             Log.d(TAG,"updating optional codec support as previous and current codec are different.");
+             mA2dpService.updateOptionalCodecsSupport(mDevice);
+        }
+
         if (mA2dpOffloadEnabled) {
             boolean update = false;
             BluetoothCodecConfig newCodecConfig = mCodecStatus.getCodecConfig();
@@ -771,6 +780,16 @@
         return Integer.toString(what);
     }
 
+    private static boolean sameSelectableCodec(BluetoothCodecStatus prevCodecStatus,
+                                      BluetoothCodecStatus newCodecStatus) {
+        if (prevCodecStatus == null) {
+            return false;
+        }
+        return BluetoothCodecStatus.sameCapabilities(
+                prevCodecStatus.getCodecsSelectableCapabilities(),
+                newCodecStatus.getCodecsSelectableCapabilities());
+    }
+
     private static String profileStateToString(int state) {
         switch (state) {
             case BluetoothProfile.STATE_DISCONNECTED:
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
index 6502706..8a45ced 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
@@ -34,6 +34,8 @@
 import android.widget.Toast;
 
 import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.hfp.HeadsetService;
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.a2dpsink.mbs.A2dpMediaBrowserService;
 import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
@@ -63,6 +65,9 @@
 
     private A2dpSinkStateMachine mStateMachine;
     private static A2dpSinkService sA2dpSinkService;
+    private static A2dpService sA2dpService;
+    private static HeadsetService sHeadsetService;
+    private static boolean mA2dpSrcSnkConcurrency;
     protected static BluetoothDevice mStreamingDevice;
 
     private static int mMaxA2dpSinkConnections = 1;
@@ -94,6 +99,11 @@
         mMaxA2dpSinkConnections = Math.min(
                 SystemProperties.getInt("persist.vendor.bt.a2dp.sink_conn", 1),
                 MAX_ALLOWED_SINK_CONNECTIONS);
+        mA2dpSrcSnkConcurrency= SystemProperties.getBoolean(
+                                "persist.vendor.service.bt.a2dp_concurrency", false);
+        if (DBG) {
+            Log.d(TAG, "A2DP concurrency set to " + mA2dpSrcSnkConcurrency);
+        }
         // Start the media browser service.
         Intent startIntent = new Intent(this, A2dpMediaBrowserService.class);
         startService(startIntent);
@@ -190,12 +200,28 @@
             } else if (sm == null) {
                 return false;
             }
+
+            if (mA2dpSrcSnkConcurrency) {
+                sA2dpService = A2dpService.getA2dpService();
+                List<BluetoothDevice> snkDevs = sA2dpService.getConnectedDevices();
+                for( BluetoothDevice snk : snkDevs ) {
+                    Log.d(TAG, "calling src disconnect to " + snk);
+                    sA2dpService.disconnect(snk);
+                }
+                sHeadsetService = HeadsetService.getHeadsetService();
+                List<BluetoothDevice> hsDevs = sHeadsetService.getConnectedDevices();
+                for ( BluetoothDevice hs : hsDevs ) {
+                    Log.d(TAG, "calling headset disconnect to " + hs);
+                    sHeadsetService.disconnect(hs);
+                }
+            }
+
             sm.sendMessage(A2dpSinkStateMachine.CONNECT);
         }
         return true;
     }
 
-    boolean disconnect(BluetoothDevice device) {
+    public boolean disconnect(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
 
         if (DBG) {
@@ -615,6 +641,22 @@
                 sm.new StackEvent(A2dpSinkStateMachine.EVENT_TYPE_CONNECTION_STATE_CHANGED);
         event.device = device;
         event.valueInt = state;
+        if (mA2dpSrcSnkConcurrency &&
+            (state == BluetoothProfile.STATE_CONNECTING ||
+             state == BluetoothProfile.STATE_CONNECTED)) {
+            sA2dpService = A2dpService.getA2dpService();
+            List<BluetoothDevice> snkDevs = sA2dpService.getConnectedDevices();
+            for ( BluetoothDevice snk : snkDevs ) {
+                Log.d(TAG, "calling src disconnect to " + snk);
+                sA2dpService.disconnect(snk);
+            }
+            sHeadsetService = HeadsetService.getHeadsetService();
+            List<BluetoothDevice> hsDevs = sHeadsetService.getConnectedDevices();
+            for ( BluetoothDevice hs : hsDevs ) {
+                Log.d(TAG, "calling headset disconnect to " + hs);
+                sHeadsetService.disconnect(hs);
+            }
+        }
         sm.sendMessage(A2dpSinkStateMachine.STACK_EVENT, event);
     }
 
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
index 571d5d6..5b96e13 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
@@ -323,8 +323,6 @@
             Log.e(TAG, "stopAvrcpUpdates failed because of connection.");
         }
 
-        CoverArtUtils coverArt = new CoverArtUtils();
-        coverArt.broadcastInValidHandle(mContext ,avrcpService, mStreamAvailable);
     }
 
     private void sendAvrcpPause() {
diff --git a/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java b/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java
index 19183e3..c1dba46 100644
--- a/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java
+++ b/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.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;
@@ -47,6 +51,11 @@
     private static final int DISCONNECTED = 0;
     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;
@@ -62,6 +71,8 @@
 
     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;
@@ -89,6 +100,45 @@
 
     /* 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 +150,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 +174,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.RSP_INTERNAL_ERR,
+            mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants.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);
@@ -478,6 +540,60 @@
         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 void updateBrowsablePlayerList(String packageName) {
+        if (packageName == null || packageName.isEmpty())
+            return;
+        if (mBrowsablePlayerList.contains(packageName)) {
+            Log.w(TAG, "Remove pkg" + packageName + "from list" + mBrowsablePlayerList);
+            mBrowsablePlayerList.remove(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, "isPlayerConnectedMBS for package = " + mBrowsablePlayerList);
+        for (String pkg : mBrowsablePlayerList) {
+            if (packageName.equals(pkg))
+                return true;
+        }
+        return false;
+    }
+
+    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");
+    }
+
     public void setCurrentPackage(String packageName, String cls) {
         Log.w(TAG, "Set current Browse based on Addr Player as " + packageName);
         mCurrentBrowsePackage = packageName;
@@ -486,9 +602,27 @@
 
     /* 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();
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
index bf60f38..410c802 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
@@ -47,6 +47,9 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+
 /**
  * Provides Bluetooth AVRCP Controller profile, as a service in the Bluetooth application.
  */
@@ -54,7 +57,7 @@
     static final String TAG = "AvrcpControllerService";
     static final String LOG_TAG = "AvrcpController";
     static final boolean DBG = true;
-    static final boolean VDBG = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+    static final boolean VDBG = true;
     /*
      *  Play State Values from JNI
      */
@@ -710,8 +713,11 @@
                 return null;
             }
             avrcpCtSm = new AvrcpControllerStateMachine(sAvrcpControllerService, device);
+            Log.d(TAG, "AvrcpcontrollerSM start() called: " + device);
             avrcpCtSm.start();
+            Log.d(TAG, "AvrcpcontrollerSM started for device: " + device);
             mStateMachines.put(device, avrcpCtSm);
+            avrcpCtSm.registerReceiver(sAvrcpControllerService, device);
         }
         return avrcpCtSm;
     }
@@ -869,6 +875,7 @@
 
         AvrcpControllerStateMachine mAvrcpCtSm = getOrCreateAvrcpCtStateMachine(device);
         if (mAvrcpCtSm == null) {
+            Log.e(TAG, "onConnectionStateChanged: mAvrcpCtSm is null, return");
             return;
         }
 
@@ -901,11 +908,18 @@
         Log.i(TAG, " getRcFeatures caPsm :" + caPsm);
         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
         AvrcpControllerStateMachine mAvrcpCtSm = getAvrcpCtStateMachine(device);
-        if (mAvrcpCtSm == null)
+        if (mAvrcpCtSm == null) {
+            Log.i(TAG, "getRcFeatures: mAvrcpCtSm is null for device: " + device);
             return;
-        Message msg = mAvrcpCtSm.obtainMessage(
-            AvrcpControllerStateMachine.MESSAGE_PROCESS_RC_FEATURES, features, caPsm, device);
-        mAvrcpCtSm.sendMessage(msg);
+        }
+        try {
+            Message msg = mAvrcpCtSm.obtainMessage(
+               AvrcpControllerStateMachine.MESSAGE_PROCESS_RC_FEATURES, features, caPsm, device);
+            mAvrcpCtSm.sendMessage(msg);
+        } catch(Exception ee) {
+            Log.i(TAG, "getRcFeatures exception occured.");
+            ee.printStackTrace();
+        }
     }
 
     // Called by JNI
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 0ac58d5..dd603e5 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -150,12 +150,10 @@
 
     AvrcpControllerStateMachine(Context context, BluetoothDevice device) {
         super(TAG);
+        setDbg(DBG);
         mContext = context;
         mDevice = device;
-
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
-        mContext.registerReceiver(mBroadcastReceiver, filter);
 
         mDisconnected = new Disconnected();
         mConnected = new Connected();
@@ -182,15 +180,18 @@
         addState(mGetPlayerListing, mConnected);
         addState(mMoveToRoot, mConnected);
         mCoveArtUtils = new CoverArtUtils();
+        Log.d(TAG, "Setting initial state: Disconnected: " + mDevice);
         setInitialState(mDisconnected);
         mBipStateMachine = AvrcpControllerBipStateMachine.make(this, getHandler(), context);
+        Log.d(TAG, "BipSM created for device: " + mDevice);
     }
 
     class Disconnected extends State {
 
         @Override
         public void enter() {
-            Log.d(TAG, "Enter State: Disconnected mDevice: " + mDevice);
+            Log.d(TAG, "Enter State: Disconnected mDevice: " + mDevice +
+                                     "prevState: "  + prevState);
             mBrowsingConnected = false;
             if (prevState != -1) {
                 AvrcpControllerService.removeStateMachine(mDevice);
@@ -1034,6 +1035,14 @@
         }
     }
 
+    void registerReceiver(Context context, BluetoothDevice device) {
+        if (DBG) {
+            Log.d(TAG, " Register receiver for device: " + device);
+        }
+        IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+    }
+
     void doQuit() {
         try {
             mContext.unregisterReceiver(mBroadcastReceiver);
diff --git a/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index ea414c5..9e3e62b 100644
--- a/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -236,7 +236,10 @@
                                 (a2dpService.getConnectionState(mA2dpConnectedDevices.get(0)) ==
                                          BluetoothProfile.STATE_CONNECTED)) {
                                 Log.d(TAG, "calling set a2dp Active dev: " + mA2dpConnectedDevices.get(0));
-                                setA2dpActiveDevice(mA2dpConnectedDevices.get(0));
+                                if (!setA2dpActiveDevice(mA2dpConnectedDevices.get(0))) {
+                                    Log.w(TAG, "Set a2dp active device failed");
+                                    setA2dpActiveDevice(null);
+                                }
                             } else
                                 setA2dpActiveDevice(null);
                         }
@@ -304,8 +307,11 @@
                                (hfpService != null) &&
                                 (hfpService.getConnectionState(mHfpConnectedDevices.get(0)) ==
                                          BluetoothProfile.STATE_CONNECTED)) {
-                               setHfpActiveDevice(mHfpConnectedDevices.get(0));
                                Log.d(TAG, "calling set Active dev: " + mHfpConnectedDevices.get(0));
+                               if (!setHfpActiveDevice(mHfpConnectedDevices.get(0))) {
+                                   Log.w(TAG, "Set hfp active device failed");
+                                   setHfpActiveDevice(null);
+                               }
                             } else {
                                setHfpActiveDevice(null);
                             }
@@ -446,32 +452,34 @@
         return mHandlerThread.getLooper();
     }
 
-    private void setA2dpActiveDevice(BluetoothDevice device) {
+    private boolean setA2dpActiveDevice(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "setA2dpActiveDevice(" + device + ")");
         }
         final A2dpService a2dpService = mFactory.getA2dpService();
         if (a2dpService == null) {
-            return;
+            return false;
         }
         if (!a2dpService.setActiveDevice(device)) {
-            return;
+            return false;
         }
         mA2dpActiveDevice = device;
+        return true;
     }
 
-    private void setHfpActiveDevice(BluetoothDevice device) {
+    private boolean setHfpActiveDevice(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "setHfpActiveDevice(" + device + ")");
         }
         final HeadsetService headsetService = mFactory.getHeadsetService();
         if (headsetService == null) {
-            return;
+            return false;
         }
         if (!headsetService.setActiveDevice(device)) {
-            return;
+            return false;
         }
         mHfpActiveDevice = device;
+        return true;
     }
 
     private void setHearingAidActiveDevice(BluetoothDevice device) {
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 25b22ec..0db765c 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -2634,8 +2634,10 @@
      * @return true if Split A2DP Source LDAC  is enabled
      */
     public boolean isSplitA2DPSourceLDAC() {
+        String BT_SOC = SystemProperties.get("vendor.bluetooth.soc");
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mAdapterProperties.isSplitA2DPSourceLDAC();
+        return (!mAdapterProperties.isAddonFeaturesCmdSupported() && BT_SOC.equals("cherokee")) ||
+            mAdapterProperties.isSplitA2DPSourceLDAC();
     }
 
     /**
@@ -2654,8 +2656,10 @@
      * @return true if Split A2DP Source APTX HD  is enabled
      */
     public boolean isSplitA2DPSourceAPTXHD() {
+        String BT_SOC = SystemProperties.get("vendor.bluetooth.soc");
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mAdapterProperties.isSplitA2DPSourceAPTXHD();
+        return (!mAdapterProperties.isAddonFeaturesCmdSupported() && BT_SOC.equals("cherokee")) ||
+            mAdapterProperties.isSplitA2DPSourceAPTXHD();
     }
 
     /**
@@ -2664,8 +2668,10 @@
      * @return true if Split A2DP Source APTX ADAPTIVE  is enabled
      */
     public boolean isSplitA2DPSourceAPTXADAPTIVE() {
+        String BT_SOC = SystemProperties.get("vendor.bluetooth.soc");
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mAdapterProperties.isSplitA2DPSourceAPTXADAPTIVE();
+        return (!mAdapterProperties.isAddonFeaturesCmdSupported() && BT_SOC.equals("cherokee")) ||
+            mAdapterProperties.isSplitA2DPSourceAPTXADAPTIVE();
     }
 
     /**
diff --git a/src/com/android/bluetooth/btservice/AdapterState.java b/src/com/android/bluetooth/btservice/AdapterState.java
index 16e7633..46d8297 100644
--- a/src/com/android/bluetooth/btservice/AdapterState.java
+++ b/src/com/android/bluetooth/btservice/AdapterState.java
@@ -191,6 +191,11 @@
                     transitionTo(mTurningBleOnState);
                     break;
 
+                case BT_FORCEKILL_TIMEOUT:
+                    errorLog("Killing the process to force a restart as part of cleanup");
+                    android.os.Process.killProcess(android.os.Process.myPid());
+                    break;
+
                 default:
                     infoLog("Unhandled message - " + messageString(msg.what));
                     return false;
@@ -217,6 +222,12 @@
                     transitionTo(mTurningBleOffState);
                     break;
 
+                case BT_FORCEKILL_TIMEOUT:
+                    transitionTo(mOffState);
+                    errorLog("Killing the process to force a restart as part of cleanup");
+                    android.os.Process.killProcess(android.os.Process.myPid());
+                    break;
+
                 default:
                     infoLog("Unhandled message - " + messageString(msg.what));
                     return false;
@@ -239,6 +250,12 @@
                     transitionTo(mTurningOffState);
                     break;
 
+                case BT_FORCEKILL_TIMEOUT:
+                    transitionTo(mOffState);
+                    errorLog("Killing the process to force a restart as part of cleanup");
+                    android.os.Process.killProcess(android.os.Process.myPid());
+                    break;
+
                 default:
                     infoLog("Unhandled message - " + messageString(msg.what));
                     return false;
diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java
index 13da892..8c6bdff 100644
--- a/src/com/android/bluetooth/btservice/BondStateMachine.java
+++ b/src/com/android/bluetooth/btservice/BondStateMachine.java
@@ -415,9 +415,9 @@
 
         mAdapterProperties.onBondStateChanged(device, newState);
 
-        if ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC
+        if (devProp != null && ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC
                 || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL)
-                && newState == BluetoothDevice.BOND_BONDED && devProp.getUuids() == null) {
+                && newState == BluetoothDevice.BOND_BONDED && devProp.getUuids() == null)) {
             infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent");
             if (!mPendingBondedDevices.contains(device)) {
                 mPendingBondedDevices.add(device);
diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java
index 2355b88..7b6f37b 100644
--- a/src/com/android/bluetooth/btservice/Config.java
+++ b/src/com/android/bluetooth/btservice/Config.java
@@ -173,14 +173,24 @@
 
     private static synchronized boolean addAudioProfiles(String serviceName) {
         Log.d(TAG," addAudioProfiles profile" + serviceName);
-        boolean isA2dpSink = SystemProperties.getBoolean(
-                "persist.vendor.service.bt.a2dp.sink", false);
-        Log.i(TAG, "addAudioProfiles isA2dpSink :" + isA2dpSink);
-        /* If property not enabled and request is for A2DPSinkService, don't add */
-        if ((serviceName.equals("A2dpSinkService")) && (!isA2dpSink))
-            return false;
-        if ((serviceName.equals("A2dpService")) && (isA2dpSink))
-            return false;
+        boolean isA2dpConcurrency= SystemProperties.getBoolean(
+                  "persist.vendor.service.bt.a2dp_concurrency", false);
+        Log.i(TAG, "addAudioProfiles isA2dpConcurrency:" + isA2dpConcurrency);
+
+        if(isA2dpConcurrency) {
+            if ((serviceName.equals("A2dpSinkService")) || (serviceName.equals("A2dpService"))) {
+                return true;
+            }
+        } else {
+            boolean isA2dpSink = SystemProperties.getBoolean(
+                    "persist.vendor.service.bt.a2dp.sink", false);
+            Log.i(TAG, "addAudioProfiles isA2dpSink :" + isA2dpSink);
+            /* If property not enabled and request is for A2DPSinkService, don't add */
+            if ((serviceName.equals("A2dpSinkService")) && (!isA2dpSink))
+                return false;
+            if ((serviceName.equals("A2dpService")) && (isA2dpSink))
+                return false;
+        }
 
         boolean isBAEnabled = SystemProperties.getBoolean("persist.vendor.service.bt.bca", false);
         boolean isSplitA2dpSupported = SystemProperties.
diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java
index d4e7fec..8add34d 100644
--- a/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -323,6 +323,7 @@
                 return mRssi;
             }
         }
+
         /**
          * @return mDeviceType
          */
@@ -671,8 +672,8 @@
                             device.mUuids = newUuids;
                             if ((sAdapterService.getState() == BluetoothAdapter.STATE_ON) &&
                                                             device.autoConnect ) {
-                                sAdapterService.deviceUuidUpdated(bdDevice);
                                 debugLog("sendUuidIntent as Auto connect is set ");
+                                sAdapterService.deviceUuidUpdated(bdDevice);
                                 sendUuidIntent(bdDevice);
                             }
                             break;
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index f7fc3c2..7d7b080 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -934,7 +934,7 @@
         return true;
     }
 
-    boolean disconnect(BluetoothDevice device) {
+    public boolean disconnect(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
         Log.i(TAG, "disconnect: device=" + device + ", " + Utils.getUidPidString());
         synchronized (mStateMachines) {
@@ -1038,14 +1038,14 @@
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         ArrayList<BluetoothDevice> devices = new ArrayList<>();
-        if (states == null) {
-            return devices;
-        }
-        final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
-        if (bondedDevices == null) {
-            return devices;
-        }
         synchronized (mStateMachines) {
+            if (states == null || mAdapterService == null) {
+                return devices;
+            }
+            final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
+            if (bondedDevices == null) {
+                return devices;
+            }
             for (BluetoothDevice device : bondedDevices) {
 
                 int connectionState = getConnectionState(device);
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 8a2eab3..0a7ddfe 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -837,11 +837,13 @@
                     stateLogW("Disconnected");
                     processWBSEvent(HeadsetHalConstants.BTHF_WBS_NO);
                     stateLogD(" retryConnectCount = " + retryConnectCount);
-                    if(retryConnectCount == 1) {
-                        Log.d(TAG," retry once more ");
+                    if(retryConnectCount == 1 && !hasDeferredMessages(DISCONNECT)) {
+                        Log.d(TAG,"No deferred Disconnect, retry once more ");
                         sendMessageDelayed(CONNECT, mDevice, RETRY_CONNECT_TIME_SEC);
-                    } else if (retryConnectCount >= MAX_RETRY_CONNECT_COUNT) {
+                    } else if (retryConnectCount >= MAX_RETRY_CONNECT_COUNT ||
+                            hasDeferredMessages(DISCONNECT)) {
                         // we already tried twice.
+                        Log.d(TAG,"Already tried twice or has deferred Disconnect");
                         retryConnectCount = 0;
                     }
                     transitionTo(mDisconnected);
diff --git a/src/com/android/bluetooth/hid/HidHostService.java b/src/com/android/bluetooth/hid/HidHostService.java
index 362d360..0f34d79 100644
--- a/src/com/android/bluetooth/hid/HidHostService.java
+++ b/src/com/android/bluetooth/hid/HidHostService.java
@@ -819,8 +819,8 @@
         int bondState = adapterService.getBondState(device);
         // Allow this connection only if the device is bonded. Any attempt to connect while
         // bonding would potentially lead to an unauthorized connection.
-        if (bondState != BluetoothDevice.BOND_BONDED) {
-            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
+        if (bondState == BluetoothDevice.BOND_NONE) {
+            Log.w(TAG, "okToConnect: return false, bondState :" + bondState);
             return false;
         } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
                 && priority != BluetoothProfile.PRIORITY_ON
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
index 7bfc1ca..631e2ef 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
@@ -475,7 +475,7 @@
             mBatch.mStatus = Constants.BATCH_STATUS_FAILED;
             return;
         }
-
+        registerConnectionreceiver();
         if (mHandlerThread == null) {
             if (V) {
                 Log.v(TAG, "Create handler thread for batch " + mBatch.mId);
@@ -496,7 +496,7 @@
                 startObexSession();
             }
         }
-        registerConnectionreceiver();
+
     }
 
     /**
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java b/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
index 74fd872..7d0cfcc 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
@@ -372,24 +372,13 @@
                             mTransInfo.mID);
                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
                     // "try again"
-
                     // make current transfer "hidden"
                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
 
                     // clear correspondent notification item
                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
                             mTransInfo.mID);
-
-                    // retry the failed transfer
-                    Uri uri = BluetoothOppUtility.originalUri(Uri.parse(mTransInfo.mFileUri));
-                    BluetoothOppSendFileInfo sendFileInfo =
-                            BluetoothOppSendFileInfo.generateFileInfo(BluetoothOppTransferActivity
-                            .this, uri, mTransInfo.mFileType, false);
-                    uri = BluetoothOppUtility.generateUri(uri, sendFileInfo);
-                    BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo);
-                    mTransInfo.mFileUri = uri.toString();
-                    BluetoothOppUtility.retryTransfer(this, mTransInfo);
-
+                    retryFailedTrasfer();
                     BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(mTransInfo.mDestAddr);
 
                     // Display toast message
@@ -499,4 +488,22 @@
                     .setText(getString(R.string.upload_fail_cancel));
         }
     }
+
+ // Retry the failed transfer in background thread
+   private void retryFailedTrasfer() {
+        new Thread() {
+            @Override
+            public void run() {
+                super.run();
+                Uri uri = BluetoothOppUtility.originalUri(Uri.parse(mTransInfo.mFileUri));
+                BluetoothOppSendFileInfo sendFileInfo =
+                        BluetoothOppSendFileInfo.generateFileInfo(BluetoothOppTransferActivity
+                        .this, uri, mTransInfo.mFileType, false);
+                uri = BluetoothOppUtility.generateUri(uri, sendFileInfo);
+                BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo);
+                mTransInfo.mFileUri = uri.toString();
+                BluetoothOppUtility.retryTransfer(BluetoothOppTransferActivity.this, mTransInfo);
+            }
+        }.start();
+    }
 }
diff --git a/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java b/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
index d67a51d..939e068 100644
--- a/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
@@ -143,7 +143,7 @@
      *
      * @param device test device
      * @param bondState bond state value, could be invalid
-     * @param priority value, could be invalid, coudl be invalid
+     * @param priority value, could be invalid
      * @param expected expected result from okToConnect()
      */
     private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,