[automerger skipped] DO NOT MERGE Separate SDP procedure from bonding state (2/2) am: 30e2e54327
am: 2d6b83c629 -s ours
am skip reason: change_id Ifefb749e0274ae018714340654287a0412b59b89 with SHA1 55d82d63b7 is in history

Change-Id: I604b8f1077c6a9a3aae4488a5f2180a13a1cf913
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..726a790
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+    "jni",
+]
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 379440d..a086284 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -210,7 +210,8 @@
                   android:label=""
                   android:excludeFromRecents="true"
                   android:configChanges="orientation|keyboardHidden"
-                  android:enabled="@bool/profile_supported_opp">
+                  android:enabled="@bool/profile_supported_opp"
+                  android:theme="@android:style/Theme.DeviceDefault.Settings">
             <intent-filter>
                 <action android:name="com.android.bluetooth.action.TransferHistory" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/jni/Android.bp b/jni/Android.bp
new file mode 100644
index 0000000..73700e8
--- /dev/null
+++ b/jni/Android.bp
@@ -0,0 +1,39 @@
+cc_library_shared {
+    name: "libbluetooth_jni",
+    srcs: [
+        "com_android_bluetooth_btservice_AdapterService.cpp",
+        "com_android_bluetooth_hfp.cpp",
+        "com_android_bluetooth_hfpclient.cpp",
+        "com_android_bluetooth_a2dp.cpp",
+        "com_android_bluetooth_a2dp_sink.cpp",
+        "com_android_bluetooth_avrcp.cpp",
+        "com_android_bluetooth_avrcp_controller.cpp",
+        "com_android_bluetooth_hid.cpp",
+        "com_android_bluetooth_hidd.cpp",
+        "com_android_bluetooth_hdp.cpp",
+        "com_android_bluetooth_pan.cpp",
+        "com_android_bluetooth_gatt.cpp",
+        "com_android_bluetooth_sdp.cpp",
+    ],
+    include_dirs: [
+        "libnativehelper/include/nativehelper",
+        "system/bt/types",
+    ],
+    shared_libs: [
+        "libandroid_runtime",
+        "libchrome",
+        "libnativehelper",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+    ],
+    static_libs: [
+        "libbluetooth-types",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+}
diff --git a/jni/Android.mk b/jni/Android.mk
deleted file mode 100644
index 971b614..0000000
--- a/jni/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    com_android_bluetooth_btservice_AdapterService.cpp \
-    com_android_bluetooth_hfp.cpp \
-    com_android_bluetooth_hfpclient.cpp \
-    com_android_bluetooth_a2dp.cpp \
-    com_android_bluetooth_a2dp_sink.cpp \
-    com_android_bluetooth_avrcp.cpp \
-    com_android_bluetooth_avrcp_controller.cpp \
-    com_android_bluetooth_hid.cpp \
-    com_android_bluetooth_hidd.cpp \
-    com_android_bluetooth_hdp.cpp \
-    com_android_bluetooth_pan.cpp \
-    com_android_bluetooth_gatt.cpp \
-    com_android_bluetooth_sdp.cpp
-
-LOCAL_C_INCLUDES += \
-    $(JNI_H_INCLUDE) \
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
-    libchrome \
-    libnativehelper \
-    libcutils \
-    libutils \
-    liblog \
-    libhardware
-
-LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
-
-LOCAL_MODULE := libbluetooth_jni
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/jni/com_android_bluetooth_a2dp.cpp b/jni/com_android_bluetooth_a2dp.cpp
index a2928ff..26c9359 100644
--- a/jni/com_android_bluetooth_a2dp.cpp
+++ b/jni/com_android_bluetooth_a2dp.cpp
@@ -48,38 +48,38 @@
 static jobject mCallbacksObj = NULL;
 
 static void bta2dp_connection_state_callback(btav_connection_state_t state,
-                                             bt_bdaddr_t* bd_addr) {
+                                             RawAddress* bd_addr) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
                                (jint)state, addr.get());
 }
 
 static void bta2dp_audio_state_callback(btav_audio_state_t state,
-                                        bt_bdaddr_t* bd_addr) {
+                                        RawAddress* bd_addr) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged,
                                (jint)state, addr.get());
@@ -319,7 +319,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothA2dpInterface->connect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF connection, status: %d", status);
   }
@@ -337,7 +337,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF disconnection, status: %d", status);
   }
diff --git a/jni/com_android_bluetooth_a2dp_sink.cpp b/jni/com_android_bluetooth_a2dp_sink.cpp
index 185fc69..989cd6f 100644
--- a/jni/com_android_bluetooth_a2dp_sink.cpp
+++ b/jni/com_android_bluetooth_a2dp_sink.cpp
@@ -34,44 +34,44 @@
 static jobject mCallbacksObj = NULL;
 
 static void bta2dp_connection_state_callback(btav_connection_state_t state,
-                                             bt_bdaddr_t* bd_addr) {
+                                             RawAddress* bd_addr) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
                                (jint)state, addr.get());
 }
 
 static void bta2dp_audio_state_callback(btav_audio_state_t state,
-                                        bt_bdaddr_t* bd_addr) {
+                                        RawAddress* bd_addr) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged,
                                (jint)state, addr.get());
 }
 
-static void bta2dp_audio_config_callback(bt_bdaddr_t* bd_addr,
+static void bta2dp_audio_config_callback(RawAddress* bd_addr,
                                          uint32_t sample_rate,
                                          uint8_t channel_count) {
   ALOGI("%s", __func__);
@@ -79,13 +79,13 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConfigChanged,
                                addr.get(), (jint)sample_rate,
@@ -177,7 +177,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothA2dpInterface->connect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF connection, status: %d", status);
   }
@@ -195,7 +195,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothA2dpInterface->disconnect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF disconnection, status: %d", status);
   }
diff --git a/jni/com_android_bluetooth_avrcp.cpp b/jni/com_android_bluetooth_avrcp.cpp
index 5647705..d365b53 100644
--- a/jni/com_android_bluetooth_avrcp.cpp
+++ b/jni/com_android_bluetooth_avrcp.cpp
@@ -57,7 +57,7 @@
 
 static void cleanup_items(btrc_folder_items_t* p_items, int numItems);
 
-static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_remote_features_callback(RawAddress* bd_addr,
                                              btrc_remote_features_t features) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -68,20 +68,20 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Unable to allocate byte array for bd_addr");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr.get(),
                                (jint)features);
 }
 
 /** Callback for play status request */
-static void btavrcp_get_play_status_callback(bt_bdaddr_t* bd_addr) {
+static void btavrcp_get_play_status_callback(RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -91,20 +91,20 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for get_play_status command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr.get());
 }
 
 static void btavrcp_get_element_attr_callback(uint8_t num_attr,
                                               btrc_media_attr_t* p_attrs,
-                                              bt_bdaddr_t* bd_addr) {
+                                              RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -114,7 +114,7 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for get_element_attr command");
     return;
@@ -129,7 +129,7 @@
 
   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr.get(),
                                (jbyte)num_attr, attrs.get());
@@ -137,7 +137,7 @@
 
 static void btavrcp_register_notification_callback(btrc_event_id_t event_id,
                                                    uint32_t param,
-                                                   bt_bdaddr_t* bd_addr) {
+                                                   RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -147,20 +147,20 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for register_notification command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
                                addr.get(), (jint)event_id, (jint)param);
 }
 
 static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype,
-                                           bt_bdaddr_t* bd_addr) {
+                                           RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -170,13 +170,13 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for volume_change command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback,
@@ -184,7 +184,7 @@
 }
 
 static void btavrcp_passthrough_command_callback(int id, int pressed,
-                                                 bt_bdaddr_t* bd_addr) {
+                                                 RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -194,12 +194,12 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for passthrough_command command");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd,
@@ -207,7 +207,7 @@
 }
 
 static void btavrcp_set_addressed_player_callback(uint16_t player_id,
-                                                  bt_bdaddr_t* bd_addr) {
+                                                  RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -217,20 +217,20 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for set_addressed_player command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback,
                                addr.get(), (jint)player_id);
 }
 
 static void btavrcp_set_browsed_player_callback(uint16_t player_id,
-                                                bt_bdaddr_t* bd_addr) {
+                                                RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -239,12 +239,12 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for set_browsed_player command");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayerCallback,
@@ -253,7 +253,7 @@
 
 static void btavrcp_get_folder_items_callback(
     uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
-    uint32_t* p_attr_ids, bt_bdaddr_t* bd_addr) {
+    uint32_t* p_attr_ids, RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -263,7 +263,7 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for get_folder_items command");
     return;
@@ -271,7 +271,7 @@
 
   uint32_t* puiAttr = (uint32_t*)p_attr_ids;
   ScopedLocalRef<jintArray> attr_ids(sCallbackEnv.get(), NULL);
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   /* check number of attributes requested by remote device */
@@ -293,7 +293,7 @@
 }
 
 static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid,
-                                         bt_bdaddr_t* bd_addr) {
+                                         RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -310,13 +310,13 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for change_path command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetByteArrayRegion(
       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)folder_uid);
@@ -328,7 +328,7 @@
                                            uint16_t uid_counter,
                                            uint8_t num_attr,
                                            btrc_media_attr_t* p_attrs,
-                                           bt_bdaddr_t* bd_addr) {
+                                           RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -345,7 +345,7 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for get_item_attr command");
     return;
@@ -358,7 +358,7 @@
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
   sCallbackEnv->SetByteArrayRegion(
@@ -370,7 +370,7 @@
 }
 
 static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter,
-                                       uint8_t* uid, bt_bdaddr_t* bd_addr) {
+                                       uint8_t* uid, RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -386,13 +386,13 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for play_item command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetByteArrayRegion(
       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
@@ -402,7 +402,7 @@
 }
 
 static void btavrcp_get_total_num_items_callback(uint8_t scope,
-                                                 bt_bdaddr_t* bd_addr) {
+                                                 RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -411,20 +411,20 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for get_total_num_items command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getTotalNumOfItemsCallback,
                                addr.get(), (jbyte)scope);
 }
 
 static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len,
-                                    uint8_t* p_str, bt_bdaddr_t* bd_addr) {
+                                    uint8_t* p_str, RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -440,13 +440,13 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for search command");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetByteArrayRegion(attrs.get(), 0, str_len * sizeof(uint8_t),
                                    (jbyte*)p_str);
@@ -456,7 +456,7 @@
 
 static void btavrcp_add_to_play_list_callback(uint8_t scope, uint8_t* uid,
                                               uint16_t uid_counter,
-                                              bt_bdaddr_t* bd_addr) {
+                                              RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -465,7 +465,7 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for add_to_play_list command");
     return;
@@ -478,7 +478,7 @@
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetByteArrayRegion(
       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
@@ -630,7 +630,7 @@
   }
 
   bt_status_t status = sBluetoothAvrcpInterface->get_play_status_rsp(
-      (bt_bdaddr_t*)addr, (btrc_play_status_t)playStatus, songLen, songPos);
+      (RawAddress*)addr, (btrc_play_status_t)playStatus, songLen, songPos);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed get_play_status_rsp, status: %d", status);
   }
@@ -692,7 +692,7 @@
     return JNI_FALSE;
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status =
       sBluetoothAvrcpInterface->get_element_attr_rsp(btAddr, numAttr, pAttrs);
   if (status != BT_STATUS_SUCCESS) {
@@ -756,7 +756,7 @@
     }
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->get_item_attr_rsp(
       btAddr, (btrc_status_t)rspStatus, numAttr, pAttrs);
   if (status != BT_STATUS_SUCCESS)
@@ -1022,7 +1022,7 @@
     }
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
       btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
   if (status != BT_STATUS_SUCCESS) {
@@ -1157,7 +1157,7 @@
     }
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
       btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
   if (status != BT_STATUS_SUCCESS)
@@ -1195,7 +1195,7 @@
     return JNI_FALSE;
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_rsp(
       btAddr, (btrc_status_t)rspStatus);
   if (status != BT_STATUS_SUCCESS) {
@@ -1249,7 +1249,7 @@
   uint8_t folder_depth =
       depth; /* folder_depth is 0 if current folder is root */
   uint16_t charset_id = BTRC_CHARSET_ID_UTF8;
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_rsp(
       btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth,
       p_folders);
@@ -1280,7 +1280,7 @@
   }
 
   uint32_t nItems = (uint32_t)numItems;
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->change_path_rsp(
       btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems);
   if (status != BT_STATUS_SUCCESS) {
@@ -1306,7 +1306,7 @@
   }
 
   uint32_t nItems = (uint32_t)numItems;
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->search_rsp(
       btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
   if (status != BT_STATUS_SUCCESS) {
@@ -1331,7 +1331,7 @@
     return JNI_FALSE;
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status =
       sBluetoothAvrcpInterface->play_item_rsp(btAddr, (btrc_status_t)rspStatus);
   if (status != BT_STATUS_SUCCESS) {
@@ -1357,7 +1357,7 @@
   }
 
   uint32_t nItems = (uint32_t)numItems;
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp(
       btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
   if (status != BT_STATUS_SUCCESS) {
@@ -1381,7 +1381,7 @@
     return JNI_FALSE;
   }
 
-  bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
+  RawAddress* btAddr = (RawAddress*)addr;
   bt_status_t status = sBluetoothAvrcpInterface->add_to_now_playing_rsp(
       btAddr, (btrc_status_t)rspStatus);
   if (status != BT_STATUS_SUCCESS) {
diff --git a/jni/com_android_bluetooth_avrcp_controller.cpp b/jni/com_android_bluetooth_avrcp_controller.cpp
index cd2f888..40982ee 100644
--- a/jni/com_android_bluetooth_avrcp_controller.cpp
+++ b/jni/com_android_bluetooth_avrcp_controller.cpp
@@ -53,20 +53,20 @@
 static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL;
 static jobject sCallbacksObj = NULL;
 
-static void btavrcp_passthrough_response_callback(bt_bdaddr_t* bd_addr, int id,
+static void btavrcp_passthrough_response_callback(RawAddress* bd_addr, int id,
                                                   int pressed) {
   ALOGI("%s: id: %d, pressed: %d", __func__, id, pressed);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for passthrough response");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handlePassthroughRsp,
                                (jint)id, (jint)pressed, addr.get());
@@ -82,77 +82,76 @@
 }
 
 static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
-                                              bt_bdaddr_t* bd_addr) {
+                                              RawAddress* bd_addr) {
   ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for connection state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged,
                                (jboolean)rc_connect, (jboolean)br_connect,
                                addr.get());
 }
 
-static void btavrcp_get_rcfeatures_callback(bt_bdaddr_t* bd_addr,
-                                            int features) {
+static void btavrcp_get_rcfeatures_callback(RawAddress* bd_addr, int features) {
   ALOGV("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr ");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcFeatures, addr.get(),
                                (jint)features);
 }
 
 static void btavrcp_setplayerapplicationsetting_rsp_callback(
-    bt_bdaddr_t* bd_addr, uint8_t accepted) {
+    RawAddress* bd_addr, uint8_t accepted) {
   ALOGV("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr ");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_setplayerappsettingrsp,
                                addr.get(), (jint)accepted);
 }
 
 static void btavrcp_playerapplicationsetting_callback(
-    bt_bdaddr_t* bd_addr, uint8_t num_attr, btrc_player_app_attr_t* app_attrs,
+    RawAddress* bd_addr, uint8_t num_attr, btrc_player_app_attr_t* app_attrs,
     uint8_t num_ext_attr, btrc_player_app_ext_attr_t* ext_attrs) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr ");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   /* TODO ext attrs
    * Flattening defined attributes: <id,num_values,values[]>
@@ -188,18 +187,18 @@
 }
 
 static void btavrcp_playerapplicationsetting_changed_callback(
-    bt_bdaddr_t* bd_addr, btrc_player_settings_t* p_vals) {
+    RawAddress* bd_addr, btrc_player_settings_t* p_vals) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   int arraylen = p_vals->num_attr * 2;
@@ -225,46 +224,46 @@
                                playerattribs.get(), (jint)arraylen);
 }
 
-static void btavrcp_set_abs_vol_cmd_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_set_abs_vol_cmd_callback(RawAddress* bd_addr,
                                              uint8_t abs_vol, uint8_t label) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAbsVolume,
                                addr.get(), (jbyte)abs_vol, (jbyte)label);
 }
 
-static void btavrcp_register_notification_absvol_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_register_notification_absvol_callback(RawAddress* bd_addr,
                                                           uint8_t label) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj,
                                method_handleRegisterNotificationAbsVol,
                                addr.get(), (jbyte)label);
 }
 
-static void btavrcp_track_changed_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_track_changed_callback(RawAddress* bd_addr,
                                            uint8_t num_attr,
                                            btrc_element_attr_val_t* p_attrs) {
   /*
@@ -276,7 +275,7 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
@@ -288,7 +287,7 @@
     ALOGE(" failed to set new array for attribIds");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
@@ -318,7 +317,7 @@
                                stringArray.get());
 }
 
-static void btavrcp_play_position_changed_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_play_position_changed_callback(RawAddress* bd_addr,
                                                    uint32_t song_len,
                                                    uint32_t song_pos) {
   ALOGI("%s", __func__);
@@ -326,37 +325,37 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaypositionchanged,
                                addr.get(), (jint)(song_len), (jint)song_pos);
 }
 
 static void btavrcp_play_status_changed_callback(
-    bt_bdaddr_t* bd_addr, btrc_play_status_t play_status) {
+    RawAddress* bd_addr, btrc_play_status_t play_status) {
   ALOGI("%s", __func__);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to get new array ");
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged,
                                addr.get(), (jbyte)play_status);
 }
 
 static void btavrcp_get_folder_items_callback(
-    bt_bdaddr_t* bd_addr, btrc_status_t status,
+    RawAddress* bd_addr, btrc_status_t status,
     const btrc_folder_items_t* folder_items, uint8_t count) {
   /* Folder items are list of items that can be either BTRC_ITEM_PLAYER
    * BTRC_ITEM_MEDIA, BTRC_ITEM_FOLDER. Here we translate them to their java
@@ -546,7 +545,7 @@
   }
 }
 
-static void btavrcp_change_path_callback(bt_bdaddr_t* bd_addr, uint8_t count) {
+static void btavrcp_change_path_callback(RawAddress* bd_addr, uint8_t count) {
   ALOGI("%s count %d", __func__, count);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -555,7 +554,7 @@
                                (jint)count);
 }
 
-static void btavrcp_set_browsed_player_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_set_browsed_player_callback(RawAddress* bd_addr,
                                                 uint8_t num_items,
                                                 uint8_t depth) {
   ALOGI("%s items %d depth %d", __func__, num_items, depth);
@@ -566,7 +565,7 @@
                                (jint)num_items, (jint)depth);
 }
 
-static void btavrcp_set_addressed_player_callback(bt_bdaddr_t* bd_addr,
+static void btavrcp_set_addressed_player_callback(RawAddress* bd_addr,
                                                   uint8_t status) {
   ALOGI("%s status %d", __func__, status);
 
@@ -740,7 +739,7 @@
   }
 
   bt_status_t status = sBluetoothAvrcpInterface->send_pass_through_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)key_code, (uint8_t)key_state);
+      (RawAddress*)addr, (uint8_t)key_code, (uint8_t)key_state);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending passthru command, status: %d", status);
   }
@@ -766,7 +765,7 @@
   }
 
   bt_status_t status = sBluetoothAvrcpInterface->send_group_navigation_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)key_code, (uint8_t)key_state);
+      (RawAddress*)addr, (uint8_t)key_code, (uint8_t)key_state);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending Grp Navigation command, status: %d", status);
   }
@@ -813,7 +812,7 @@
   }
 
   bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)num_attrib, pAttrs, pAttrsVal);
+      (RawAddress*)addr, (uint8_t)num_attrib, pAttrs, pAttrsVal);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending setPlAppSettValNative command, status: %d", status);
   }
@@ -836,7 +835,7 @@
 
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->set_volume_rsp(
-      (bt_bdaddr_t*)addr, (uint8_t)abs_vol, (uint8_t)label);
+      (RawAddress*)addr, (uint8_t)abs_vol, (uint8_t)label);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status);
   }
@@ -855,7 +854,7 @@
   }
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp(
-      (bt_bdaddr_t*)addr, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol,
+      (RawAddress*)addr, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol,
       (uint8_t)label);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d",
@@ -875,7 +874,7 @@
   }
   ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status =
-      sBluetoothAvrcpInterface->get_playback_state_cmd((bt_bdaddr_t*)addr);
+      sBluetoothAvrcpInterface->get_playback_state_cmd((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending getPlaybackStateNative command, status: %d", status);
   }
@@ -893,7 +892,7 @@
   }
   ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items);
+      (RawAddress*)addr, (uint8_t)start, (uint8_t)items);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending getNowPlayingListNative command, status: %d", status);
   }
@@ -910,7 +909,7 @@
   }
   ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->get_folder_list_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items);
+      (RawAddress*)addr, (uint8_t)start, (uint8_t)items);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending getFolderListNative command, status: %d", status);
   }
@@ -928,7 +927,7 @@
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
 
   bt_status_t status = sBluetoothAvrcpInterface->get_player_list_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)start, (uint8_t)items);
+      (RawAddress*)addr, (uint8_t)start, (uint8_t)items);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending getPlayerListNative command, status: %d", status);
   }
@@ -954,7 +953,7 @@
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
 
   bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)direction, (uint8_t*)uid);
+      (RawAddress*)addr, (uint8_t)direction, (uint8_t*)uid);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending changeFolderPathNative command, status: %d", status);
   }
@@ -972,7 +971,7 @@
 
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
-      (bt_bdaddr_t*)addr, (uint16_t)id);
+      (RawAddress*)addr, (uint16_t)id);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending setBrowsedPlayerNative command, status: %d", status);
   }
@@ -990,7 +989,7 @@
 
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(
-      (bt_bdaddr_t*)addr, (uint16_t)id);
+      (RawAddress*)addr, (uint16_t)id);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending setAddressedPlayerNative command, status: %d",
           status);
@@ -1015,7 +1014,7 @@
 
   ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
   bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
-      (bt_bdaddr_t*)addr, (uint8_t)scope, (uint8_t*)uid, (uint16_t)uidCounter);
+      (RawAddress*)addr, (uint8_t)scope, (uint8_t*)uid, (uint16_t)uidCounter);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending playItemNative command, status: %d", status);
   }
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index f743ec5..dc2e07a 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -148,7 +148,7 @@
 }
 
 static void remote_device_properties_callback(bt_status_t status,
-                                              bt_bdaddr_t* bd_addr,
+                                              RawAddress* bd_addr,
                                               int num_properties,
                                               bt_property_t* properties) {
   CallbackEnv sCallbackEnv(__func__);
@@ -191,13 +191,13 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Error while allocation byte array in %s", __func__);
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   jintArray typesPtr = types.get();
@@ -239,15 +239,14 @@
         (const char*)properties[addr_index].val);
 
   remote_device_properties_callback(BT_STATUS_SUCCESS,
-                                    (bt_bdaddr_t*)properties[addr_index].val,
+                                    (RawAddress*)properties[addr_index].val,
                                     num_properties, properties);
 
   sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback,
                                addr.get());
 }
 
-static void bond_state_changed_callback(bt_status_t status,
-                                        bt_bdaddr_t* bd_addr,
+static void bond_state_changed_callback(bt_status_t status, RawAddress* bd_addr,
                                         bt_bond_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -258,19 +257,19 @@
   }
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Address allocation failed in %s", __func__);
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback,
                                (jint)status, addr.get(), (jint)state);
 }
 
-static void acl_state_changed_callback(bt_status_t status, bt_bdaddr_t* bd_addr,
+static void acl_state_changed_callback(bt_status_t status, RawAddress* bd_addr,
                                        bt_acl_state_t state) {
   if (!bd_addr) {
     ALOGE("Address is null in %s", __func__);
@@ -281,12 +280,12 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Address allocation failed in %s", __func__);
     return;
   }
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_aclStateChangeCallback,
@@ -303,7 +302,7 @@
       sJniCallbacksObj, method_discoveryStateChangeCallback, (jint)state);
 }
 
-static void pin_request_callback(bt_bdaddr_t* bd_addr, bt_bdname_t* bdname,
+static void pin_request_callback(RawAddress* bd_addr, bt_bdname_t* bdname,
                                  uint32_t cod, bool min_16_digits) {
   if (!bd_addr) {
     ALOGE("Address is null in %s", __func__);
@@ -314,13 +313,13 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Error while allocating in: %s", __func__);
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   ScopedLocalRef<jbyteArray> devname(
@@ -337,7 +336,7 @@
                                addr.get(), devname.get(), cod, min_16_digits);
 }
 
-static void ssp_request_callback(bt_bdaddr_t* bd_addr, bt_bdname_t* bdname,
+static void ssp_request_callback(RawAddress* bd_addr, bt_bdname_t* bdname,
                                  uint32_t cod, bt_ssp_variant_t pairing_variant,
                                  uint32_t pass_key) {
   if (!bd_addr) {
@@ -348,13 +347,13 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Error while allocating in: %s", __func__);
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
 
   ScopedLocalRef<jbyteArray> devname(
@@ -751,7 +750,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->create_bond((bt_bdaddr_t*)addr, transport);
+  int ret = sBluetoothInterface->create_bond((RawAddress*)addr, transport);
   env->ReleaseByteArrayElements(address, addr, 0);
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
@@ -848,7 +847,7 @@
     memcpy(oob_data.le_sc_r, leScRBytes, len);
   }
 
-  status = sBluetoothInterface->create_bond_out_of_band((bt_bdaddr_t*)addr,
+  status = sBluetoothInterface->create_bond_out_of_band((RawAddress*)addr,
                                                         transport, &oob_data);
 
 done:
@@ -877,7 +876,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t*)addr);
+  int ret = sBluetoothInterface->remove_bond((RawAddress*)addr);
   env->ReleaseByteArrayElements(address, addr, 0);
 
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
@@ -894,7 +893,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t*)addr);
+  int ret = sBluetoothInterface->cancel_bond((RawAddress*)addr);
   env->ReleaseByteArrayElements(address, addr, 0);
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
@@ -910,7 +909,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->get_connection_state((bt_bdaddr_t*)addr);
+  int ret = sBluetoothInterface->get_connection_state((RawAddress*)addr);
   env->ReleaseByteArrayElements(address, addr, 0);
 
   return ret;
@@ -938,7 +937,7 @@
     }
   }
 
-  int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len,
+  int ret = sBluetoothInterface->pin_reply((RawAddress*)addr, accept, len,
                                            (bt_pin_code_t*)pinPtr);
   env->ReleaseByteArrayElements(address, addr, 0);
   env->ReleaseByteArrayElements(pinArray, pinPtr, 0);
@@ -959,7 +958,7 @@
   }
 
   int ret = sBluetoothInterface->ssp_reply(
-      (bt_bdaddr_t*)addr, (bt_ssp_variant_t)type, accept, passkey);
+      (RawAddress*)addr, (bt_ssp_variant_t)type, accept, passkey);
   env->ReleaseByteArrayElements(address, addr, 0);
 
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
@@ -1014,7 +1013,7 @@
   }
 
   int ret = sBluetoothInterface->get_remote_device_property(
-      (bt_bdaddr_t*)addr, (bt_property_type_t)type);
+      (RawAddress*)addr, (bt_property_type_t)type);
   env->ReleaseByteArrayElements(address, addr, 0);
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
@@ -1044,8 +1043,8 @@
   prop.len = env->GetArrayLength(value);
   prop.val = val;
 
-  int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t*)addr,
-                                                            &prop);
+  int ret =
+      sBluetoothInterface->set_remote_device_property((RawAddress*)addr, &prop);
   env->ReleaseByteArrayElements(value, val, 0);
   env->ReleaseByteArrayElements(address, addr, 0);
 
@@ -1064,7 +1063,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->get_remote_services((bt_bdaddr_t*)addr);
+  int ret = sBluetoothInterface->get_remote_services((RawAddress*)addr);
   env->ReleaseByteArrayElements(address, addr, 0);
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
@@ -1092,7 +1091,7 @@
 
   int socket_fd = -1;
   bt_status_t status = sBluetoothSocketInterface->connect(
-      (bt_bdaddr_t*)addr, (btsock_type_t)type, (const uint8_t*)uuid, channel,
+      (RawAddress*)addr, (btsock_type_t)type, (const uint8_t*)uuid, channel,
       &socket_fd, flag, callingUid);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Socket connection failed: %d", status);
@@ -1205,8 +1204,7 @@
     return;
   }
 
-  sBluetoothInterface->interop_database_add(feature, (bt_bdaddr_t*)addr,
-                                            length);
+  sBluetoothInterface->interop_database_add(feature, (RawAddress*)addr, length);
   env->ReleaseByteArrayElements(address, addr, 0);
 }
 
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index 9e721aa..e57a1d0 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -40,7 +40,7 @@
 
 #define BD_ADDR_LEN 6
 
-#define UUID_PARAMS(uuid_ptr) uuid_lsb(uuid_ptr), uuid_msb(uuid_ptr)
+#define UUID_PARAMS(uuid) uuid_lsb(uuid), uuid_msb(uuid)
 
 static void set_uuid(uint8_t* uuid, jlong uuid_msb, jlong uuid_lsb) {
   for (int i = 0; i != 8; ++i) {
@@ -49,67 +49,40 @@
   }
 }
 
-static uint64_t uuid_lsb(const bt_uuid_t* uuid) {
+static uint64_t uuid_lsb(const bt_uuid_t& uuid) {
   uint64_t lsb = 0;
 
   for (int i = 7; i >= 0; i--) {
     lsb <<= 8;
-    lsb |= uuid->uu[i];
+    lsb |= uuid.uu[i];
   }
 
   return lsb;
 }
 
-static uint64_t uuid_msb(const bt_uuid_t* uuid) {
+static uint64_t uuid_msb(const bt_uuid_t& uuid) {
   uint64_t msb = 0;
 
   for (int i = 15; i >= 8; i--) {
     msb <<= 8;
-    msb |= uuid->uu[i];
+    msb |= uuid.uu[i];
   }
 
   return msb;
 }
 
-static void bd_addr_str_to_addr(const char* str, uint8_t* bd_addr) {
-  int i;
-  char c;
+static RawAddress str2addr(JNIEnv* env, jstring address) {
+  RawAddress bd_addr;
+  const char* c_address = env->GetStringUTFChars(address, NULL);
+  if (!c_address) return bd_addr;
 
-  c = *str++;
-  for (i = 0; i < BD_ADDR_LEN; i++) {
-    if (c >= '0' && c <= '9')
-      bd_addr[i] = c - '0';
-    else if (c >= 'a' && c <= 'z')
-      bd_addr[i] = c - 'a' + 10;
-    else  // (c >= 'A' && c <= 'Z')
-      bd_addr[i] = c - 'A' + 10;
+  RawAddress::FromString(std::string(c_address), bd_addr);
+  env->ReleaseStringUTFChars(address, c_address);
 
-    c = *str++;
-    if (c != ':') {
-      bd_addr[i] <<= 4;
-      if (c >= '0' && c <= '9')
-        bd_addr[i] |= c - '0';
-      else if (c >= 'a' && c <= 'z')
-        bd_addr[i] |= c - 'a' + 10;
-      else  // (c >= 'A' && c <= 'Z')
-        bd_addr[i] |= c - 'A' + 10;
-
-      c = *str++;
-    }
-
-    c = *str++;
-  }
+  return bd_addr;
 }
 
-static void jstr2bdaddr(JNIEnv* env, bt_bdaddr_t* bda, jstring address) {
-  const char* c_bda = env->GetStringUTFChars(address, NULL);
-  if (c_bda != NULL && bda != NULL && strlen(c_bda) == 17) {
-    bd_addr_str_to_addr(c_bda, bda->address);
-    env->ReleaseStringUTFChars(address, c_bda);
-  }
-}
-
-static jstring bdaddr2newjstr(JNIEnv* env, bt_bdaddr_t* bda) {
+static jstring bdaddr2newjstr(JNIEnv* env, const RawAddress* bda) {
   char c_address[32];
   snprintf(c_address, sizeof(c_address), "%02X:%02X:%02X:%02X:%02X:%02X",
            bda->address[0], bda->address[1], bda->address[2], bda->address[3],
@@ -219,7 +192,8 @@
  * BTA client callbacks
  */
 
-void btgattc_register_app_cb(int status, int clientIf, bt_uuid_t* app_uuid) {
+void btgattc_register_app_cb(int status, int clientIf,
+                             const bt_uuid_t& app_uuid) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
@@ -227,7 +201,7 @@
 }
 
 void btgattc_scan_result_cb(uint16_t event_type, uint8_t addr_type,
-                            bt_bdaddr_t* bda, uint8_t primary_phy,
+                            RawAddress* bda, uint8_t primary_phy,
                             uint8_t secondary_phy, uint8_t advertising_sid,
                             int8_t tx_power, int8_t rssi,
                             uint16_t periodic_adv_int,
@@ -248,22 +222,24 @@
                                periodic_adv_int, jb.get());
 }
 
-void btgattc_open_cb(int conn_id, int status, int clientIf, bt_bdaddr_t* bda) {
+void btgattc_open_cb(int conn_id, int status, int clientIf,
+                     const RawAddress& bda) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnected, clientIf,
                                conn_id, status, address.get());
 }
 
-void btgattc_close_cb(int conn_id, int status, int clientIf, bt_bdaddr_t* bda) {
+void btgattc_close_cb(int conn_id, int status, int clientIf,
+                      const RawAddress& bda) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDisconnected, clientIf,
                                conn_id, status, address.get());
 }
@@ -285,19 +261,19 @@
                                conn_id, status, registered, handle);
 }
 
-void btgattc_notify_cb(int conn_id, btgatt_notify_params_t* p_data) {
+void btgattc_notify_cb(int conn_id, const btgatt_notify_params_t& p_data) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(
-      sCallbackEnv.get(), bdaddr2newjstr(sCallbackEnv.get(), &p_data->bda));
+      sCallbackEnv.get(), bdaddr2newjstr(sCallbackEnv.get(), &p_data.bda));
   ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(),
-                                sCallbackEnv->NewByteArray(p_data->len));
-  sCallbackEnv->SetByteArrayRegion(jb.get(), 0, p_data->len,
-                                   (jbyte*)p_data->value);
+                                sCallbackEnv->NewByteArray(p_data.len));
+  sCallbackEnv->SetByteArrayRegion(jb.get(), 0, p_data.len,
+                                   (jbyte*)p_data.value);
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNotify, conn_id,
-                               address.get(), p_data->handle, p_data->is_notify,
+                               address.get(), p_data.handle, p_data.is_notify,
                                jb.get());
 }
 
@@ -338,21 +314,21 @@
 }
 
 void btgattc_read_descriptor_cb(int conn_id, int status,
-                                btgatt_read_params_t* p_data) {
+                                const btgatt_read_params_t& p_data) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(), NULL);
-  if (p_data->value.len != 0) {
-    jb.reset(sCallbackEnv->NewByteArray(p_data->value.len));
-    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, p_data->value.len,
-                                     (jbyte*)p_data->value.value);
+  if (p_data.value.len != 0) {
+    jb.reset(sCallbackEnv->NewByteArray(p_data.value.len));
+    sCallbackEnv->SetByteArrayRegion(jb.get(), 0, p_data.value.len,
+                                     (jbyte*)p_data.value.value);
   } else {
     jb.reset(sCallbackEnv->NewByteArray(1));
   }
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadDescriptor, conn_id,
-                               status, p_data->handle, jb.get());
+                               status, p_data.handle, jb.get());
 }
 
 void btgattc_write_descriptor_cb(int conn_id, int status, uint16_t handle) {
@@ -363,13 +339,13 @@
                                status, handle);
 }
 
-void btgattc_remote_rssi_cb(int client_if, bt_bdaddr_t* bda, int rssi,
+void btgattc_remote_rssi_cb(int client_if, const RawAddress& bda, int rssi,
                             int status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
 
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadRemoteRssi,
                                client_if, address.get(), rssi, status);
@@ -488,7 +464,7 @@
 
     ScopedLocalRef<jobject> uuid(
         env, env->NewObject(uuidClazz.get(), uuidConstructor,
-                            uuid_msb(&curr.uuid), uuid_lsb(&curr.uuid)));
+                            uuid_msb(curr.uuid), uuid_lsb(curr.uuid)));
     fid = env->GetFieldID(gattDbElementClazz.get(), "uuid", "Ljava/util/UUID;");
     env->SetObjectField(element.get(), fid, uuid.get());
 
@@ -511,7 +487,8 @@
   }
 }
 
-void btgattc_get_gatt_db_cb(int conn_id, btgatt_db_element_t* db, int count) {
+void btgattc_get_gatt_db_cb(int conn_id, const btgatt_db_element_t* db,
+                            int count) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -579,7 +556,7 @@
  * BTA server callbacks
  */
 
-void btgatts_register_app_cb(int status, int server_if, bt_uuid_t* uuid) {
+void btgatts_register_app_cb(int status, int server_if, const bt_uuid_t& uuid) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerRegistered, status,
@@ -587,12 +564,12 @@
 }
 
 void btgatts_connection_cb(int conn_id, int server_if, int connected,
-                           bt_bdaddr_t* bda) {
+                           const RawAddress& bda) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientConnected,
                                address.get(), connected, conn_id, server_if);
 }
@@ -631,41 +608,42 @@
 }
 
 void btgatts_request_read_characteristic_cb(int conn_id, int trans_id,
-                                            bt_bdaddr_t* bda, int attr_handle,
-                                            int offset, bool is_long) {
+                                            const RawAddress& bda,
+                                            int attr_handle, int offset,
+                                            bool is_long) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerReadCharacteristic,
                                address.get(), conn_id, trans_id, attr_handle,
                                offset, is_long);
 }
 
 void btgatts_request_read_descriptor_cb(int conn_id, int trans_id,
-                                        bt_bdaddr_t* bda, int attr_handle,
+                                        const RawAddress& bda, int attr_handle,
                                         int offset, bool is_long) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerReadDescriptor,
                                address.get(), conn_id, trans_id, attr_handle,
                                offset, is_long);
 }
 
 void btgatts_request_write_characteristic_cb(int conn_id, int trans_id,
-                                             bt_bdaddr_t* bda, int attr_handle,
-                                             int offset, bool need_rsp,
-                                             bool is_prep,
+                                             const RawAddress& bda,
+                                             int attr_handle, int offset,
+                                             bool need_rsp, bool is_prep,
                                              std::vector<uint8_t> value) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   ScopedLocalRef<jbyteArray> val(sCallbackEnv.get(),
                                  sCallbackEnv->NewByteArray(value.size()));
   if (val.get())
@@ -678,7 +656,7 @@
 }
 
 void btgatts_request_write_descriptor_cb(int conn_id, int trans_id,
-                                         bt_bdaddr_t* bda, int attr_handle,
+                                         const RawAddress& bda, int attr_handle,
                                          int offset, bool need_rsp,
                                          bool is_prep,
                                          std::vector<uint8_t> value) {
@@ -686,7 +664,7 @@
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   ScopedLocalRef<jbyteArray> val(sCallbackEnv.get(),
                                  sCallbackEnv->NewByteArray(value.size()));
   if (val.get())
@@ -698,13 +676,13 @@
                                val.get());
 }
 
-void btgatts_request_exec_write_cb(int conn_id, int trans_id, bt_bdaddr_t* bda,
-                                   int exec_write) {
+void btgatts_request_exec_write_cb(int conn_id, int trans_id,
+                                   const RawAddress& bda, int exec_write) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jstring> address(sCallbackEnv.get(),
-                                  bdaddr2newjstr(sCallbackEnv.get(), bda));
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExecuteWrite,
                                address.get(), conn_id, trans_id, exec_write);
 }
@@ -848,7 +826,7 @@
   method_onGetGattDb =
       env->GetMethodID(clazz, "onGetGattDb", "(ILjava/util/ArrayList;)V");
   method_onClientPhyRead =
-      env->GetMethodID(clazz, "onClientPhyRead", "(IIII)V");
+      env->GetMethodID(clazz, "onClientPhyRead", "(ILjava/lang/String;III)V");
   method_onClientPhyUpdate =
       env->GetMethodID(clazz, "onClientPhyUpdate", "(IIII)V");
   method_onClientConnUpdate =
@@ -884,7 +862,7 @@
       env->GetMethodID(clazz, "onServerCongestion", "(IZ)V");
   method_onServerMtuChanged = env->GetMethodID(clazz, "onMtuChanged", "(II)V");
   method_onServerPhyRead =
-      env->GetMethodID(clazz, "onServerPhyRead", "(IIII)V");
+      env->GetMethodID(clazz, "onServerPhyRead", "(ILjava/lang/String;III)V");
   method_onServerPhyUpdate =
       env->GetMethodID(clazz, "onServerPhyUpdate", "(IIII)V");
   method_onServerConnUpdate =
@@ -955,9 +933,7 @@
 static int gattClientGetDeviceTypeNative(JNIEnv* env, jobject object,
                                          jstring address) {
   if (!sGattIf) return 0;
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  return sGattIf->client->get_device_type(&bda);
+  return sGattIf->client->get_device_type(str2addr(env, address));
 }
 
 static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
@@ -967,7 +943,7 @@
 
   if (!sGattIf) return;
   set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb);
-  sGattIf->client->register_client(&uuid);
+  sGattIf->client->register_client(uuid);
 }
 
 static void gattClientUnregisterAppNative(JNIEnv* env, jobject object,
@@ -981,7 +957,7 @@
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onScannerRegistered,
-                               status, scannerId, UUID_PARAMS(&app_uuid));
+                               status, scannerId, UUID_PARAMS(app_uuid));
 }
 
 static void registerScannerNative(JNIEnv* env, jobject object,
@@ -1012,51 +988,51 @@
                                     jint initiating_phys) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  sGattIf->client->connect(clientif, &bda, isDirect, transport, opportunistic,
-                           initiating_phys);
+  sGattIf->client->connect(clientif, str2addr(env, address), isDirect,
+                           transport, opportunistic, initiating_phys);
 }
 
 static void gattClientDisconnectNative(JNIEnv* env, jobject object,
                                        jint clientIf, jstring address,
                                        jint conn_id) {
   if (!sGattIf) return;
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  sGattIf->client->disconnect(clientIf, &bda, conn_id);
+  sGattIf->client->disconnect(clientIf, str2addr(env, address), conn_id);
 }
 
 static void gattClientSetPreferredPhyNative(JNIEnv* env, jobject object,
-                                            jint clientIf, jint conn_id,
+                                            jint clientIf, jstring address,
                                             jint tx_phy, jint rx_phy,
                                             jint phy_options) {
   if (!sGattIf) return;
-  sGattIf->client->set_preferred_phy(conn_id, tx_phy, rx_phy, phy_options);
+  sGattIf->client->set_preferred_phy(str2addr(env, address), tx_phy, rx_phy,
+                                     phy_options);
 }
 
-static void readClientPhyCb(int conn_id, uint8_t tx_phy, uint8_t rx_phy,
-                            uint8_t status) {
+static void readClientPhyCb(uint8_t clientIf, RawAddress bda, uint8_t tx_phy,
+                            uint8_t rx_phy, uint8_t status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
-  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientPhyRead, conn_id,
-                               tx_phy, rx_phy, status);
+  ScopedLocalRef<jstring> address(sCallbackEnv.get(),
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
+
+  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientPhyRead, clientIf,
+                               address.get(), tx_phy, rx_phy, status);
 }
 
 static void gattClientReadPhyNative(JNIEnv* env, jobject object, jint clientIf,
-                                    jint conn_id) {
+                                    jstring address) {
   if (!sGattIf) return;
-  sGattIf->client->read_phy(conn_id, base::Bind(readClientPhyCb, conn_id));
+
+  RawAddress bda = str2addr(env, address);
+  sGattIf->client->read_phy(bda, base::Bind(&readClientPhyCb, clientIf, bda));
 }
 
 static void gattClientRefreshNative(JNIEnv* env, jobject object, jint clientIf,
                                     jstring address) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  sGattIf->client->refresh(clientIf, &bda);
+  sGattIf->client->refresh(clientIf, str2addr(env, address));
 }
 
 static void gattClientSearchServiceNative(JNIEnv* env, jobject object,
@@ -1078,7 +1054,7 @@
 
   bt_uuid_t uuid;
   set_uuid(uuid.uu, service_uuid_msb, service_uuid_lsb);
-  sGattIf->client->btif_gattc_discover_service_by_uuid(conn_id, &uuid);
+  sGattIf->client->btif_gattc_discover_service_by_uuid(conn_id, uuid);
 }
 
 static void gattClientGetGattDbNative(JNIEnv* env, jobject object,
@@ -1103,7 +1079,7 @@
 
   bt_uuid_t uuid;
   set_uuid(uuid.uu, uuid_msb, uuid_lsb);
-  sGattIf->client->read_using_characteristic_uuid(conn_id, &uuid, s_handle,
+  sGattIf->client->read_using_characteristic_uuid(conn_id, uuid, s_handle,
                                                   e_handle, authReq);
 }
 
@@ -1169,24 +1145,18 @@
     jboolean enable) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bd_addr;
-  const char* c_address = env->GetStringUTFChars(address, NULL);
-  bd_addr_str_to_addr(c_address, bd_addr.address);
-
+  RawAddress bd_addr = str2addr(env, address);
   if (enable)
-    sGattIf->client->register_for_notification(clientIf, &bd_addr, handle);
+    sGattIf->client->register_for_notification(clientIf, bd_addr, handle);
   else
-    sGattIf->client->deregister_for_notification(clientIf, &bd_addr, handle);
+    sGattIf->client->deregister_for_notification(clientIf, bd_addr, handle);
 }
 
 static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject object,
                                            jint clientif, jstring address) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-
-  sGattIf->client->read_remote_rssi(clientif, &bda);
+  sGattIf->client->read_remote_rssi(clientif, str2addr(env, address));
 }
 
 void set_scan_params_cmpl_cb(int client_if, uint8_t status) {
@@ -1300,8 +1270,7 @@
   switch (filt_type) {
     case 0:  // BTM_BLE_PF_ADDR_FILTER
     {
-      bt_bdaddr_t bda;
-      jstr2bdaddr(env, &bda, address);
+      RawAddress bda = str2addr(env, address);
       sGattIf->scanner->ScanFilterAddRemove(
           action, filt_type, filt_index, 0, 0, NULL, NULL, &bda, addr_type, {},
           {}, base::Bind(&scan_filter_cfg_cb, client_if));
@@ -1442,10 +1411,8 @@
                                                 jint max_interval, jint latency,
                                                 jint timeout) {
   if (!sGattIf) return;
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  sGattIf->client->conn_parameter_update(&bda, min_interval, max_interval,
-                                         latency, timeout);
+  sGattIf->client->conn_parameter_update(str2addr(env, address), min_interval,
+                                         max_interval, latency, timeout);
 }
 
 void batchscan_cfg_storage_cb(uint8_t client_if, uint8_t status) {
@@ -1505,7 +1472,7 @@
   bt_uuid_t uuid;
   if (!sGattIf) return;
   set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb);
-  sGattIf->server->register_server(&uuid);
+  sGattIf->server->register_server(uuid);
 }
 
 static void gattServerUnregisterAppNative(JNIEnv* env, jobject object,
@@ -1519,43 +1486,44 @@
                                     jint transport) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bd_addr;
-  const char* c_address = env->GetStringUTFChars(address, NULL);
-  bd_addr_str_to_addr(c_address, bd_addr.address);
-
-  sGattIf->server->connect(server_if, &bd_addr, is_direct, transport);
+  RawAddress bd_addr = str2addr(env, address);
+  sGattIf->server->connect(server_if, bd_addr, is_direct, transport);
 }
 
 static void gattServerDisconnectNative(JNIEnv* env, jobject object,
                                        jint serverIf, jstring address,
                                        jint conn_id) {
   if (!sGattIf) return;
-  bt_bdaddr_t bda;
-  jstr2bdaddr(env, &bda, address);
-  sGattIf->server->disconnect(serverIf, &bda, conn_id);
+  sGattIf->server->disconnect(serverIf, str2addr(env, address), conn_id);
 }
 
 static void gattServerSetPreferredPhyNative(JNIEnv* env, jobject object,
-                                            jint serverIf, jint conn_id,
+                                            jint serverIf, jstring address,
                                             jint tx_phy, jint rx_phy,
                                             jint phy_options) {
   if (!sGattIf) return;
-  sGattIf->server->set_preferred_phy(conn_id, tx_phy, rx_phy, phy_options);
+  RawAddress bda = str2addr(env, address);
+  sGattIf->server->set_preferred_phy(bda, tx_phy, rx_phy, phy_options);
 }
 
-static void readServerPhyCb(int conn_id, uint8_t tx_phy, uint8_t rx_phy,
-                            uint8_t status) {
+static void readServerPhyCb(uint8_t serverIf, RawAddress bda, uint8_t tx_phy,
+                            uint8_t rx_phy, uint8_t status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
-  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerPhyRead, conn_id,
-                               tx_phy, rx_phy, status);
+  ScopedLocalRef<jstring> address(sCallbackEnv.get(),
+                                  bdaddr2newjstr(sCallbackEnv.get(), &bda));
+
+  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerPhyRead, serverIf,
+                               address.get(), tx_phy, rx_phy, status);
 }
 
 static void gattServerReadPhyNative(JNIEnv* env, jobject object, jint serverIf,
-                                    jint conn_id) {
+                                    jstring address) {
   if (!sGattIf) return;
-  sGattIf->server->read_phy(conn_id, base::Bind(readServerPhyCb, conn_id));
+
+  RawAddress bda = str2addr(env, address);
+  sGattIf->server->read_phy(bda, base::Bind(&readServerPhyCb, serverIf, bda));
 }
 
 static void gattServerAddServiceNative(JNIEnv* env, jobject object,
@@ -1696,7 +1664,7 @@
     env->ReleaseByteArrayElements(val, array, JNI_ABORT);
   }
 
-  sGattIf->server->send_response(conn_id, trans_id, status, &response);
+  sGattIf->server->send_response(conn_id, trans_id, status, response);
 }
 
 static void advertiseClassInitNative(JNIEnv* env, jclass clazz) {
@@ -1875,7 +1843,7 @@
 }
 
 static void getOwnAddressCb(uint8_t advertiser_id, uint8_t address_type,
-                            bt_bdaddr_t address) {
+                            RawAddress address) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -2026,8 +1994,8 @@
 }
 
 static void onSyncStarted(int reg_id, uint8_t status, uint16_t sync_handle,
-                          uint8_t sid, uint8_t address_type,
-                          bt_bdaddr_t address, uint8_t phy, uint16_t interval) {
+                          uint8_t sid, uint8_t address_type, RawAddress address,
+                          uint8_t phy, uint16_t interval) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -2064,12 +2032,10 @@
                             jint reg_id) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t tmp;
-  jstr2bdaddr(env, &tmp, address);
-
-  sGattIf->scanner->StartSync(
-      sid, tmp, skip, timeout, base::Bind(&onSyncStarted, reg_id),
-      base::Bind(&onSyncReport), base::Bind(&onSyncLost));
+  sGattIf->scanner->StartSync(sid, str2addr(env, address), skip, timeout,
+                              base::Bind(&onSyncStarted, reg_id),
+                              base::Bind(&onSyncReport),
+                              base::Bind(&onSyncLost));
 }
 
 static void stopSyncNative(int sync_handle) {
@@ -2083,8 +2049,7 @@
                            jint p1, jint p2, jint p3, jint p4, jint p5) {
   if (!sGattIf) return;
 
-  bt_bdaddr_t bt_bda1;
-  jstr2bdaddr(env, &bt_bda1, bda1);
+  RawAddress bt_bda1 = str2addr(env, bda1);
 
   bt_uuid_t uuid1;
   set_uuid(uuid1.uu, uuid1_msb, uuid1_lsb);
@@ -2097,7 +2062,7 @@
   params.u3 = p3;
   params.u4 = p4;
   params.u5 = p5;
-  sGattIf->client->test_command(command, &params);
+  sGattIf->client->test_command(command, params);
 }
 
 /**
@@ -2191,9 +2156,10 @@
      (void*)gattClientConnectNative},
     {"gattClientDisconnectNative", "(ILjava/lang/String;I)V",
      (void*)gattClientDisconnectNative},
-    {"gattClientSetPreferredPhyNative", "(IIIII)V",
+    {"gattClientSetPreferredPhyNative", "(ILjava/lang/String;III)V",
      (void*)gattClientSetPreferredPhyNative},
-    {"gattClientReadPhyNative", "(II)V", (void*)gattClientReadPhyNative},
+    {"gattClientReadPhyNative", "(ILjava/lang/String;)V",
+     (void*)gattClientReadPhyNative},
     {"gattClientRefreshNative", "(ILjava/lang/String;)V",
      (void*)gattClientRefreshNative},
     {"gattClientSearchServiceNative", "(IZJJ)V",
@@ -2229,9 +2195,10 @@
      (void*)gattServerConnectNative},
     {"gattServerDisconnectNative", "(ILjava/lang/String;I)V",
      (void*)gattServerDisconnectNative},
-    {"gattServerSetPreferredPhyNative", "(IIIII)V",
+    {"gattServerSetPreferredPhyNative", "(ILjava/lang/String;III)V",
      (void*)gattServerSetPreferredPhyNative},
-    {"gattServerReadPhyNative", "(II)V", (void*)gattServerReadPhyNative},
+    {"gattServerReadPhyNative", "(ILjava/lang/String;)V",
+     (void*)gattServerReadPhyNative},
     {"gattServerAddServiceNative", "(ILjava/util/List;)V",
      (void*)gattServerAddServiceNative},
     {"gattServerStopServiceNative", "(II)V",
diff --git a/jni/com_android_bluetooth_hdp.cpp b/jni/com_android_bluetooth_hdp.cpp
index c49854e..3abc243 100644
--- a/jni/com_android_bluetooth_hdp.cpp
+++ b/jni/com_android_bluetooth_hdp.cpp
@@ -42,13 +42,13 @@
                                app_id, (jint)state);
 }
 
-static void channel_state_callback(int app_id, bt_bdaddr_t* bd_addr,
+static void channel_state_callback(int app_id, RawAddress* bd_addr,
                                    int mdep_cfg_index, int channel_id,
                                    bthl_channel_state_t state, int fd) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for channel state");
     return;
@@ -64,7 +64,7 @@
     }
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onChannelStateChanged,
                                app_id, addr.get(), mdep_cfg_index, channel_id,
@@ -203,7 +203,7 @@
 
   jint chan_id;
   bt_status_t status = sBluetoothHdpInterface->connect_channel(
-      app_id, (bt_bdaddr_t*)addr, 0, &chan_id);
+      app_id, (RawAddress*)addr, 0, &chan_id);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HDP channel connection, status: %d", status);
     chan_id = -1;
diff --git a/jni/com_android_bluetooth_hfp.cpp b/jni/com_android_bluetooth_hfp.cpp
index 863c7a3..5bb0d6e 100644
--- a/jni/com_android_bluetooth_hfp.cpp
+++ b/jni/com_android_bluetooth_hfp.cpp
@@ -55,22 +55,22 @@
 static jobject mCallbacksObj = NULL;
 static std::shared_timed_mutex callbacks_mutex;
 
-static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) {
+static jbyteArray marshall_bda(RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return NULL;
 
-  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
   if (!addr) {
     ALOGE("Fail to new jbyteArray bd addr");
     return NULL;
   }
-  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   return addr;
 }
 
 static void connection_state_callback(bthf_connection_state_t state,
-                                      bt_bdaddr_t* bd_addr) {
+                                      RawAddress* bd_addr) {
   ALOGI("%s", __func__);
 
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
@@ -85,7 +85,7 @@
 }
 
 static void audio_state_callback(bthf_audio_state_t state,
-                                 bt_bdaddr_t* bd_addr) {
+                                 RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -98,7 +98,7 @@
 }
 
 static void voice_recognition_callback(bthf_vr_state_t state,
-                                       bt_bdaddr_t* bd_addr) {
+                                       RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -113,7 +113,7 @@
                                (jint)state, addr.get());
 }
 
-static void answer_call_callback(bt_bdaddr_t* bd_addr) {
+static void answer_call_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -127,7 +127,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAnswerCall, addr.get());
 }
 
-static void hangup_call_callback(bt_bdaddr_t* bd_addr) {
+static void hangup_call_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -142,7 +142,7 @@
 }
 
 static void volume_control_callback(bthf_volume_type_t type, int volume,
-                                    bt_bdaddr_t* bd_addr) {
+                                    RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -157,7 +157,7 @@
                                (jint)type, (jint)volume, addr.get());
 }
 
-static void dial_call_callback(char* number, bt_bdaddr_t* bd_addr) {
+static void dial_call_callback(char* number, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -174,7 +174,7 @@
                                js_number.get(), addr.get());
 }
 
-static void dtmf_cmd_callback(char dtmf, bt_bdaddr_t* bd_addr) {
+static void dtmf_cmd_callback(char dtmf, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -190,7 +190,7 @@
                                addr.get());
 }
 
-static void noice_reduction_callback(bthf_nrec_t nrec, bt_bdaddr_t* bd_addr) {
+static void noice_reduction_callback(bthf_nrec_t nrec, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -204,7 +204,7 @@
                                nrec == BTHF_NREC_START, addr.get());
 }
 
-static void wbs_callback(bthf_wbs_config_t wbs_config, bt_bdaddr_t* bd_addr) {
+static void wbs_callback(bthf_wbs_config_t wbs_config, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -216,25 +216,25 @@
                                addr.get());
 }
 
-static void at_chld_callback(bthf_chld_type_t chld, bt_bdaddr_t* bd_addr) {
+static void at_chld_callback(bthf_chld_type_t chld, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) {
     ALOGE("Fail to new jbyteArray bd addr for audio state");
     return;
   }
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtChld, chld,
                                addr.get());
 }
 
-static void at_cnum_callback(bt_bdaddr_t* bd_addr) {
+static void at_cnum_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -248,7 +248,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCnum, addr.get());
 }
 
-static void at_cind_callback(bt_bdaddr_t* bd_addr) {
+static void at_cind_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -262,7 +262,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCind, addr.get());
 }
 
-static void at_cops_callback(bt_bdaddr_t* bd_addr) {
+static void at_cops_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -276,7 +276,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCops, addr.get());
 }
 
-static void at_clcc_callback(bt_bdaddr_t* bd_addr) {
+static void at_clcc_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -290,7 +290,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtClcc, addr.get());
 }
 
-static void unknown_at_callback(char* at_string, bt_bdaddr_t* bd_addr) {
+static void unknown_at_callback(char* at_string, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -307,7 +307,7 @@
                                js_at_string.get(), addr.get());
 }
 
-static void key_pressed_callback(bt_bdaddr_t* bd_addr) {
+static void key_pressed_callback(RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -321,7 +321,7 @@
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onKeyPressed, addr.get());
 }
 
-static void at_bind_callback(char* at_string, bt_bdaddr_t* bd_addr) {
+static void at_bind_callback(char* at_string, RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -337,7 +337,7 @@
 }
 
 static void at_biev_callback(bthf_hf_ind_type_t ind_id, int ind_value,
-                             bt_bdaddr_t* bd_addr) {
+                             RawAddress* bd_addr) {
   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;
@@ -479,7 +479,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHfpInterface->connect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHfpInterface->connect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF connection, status: %d", status);
   }
@@ -498,7 +498,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHfpInterface->disconnect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHfpInterface->disconnect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF disconnection, status: %d", status);
   }
@@ -517,8 +517,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status =
-      sBluetoothHfpInterface->connect_audio((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHfpInterface->connect_audio((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF audio connection, status: %d", status);
   }
@@ -538,7 +537,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpInterface->disconnect_audio((bt_bdaddr_t*)addr);
+      sBluetoothHfpInterface->disconnect_audio((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF audio disconnection, status: %d", status);
   }
@@ -558,7 +557,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpInterface->start_voice_recognition((bt_bdaddr_t*)addr);
+      sBluetoothHfpInterface->start_voice_recognition((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to start voice recognition, status: %d", status);
   }
@@ -578,7 +577,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpInterface->stop_voice_recognition((bt_bdaddr_t*)addr);
+      sBluetoothHfpInterface->stop_voice_recognition((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to stop voice recognition, status: %d", status);
   }
@@ -598,7 +597,7 @@
   }
 
   bt_status_t status = sBluetoothHfpInterface->volume_control(
-      (bthf_volume_type_t)volume_type, volume, (bt_bdaddr_t*)addr);
+      (bthf_volume_type_t)volume_type, volume, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("FAILED to control volume, status: %d", status);
   }
@@ -635,7 +634,7 @@
   const char* operator_name = env->GetStringUTFChars(operator_str, NULL);
 
   bt_status_t status =
-      sBluetoothHfpInterface->cops_response(operator_name, (bt_bdaddr_t*)addr);
+      sBluetoothHfpInterface->cops_response(operator_name, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending cops response, status: %d", status);
   }
@@ -661,7 +660,7 @@
 
   bt_status_t status = sBluetoothHfpInterface->cind_response(
       service, num_active, num_held, (bthf_call_state_t)call_state, signal,
-      roam, battery_charge, (bt_bdaddr_t*)addr);
+      roam, battery_charge, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed cind_response, status: %d", status);
   }
@@ -685,7 +684,7 @@
   bt_status_t status = sBluetoothHfpInterface->bind_response(
       (bthf_hf_ind_type_t)ind_id,
       ind_status ? BTHF_HF_IND_ENABLED : BTHF_HF_IND_DISABLED,
-      (bt_bdaddr_t*)addr);
+      (RawAddress*)addr);
 
   if (status != BT_STATUS_SUCCESS)
     ALOGE("%s: Failed bind_response, status: %d", __func__, status);
@@ -709,7 +708,7 @@
   const char* response = env->GetStringUTFChars(response_str, NULL);
 
   bt_status_t status = sBluetoothHfpInterface->formatted_at_response(
-      response, (bt_bdaddr_t*)addr);
+      response, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed formatted AT response, status: %d", status);
   }
@@ -731,7 +730,7 @@
   }
 
   bt_status_t status = sBluetoothHfpInterface->at_response(
-      (bthf_at_response_t)response_code, cmee_code, (bt_bdaddr_t*)addr);
+      (bthf_at_response_t)response_code, cmee_code, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed AT response, status: %d", status);
   }
@@ -759,7 +758,7 @@
       index, (bthf_call_direction_t)dir, (bthf_call_state_t)callStatus,
       (bthf_call_mode_t)mode,
       mpty ? BTHF_CALL_MPTY_TYPE_MULTI : BTHF_CALL_MPTY_TYPE_SINGLE, number,
-      (bthf_call_addrtype_t)type, (bt_bdaddr_t*)addr);
+      (bthf_call_addrtype_t)type, (RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed sending CLCC response, status: %d", status);
   }
@@ -799,7 +798,7 @@
   }
 
   bt_status_t status = sBluetoothHfpInterface->configure_wbs(
-      (bt_bdaddr_t*)addr, (bthf_wbs_config_t)codec_config);
+      (RawAddress*)addr, (bthf_wbs_config_t)codec_config);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HF WBS codec config, status: %d", status);
   }
@@ -807,6 +806,18 @@
   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
 
+static jboolean setScoAllowedNative(JNIEnv* env, jobject object,
+                                    jboolean value) {
+  if (!sBluetoothHfpInterface) return JNI_FALSE;
+
+  bt_status_t status =
+      sBluetoothHfpInterface->set_sco_allowed(value == JNI_TRUE);
+  if (status != BT_STATUS_SUCCESS) {
+    ALOGE("Failed HF set sco allowed, status: %d", status);
+  }
+  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+}
+
 static JNINativeMethod sMethods[] = {
     {"classInitNative", "()V", (void*)classInitNative},
     {"initializeNative", "(IZ)V", (void*)initializeNative},
@@ -832,6 +843,7 @@
     {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z",
      (void*)phoneStateChangeNative},
     {"configureWBSNative", "([BI)Z", (void*)configureWBSNative},
+    {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative},
 };
 
 int register_com_android_bluetooth_hfp(JNIEnv* env) {
diff --git a/jni/com_android_bluetooth_hfpclient.cpp b/jni/com_android_bluetooth_hfpclient.cpp
index 4bb1380..04e963b 100644
--- a/jni/com_android_bluetooth_hfpclient.cpp
+++ b/jni/com_android_bluetooth_hfpclient.cpp
@@ -50,21 +50,21 @@
 static jmethodID method_onLastVoiceTagNumber;
 static jmethodID method_onRingIndication;
 
-static jbyteArray marshall_bda(const bt_bdaddr_t* bd_addr) {
+static jbyteArray marshall_bda(const RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return NULL;
 
-  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
   if (!addr) {
     ALOGE("Fail to new jbyteArray bd addr");
     return NULL;
   }
-  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   return addr;
 }
 
-static void connection_state_cb(const bt_bdaddr_t* bd_addr,
+static void connection_state_cb(const RawAddress* bd_addr,
                                 bthf_client_connection_state_t state,
                                 unsigned int peer_feat,
                                 unsigned int chld_feat) {
@@ -80,7 +80,7 @@
                                addr.get());
 }
 
-static void audio_state_cb(const bt_bdaddr_t* bd_addr,
+static void audio_state_cb(const RawAddress* bd_addr,
                            bthf_client_audio_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -92,15 +92,14 @@
                                (jint)state, addr.get());
 }
 
-static void vr_cmd_cb(const bt_bdaddr_t* bd_addr,
-                      bthf_client_vr_state_t state) {
+static void vr_cmd_cb(const RawAddress* bd_addr, bthf_client_vr_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged,
                                (jint)state);
 }
 
-static void network_state_cb(const bt_bdaddr_t* bd_addr,
+static void network_state_cb(const RawAddress* bd_addr,
                              bthf_client_network_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -112,7 +111,7 @@
                                (jint)state, addr.get());
 }
 
-static void network_roaming_cb(const bt_bdaddr_t* bd_addr,
+static void network_roaming_cb(const RawAddress* bd_addr,
                                bthf_client_service_type_t type) {
   CallbackEnv sCallbackEnv(__func__);
 
@@ -123,7 +122,7 @@
                                (jint)type, addr.get());
 }
 
-static void network_signal_cb(const bt_bdaddr_t* bd_addr, int signal) {
+static void network_signal_cb(const RawAddress* bd_addr, int signal) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -134,7 +133,7 @@
                                (jint)signal, addr.get());
 }
 
-static void battery_level_cb(const bt_bdaddr_t* bd_addr, int level) {
+static void battery_level_cb(const RawAddress* bd_addr, int level) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -145,7 +144,7 @@
                                (jint)level, addr.get());
 }
 
-static void current_operator_cb(const bt_bdaddr_t* bd_addr, const char* name) {
+static void current_operator_cb(const RawAddress* bd_addr, const char* name) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -158,7 +157,7 @@
                                js_name.get(), addr.get());
 }
 
-static void call_cb(const bt_bdaddr_t* bd_addr, bthf_client_call_t call) {
+static void call_cb(const RawAddress* bd_addr, bthf_client_call_t call) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -169,7 +168,7 @@
                                addr.get());
 }
 
-static void callsetup_cb(const bt_bdaddr_t* bd_addr,
+static void callsetup_cb(const RawAddress* bd_addr,
                          bthf_client_callsetup_t callsetup) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -185,7 +184,7 @@
                                (jint)callsetup, addr.get());
 }
 
-static void callheld_cb(const bt_bdaddr_t* bd_addr,
+static void callheld_cb(const RawAddress* bd_addr,
                         bthf_client_callheld_t callheld) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -197,7 +196,7 @@
                                addr.get());
 }
 
-static void resp_and_hold_cb(const bt_bdaddr_t* bd_addr,
+static void resp_and_hold_cb(const RawAddress* bd_addr,
                              bthf_client_resp_and_hold_t resp_and_hold) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -209,7 +208,7 @@
                                (jint)resp_and_hold, addr.get());
 }
 
-static void clip_cb(const bt_bdaddr_t* bd_addr, const char* number) {
+static void clip_cb(const RawAddress* bd_addr, const char* number) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -222,7 +221,7 @@
                                addr.get());
 }
 
-static void call_waiting_cb(const bt_bdaddr_t* bd_addr, const char* number) {
+static void call_waiting_cb(const RawAddress* bd_addr, const char* number) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -234,7 +233,7 @@
                                js_number.get(), addr.get());
 }
 
-static void current_calls_cb(const bt_bdaddr_t* bd_addr, int index,
+static void current_calls_cb(const RawAddress* bd_addr, int index,
                              bthf_client_call_direction_t dir,
                              bthf_client_call_state_t state,
                              bthf_client_call_mpty_type_t mpty,
@@ -250,7 +249,7 @@
                                state, mpty, js_number.get(), addr.get());
 }
 
-static void volume_change_cb(const bt_bdaddr_t* bd_addr,
+static void volume_change_cb(const RawAddress* bd_addr,
                              bthf_client_volume_type_t type, int volume) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -261,7 +260,7 @@
                                (jint)volume, addr.get());
 }
 
-static void cmd_complete_cb(const bt_bdaddr_t* bd_addr,
+static void cmd_complete_cb(const RawAddress* bd_addr,
                             bthf_client_cmd_complete_t type, int cme) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -272,7 +271,7 @@
                                (jint)cme, addr.get());
 }
 
-static void subscriber_info_cb(const bt_bdaddr_t* bd_addr, const char* name,
+static void subscriber_info_cb(const RawAddress* bd_addr, const char* name,
                                bthf_client_subscriber_service_type_t type) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -285,7 +284,7 @@
                                js_name.get(), (jint)type, addr.get());
 }
 
-static void in_band_ring_cb(const bt_bdaddr_t* bd_addr,
+static void in_band_ring_cb(const RawAddress* bd_addr,
                             bthf_client_in_band_ring_state_t in_band) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -296,7 +295,7 @@
                                (jint)in_band, addr.get());
 }
 
-static void last_voice_tag_number_cb(const bt_bdaddr_t* bd_addr,
+static void last_voice_tag_number_cb(const RawAddress* bd_addr,
                                      const char* number) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -309,7 +308,7 @@
                                js_number.get(), addr.get());
 }
 
-static void ring_indication_cb(const bt_bdaddr_t* bd_addr) {
+static void ring_indication_cb(const RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -445,8 +444,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status =
-      sBluetoothHfpClientInterface->connect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHfpClientInterface->connect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed AG connection, status: %d", status);
   }
@@ -465,7 +463,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpClientInterface->disconnect((const bt_bdaddr_t*)addr);
+      sBluetoothHfpClientInterface->disconnect((const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed AG disconnection, status: %d", status);
   }
@@ -484,7 +482,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpClientInterface->connect_audio((const bt_bdaddr_t*)addr);
+      sBluetoothHfpClientInterface->connect_audio((const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed AG audio connection, status: %d", status);
   }
@@ -503,7 +501,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpClientInterface->disconnect_audio((const bt_bdaddr_t*)addr);
+      sBluetoothHfpClientInterface->disconnect_audio((const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed AG audio disconnection, status: %d", status);
   }
@@ -522,7 +520,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->start_voice_recognition(
-      (const bt_bdaddr_t*)addr);
+      (const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to start voice recognition, status: %d", status);
   }
@@ -541,7 +539,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->stop_voice_recognition(
-      (const bt_bdaddr_t*)addr);
+      (const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to stop voice recognition, status: %d", status);
   }
@@ -560,7 +558,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->volume_control(
-      (const bt_bdaddr_t*)addr, (bthf_client_volume_type_t)volume_type, volume);
+      (const RawAddress*)addr, (bthf_client_volume_type_t)volume_type, volume);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("FAILED to control volume, status: %d", status);
   }
@@ -584,7 +582,7 @@
   }
 
   bt_status_t status =
-      sBluetoothHfpClientInterface->dial((const bt_bdaddr_t*)addr, number);
+      sBluetoothHfpClientInterface->dial((const RawAddress*)addr, number);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to dial, status: %d", status);
   }
@@ -606,7 +604,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->dial_memory(
-      (const bt_bdaddr_t*)addr, (int)location);
+      (const RawAddress*)addr, (int)location);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to dial from memory, status: %d", status);
   }
@@ -627,7 +625,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->handle_call_action(
-      (const bt_bdaddr_t*)addr, (bthf_client_call_action_t)action, (int)index);
+      (const RawAddress*)addr, (bthf_client_call_action_t)action, (int)index);
 
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to enter private mode, status: %d", status);
@@ -647,7 +645,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->query_current_calls(
-      (const bt_bdaddr_t*)addr);
+      (const RawAddress*)addr);
 
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to query current calls, status: %d", status);
@@ -668,7 +666,7 @@
 
   bt_status_t status =
       sBluetoothHfpClientInterface->query_current_operator_name(
-          (const bt_bdaddr_t*)addr);
+          (const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to query current operator name, status: %d", status);
   }
@@ -688,7 +686,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->retrieve_subscriber_info(
-      (const bt_bdaddr_t*)addr);
+      (const RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to retrieve subscriber info, status: %d", status);
   }
@@ -708,7 +706,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->send_dtmf(
-      (const bt_bdaddr_t*)addr, (char)code);
+      (const RawAddress*)addr, (char)code);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to send DTMF, status: %d", status);
   }
@@ -729,7 +727,7 @@
 
   bt_status_t status =
       sBluetoothHfpClientInterface->request_last_voice_tag_number(
-          (const bt_bdaddr_t*)addr);
+          (const RawAddress*)addr);
 
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to request last Voice Tag number, status: %d", status);
@@ -756,7 +754,7 @@
   }
 
   bt_status_t status = sBluetoothHfpClientInterface->send_at_cmd(
-      (const bt_bdaddr_t*)addr, cmd, val1, val2, arg);
+      (const RawAddress*)addr, cmd, val1, val2, arg);
 
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed to send cmd, status: %d", status);
diff --git a/jni/com_android_bluetooth_hid.cpp b/jni/com_android_bluetooth_hid.cpp
index d649063..8a58c29 100644
--- a/jni/com_android_bluetooth_hid.cpp
+++ b/jni/com_android_bluetooth_hid.cpp
@@ -37,21 +37,21 @@
 static const bthh_interface_t* sBluetoothHidInterface = NULL;
 static jobject mCallbacksObj = NULL;
 
-static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) {
+static jbyteArray marshall_bda(RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return NULL;
 
-  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
   if (!addr) {
     ALOGE("Fail to new jbyteArray bd addr");
     return NULL;
   }
-  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   return addr;
 }
 
-static void connection_state_callback(bt_bdaddr_t* bd_addr,
+static void connection_state_callback(RawAddress* bd_addr,
                                       bthh_connection_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -69,7 +69,7 @@
                                addr.get(), (jint)state);
 }
 
-static void get_protocol_mode_callback(bt_bdaddr_t* bd_addr,
+static void get_protocol_mode_callback(RawAddress* bd_addr,
                                        bthh_status_t hh_status,
                                        bthh_protocol_mode_t mode) {
   CallbackEnv sCallbackEnv(__func__);
@@ -93,7 +93,7 @@
                                addr.get(), (jint)mode);
 }
 
-static void get_report_callback(bt_bdaddr_t* bd_addr, bthh_status_t hh_status,
+static void get_report_callback(RawAddress* bd_addr, bthh_status_t hh_status,
                                 uint8_t* rpt_data, int rpt_size) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -123,7 +123,7 @@
                                data.get(), (jint)rpt_size);
 }
 
-static void virtual_unplug_callback(bt_bdaddr_t* bd_addr,
+static void virtual_unplug_callback(RawAddress* bd_addr,
                                     bthh_status_t hh_status) {
   ALOGV("call to virtual_unplug_callback");
   CallbackEnv sCallbackEnv(__func__);
@@ -141,7 +141,7 @@
                                addr.get(), (jint)hh_status);
 }
 
-static void handshake_callback(bt_bdaddr_t* bd_addr, bthh_status_t hh_status) {
+static void handshake_callback(RawAddress* bd_addr, bthh_status_t hh_status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
   if (!mCallbacksObj) {
@@ -158,8 +158,8 @@
                                (jint)hh_status);
 }
 
-static void get_idle_time_callback(bt_bdaddr_t* bd_addr,
-                                   bthh_status_t hh_status, int idle_time) {
+static void get_idle_time_callback(RawAddress* bd_addr, bthh_status_t hh_status,
+                                   int idle_time) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
@@ -265,7 +265,7 @@
   }
 
   jboolean ret = JNI_TRUE;
-  bt_status_t status = sBluetoothHidInterface->connect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHidInterface->connect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed HID channel connection, status: %d", status);
     ret = JNI_FALSE;
@@ -287,7 +287,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHidInterface->disconnect((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed disconnect hid channel, status: %d", status);
     ret = JNI_FALSE;
@@ -311,7 +311,7 @@
   // TODO: protocolMode is unused by the backend: see b/28908173
   bthh_protocol_mode_t protocolMode = BTHH_UNSUPPORTED_MODE;
   bt_status_t status = sBluetoothHidInterface->get_protocol(
-      (bt_bdaddr_t*)addr, (bthh_protocol_mode_t)protocolMode);
+      (RawAddress*)addr, (bthh_protocol_mode_t)protocolMode);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed get protocol mode, status: %d", status);
     ret = JNI_FALSE;
@@ -333,7 +333,7 @@
 
   jboolean ret = JNI_TRUE;
   bt_status_t status =
-      sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t*)addr);
+      sBluetoothHidInterface->virtual_unplug((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed virual unplug, status: %d", status);
     ret = JNI_FALSE;
@@ -369,7 +369,7 @@
 
   jboolean ret = JNI_TRUE;
   bt_status_t status =
-      sBluetoothHidInterface->set_protocol((bt_bdaddr_t*)addr, mode);
+      sBluetoothHidInterface->set_protocol((RawAddress*)addr, mode);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed set protocol mode, status: %d", status);
     ret = JNI_FALSE;
@@ -396,7 +396,7 @@
   jint rId = reportId;
 
   bt_status_t status = sBluetoothHidInterface->get_report(
-      (bt_bdaddr_t*)addr, (bthh_report_type_t)rType, (uint8_t)rId, bufferSize);
+      (RawAddress*)addr, (bthh_report_type_t)rType, (uint8_t)rId, bufferSize);
   jboolean ret = JNI_TRUE;
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed get report, status: %d", status);
@@ -422,7 +422,7 @@
 
   jboolean ret = JNI_TRUE;
   bt_status_t status = sBluetoothHidInterface->set_report(
-      (bt_bdaddr_t*)addr, (bthh_report_type_t)rType, (char*)c_report);
+      (RawAddress*)addr, (bthh_report_type_t)rType, (char*)c_report);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed set report, status: %d", status);
     ret = JNI_FALSE;
@@ -448,7 +448,7 @@
   const char* c_report = env->GetStringUTFChars(report, NULL);
 
   bt_status_t status =
-      sBluetoothHidInterface->send_data((bt_bdaddr_t*)addr, (char*)c_report);
+      sBluetoothHidInterface->send_data((RawAddress*)addr, (char*)c_report);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("Failed set data, status: %d", status);
     ret = JNI_FALSE;
@@ -469,7 +469,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHidInterface->get_idle_time((bt_bdaddr_t*)addr);
+  bt_status_t status = sBluetoothHidInterface->get_idle_time((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("%s: Failed get idle time, status: %d", __func__, status);
   }
@@ -488,8 +488,8 @@
     return JNI_FALSE;
   }
 
-  bt_status_t status = sBluetoothHidInterface->set_idle_time(
-           (bt_bdaddr_t*)addr, idle_time);
+  bt_status_t status =
+      sBluetoothHidInterface->set_idle_time((RawAddress*)addr, idle_time);
   if (status != BT_STATUS_SUCCESS) {
     ALOGE("%s: Failed set idle time, status: %d", __func__, status);
   }
diff --git a/jni/com_android_bluetooth_hidd.cpp b/jni/com_android_bluetooth_hidd.cpp
index 5b0beec..b0e084a 100644
--- a/jni/com_android_bluetooth_hidd.cpp
+++ b/jni/com_android_bluetooth_hidd.cpp
@@ -38,21 +38,21 @@
 static const bthd_interface_t* sHiddIf = NULL;
 static jobject mCallbacksObj = NULL;
 
-static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) {
+static jbyteArray marshall_bda(RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return NULL;
 
-  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
   if (!addr) {
     ALOGE("Fail to new jbyteArray bd addr");
     return NULL;
   }
-  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   return addr;
 }
 
-static void application_state_callback(bt_bdaddr_t* bd_addr,
+static void application_state_callback(RawAddress* bd_addr,
                                        bthd_application_state_t state) {
   jboolean registered = JNI_FALSE;
 
@@ -76,7 +76,7 @@
                                addr.get(), registered);
 }
 
-static void connection_state_callback(bt_bdaddr_t* bd_addr,
+static void connection_state_callback(RawAddress* bd_addr,
                                       bthd_connection_state_t state) {
   CallbackEnv sCallbackEnv(__func__);
 
@@ -426,7 +426,7 @@
     return JNI_FALSE;
   }
 
-  bt_status_t ret = sHiddIf->connect((bt_bdaddr_t*)addr);
+  bt_status_t ret = sHiddIf->connect((RawAddress*)addr);
 
   ALOGV("%s: connect() returned %d", __FUNCTION__, ret);
 
diff --git a/jni/com_android_bluetooth_pan.cpp b/jni/com_android_bluetooth_pan.cpp
index 2786a80..85107a0 100644
--- a/jni/com_android_bluetooth_pan.cpp
+++ b/jni/com_android_bluetooth_pan.cpp
@@ -44,16 +44,16 @@
 static const btpan_interface_t* sPanIf = NULL;
 static jobject mCallbacksObj = NULL;
 
-static jbyteArray marshall_bda(const bt_bdaddr_t* bd_addr) {
+static jbyteArray marshall_bda(const RawAddress* bd_addr) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return NULL;
 
-  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
   if (!addr) {
     ALOGE("Fail to new jbyteArray bd addr");
     return NULL;
   }
-  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   return addr;
 }
@@ -76,8 +76,8 @@
 
 static void connection_state_callback(btpan_connection_state_t state,
                                       bt_status_t error,
-                                      const bt_bdaddr_t* bd_addr,
-                                      int local_role, int remote_role) {
+                                      const RawAddress* bd_addr, int local_role,
+                                      int remote_role) {
   debug("state:%d, local_role:%d, remote_role:%d", state, local_role,
         remote_role);
   if (mCallbacksObj == NULL) {
@@ -200,7 +200,7 @@
   }
 
   jboolean ret = JNI_TRUE;
-  bt_status_t status = sPanIf->connect((bt_bdaddr_t*)addr, src_role, dest_role);
+  bt_status_t status = sPanIf->connect((RawAddress*)addr, src_role, dest_role);
   if (status != BT_STATUS_SUCCESS) {
     error("Failed PAN channel connection, status: %d", status);
     ret = JNI_FALSE;
@@ -221,7 +221,7 @@
   }
 
   jboolean ret = JNI_TRUE;
-  bt_status_t status = sPanIf->disconnect((bt_bdaddr_t*)addr);
+  bt_status_t status = sPanIf->disconnect((RawAddress*)addr);
   if (status != BT_STATUS_SUCCESS) {
     error("Failed disconnect pan channel, status: %d", status);
     ret = JNI_FALSE;
diff --git a/jni/com_android_bluetooth_sdp.cpp b/jni/com_android_bluetooth_sdp.cpp
index fb68f47..f658413 100644
--- a/jni/com_android_bluetooth_sdp.cpp
+++ b/jni/com_android_bluetooth_sdp.cpp
@@ -59,7 +59,7 @@
 
 static const btsdp_interface_t* sBluetoothSdpInterface = NULL;
 
-static void sdp_search_callback(bt_status_t status, bt_bdaddr_t* bd_addr,
+static void sdp_search_callback(bt_status_t status, RawAddress* bd_addr,
                                 uint8_t* uuid_in, int record_size,
                                 bluetooth_sdp_record* record);
 
@@ -135,7 +135,7 @@
   }
   ALOGD("%s UUID %.*s", __func__, 16, (uint8_t*)uuid);
 
-  int ret = sBluetoothSdpInterface->sdp_search((bt_bdaddr_t*)addr,
+  int ret = sBluetoothSdpInterface->sdp_search((RawAddress*)addr,
                                                (const uint8_t*)uuid);
   if (ret != BT_STATUS_SUCCESS) {
     ALOGE("SDP Search initialization failed: %d", ret);
@@ -146,21 +146,21 @@
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
 
-static void sdp_search_callback(bt_status_t status, bt_bdaddr_t* bd_addr,
+static void sdp_search_callback(bt_status_t status, RawAddress* bd_addr,
                                 uint8_t* uuid_in, int count,
                                 bluetooth_sdp_record* records) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
 
   ScopedLocalRef<jbyteArray> addr(
-      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
+      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
   if (!addr.get()) return;
 
   ScopedLocalRef<jbyteArray> uuid(
       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_uuid_t)));
   if (!uuid.get()) return;
 
-  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
+  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                    (jbyte*)bd_addr);
   sCallbackEnv->SetByteArrayRegion(uuid.get(), 0, sizeof(bt_uuid_t),
                                    (jbyte*)uuid_in);
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index dc5135d..68d0e06 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -74,7 +74,7 @@
     <string name="bt_error_btn_ok" msgid="5965151173011534240">"حسنًا"</string>
     <string name="unknown_file" msgid="6092727753965095366">"ملف غير معروف"</string>
     <string name="unknown_file_desc" msgid="480434281415453287">"ليس هناك تطبيق لمعالجة هذا النوع من الملفات. \n"</string>
-    <string name="not_exist_file" msgid="3489434189599716133">"ليست هناك أية ملفات"</string>
+    <string name="not_exist_file" msgid="3489434189599716133">"ليست هناك أي ملفات"</string>
     <string name="not_exist_file_desc" msgid="4059531573790529229">"الملف غير موجود. \n"</string>
     <string name="enabling_progress_title" msgid="436157952334723406">"يرجى الانتظار…"</string>
     <string name="enabling_progress_content" msgid="4601542238119927904">"جارٍ تشغيل البلوتوث..."</string>
diff --git a/res/values-en-rCA/config.xml b/res/values-en-rCA/config.xml
new file mode 100644
index 0000000..4f96544
--- /dev/null
+++ b/res/values-en-rCA/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2009-2012 Broadcom Corporation
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pairing_ui_package" msgid="6399948348712579121">"com.android.settings"</string>
+</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..f43c385
--- /dev/null
+++ b/res/values-en-rCA/strings.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Access download manager."</string>
+    <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Allows the application to access the Bluetooth Share manager and to use it to transfer files."</string>
+    <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Whitelist bluetooth device access."</string>
+    <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Allows the app to temporarily whitelist a Bluetooth device, allowing that device to send files to this device without user confirmation."</string>
+    <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+    <string name="unknown_device" msgid="9221903979877041009">"Unknown device"</string>
+    <string name="unknownNumber" msgid="4994750948072751566">"Unknown"</string>
+    <string name="airplane_error_title" msgid="2683839635115739939">"Airplane mode"</string>
+    <string name="airplane_error_msg" msgid="8698965595254137230">"You can\'t use Bluetooth in Airplane mode."</string>
+    <string name="bt_enable_title" msgid="8657832550503456572"></string>
+    <string name="bt_enable_line1" msgid="7203551583048149">"To use Bluetooth services, you must first turn on Bluetooth."</string>
+    <string name="bt_enable_line2" msgid="4341936569415937994">"Turn on Bluetooth now?"</string>
+    <string name="bt_enable_cancel" msgid="1988832367505151727">"Cancel"</string>
+    <string name="bt_enable_ok" msgid="3432462749994538265">"Turn on"</string>
+    <string name="incoming_file_confirm_title" msgid="8139874248612182627">"File transfer"</string>
+    <string name="incoming_file_confirm_content" msgid="2752605552743148036">"Accept incoming file?"</string>
+    <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Decline"</string>
+    <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accept"</string>
+    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+    <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"There was a timeout while accepting an incoming file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+    <string name="incoming_file_confirm_Notification_title" msgid="5573329005298936903">"Incoming file"</string>
+    <string name="incoming_file_confirm_Notification_content" msgid="3359694069319644738">"<xliff:g id="SENDER">%1$s</xliff:g> is ready to send <xliff:g id="FILE">%2$s</xliff:g>"</string>
+    <string name="notification_receiving" msgid="4674648179652543984">"Bluetooth share: Receiving <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="notification_received" msgid="3324588019186687985">"Bluetooth share: Received <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth share: File <xliff:g id="FILE">%1$s</xliff:g> not received"</string>
+    <string name="notification_sending" msgid="3035748958534983833">"Bluetooth share: Sending <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="notification_sent" msgid="9218710861333027778">"Bluetooth share: Sent <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="notification_sent_complete" msgid="302943281067557969">"100% complete"</string>
+    <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetooth share: File <xliff:g id="FILE">%1$s</xliff:g> not sent"</string>
+    <string name="download_title" msgid="3353228219772092586">"File transfer"</string>
+    <string name="download_line1" msgid="4926604799202134144">"From: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+    <string name="download_line2" msgid="5876973543019417712">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="download_line3" msgid="4384821622908676061">"File size: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+    <string name="download_line4" msgid="8535996869722666525"></string>
+    <string name="download_line5" msgid="3069560415845295386">"Receiving file…"</string>
+    <string name="download_cancel" msgid="9177305996747500768">"Stop"</string>
+    <string name="download_ok" msgid="5000360731674466039">"Hide"</string>
+    <string name="incoming_line1" msgid="2127419875681087545">"From"</string>
+    <string name="incoming_line2" msgid="3348994249285315873">"Filename"</string>
+    <string name="incoming_line3" msgid="7954237069667474024">"Size"</string>
+    <string name="download_fail_line1" msgid="3846450148862894552">"File not received"</string>
+    <string name="download_fail_line2" msgid="8950394574689971071">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="download_fail_line3" msgid="3451040656154861722">"Reason: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+    <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+    <string name="download_succ_line5" msgid="4509944688281573595">"File received"</string>
+    <string name="download_succ_ok" msgid="7053688246357050216">"Open"</string>
+    <string name="upload_line1" msgid="2055952074059709052">"To: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+    <string name="upload_line3" msgid="4920689672457037437">"File type: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+    <string name="upload_line5" msgid="7759322537674229752">"Sending file…"</string>
+    <string name="upload_succ_line5" msgid="5687317197463383601">"File sent"</string>
+    <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+    <string name="upload_fail_line1" msgid="7899394672421491701">"The file wasn\'t sent to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\"."</string>
+    <string name="upload_fail_line1_2" msgid="2108129204050841798">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+    <string name="upload_fail_ok" msgid="5807702461606714296">"Try again"</string>
+    <string name="upload_fail_cancel" msgid="9118496285835687125">"Close"</string>
+    <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+    <string name="unknown_file" msgid="6092727753965095366">"Unknown file"</string>
+    <string name="unknown_file_desc" msgid="480434281415453287">"There\'s no app to handle this type of file. \n"</string>
+    <string name="not_exist_file" msgid="3489434189599716133">"No file"</string>
+    <string name="not_exist_file_desc" msgid="4059531573790529229">"The file doesn\'t exist. \n"</string>
+    <string name="enabling_progress_title" msgid="436157952334723406">"Please wait…"</string>
+    <string name="enabling_progress_content" msgid="4601542238119927904">"Turning on Bluetooth…"</string>
+    <string name="bt_toast_1" msgid="972182708034353383">"The file will be received. Check progress in the Notifications panel."</string>
+    <string name="bt_toast_2" msgid="8602553334099066582">"The file can\'t be received."</string>
+    <string name="bt_toast_3" msgid="6707884165086862518">"Stopped receiving file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+    <string name="bt_toast_4" msgid="4678812947604395649">"Sending file to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+    <string name="bt_toast_5" msgid="2846870992823019494">"Sending <xliff:g id="NUMBER">%1$s</xliff:g> files to \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+    <string name="bt_toast_6" msgid="1855266596936622458">"Stopped sending file to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+    <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"There isn\'t enough space in USB storage to save the file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+    <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"There isn\'t enough space on the SD card to save the file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+    <string name="bt_sm_2_2" msgid="2965243265852680543">"Space needed: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+    <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Too many requests are being processed. Try again later."</string>
+    <string name="status_pending" msgid="2503691772030877944">"File transfer not started yet"</string>
+    <string name="status_running" msgid="6562808920311008696">"File transfer is ongoing."</string>
+    <string name="status_success" msgid="239573225847565868">"File transfer completed successfully."</string>
+    <string name="status_not_accept" msgid="1695082417193780738">"Content isn\'t supported."</string>
+    <string name="status_forbidden" msgid="613956401054050725">"Transfer forbidden by target device."</string>
+    <string name="status_canceled" msgid="6664490318773098285">"Transfer cancelled by user."</string>
+    <string name="status_file_error" msgid="3671917770630165299">"Storage issue"</string>
+    <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"No USB storage."</string>
+    <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"No SD card. Insert an SD card to save transferred files."</string>
+    <string name="status_connection_error" msgid="947681831523219891">"Connection unsuccessful."</string>
+    <string name="status_protocol_error" msgid="3245444473429269539">"Request can\'t be handled correctly."</string>
+    <string name="status_unknown_error" msgid="8156660554237824912">"Unknown error."</string>
+    <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth received"</string>
+    <string name="opp_notification_group" msgid="3486303082135789982">"Bluetooth Share"</string>
+    <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Received complete."</string>
+    <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Sent complete."</string>
+    <string name="inbound_history_title" msgid="6940914942271327563">"Inbound transfers"</string>
+    <string name="outbound_history_title" msgid="4279418703178140526">"Outbound transfers"</string>
+    <string name="no_transfers" msgid="3482965619151865672">"Transfer history is empty."</string>
+    <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"All items will be cleared from the list."</string>
+    <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetooth share: Sent files"</string>
+    <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth share: Received files"</string>
+    <plurals name="noti_caption_unsuccessful" formatted="false" msgid="2020750076679526122">
+      <item quantity="other"><xliff:g id="UNSUCCESSFUL_NUMBER_1">%1$d</xliff:g> unsuccessful.</item>
+      <item quantity="one"><xliff:g id="UNSUCCESSFUL_NUMBER_0">%1$d</xliff:g> unsuccessful.</item>
+    </plurals>
+    <plurals name="noti_caption_success" formatted="false" msgid="1572472450257645181">
+      <item quantity="other"><xliff:g id="SUCCESSFUL_NUMBER_1">%1$d</xliff:g> successful, %2$s</item>
+      <item quantity="one"><xliff:g id="SUCCESSFUL_NUMBER_0">%1$d</xliff:g> successful, %2$s</item>
+    </plurals>
+    <string name="transfer_menu_clear_all" msgid="790017462957873132">"Clear list"</string>
+    <string name="transfer_menu_open" msgid="3368984869083107200">"Open"</string>
+    <string name="transfer_menu_clear" msgid="5854038118831427492">"Clear from list"</string>
+    <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Clear"</string>
+    <string name="bluetooth_map_settings_save" msgid="7635491847388074606">"Save"</string>
+    <string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"Cancel"</string>
+    <string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Select the accounts that you want to share through Bluetooth. You still have to accept any access to the accounts when connecting."</string>
+    <string name="bluetooth_map_settings_count" msgid="4557473074937024833">"Slots left:"</string>
+    <string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"Application Icon"</string>
+    <string name="bluetooth_map_settings_title" msgid="7420332483392851321">"Bluetooth Message Sharing Settings"</string>
+    <string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"Cannot select account. 0 slots left"</string>
+    <string name="bluetooth_connected" msgid="6718623220072656906">"Bluetooth audio connected"</string>
+    <string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio disconnected"</string>
+    <string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
+</resources>
diff --git a/res/values-en-rCA/strings_pbap.xml b/res/values-en-rCA/strings_pbap.xml
new file mode 100644
index 0000000..c80ccb6
--- /dev/null
+++ b/res/values-en-rCA/strings_pbap.xml
@@ -0,0 +1,16 @@
+<?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="pbap_session_key_dialog_title" msgid="3580996574333882561">"Type session key for %1$s"</string>
+    <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Bluetooth session key required"</string>
+    <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"There was time out to accept connection with %1$s"</string>
+    <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"There was time out to input session key with %1$s"</string>
+    <string name="auth_notif_ticker" msgid="1575825798053163744">"Obex authentication request"</string>
+    <string name="auth_notif_title" msgid="7599854855681573258">"Session Key"</string>
+    <string name="auth_notif_message" msgid="6667218116427605038">"Type session key for %1$s"</string>
+    <string name="defaultname" msgid="4821590500649090078">"Car Kit"</string>
+    <string name="unknownName" msgid="2841414754740600042">"Unknown name"</string>
+    <string name="localPhoneName" msgid="2349001318925409159">"My name"</string>
+    <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+    <string name="pbap_notification_group" msgid="8487669554703627168">"Bluetooth Contact share"</string>
+</resources>
diff --git a/res/values-en-rCA/strings_pbap_client.xml b/res/values-en-rCA/strings_pbap_client.xml
new file mode 100644
index 0000000..186b23a
--- /dev/null
+++ b/res/values-en-rCA/strings_pbap_client.xml
@@ -0,0 +1,5 @@
+<?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="pbap_account_type" msgid="6257077123906049322">"com.android.bluetooth.pbapsink"</string>
+</resources>
diff --git a/res/values-en-rCA/strings_sap.xml b/res/values-en-rCA/strings_sap.xml
new file mode 100644
index 0000000..c79b034
--- /dev/null
+++ b/res/values-en-rCA/strings_sap.xml
@@ -0,0 +1,10 @@
+<?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="bluetooth_sap_notif_title" msgid="6877860822993195074">"Bluetooth SIM access"</string>
+    <string name="bluetooth_sap_notif_ticker" msgid="6807778527893726699">"Bluetooth SIM Access"</string>
+    <string name="bluetooth_sap_notif_message" msgid="7138657801087500690">"Request client to disconnect?"</string>
+    <string name="bluetooth_sap_notif_disconnecting" msgid="819150843490233288">"Waiting for client to disconnect"</string>
+    <string name="bluetooth_sap_notif_disconnect_button" msgid="3678476872583356919">"Disconnect"</string>
+    <string name="bluetooth_sap_notif_force_disconnect_button" msgid="8144086340185532030">"Force disconnect"</string>
+</resources>
diff --git a/res/values-en-rCA/test_strings.xml b/res/values-en-rCA/test_strings.xml
new file mode 100644
index 0000000..63128ee
--- /dev/null
+++ b/res/values-en-rCA/test_strings.xml
@@ -0,0 +1,13 @@
+<?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"</string>
+    <string name="insert_record" msgid="1450997173838378132">"Insert record"</string>
+    <string name="update_record" msgid="2480425402384910635">"Confirm record"</string>
+    <string name="ack_record" msgid="6716152390978472184">"Ack record"</string>
+    <string name="deleteAll_record" msgid="4383349788485210582">"Delete all record"</string>
+    <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+    <string name="delete_record" msgid="4645040331967533724">"Delete record"</string>
+    <string name="start_server" msgid="9034821924409165795">"Start TCP server"</string>
+    <string name="notify_server" msgid="4369106744022969655">"Notify TCP server"</string>
+</resources>
diff --git a/res/values-en-rXC/config.xml b/res/values-en-rXC/config.xml
new file mode 100644
index 0000000..c77a0a4
--- /dev/null
+++ b/res/values-en-rXC/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2009-2012 Broadcom Corporation
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pairing_ui_package" msgid="6399948348712579121">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎com.android.settings‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..443e0a0
--- /dev/null
+++ b/res/values-en-rXC/strings.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎Access download manager.‎‏‎‎‏‎"</string>
+    <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎Allows the app to access the BluetoothShare manager and use it to transfer files.‎‏‎‎‏‎"</string>
+    <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎Whitelist bluetooth device access.‎‏‎‎‏‎"</string>
+    <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎Allows the app to temporarily whitelist a Bluetooth device, allowing that device to send files to this device without user confirmation.‎‏‎‎‏‎"</string>
+    <string name="bt_share_picker_label" msgid="6268100924487046932">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‎Bluetooth‎‏‎‎‏‎"</string>
+    <string name="unknown_device" msgid="9221903979877041009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‎Unknown device‎‏‎‎‏‎"</string>
+    <string name="unknownNumber" msgid="4994750948072751566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎Unknown‎‏‎‎‏‎"</string>
+    <string name="airplane_error_title" msgid="2683839635115739939">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎Airplane mode‎‏‎‎‏‎"</string>
+    <string name="airplane_error_msg" msgid="8698965595254137230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‎‎You can\'t use Bluetooth in Airplane mode.‎‏‎‎‏‎"</string>
+    <string name="bt_enable_title" msgid="8657832550503456572"></string>
+    <string name="bt_enable_line1" msgid="7203551583048149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎To use Bluetooth services, you must first turn on Bluetooth.‎‏‎‎‏‎"</string>
+    <string name="bt_enable_line2" msgid="4341936569415937994">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎Turn on Bluetooth now?‎‏‎‎‏‎"</string>
+    <string name="bt_enable_cancel" msgid="1988832367505151727">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎Cancel‎‏‎‎‏‎"</string>
+    <string name="bt_enable_ok" msgid="3432462749994538265">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‎‎‏‎Turn on‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_title" msgid="8139874248612182627">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎File transfer‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_content" msgid="2752605552743148036">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎Accept incoming file?‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎Decline‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_ok" msgid="281462442932231475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎Accept‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎OK‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎There was a timeout while accepting an incoming file from \"‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_Notification_title" msgid="5573329005298936903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎Incoming file‎‏‎‎‏‎"</string>
+    <string name="incoming_file_confirm_Notification_content" msgid="3359694069319644738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is ready to send ‎‏‎‎‏‏‎<xliff:g id="FILE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="notification_receiving" msgid="4674648179652543984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎Bluetooth share: Receiving ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="notification_received" msgid="3324588019186687985">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎Bluetooth share: Received ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="notification_received_fail" msgid="3619350997285714746">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎Bluetooth share: File ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ not received‎‏‎‎‏‎"</string>
+    <string name="notification_sending" msgid="3035748958534983833">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎Bluetooth share: Sending ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="notification_sent" msgid="9218710861333027778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎Bluetooth share: Sent ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="notification_sent_complete" msgid="302943281067557969">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‎100% complete‎‏‎‎‏‎"</string>
+    <string name="notification_sent_fail" msgid="6696082233774569445">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎Bluetooth share: File ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ not sent‎‏‎‎‏‎"</string>
+    <string name="download_title" msgid="3353228219772092586">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎File transfer‎‏‎‎‏‎"</string>
+    <string name="download_line1" msgid="4926604799202134144">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‎From: \"‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="download_line2" msgid="5876973543019417712">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎File: ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="download_line3" msgid="4384821622908676061">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎File size: ‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="download_line4" msgid="8535996869722666525"></string>
+    <string name="download_line5" msgid="3069560415845295386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎Receiving file…‎‏‎‎‏‎"</string>
+    <string name="download_cancel" msgid="9177305996747500768">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎Stop‎‏‎‎‏‎"</string>
+    <string name="download_ok" msgid="5000360731674466039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎Hide‎‏‎‎‏‎"</string>
+    <string name="incoming_line1" msgid="2127419875681087545">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎From‎‏‎‎‏‎"</string>
+    <string name="incoming_line2" msgid="3348994249285315873">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‎Filename‎‏‎‎‏‎"</string>
+    <string name="incoming_line3" msgid="7954237069667474024">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎Size‎‏‎‎‏‎"</string>
+    <string name="download_fail_line1" msgid="3846450148862894552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‎File not received‎‏‎‎‏‎"</string>
+    <string name="download_fail_line2" msgid="8950394574689971071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎File: ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="download_fail_line3" msgid="3451040656154861722">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‏‎‎Reason: ‎‏‎‎‏‏‎<xliff:g id="REASON">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="download_fail_ok" msgid="1521733664438320300">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎OK‎‏‎‎‏‎"</string>
+    <string name="download_succ_line5" msgid="4509944688281573595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎File received‎‏‎‎‏‎"</string>
+    <string name="download_succ_ok" msgid="7053688246357050216">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎Open‎‏‎‎‏‎"</string>
+    <string name="upload_line1" msgid="2055952074059709052">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎To: \"‎‏‎‎‏‏‎<xliff:g id="RECIPIENT">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="upload_line3" msgid="4920689672457037437">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎File type: ‎‏‎‎‏‏‎<xliff:g id="TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ (‎‏‎‎‏‏‎<xliff:g id="SIZE">%2$s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
+    <string name="upload_line5" msgid="7759322537674229752">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎Sending file…‎‏‎‎‏‎"</string>
+    <string name="upload_succ_line5" msgid="5687317197463383601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‏‎File sent‎‏‎‎‏‎"</string>
+    <string name="upload_succ_ok" msgid="7705428476405478828">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎OK‎‏‎‎‏‎"</string>
+    <string name="upload_fail_line1" msgid="7899394672421491701">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎The file wasn\'t sent to \"‎‏‎‎‏‏‎<xliff:g id="RECIPIENT">%1$s</xliff:g>‎‏‎‎‏‏‏‎\".‎‏‎‎‏‎"</string>
+    <string name="upload_fail_line1_2" msgid="2108129204050841798">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‎‎File: ‎‏‎‎‏‏‎<xliff:g id="FILE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="upload_fail_ok" msgid="5807702461606714296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎Try again‎‏‎‎‏‎"</string>
+    <string name="upload_fail_cancel" msgid="9118496285835687125">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎Close‎‏‎‎‏‎"</string>
+    <string name="bt_error_btn_ok" msgid="5965151173011534240">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎OK‎‏‎‎‏‎"</string>
+    <string name="unknown_file" msgid="6092727753965095366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎Unknown file‎‏‎‎‏‎"</string>
+    <string name="unknown_file_desc" msgid="480434281415453287">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎There\'s no app to handle this type of file. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="not_exist_file" msgid="3489434189599716133">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎No file‎‏‎‎‏‎"</string>
+    <string name="not_exist_file_desc" msgid="4059531573790529229">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎The file doesn\'t exist. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="enabling_progress_title" msgid="436157952334723406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎Please wait…‎‏‎‎‏‎"</string>
+    <string name="enabling_progress_content" msgid="4601542238119927904">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎Turning on Bluetooth…‎‏‎‎‏‎"</string>
+    <string name="bt_toast_1" msgid="972182708034353383">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎The file will be received. Check progress in the Notifications panel.‎‏‎‎‏‎"</string>
+    <string name="bt_toast_2" msgid="8602553334099066582">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎The file can\'t be received.‎‏‎‎‏‎"</string>
+    <string name="bt_toast_3" msgid="6707884165086862518">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎Stopped receiving file from \"‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_toast_4" msgid="4678812947604395649">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎Sending file to \"‎‏‎‎‏‏‎<xliff:g id="RECIPIENT">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_toast_5" msgid="2846870992823019494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎Sending ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ files to \"‎‏‎‎‏‏‎<xliff:g id="RECIPIENT">%2$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_toast_6" msgid="1855266596936622458">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎Stopped sending file to \"‎‏‎‎‏‏‎<xliff:g id="RECIPIENT">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎There isn\'t enough space in USB storage to save the file from \"‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎There isn\'t enough space on the SD card to save the file from \"‎‏‎‎‏‏‎<xliff:g id="SENDER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎"</string>
+    <string name="bt_sm_2_2" msgid="2965243265852680543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‏‎Space needed: ‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="ErrorTooManyRequests" msgid="8578277541472944529">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎Too many requests are being processed. Try again later.‎‏‎‎‏‎"</string>
+    <string name="status_pending" msgid="2503691772030877944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎File transfer not started yet.‎‏‎‎‏‎"</string>
+    <string name="status_running" msgid="6562808920311008696">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎File transfer is ongoing.‎‏‎‎‏‎"</string>
+    <string name="status_success" msgid="239573225847565868">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎File transfer completed successfully.‎‏‎‎‏‎"</string>
+    <string name="status_not_accept" msgid="1695082417193780738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎Content isn\'t supported.‎‏‎‎‏‎"</string>
+    <string name="status_forbidden" msgid="613956401054050725">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎Transfer forbidden by target device.‎‏‎‎‏‎"</string>
+    <string name="status_canceled" msgid="6664490318773098285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‎Transfer canceled by user.‎‏‎‎‏‎"</string>
+    <string name="status_file_error" msgid="3671917770630165299">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎Storage issue.‎‏‎‎‏‎"</string>
+    <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎No USB storage.‎‏‎‎‏‎"</string>
+    <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎No SD card. Insert an SD card to save transferred files.‎‏‎‎‏‎"</string>
+    <string name="status_connection_error" msgid="947681831523219891">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎Connection unsuccessful.‎‏‎‎‏‎"</string>
+    <string name="status_protocol_error" msgid="3245444473429269539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‏‎Request can\'t be handled correctly.‎‏‎‎‏‎"</string>
+    <string name="status_unknown_error" msgid="8156660554237824912">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎Unknown error.‎‏‎‎‏‎"</string>
+    <string name="btopp_live_folder" msgid="7967791481444474554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎Bluetooth received‎‏‎‎‏‎"</string>
+    <string name="opp_notification_group" msgid="3486303082135789982">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎Bluetooth Share‎‏‎‎‏‎"</string>
+    <string name="download_success" msgid="7036160438766730871">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="FILE_SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ Received complete.‎‏‎‎‏‎"</string>
+    <string name="upload_success" msgid="4014469387779648949">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="FILE_SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ Sent complete.‎‏‎‎‏‎"</string>
+    <string name="inbound_history_title" msgid="6940914942271327563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‎Inbound transfers‎‏‎‎‏‎"</string>
+    <string name="outbound_history_title" msgid="4279418703178140526">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎Outbound transfers‎‏‎‎‏‎"</string>
+    <string name="no_transfers" msgid="3482965619151865672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎Transfer history is empty.‎‏‎‎‏‎"</string>
+    <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎All items will be cleared from the list.‎‏‎‎‏‎"</string>
+    <string name="outbound_noti_title" msgid="8051906709452260849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎Bluetooth share: Sent files‎‏‎‎‏‎"</string>
+    <string name="inbound_noti_title" msgid="4143352641953027595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎Bluetooth share: Received files‎‏‎‎‏‎"</string>
+    <plurals name="noti_caption_unsuccessful" formatted="false" msgid="2020750076679526122">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="UNSUCCESSFUL_NUMBER_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ unsuccessful.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="UNSUCCESSFUL_NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ unsuccessful.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="noti_caption_success" formatted="false" msgid="1572472450257645181">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="SUCCESSFUL_NUMBER_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ successful, %2$s‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="SUCCESSFUL_NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ successful, %2$s‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="transfer_menu_clear_all" msgid="790017462957873132">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎Clear list‎‏‎‎‏‎"</string>
+    <string name="transfer_menu_open" msgid="3368984869083107200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎Open‎‏‎‎‏‎"</string>
+    <string name="transfer_menu_clear" msgid="5854038118831427492">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‎Clear from list‎‏‎‎‏‎"</string>
+    <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎Clear‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_save" msgid="7635491847388074606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎Save‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎Cancel‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎Select the accounts you want to share through Bluetooth. You still have to accept any access to the accounts when connecting.‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_count" msgid="4557473074937024833">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎Slots left:‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎Application Icon‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_title" msgid="7420332483392851321">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎Bluetooth Message Sharing Settings‎‏‎‎‏‎"</string>
+    <string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎Cannot select account. 0 slots left‎‏‎‎‏‎"</string>
+    <string name="bluetooth_connected" msgid="6718623220072656906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎Bluetooth audio connected‎‏‎‎‏‎"</string>
+    <string name="bluetooth_disconnected" msgid="3318303728981478873">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎Bluetooth audio disconnected‎‏‎‎‏‎"</string>
+    <string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎Bluetooth Audio‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/strings_pbap.xml b/res/values-en-rXC/strings_pbap.xml
new file mode 100644
index 0000000..fee6dbd
--- /dev/null
+++ b/res/values-en-rXC/strings_pbap.xml
@@ -0,0 +1,16 @@
+<?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="pbap_session_key_dialog_title" msgid="3580996574333882561">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎Type session key for %1$s‎‏‎‎‏‎"</string>
+    <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎Bluetooth session key required‎‏‎‎‏‎"</string>
+    <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎There was time out to accept connection with %1$s‎‏‎‎‏‎"</string>
+    <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎There was time out to input session key with %1$s‎‏‎‎‏‎"</string>
+    <string name="auth_notif_ticker" msgid="1575825798053163744">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎Obex authentication request‎‏‎‎‏‎"</string>
+    <string name="auth_notif_title" msgid="7599854855681573258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎Session Key‎‏‎‎‏‎"</string>
+    <string name="auth_notif_message" msgid="6667218116427605038">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎Type session key for %1$s‎‏‎‎‏‎"</string>
+    <string name="defaultname" msgid="4821590500649090078">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎Carkit‎‏‎‎‏‎"</string>
+    <string name="unknownName" msgid="2841414754740600042">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎Unknown name‎‏‎‎‏‎"</string>
+    <string name="localPhoneName" msgid="2349001318925409159">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎My name‎‏‎‎‏‎"</string>
+    <string name="defaultnumber" msgid="8520116145890867338">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎000000‎‏‎‎‏‎"</string>
+    <string name="pbap_notification_group" msgid="8487669554703627168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎Bluetooth Contact share‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/strings_pbap_client.xml b/res/values-en-rXC/strings_pbap_client.xml
new file mode 100644
index 0000000..5d7540f
--- /dev/null
+++ b/res/values-en-rXC/strings_pbap_client.xml
@@ -0,0 +1,5 @@
+<?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="pbap_account_type" msgid="6257077123906049322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎com.android.bluetooth.pbapsink‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/strings_sap.xml b/res/values-en-rXC/strings_sap.xml
new file mode 100644
index 0000000..0b0524f
--- /dev/null
+++ b/res/values-en-rXC/strings_sap.xml
@@ -0,0 +1,10 @@
+<?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="bluetooth_sap_notif_title" msgid="6877860822993195074">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎Bluetooth SIM access‎‏‎‎‏‎"</string>
+    <string name="bluetooth_sap_notif_ticker" msgid="6807778527893726699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‎Bluetooth SIM Access‎‏‎‎‏‎"</string>
+    <string name="bluetooth_sap_notif_message" msgid="7138657801087500690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎Request client to disconnect?‎‏‎‎‏‎"</string>
+    <string name="bluetooth_sap_notif_disconnecting" msgid="819150843490233288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎Waiting for client to disconnect‎‏‎‎‏‎"</string>
+    <string name="bluetooth_sap_notif_disconnect_button" msgid="3678476872583356919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎Disconnect‎‏‎‎‏‎"</string>
+    <string name="bluetooth_sap_notif_force_disconnect_button" msgid="8144086340185532030">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎Force disconnect‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/test_strings.xml b/res/values-en-rXC/test_strings.xml
new file mode 100644
index 0000000..c0638ff
--- /dev/null
+++ b/res/values-en-rXC/test_strings.xml
@@ -0,0 +1,13 @@
+<?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‎‏‎‎‏‎"</string>
+    <string name="insert_record" msgid="1450997173838378132">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎Insert record‎‏‎‎‏‎"</string>
+    <string name="update_record" msgid="2480425402384910635">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎Confirm record‎‏‎‎‏‎"</string>
+    <string name="ack_record" msgid="6716152390978472184">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‎‎Ack record‎‏‎‎‏‎"</string>
+    <string name="deleteAll_record" msgid="4383349788485210582">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎Delete all record‎‏‎‎‏‎"</string>
+    <string name="ok_button" msgid="6519033415223065454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎OK‎‏‎‎‏‎"</string>
+    <string name="delete_record" msgid="4645040331967533724">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎Delete record‎‏‎‎‏‎"</string>
+    <string name="start_server" msgid="9034821924409165795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎Start TCP server‎‏‎‎‏‎"</string>
+    <string name="notify_server" msgid="4369106744022969655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎Notify TCP server‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 835d146..4089e71 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -125,10 +125,10 @@
     <string name="bluetooth_map_settings_save" msgid="7635491847388074606">"Gorde"</string>
     <string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"Utzi"</string>
     <string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Hautatu Bluetooth bidez partekatu nahi dituzun kontuak. Konektatzean, berariaz eman beharko duzu kontuetarako sarbidea."</string>
-    <string name="bluetooth_map_settings_count" msgid="4557473074937024833">"Geratzen diren erretenak:"</string>
+    <string name="bluetooth_map_settings_count" msgid="4557473074937024833">"Geratzen diren zirrikituak:"</string>
     <string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"Aplikazioaren ikonoa"</string>
     <string name="bluetooth_map_settings_title" msgid="7420332483392851321">"Bluetooth bidez mezuak partekatzeko ezarpenak"</string>
-    <string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"Ezin da hautatu kontua. Ez da erretenik geratzen."</string>
+    <string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"Ezin da hautatu kontua. Ez da geratzen zirrikiturik."</string>
     <string name="bluetooth_connected" msgid="6718623220072656906">"Konektatu da Bluetooth bidezko audioa"</string>
     <string name="bluetooth_disconnected" msgid="3318303728981478873">"Deskonektatu da Bluetooth bidezko audioa"</string>
     <string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth bidezko audioa"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 53ab99b..ca48a38 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -78,7 +78,7 @@
     <string name="not_exist_file_desc" msgid="4059531573790529229">"הקובץ לא קיים. \n"</string>
     <string name="enabling_progress_title" msgid="436157952334723406">"המתן..."</string>
     <string name="enabling_progress_content" msgid="4601542238119927904">"‏מפעיל Bluetooth…"</string>
-    <string name="bt_toast_1" msgid="972182708034353383">"הקובץ יתקבל. בדוק את ההתקדמות בחלונית \'התראות\'."</string>
+    <string name="bt_toast_1" msgid="972182708034353383">"הקובץ יתקבל. בדוק את ההתקדמות בחלונית \'הודעות\'."</string>
     <string name="bt_toast_2" msgid="8602553334099066582">"לא ניתן לקבל את הקובץ."</string>
     <string name="bt_toast_3" msgid="6707884165086862518">"הופסקה קבלת קובץ מאת \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
     <string name="bt_toast_4" msgid="4678812947604395649">"שולח קובץ אל \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 9c38985..37279c0 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -34,7 +34,7 @@
     <string name="incoming_file_confirm_content" msgid="2752605552743148036">"ဝင်လာသည့် ဖိုင်ကို လက်ခံမလား?"</string>
     <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"လက်မခံပါ"</string>
     <string name="incoming_file_confirm_ok" msgid="281462442932231475">"လက်ခံရန်"</string>
-    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"အိုကေ"</string>
+    <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
     <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"\"<xliff:g id="SENDER">%1$s</xliff:g>\"မှ အဝင်ဖိုင်ကို လက်ခံနေစဥ် အချိန်ကုန်ဆုံးသွားပါပြီ"</string>
     <string name="incoming_file_confirm_Notification_title" msgid="5573329005298936903">"အဝင် ဖိုင်"</string>
     <string name="incoming_file_confirm_Notification_content" msgid="3359694069319644738">"<xliff:g id="SENDER">%1$s</xliff:g> က <xliff:g id="FILE">%2$s</xliff:g>ကို ပို့ရန် အသင့်ပါ"</string>
@@ -59,19 +59,19 @@
     <string name="download_fail_line1" msgid="3846450148862894552">"ဖိုင် မရရှိပါ"</string>
     <string name="download_fail_line2" msgid="8950394574689971071">"ဖိုင် - <xliff:g id="FILE">%1$s</xliff:g>"</string>
     <string name="download_fail_line3" msgid="3451040656154861722">"အကြောင်းပြချက် - <xliff:g id="REASON">%1$s</xliff:g>"</string>
-    <string name="download_fail_ok" msgid="1521733664438320300">"အိုကေ"</string>
+    <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
     <string name="download_succ_line5" msgid="4509944688281573595">"လက်ခံရပြီးဖိုင်"</string>
     <string name="download_succ_ok" msgid="7053688246357050216">"ဖွင့်ရန်"</string>
     <string name="upload_line1" msgid="2055952074059709052">"သို့ - \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
     <string name="upload_line3" msgid="4920689672457037437">"ဖိုင်အမျိုးအစား - <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
     <string name="upload_line5" msgid="7759322537674229752">"ဖိုင်ပို့နေပါသည်"</string>
     <string name="upload_succ_line5" msgid="5687317197463383601">"ဖိုင်ပို့ပြီး"</string>
-    <string name="upload_succ_ok" msgid="7705428476405478828">"အိုကေ"</string>
+    <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
     <string name="upload_fail_line1" msgid="7899394672421491701">"\"<xliff:g id="RECIPIENT">%1$s</xliff:g>\"ထံသို့ ဖိုင်ကို မပို့ပါ"</string>
     <string name="upload_fail_line1_2" msgid="2108129204050841798">"ဖိုင် - <xliff:g id="FILE">%1$s</xliff:g>"</string>
     <string name="upload_fail_ok" msgid="5807702461606714296">"ပြန်ကြိုးစားပါ"</string>
     <string name="upload_fail_cancel" msgid="9118496285835687125">"ပိတ်ရန်"</string>
-    <string name="bt_error_btn_ok" msgid="5965151173011534240">"အိုကေ"</string>
+    <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
     <string name="unknown_file" msgid="6092727753965095366">"အမျိုးအမည် မသိသောဖိုင်"</string>
     <string name="unknown_file_desc" msgid="480434281415453287">"ဤဖိုင်အမျိုးအစားကို ကိုင်တွယ်ရန် အပလီကေးရှင်းမရှိပါ\n"</string>
     <string name="not_exist_file" msgid="3489434189599716133">"ဖိုင်မရှိပါ"</string>
diff --git a/res/values-my/test_strings.xml b/res/values-my/test_strings.xml
index 34b8f8a..e9cf314 100644
--- a/res/values-my/test_strings.xml
+++ b/res/values-my/test_strings.xml
@@ -6,7 +6,7 @@
     <string name="update_record" msgid="2480425402384910635">"မှတ်တမ်းအတည်ပြုရန်"</string>
     <string name="ack_record" msgid="6716152390978472184">"အသိအမှတ်ပြု မှတ်တမ်း"</string>
     <string name="deleteAll_record" msgid="4383349788485210582">"မှတ်တမ်းအားလုံးကို ဖျက်ရန်"</string>
-    <string name="ok_button" msgid="6519033415223065454">"အိုကေ"</string>
+    <string name="ok_button" msgid="6519033415223065454">"OK"</string>
     <string name="delete_record" msgid="4645040331967533724">"မှတ်တမ်းကို ဖျက်ရန်"</string>
     <string name="start_server" msgid="9034821924409165795">"TCP ဆာဗာ စတင်ရန်"</string>
     <string name="notify_server" msgid="4369106744022969655">"TCP ဆာဗာကို အကြောင်းကြားရန်"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index da66b45..84030ba 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -101,7 +101,7 @@
     <string name="status_protocol_error" msgid="3245444473429269539">"अनुरोधलाई सही रूपमा सम्हाल्न सकिँदैन।"</string>
     <string name="status_unknown_error" msgid="8156660554237824912">"अज्ञात त्रुटि।"</string>
     <string name="btopp_live_folder" msgid="7967791481444474554">"ब्लुटुथ प्राप्त भयो"</string>
-    <string name="opp_notification_group" msgid="3486303082135789982">"ब्लुटुथमार्फत गरिने आदान-प्रदान"</string>
+    <string name="opp_notification_group" msgid="3486303082135789982">"ब्लुटुथमार्फत गरिने आदान प्रदान"</string>
     <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> प्राप्त गर्ने कार्य सम्पन्न भयो।"</string>
     <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> पठाउने कार्य पुरा भयो।"</string>
     <string name="inbound_history_title" msgid="6940914942271327563">"इनबाउन्ड स्थानान्तरण"</string>
diff --git a/res/values-ne/strings_pbap.xml b/res/values-ne/strings_pbap.xml
index dcd1b20..8d3167e 100644
--- a/res/values-ne/strings_pbap.xml
+++ b/res/values-ne/strings_pbap.xml
@@ -12,5 +12,5 @@
     <string name="unknownName" msgid="2841414754740600042">"अज्ञात नाम"</string>
     <string name="localPhoneName" msgid="2349001318925409159">"मेरो नाम"</string>
     <string name="defaultnumber" msgid="8520116145890867338">"००००००"</string>
-    <string name="pbap_notification_group" msgid="8487669554703627168">"ब्लुटुथमार्फत सम्पर्कको आदान-प्रदान"</string>
+    <string name="pbap_notification_group" msgid="8487669554703627168">"ब्लुटुथमार्फत सम्पर्कको आदान प्रदान"</string>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index b95417b..05448c5 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -58,11 +58,15 @@
 
     <bool name="headset_client_initial_audio_route_allowed">true</bool>
 
-    <!-- For AVRCP absolute volume feature. If the threshold is non-zero,
-         restrict the initial volume to the threshold.
-         Valid value is 1-14, and recommended value is 8 -->
+    <!-- @deprecated: use a2dp_absolute_volume_initial_threshold_percent
+         instead. -->
     <integer name="a2dp_absolute_volume_initial_threshold">8</integer>
 
+    <!-- AVRCP absolute volume initial value as percent of the maximum value.
+         Valid values are in the interval [0, 100].
+         Recommended value is 50. -->
+    <integer name="a2dp_absolute_volume_initial_threshold_percent">50</integer>
+
     <!-- For A2DP sink ducking volume feature. -->
     <integer name="a2dp_sink_duck_percent">25</integer>
 
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index cca1533..7a18989 100755
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -625,6 +625,10 @@
                         broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                                        BluetoothProfile.STATE_CONNECTING);
                         break;
+                    } else {
+                        broadcastConnectionState(mCurrentDevice,
+                                BluetoothProfile.STATE_DISCONNECTING,
+                                BluetoothProfile.STATE_CONNECTED);
                     }
 
                     synchronized (A2dpStateMachine.this) {
@@ -643,7 +647,7 @@
                                    BluetoothProfile.STATE_CONNECTED);
                     if (!disconnectA2dpNative(getByteAddress(device))) {
                         broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
-                                       BluetoothProfile.STATE_DISCONNECTED);
+                                BluetoothProfile.STATE_DISCONNECTING);
                         break;
                     }
                     synchronized (A2dpStateMachine.this) {
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
index 33fe1ec..dae6df5 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
@@ -16,8 +16,10 @@
 
 package com.android.bluetooth.a2dpsink;
 
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.os.Handler;
@@ -27,6 +29,8 @@
 import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
 import com.android.bluetooth.R;
 
+import java.util.List;
+
 /**
  * Bluetooth A2DP SINK Streaming Handler.
  *
@@ -209,8 +213,22 @@
      * Utility functions.
      */
     private int requestAudioFocus() {
-        int focusRequestStatus = mAudioManager.requestAudioFocus(
-                mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+        // Bluetooth A2DP may carry Music, Audio Books, Navigation, or other sounds so mark content
+        // type unknown.
+        AudioAttributes streamAttributes =
+                new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_MEDIA)
+                        .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+                        .build();
+        // Bluetooth ducking is handled at the native layer so tell the Audio Manger to notify the
+        // focus change listener via .setWillPauseWhenDucked().
+        AudioFocusRequest focusRequest =
+                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+                        .setAudioAttributes(streamAttributes)
+                        .setWillPauseWhenDucked(true)
+                        .setOnAudioFocusChangeListener(mAudioFocusListener, this)
+                        .build();
+        int focusRequestStatus = mAudioManager.requestAudioFocus(focusRequest);
         // If the request is granted begin streaming immediately and schedule an upgrade.
         if (focusRequestStatus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
             startAvrcpUpdates();
@@ -275,16 +293,20 @@
         if (DBG) {
             Log.d(TAG, "sendAvrcpPause");
         }
-        if (avrcpService != null && avrcpService.getConnectedDevices().size() == 1) {
-            if (DBG) {
-                Log.d(TAG, "Pausing AVRCP.");
+        if (avrcpService != null) {
+            List<BluetoothDevice> connectedDevices = avrcpService.getConnectedDevices();
+            if (!connectedDevices.isEmpty()) {
+                BluetoothDevice targetDevice = connectedDevices.get(0);
+                if (DBG) {
+                    Log.d(TAG, "Pausing AVRCP.");
+                }
+                avrcpService.sendPassThroughCmd(targetDevice,
+                        AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE,
+                        AvrcpControllerService.KEY_STATE_PRESSED);
+                avrcpService.sendPassThroughCmd(targetDevice,
+                        AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE,
+                        AvrcpControllerService.KEY_STATE_RELEASED);
             }
-            avrcpService.sendPassThroughCmd(avrcpService.getConnectedDevices().get(0),
-                    AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE,
-                    AvrcpControllerService.KEY_STATE_PRESSED);
-            avrcpService.sendPassThroughCmd(avrcpService.getConnectedDevices().get(0),
-                    AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE,
-                    AvrcpControllerService.KEY_STATE_RELEASED);
         } else {
             Log.e(TAG, "Passthrough not sent, connection un-available.");
         }
@@ -297,16 +319,20 @@
         if (DBG) {
             Log.d(TAG, "sendAvrcpPlay");
         }
-        if (avrcpService != null && avrcpService.getConnectedDevices().size() == 1) {
-            if (DBG) {
-                Log.d(TAG, "Playing AVRCP.");
+        if (avrcpService != null) {
+            List<BluetoothDevice> connectedDevices = avrcpService.getConnectedDevices();
+            if (!connectedDevices.isEmpty()) {
+                BluetoothDevice targetDevice = connectedDevices.get(0);
+                if (DBG) {
+                    Log.d(TAG, "Playing AVRCP.");
+                }
+                avrcpService.sendPassThroughCmd(targetDevice,
+                        AvrcpControllerService.PASS_THRU_CMD_ID_PLAY,
+                        AvrcpControllerService.KEY_STATE_PRESSED);
+                avrcpService.sendPassThroughCmd(targetDevice,
+                        AvrcpControllerService.PASS_THRU_CMD_ID_PLAY,
+                        AvrcpControllerService.KEY_STATE_RELEASED);
             }
-            avrcpService.sendPassThroughCmd(avrcpService.getConnectedDevices().get(0),
-                    AvrcpControllerService.PASS_THRU_CMD_ID_PLAY,
-                    AvrcpControllerService.KEY_STATE_PRESSED);
-            avrcpService.sendPassThroughCmd(avrcpService.getConnectedDevices().get(0),
-                    AvrcpControllerService.PASS_THRU_CMD_ID_PLAY,
-                    AvrcpControllerService.KEY_STATE_RELEASED);
         } else {
             Log.e(TAG, "Passthrough not sent, connection un-available.");
         }
diff --git a/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java b/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java
index a43bb58..84dec4f 100644
--- a/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java
+++ b/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java
@@ -356,11 +356,12 @@
                 }
             } else if (AvrcpControllerService.ACTION_TRACK_EVENT.equals(action)) {
                 PlaybackState pbb =
-                    intent.getParcelableExtra(AvrcpControllerService.EXTRA_PLAYBACK);
+                        intent.getParcelableExtra(AvrcpControllerService.EXTRA_PLAYBACK);
                 MediaMetadata mmd =
-                    intent.getParcelableExtra(AvrcpControllerService.EXTRA_METADATA);
-                mAvrcpCommandQueue.obtainMessage(
-                    MSG_TRACK, new Pair<PlaybackState, MediaMetadata>(pbb, mmd)).sendToTarget();
+                        intent.getParcelableExtra(AvrcpControllerService.EXTRA_METADATA);
+                mAvrcpCommandQueue
+                        .obtainMessage(MSG_TRACK, new Pair<PlaybackState, MediaMetadata>(pbb, mmd))
+                        .sendToTarget();
             } else if (AvrcpControllerService.ACTION_FOLDER_LIST.equals(action)) {
                 mAvrcpCommandQueue.obtainMessage(MSG_FOLDER_LIST, intent).sendToTarget();
             }
@@ -432,6 +433,8 @@
         // Set device to null.
         mA2dpDevice = null;
         mBrowseConnected = false;
+        // update playerList.
+        notifyChildrenChanged("__ROOT__");
     }
 
     private void msgTrack(PlaybackState pb, MediaMetadata mmd) {
@@ -506,6 +509,8 @@
             return;
         }
         mBrowseConnected = true;
+        // update playerList
+        notifyChildrenChanged("__ROOT__");
     }
 
     private void msgFolderList(Intent intent) {
diff --git a/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java b/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java
index d2c941e..da19b32 100644
--- a/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java
+++ b/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java
@@ -57,14 +57,12 @@
     private final List<MediaSession.QueueItem> mEmptyNowPlayingList;
 
     private long mLastTrackIdSent;
-    private boolean mNowPlayingListUpdated;
 
     public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) {
         mEmptyNowPlayingList = new ArrayList<MediaSession.QueueItem>();
         mNowPlayingList = mEmptyNowPlayingList;
         mMediaInterface = mediaInterface;
         mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID;
-        mNowPlayingListUpdated = false;
     }
 
     void cleanup() {
@@ -72,7 +70,6 @@
         mNowPlayingList = mEmptyNowPlayingList;
         mMediaInterface = null;
         mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID;
-        mNowPlayingListUpdated = false;
     }
 
     /* get now playing list from addressed player */
@@ -84,7 +81,7 @@
             mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants.RSP_NO_AVBL_PLAY, null);
             return;
         }
-        List<MediaSession.QueueItem> items = getNowPlayingList(mediaController);
+        List<MediaSession.QueueItem> items = updateNowPlayingList(mediaController);
         getFolderItemsFilterAttr(bdaddr, reqObj, items, AvrcpConstants.BTRC_SCOPE_NOW_PLAYING,
                 reqObj.mStartItem, reqObj.mEndItem, mediaController);
     }
@@ -94,17 +91,17 @@
             @Nullable MediaController mediaController) {
         int status = AvrcpConstants.RSP_NO_ERROR;
         long mediaId = ByteBuffer.wrap(itemAttr.mUid).getLong();
-        List<MediaSession.QueueItem> items = getNowPlayingList(mediaController);
+        List<MediaSession.QueueItem> items = updateNowPlayingList(mediaController);
 
         // NOTE: this is out-of-spec (AVRCP 1.6.1 sec 6.10.4.3, p90) but we answer it anyway
         // because some CTs ask for it.
         if (Arrays.equals(itemAttr.mUid, AvrcpConstants.TRACK_IS_SELECTED)) {
-            if (DEBUG) Log.d(TAG, "getItemAttr: Remote requests for now playing contents:");
-
-            // get the current playing metadata and send.
-            getItemAttrFilterAttr(bdaddr, itemAttr, getCurrentQueueItem(mediaController, mediaId),
-                    mediaController);
-            return;
+            mediaId = getActiveQueueItemId(mediaController);
+            if (DEBUG) {
+                Log.d(TAG,
+                        "getItemAttr: Remote requests for now playing contents, sending UID: "
+                                + mediaId);
+            }
         }
 
         if (DEBUG) Log.d(TAG, "getItemAttr-UID: 0x" + Utils.byteArrayToString(itemAttr.mUid));
@@ -121,29 +118,43 @@
 
     /* Refresh and get the queue of now playing.
      */
-    private @NonNull List<MediaSession.QueueItem> getNowPlayingList(
-            @Nullable MediaController mediaController) {
+    @NonNull
+    List<MediaSession.QueueItem> updateNowPlayingList(@Nullable MediaController mediaController) {
         if (mediaController == null) return mEmptyNowPlayingList;
         List<MediaSession.QueueItem> items = mediaController.getQueue();
-        if (items != null && !mNowPlayingListUpdated) {
-            mNowPlayingList = items;
-            return mNowPlayingList;
-        }
         if (items == null) {
             Log.i(TAG, "null queue from " + mediaController.getPackageName()
                             + ", constructing single-item list");
-            MediaMetadata metadata = mediaController.getMetadata();
+
             // Because we are database-unaware, we can just number the item here whatever we want
             // because they have to re-poll it every time.
-            MediaSession.QueueItem current = getCurrentQueueItem(mediaController, SINGLE_QID);
+            MediaMetadata metadata = mediaController.getMetadata();
+            if (metadata == null) {
+                Log.w(TAG, "Controller has no metadata!? Making an empty one");
+                metadata = (new MediaMetadata.Builder()).build();
+            }
+
+            MediaDescription.Builder bob = new MediaDescription.Builder();
+            MediaDescription desc = metadata.getDescription();
+
+            // set the simple ones that MediaMetadata builds for us
+            bob.setMediaId(desc.getMediaId());
+            bob.setTitle(desc.getTitle());
+            bob.setSubtitle(desc.getSubtitle());
+            bob.setDescription(desc.getDescription());
+            // fill the ones that we use later
+            bob.setExtras(fillBundle(metadata, desc.getExtras()));
+
+            // build queue item with the new metadata
+            MediaSession.QueueItem current = new QueueItem(bob.build(), SINGLE_QID);
+
             items = new ArrayList<MediaSession.QueueItem>();
             items.add(current);
         }
 
+        if (!items.equals(mNowPlayingList)) sendNowPlayingListChanged();
         mNowPlayingList = items;
 
-        if (mNowPlayingListUpdated) sendNowPlayingListChanged();
-
         return mNowPlayingList;
     }
 
@@ -151,40 +162,6 @@
         if (mMediaInterface == null) return;
         if (DEBUG) Log.d(TAG, "sendNowPlayingListChanged()");
         mMediaInterface.nowPlayingChangedRsp(AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
-        mNowPlayingListUpdated = false;
-    }
-
-    /* Constructs a queue item representing the current playing metadata from an
-     * active controller with queue id |qid|.
-     */
-    private MediaSession.QueueItem getCurrentQueueItem(
-            @Nullable MediaController controller, long qid) {
-        if (controller == null) {
-            MediaDescription.Builder bob = new MediaDescription.Builder();
-            bob.setTitle(UNKNOWN_TITLE);
-            return new QueueItem(bob.build(), qid);
-        }
-
-        MediaMetadata metadata = controller.getMetadata();
-        if (metadata == null) {
-            Log.w(TAG, "Controller has no metadata!? Making an empty one");
-            metadata = (new MediaMetadata.Builder()).build();
-        }
-
-        MediaDescription.Builder bob = new MediaDescription.Builder();
-        MediaDescription desc = metadata.getDescription();
-
-        // set the simple ones that MediaMetadata builds for us
-        bob.setMediaId(desc.getMediaId());
-        bob.setTitle(desc.getTitle());
-        bob.setSubtitle(desc.getSubtitle());
-        bob.setDescription(desc.getDescription());
-        // fill the ones that we use later
-        bob.setExtras(fillBundle(metadata, desc.getExtras()));
-
-        // build queue item with the new metadata
-        desc = bob.build();
-        return new QueueItem(desc, qid);
     }
 
     private Bundle fillBundle(MediaMetadata metadata, Bundle currentExtras) {
@@ -211,15 +188,10 @@
         return bundle;
     }
 
-    void updateNowPlayingList(@Nullable MediaController mediaController) {
-        mNowPlayingListUpdated = true;
-        getNowPlayingList(mediaController);
-    }
-
     /* Instructs media player to play particular media item */
     void playItem(byte[] bdaddr, byte[] uid, @Nullable MediaController mediaController) {
         long qid = ByteBuffer.wrap(uid).getLong();
-        List<MediaSession.QueueItem> items = getNowPlayingList(mediaController);
+        List<MediaSession.QueueItem> items = updateNowPlayingList(mediaController);
 
         if (mediaController == null) {
             Log.e(TAG, "No mediaController when PlayItem " + qid + " requested");
@@ -250,7 +222,7 @@
     }
 
     void getTotalNumOfItems(byte[] bdaddr, @Nullable MediaController mediaController) {
-        List<MediaSession.QueueItem> items = getNowPlayingList(mediaController);
+        List<MediaSession.QueueItem> items = updateNowPlayingList(mediaController);
         if (DEBUG) Log.d(TAG, "getTotalNumOfItems: " + items.size() + " items.");
         mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size());
     }
diff --git a/src/com/android/bluetooth/avrcp/Avrcp.java b/src/com/android/bluetooth/avrcp/Avrcp.java
index 274c10b..a00502c 100644
--- a/src/com/android/bluetooth/avrcp/Avrcp.java
+++ b/src/com/android/bluetooth/avrcp/Avrcp.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.content.SharedPreferences;
 import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.browse.MediaBrowser;
@@ -78,6 +79,8 @@
     private Context mContext;
     private final AudioManager mAudioManager;
     private AvrcpMessageHandler mHandler;
+    private Handler mAudioManagerPlaybackHandler;
+    private AudioManagerPlaybackListener mAudioManagerPlaybackCb;
     private MediaSessionManager mMediaSessionManager;
     private @Nullable MediaController mMediaController;
     private MediaControllerListener mMediaControllerCb;
@@ -87,6 +90,7 @@
     private int mTransportControlFlags;
     private @NonNull PlaybackState mCurrentPlayState;
     private int mA2dpState;
+    private boolean mAudioManagerIsPlaying;
     private int mPlayStatusChangedNT;
     private byte mReportedPlayStatus;
     private int mTrackChangedNT;
@@ -240,6 +244,7 @@
         mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
         mReportedPlayStatus = PLAYSTATUS_ERROR;
         mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING;
+        mAudioManagerIsPlaying = false;
         mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
         mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
         mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
@@ -279,6 +284,13 @@
         Resources resources = context.getResources();
         if (resources != null) {
             mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold);
+
+            // Update the threshold if the threshold_percent is valid
+            int threshold_percent =
+                    resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold_percent);
+            if (threshold_percent >= 0 && threshold_percent <= 100) {
+                mAbsVolThreshold = (threshold_percent * mAudioStreamMax) / 100;
+            }
         }
 
         // Register for package removal intent broadcasts for media button receiver persistence
@@ -300,6 +312,8 @@
         thread.start();
         Looper looper = thread.getLooper();
         mHandler = new AvrcpMessageHandler(looper);
+        mAudioManagerPlaybackHandler = new Handler(looper);
+        mAudioManagerPlaybackCb = new AudioManagerPlaybackListener();
         mMediaControllerCb = new MediaControllerListener();
         mAvrcpMediaRsp = new AvrcpMediaRsp();
         mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>();
@@ -329,6 +343,9 @@
             // initialize browsable player list and build media player list
             buildBrowsablePlayerList();
         }
+
+        mAudioManager.registerAudioPlaybackCallback(
+                mAudioManagerPlaybackCb, mAudioManagerPlaybackHandler);
     }
 
     public static Avrcp make(Context context) {
@@ -340,18 +357,23 @@
 
     public synchronized void doQuit() {
         if (DEBUG) Log.d(TAG, "doQuit");
+        if (mAudioManager != null) {
+            mAudioManager.unregisterAudioPlaybackCallback(mAudioManagerPlaybackCb);
+        }
         if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb);
         if (mMediaSessionManager != null) {
             mMediaSessionManager.setCallback(null, null);
             mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveSessionListener);
         }
 
+        mAudioManagerPlaybackHandler.removeCallbacksAndMessages(null);
         mHandler.removeCallbacksAndMessages(null);
         Looper looper = mHandler.getLooper();
         if (looper != null) {
             looper.quit();
         }
 
+        mAudioManagerPlaybackHandler = null;
         mHandler = null;
         mContext.unregisterReceiver(mAvrcpReceiver);
         mContext.unregisterReceiver(mBootReceiver);
@@ -367,6 +389,30 @@
             mVolumeMapping.clear();
     }
 
+    private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
+        @Override
+        public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+            super.onPlaybackConfigChanged(configs);
+            boolean isPlaying = false;
+            for (AudioPlaybackConfiguration config : configs) {
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "AudioManager Player: "
+                                    + AudioPlaybackConfiguration.toLogFriendlyString(config));
+                }
+                if (config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+                    isPlaying = true;
+                    break;
+                }
+            }
+            if (DEBUG) Log.d(TAG, "AudioManager isPlaying: " + isPlaying);
+            if (mAudioManagerIsPlaying != isPlaying) {
+                mAudioManagerIsPlaying = isPlaying;
+                updateCurrentMediaState();
+            }
+        }
+    }
+
     private class MediaControllerListener extends MediaController.Callback {
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
@@ -413,10 +459,13 @@
             case MSG_NATIVE_REQ_GET_RC_FEATURES:
             {
                 String address = (String) msg.obj;
-                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_RC_FEATURES: address="+address+
-                        ", features="+msg.arg1);
                 mFeatures = msg.arg1;
                 mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address);
+                if (DEBUG) {
+                    Log.v(TAG,
+                            "MSG_NATIVE_REQ_GET_RC_FEATURES: address=" + address
+                                    + ", features=" + msg.arg1 + ", mFeatures=" + mFeatures);
+                }
                 mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
                 mLastLocalVolume = -1;
                 mRemoteVolume = -1;
@@ -797,10 +846,22 @@
 
             if (controllerState != null) {
                 newState = controllerState;
-            } else if (mAudioManager != null && mAudioManager.isMusicActive()) {
-                // Use A2DP state if we don't have a state from MediaControlller
+            }
+            // Use the AudioManager to update the playback state.
+            // NOTE: We cannot use the
+            //    (mA2dpState == BluetoothA2dp.STATE_PLAYING)
+            // check, because after Pause, the A2DP state remains in
+            // STATE_PLAYING for 3 more seconds.
+            // As a result of that, if we pause the music, on carkits the
+            // Play status indicator will continue to display "Playing"
+            // for 3 more seconds which can be confusing.
+            if ((mAudioManagerIsPlaying && newState.getState() != PlaybackState.STATE_PLAYING)
+                    || (controllerState == null && mAudioManager != null
+                               && mAudioManager.isMusicActive())) {
+                // Use AudioManager playback state if we don't have the state
+                // from MediaControlller
                 PlaybackState.Builder builder = new PlaybackState.Builder();
-                if (mA2dpState == BluetoothA2dp.STATE_PLAYING) {
+                if (mAudioManagerIsPlaying) {
                     builder.setState(PlaybackState.STATE_PLAYING,
                             PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
                 } else {
@@ -1016,22 +1077,6 @@
                 mAddressedMediaPlayer.updateNowPlayingList(mMediaController);
             }
 
-            if ((newQueueId == -1 || newQueueId != mLastQueueId)
-                    && currentAttributes.equals(mMediaAttributes)
-                    && newPlayStatus == PLAYSTATUS_PLAYING
-                    && mReportedPlayStatus == PLAYSTATUS_STOPPED) {
-                // Most carkits like seeing the track changed before the
-                // playback state changed, but some controllers are slow
-                // to update their metadata. Hold of on sending the playback state
-                // update until after we know the current metadata is up to date
-                // and track changed has been sent. This was seen on BMW carkits
-                Log.i(TAG,
-                        "Waiting for metadata update to send track changed: " + newQueueId + " : "
-                                + currentAttributes + " : " + mMediaAttributes);
-
-                return;
-            }
-
             // Notify track changed if:
             //  - The CT is registered for the notification
             //  - Queue ID is UNKNOWN and MediaMetadata is different
@@ -1050,9 +1095,11 @@
         }
 
         // still send the updated play state if the playback state is none or buffering
-        Log.e(TAG, "play status change " + mReportedPlayStatus + "➡" + newPlayStatus);
+        Log.e(TAG,
+                "play status change " + mReportedPlayStatus + "➡" + newPlayStatus
+                        + " mPlayStatusChangedNT: " + mPlayStatusChangedNT);
         if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
-                && (mReportedPlayStatus != newPlayStatus)) {
+                || (mReportedPlayStatus != newPlayStatus)) {
             sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_CHANGED, newPlayStatus);
         }
 
@@ -2364,6 +2411,20 @@
                 ProfileService.println(sb, "  " + log);
             }
         }
+
+        // Print the blacklisted devices (for absolute volume control)
+        SharedPreferences pref =
+                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
+        Map<String, ?> allKeys = pref.getAll();
+        ProfileService.println(sb, "");
+        ProfileService.println(sb, "Runtime Blacklisted Devices (absolute volume):");
+        if (allKeys.isEmpty()) {
+            ProfileService.println(sb, "  None");
+        } else {
+            for (String key : allKeys.keySet()) {
+                ProfileService.println(sb, "  " + key);
+            }
+        }
     }
 
     public class AvrcpBrowseManager {
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
index b0c1926..7ff0a25 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
@@ -435,7 +435,7 @@
     public synchronized boolean getChildren(
             BluetoothDevice device, String parentMediaId, int start, int items) {
         if (DBG) {
-            Log.d(TAG, "getChildrent device = " + device + " parent " + parentMediaId);
+            Log.d(TAG, "getChildren device = " + device + " parent " + parentMediaId);
         }
 
         if (device == null) {
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index b65113c..07b7bfe 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -65,8 +65,8 @@
     private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices = new CopyOnWriteArrayList<BluetoothDevice>();
 
     private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
-    private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
-
+    private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState =
+            new HashMap<>();
 
     private volatile int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
     private volatile int mState = BluetoothAdapter.STATE_OFF;
@@ -93,35 +93,55 @@
     private boolean mIsLePeriodicAdvertisingSupported;
     private int mLeMaximumAdvertisingDataLength;
 
+    private boolean mReceiverRegistered;
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.d(TAG, "Received intent " + intent);
             String action = intent.getAction();
-            if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.HEADSET, intent);
-            } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.A2DP, intent);
-            } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.HEADSET_CLIENT, intent);
-            } else if (BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.A2DP_SINK, intent);
-            } else if (BluetoothInputHost.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.INPUT_HOST, intent);
-            } else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.INPUT_DEVICE, intent);
-            } else if (BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.AVRCP_CONTROLLER, intent);
-            } else if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.PAN, intent);
-            } else if (BluetoothMap.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.MAP, intent);
-            } else if (BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.MAP_CLIENT, intent);
-            } else if (BluetoothSap.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.SAP, intent);
-            } else if (BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                sendConnectionStateChange(BluetoothProfile.PBAP_CLIENT, intent);
+            if (action == null) {
+                Log.w(TAG, "Received intent with null action");
+                return;
+            }
+            switch (action) {
+                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.HEADSET, intent);
+                    break;
+                case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.A2DP, intent);
+                    break;
+                case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.HEADSET_CLIENT, intent);
+                    break;
+                case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.A2DP_SINK, intent);
+                    break;
+                case BluetoothInputHost.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.INPUT_HOST, intent);
+                    break;
+                case BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.INPUT_DEVICE, intent);
+                    break;
+                case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.AVRCP_CONTROLLER, intent);
+                    break;
+                case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.PAN, intent);
+                    break;
+                case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.MAP, intent);
+                    break;
+                case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.MAP_CLIENT, intent);
+                    break;
+                case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.SAP, intent);
+                    break;
+                case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
+                    sendConnectionStateChange(BluetoothProfile.PBAP_CLIENT, intent);
+                    break;
+                default:
+                    Log.w(TAG, "Received unknown intent " + intent);
+                    break;
             }
         }
     };
@@ -129,18 +149,14 @@
     // Lock for all getters and setters.
     // If finer grained locking is needer, more locks
     // can be added here.
-    private Object mObject = new Object();
+    private final Object mObject = new Object();
 
     public AdapterProperties(AdapterService service) {
         mService = service;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
     }
     public void init(RemoteDevices remoteDevices) {
-        if (mProfileConnectionState ==null) {
-            mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
-        } else {
-            mProfileConnectionState.clear();
-        }
+        mProfileConnectionState.clear();
         mRemoteDevices = remoteDevices;
 
         IntentFilter filter = new IntentFilter();
@@ -156,17 +172,17 @@
         filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothDevice.ACTION_UUID);
         mService.registerReceiver(mReceiver, filter);
+        mReceiverRegistered = true;
     }
 
     public void cleanup() {
         mRemoteDevices = null;
-        if (mProfileConnectionState != null) {
-            mProfileConnectionState.clear();
-            mProfileConnectionState = null;
+        mProfileConnectionState.clear();
+        if (mReceiverRegistered) {
+            mService.unregisterReceiver(mReceiver);
+            mReceiverRegistered = false;
         }
-        mService.unregisterReceiver(mReceiver);
         mService = null;
         mBondedDevices.clear();
     }
@@ -228,18 +244,6 @@
     }
 
     /**
-     * Set local adapter UUIDs.
-     *
-     * @param uuids the uuids to be set.
-     */
-    boolean setUuids(ParcelUuid[] uuids) {
-        synchronized (mObject) {
-            return mService.setAdapterPropertyNative(
-                    AbstractionLayer.BT_PROPERTY_UUIDS, Utils.uuidsToByteArray(uuids));
-        }
-    }
-
-    /**
      * @return the mAddress
      */
     byte[] getAddress() {
@@ -377,8 +381,10 @@
     // state changes.
     void onBondStateChanged(BluetoothDevice device, int state)
     {
-        if(device == null)
+        if (device == null) {
+            Log.w(TAG, "onBondStateChanged, device is null");
             return;
+        }
         try {
             byte[] addrByte = Utils.getByteAddress(device);
             DeviceProperties prop = mRemoteDevices.getDeviceProperties(device);
@@ -401,7 +407,7 @@
             }
         }
         catch(Exception ee) {
-            Log.e(TAG, "Exception in onBondStateChanged : ", ee);
+            Log.w(TAG, "onBondStateChanged: Exception ", ee);
         }
     }
 
@@ -437,6 +443,14 @@
         BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
         int prevState = connIntent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
         int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+        Log.d(TAG,
+                "PROFILE_CONNECTION_STATE_CHANGE: profile=" + profile + ", device=" + device + ", "
+                        + prevState + " -> " + state);
+        if (!isNormalStateTransition(prevState, state)) {
+            Log.w(TAG,
+                    "PROFILE_CONNECTION_STATE_CHANGE: unexpected transition for profile=" + profile
+                            + ", device=" + device + ", " + prevState + " -> " + state);
+        }
         sendConnectionStateChange(device, profile, state, prevState);
     }
     void sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState) {
@@ -446,8 +460,8 @@
             // with the invalid state converted to -1 in the intent.
             // Better to log an error and not send an intent with
             // invalid contents or set mAdapterConnectionState to -1.
-            errorLog("Error in sendConnectionStateChange: "
-                    + "prevState " + prevState + " state " + state);
+            errorLog("sendConnectionStateChange: invalid state transition " + prevState + " -> "
+                    + state);
             return;
         }
 
@@ -455,19 +469,25 @@
             updateProfileConnectionState(profile, state, prevState);
 
             if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
-                setConnectionState(state);
+                int newAdapterState = convertToAdapterState(state);
+                int prevAdapterState = convertToAdapterState(prevState);
+                setConnectionState(newAdapterState);
 
                 Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
                 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-                intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
-                        convertToAdapterState(state));
-                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
-                        convertToAdapterState(prevState));
+                intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, newAdapterState);
+                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevAdapterState);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                mService.sendBroadcastAsUser(intent, UserHandle.ALL,
-                        mService.BLUETOOTH_PERM);
-                Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
-                        + prevState + " -> " + state);
+                Log.d(TAG,
+                        "ADAPTER_CONNECTION_STATE_CHANGE: " + device + ": " + prevAdapterState
+                                + " -> " + newAdapterState);
+                if (!isNormalStateTransition(prevState, state)) {
+                    Log.w(TAG,
+                            "ADAPTER_CONNECTION_STATE_CHANGE: unexpected transition for profile="
+                                    + profile + ", device=" + device + ", " + prevState + " -> "
+                                    + state);
+                }
+                mService.sendBroadcastAsUser(intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
             }
         }
     }
@@ -479,8 +499,7 @@
                 state == BluetoothProfile.STATE_DISCONNECTING);
     }
 
-
-    private int convertToAdapterState(int state) {
+    private static int convertToAdapterState(int state) {
         switch (state) {
             case BluetoothProfile.STATE_DISCONNECTED:
                 return BluetoothAdapter.STATE_DISCONNECTED;
@@ -491,22 +510,46 @@
             case BluetoothProfile.STATE_CONNECTING:
                 return BluetoothAdapter.STATE_CONNECTING;
         }
-        Log.e(TAG, "Error in convertToAdapterState");
+        Log.e(TAG, "convertToAdapterState, unknow state " + state);
         return -1;
     }
 
+    private static boolean isNormalStateTransition(int prevState, int nextState) {
+        switch (prevState) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return nextState == BluetoothProfile.STATE_CONNECTING;
+            case BluetoothProfile.STATE_CONNECTED:
+                return nextState == BluetoothProfile.STATE_DISCONNECTING;
+            case BluetoothProfile.STATE_DISCONNECTING:
+            case BluetoothProfile.STATE_CONNECTING:
+                return (nextState == BluetoothProfile.STATE_DISCONNECTED)
+                        || (nextState == BluetoothProfile.STATE_CONNECTED);
+            default:
+                return false;
+        }
+    }
+
     private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
         switch (prevState) {
             case BluetoothProfile.STATE_CONNECTING:
-                mProfilesConnecting--;
+                if (mProfilesConnecting > 0)
+                    mProfilesConnecting--;
+                else
+                    Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting);
                 break;
 
             case BluetoothProfile.STATE_CONNECTED:
-                mProfilesConnected--;
+                if (mProfilesConnected > 0)
+                    mProfilesConnected--;
+                else
+                    Log.e(TAG, "mProfilesConnected " + mProfilesConnected);
                 break;
 
             case BluetoothProfile.STATE_DISCONNECTING:
-                mProfilesDisconnecting--;
+                if (mProfilesDisconnecting > 0)
+                    mProfilesDisconnecting--;
+                else
+                    Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting);
                 break;
         }
 
@@ -597,8 +640,8 @@
                         intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
                         intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName);
                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                        mService.sendBroadcastAsUser(intent, UserHandle.ALL,
-                                 mService.BLUETOOTH_PERM);
+                        mService.sendBroadcastAsUser(
+                                intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
                         debugLog("Name is: " + mName);
                         break;
                     case AbstractionLayer.BT_PROPERTY_BDADDR:
@@ -609,7 +652,7 @@
                         intent.putExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS, address);
                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                         mService.sendBroadcastAsUser(
-                                intent, UserHandle.ALL, mService.BLUETOOTH_PERM);
+                                intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
                         break;
                     case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
                         mBluetoothClass = Utils.byteArrayToInt(val, 0);
@@ -617,11 +660,11 @@
                         break;
                     case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:
                         int mode = Utils.byteArrayToInt(val, 0);
-                        mScanMode = mService.convertScanModeFromHal(mode);
+                        mScanMode = AdapterService.convertScanModeFromHal(mode);
                         intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
                         intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode);
                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                        mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
+                        mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
                         debugLog("Scan Mode:" + mScanMode);
                         if (mBluetoothDisabling) {
                             mBluetoothDisabling=false;
@@ -657,7 +700,7 @@
         }
     }
 
-    void updateFeatureSupport(byte[] val) {
+    private void updateFeatureSupport(byte[] val) {
         mVersSupported = ((0xFF & ((int)val[1])) << 8)
                             + (0xFF & ((int)val[0]));
         mNumOfAdvertisementInstancesSupported = (0xFF & ((int)val[3]));
@@ -712,12 +755,17 @@
     }
 
     void onBluetoothReady() {
-        Log.d(TAG, "ScanMode =  " + mScanMode );
-        Log.d(TAG, "State =  " + getState() );
+        debugLog("onBluetoothReady, state=" + getState() + ", ScanMode=" + mScanMode);
 
-        // When BT is being turned on, all adapter properties will be sent in 1
-        // callback. At this stage, set the scan mode.
         synchronized (mObject) {
+            // Reset adapter and profile connection states
+            setConnectionState(BluetoothAdapter.STATE_DISCONNECTED);
+            mProfileConnectionState.clear();
+            mProfilesConnected = 0;
+            mProfilesConnecting = 0;
+            mProfilesDisconnecting = 0;
+            // When BT is being turned on, all adapter properties will be sent in 1
+            // callback. At this stage, set the scan mode.
             if (getState() == BluetoothAdapter.STATE_TURNING_ON &&
                     mScanMode == BluetoothAdapter.SCAN_MODE_NONE) {
                     /* mDiscoverableTimeout is part of the
@@ -769,25 +817,25 @@
                 mDiscovering = false;
                 mDiscoveryEndMs = System.currentTimeMillis();
                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
-                mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
+                mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
             } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
                 mDiscovering = true;
                 mDiscoveryEndMs = System.currentTimeMillis() + DEFAULT_DISCOVERY_TIMEOUT_MS;
                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
-                mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
+                mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
             }
         }
     }
 
-    private void infoLog(String msg) {
+    private static void infoLog(String msg) {
         if (VDBG) Log.i(TAG, msg);
     }
 
-    private void debugLog(String msg) {
+    private static void debugLog(String msg) {
         if (DBG) Log.d(TAG, msg);
     }
 
-    private void errorLog(String msg) {
+    private static void errorLog(String msg) {
         Log.e(TAG, msg);
     }
 }
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index b3fe737..a2a675f 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -1499,6 +1499,7 @@
     }
 
      boolean startDiscovery() {
+        debugLog("startDiscovery");
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH ADMIN permission");
 
@@ -1506,6 +1507,7 @@
     }
 
      boolean cancelDiscovery() {
+        debugLog("cancelDiscovery");
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                        "Need BLUETOOTH ADMIN permission");
 
diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java
index 336e916..d7dab6d 100644
--- a/src/com/android/bluetooth/btservice/BondStateMachine.java
+++ b/src/com/android/bluetooth/btservice/BondStateMachine.java
@@ -341,7 +341,8 @@
     private void sendIntent(BluetoothDevice device, int newState, int reason) {
         DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device);
         int oldState = BluetoothDevice.BOND_NONE;
-        if (newState != BluetoothDevice.BOND_NONE && newState != BluetoothDevice.BOND_BONDING
+        if (newState != BluetoothDevice.BOND_NONE
+                && newState != BluetoothDevice.BOND_BONDING
                 && newState != BluetoothDevice.BOND_BONDED) {
             infoLog("Invalid bond state " + newState);
             return;
@@ -364,11 +365,9 @@
 
         mAdapterProperties.onBondStateChanged(device, newState);
 
-        if (devProp != null
-                && ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC
-                            || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL)
-                           && newState == BluetoothDevice.BOND_BONDED
-                           && devProp.getUuids() == null)) {
+        if (devProp != null && ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC
+                || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL)
+                && 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/PhonePolicy.java b/src/com/android/bluetooth/btservice/PhonePolicy.java
index 19817bf..b3ef04b 100644
--- a/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -41,6 +41,7 @@
 import com.android.bluetooth.pan.PanService;
 import com.android.internal.R;
 
+import java.util.HashSet;
 import java.util.List;
 
 // Describes the phone policy
@@ -78,41 +79,53 @@
     final private static int MESSAGE_CONNECT_OTHER_PROFILES = 3;
     final private static int MESSAGE_ADAPTER_STATE_TURNED_ON = 4;
 
-    public static final int PROFILE_CONN_CONNECTED = 1;
-
     // Timeouts
     final private static int CONNECT_OTHER_PROFILES_TIMEOUT = 6000; // 6s
 
     final private AdapterService mAdapterService;
     final private ServiceFactory mFactory;
     final private Handler mHandler;
+    final private HashSet<BluetoothDevice> mHeadsetRetrySet = new HashSet<>();
+    final private HashSet<BluetoothDevice> mA2dpRetrySet = new HashSet<>();
 
     // Broadcast receiver for all changes to states of various profiles
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.d(TAG, "Received intent " + intent);
-            if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
-                                BluetoothProfile.HEADSET,
-                                -1, // No-op argument
-                                intent)
-                        .sendToTarget();
-            } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
-                                BluetoothProfile.A2DP,
-                                -1, // No-op argument
-                                intent)
-                        .sendToTarget();
-            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
-                // Only pass the message on if the adapter has actually changed state from
-                // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON.
-                int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
-                if (newState == BluetoothAdapter.STATE_ON) {
-                    mHandler.obtainMessage(MESSAGE_ADAPTER_STATE_TURNED_ON).sendToTarget();
-                }
-            } else if (BluetoothDevice.ACTION_UUID.equals(intent.getAction())) {
-                mHandler.obtainMessage(MESSAGE_PROFILE_INIT_PRIORITIES, intent).sendToTarget();
+            String action = intent.getAction();
+            if (action == null) {
+                errorLog("Received intent with null action");
+                return;
+            }
+            switch (action) {
+                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
+                    mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
+                                    BluetoothProfile.HEADSET,
+                                    -1, // No-op argument
+                                    intent)
+                            .sendToTarget();
+                    break;
+                case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
+                    mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED,
+                                    BluetoothProfile.A2DP,
+                                    -1, // No-op argument
+                                    intent)
+                            .sendToTarget();
+                    break;
+                case BluetoothAdapter.ACTION_STATE_CHANGED:
+                    // Only pass the message on if the adapter has actually changed state from
+                    // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON.
+                    int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+                    if (newState == BluetoothAdapter.STATE_ON) {
+                        mHandler.obtainMessage(MESSAGE_ADAPTER_STATE_TURNED_ON).sendToTarget();
+                    }
+                    break;
+                case BluetoothDevice.ACTION_UUID:
+                    mHandler.obtainMessage(MESSAGE_PROFILE_INIT_PRIORITIES, intent).sendToTarget();
+                    break;
+                default:
+                    Log.e(TAG, "Received unexpected intent, action=" + action);
+                    break;
             }
         }
     };
@@ -132,17 +145,16 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MESSAGE_PROFILE_INIT_PRIORITIES: {
+                    Intent intent = (Intent) msg.obj;
                     BluetoothDevice device =
-                            (BluetoothDevice) ((Intent) msg.obj)
-                                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                    Parcelable[] uuids =
-                            ((Intent) msg.obj).getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
-
-                    Log.d(TAG, "UUIDs on ACTION_UUID: " + uuids + " for device " + device);
+                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                    Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
+                    debugLog("Received ACTION_UUID for device " + device);
                     if (uuids != null) {
                         ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length];
                         for (int i = 0; i < uuidsToSend.length; i++) {
                             uuidsToSend[i] = (ParcelUuid) uuids[i];
+                            debugLog("index=" + i + "uuid=" + uuidsToSend[i]);
                         }
                         processInitProfilePriorities(device, uuidsToSend);
                     }
@@ -165,6 +177,7 @@
 
                 case MESSAGE_ADAPTER_STATE_TURNED_ON:
                     // Call auto connect when adapter switches state to ON
+                    resetStates();
                     autoConnect();
                     break;
             }
@@ -182,6 +195,7 @@
     }
     protected void cleanup() {
         mAdapterService.unregisterReceiver(mReceiver);
+        resetStates();
     }
 
     PhonePolicy(AdapterService service, ServiceFactory factory) {
@@ -192,7 +206,7 @@
 
     // Policy implementation, all functions MUST be private
     private void processInitProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids) {
-        debugLog("processInitProfilePriorities() - device " + device + " UUIDs " + uuids);
+        debugLog("processInitProfilePriorities() - device " + device);
         HidService hidService = mFactory.getHidService();
         A2dpService a2dpService = mFactory.getA2dpService();
         HeadsetService headsetService = mFactory.getHeadsetService();
@@ -235,23 +249,35 @@
 
     private void processProfileStateChanged(
             BluetoothDevice device, int profileId, int nextState, int prevState) {
-        // Profiles relevant to phones.
+        debugLog("processProfileStateChanged, device=" + device + ", profile=" + profileId + ", "
+                + prevState + " -> " + nextState);
         if (((profileId == BluetoothProfile.A2DP) || (profileId == BluetoothProfile.HEADSET))
                 && (nextState == BluetoothProfile.STATE_CONNECTED)) {
-            debugLog("Profile connected id: " + profileId
-                    + " Schedule missing profile connection if any");
+            switch (profileId) {
+                case BluetoothProfile.A2DP:
+                    mA2dpRetrySet.remove(device);
+                    break;
+                case BluetoothProfile.HEADSET:
+                    mHeadsetRetrySet.remove(device);
+                    break;
+            }
             connectOtherProfile(device);
             setProfileAutoConnectionPriority(device, profileId);
         }
     }
 
+    private void resetStates() {
+        mHeadsetRetrySet.clear();
+        mA2dpRetrySet.clear();
+    }
+
     private void autoConnect() {
         if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
             errorLog("autoConnect() - BT is not ON. Exiting autoConnect");
             return;
         }
 
-        if (mAdapterService.isQuietModeEnabled() == false) {
+        if (!mAdapterService.isQuietModeEnabled()) {
             debugLog("autoConnect() - Initiate auto connection on BT on...");
             // Phone profiles.
             autoConnectHeadset();
@@ -262,45 +288,48 @@
     }
 
     private void autoConnectHeadset() {
-        HeadsetService hsService = mFactory.getHeadsetService();
+        final HeadsetService hsService = mFactory.getHeadsetService();
         if (hsService == null) {
-            errorLog("autoConnectHeadset() - service is null");
+            errorLog("autoConnectHeadset, service is null");
             return;
         }
-
-        BluetoothDevice bondedDevices[] = mAdapterService.getBondedDevices();
+        final BluetoothDevice bondedDevices[] = mAdapterService.getBondedDevices();
         if (bondedDevices == null) {
-            errorLog("autoConnectHeadset() - devices are null");
+            errorLog("autoConnectHeadset, bondedDevices are null");
             return;
         }
-
-        debugLog("autoConnectHeadset() - bondedDevices: " + bondedDevices);
         for (BluetoothDevice device : bondedDevices) {
-            debugLog("autoConnectHeadset() - attempt autoconnect with device " + device);
+            debugLog("autoConnectHeadset, attempt auto-connect with device " + device);
             if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
-                debugLog("autoConnectHeadset() - Connecting HFP with " + device.toString());
+                debugLog("autoConnectHeadset, Connecting HFP with " + device);
                 hsService.connect(device);
             }
         }
     }
 
     private void autoConnectA2dp() {
-        A2dpService a2dpSservice = mFactory.getA2dpService();
-        BluetoothDevice bondedDevices[] = mAdapterService.getBondedDevices();
-        if ((bondedDevices == null) || (a2dpSservice == null)) {
+        final A2dpService a2dpService = mFactory.getA2dpService();
+        if (a2dpService == null) {
+            errorLog("autoConnectA2dp, service is null");
+            return;
+        }
+        final BluetoothDevice bondedDevices[] = mAdapterService.getBondedDevices();
+        if (bondedDevices == null) {
+            errorLog("autoConnectA2dp, bondedDevices are null");
             return;
         }
         for (BluetoothDevice device : bondedDevices) {
-            if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
-                debugLog("autoConnectA2dp() - Connecting A2DP with " + device.toString());
-                a2dpSservice.connect(device);
+            debugLog("autoConnectA2dp, attempt auto-connect with device " + device);
+            if (a2dpService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+                debugLog("autoConnectA2dp, connecting A2DP with " + device);
+                a2dpService.connect(device);
             }
         }
     }
 
-    public void connectOtherProfile(BluetoothDevice device) {
-        if ((mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false)
-                && (mAdapterService.isQuietModeEnabled() == false)) {
+    private void connectOtherProfile(BluetoothDevice device) {
+        if ((!mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES))
+                && (!mAdapterService.isQuietModeEnabled())) {
             Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES);
             m.obj = device;
             mHandler.sendMessageDelayed(m, CONNECT_OTHER_PROFILES_TIMEOUT);
@@ -312,8 +341,9 @@
     // connect to the device that initiated the connection.  In the event that this function is
     // invoked and there are no current bluetooth connections no new profiles will be connected.
     private void processConnectOtherProfiles(BluetoothDevice device) {
-        debugLog("processConnectOtherProfiles() - device " + device);
+        debugLog("processConnectOtherProfiles, device=" + device);
         if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
+            warnLog("processConnectOtherProfiles, adapter is not ON " + mAdapterService.getState());
             return;
         }
         HeadsetService hsService = mFactory.getHeadsetService();
@@ -338,29 +368,31 @@
             allProfilesEmpty = allProfilesEmpty && panConnDevList.isEmpty();
         }
 
-        debugLog("processConnectOtherProfiles() - allProfilesEmpty " + allProfilesEmpty + " device "
-                + device);
-
         if (allProfilesEmpty) {
-            // must have connected then disconnected, don't bother connecting others.
+            // considered as fully disconnected, don't bother connecting others.
+            debugLog("processConnectOtherProfiles, all profiles disconnected for " + device);
+            // reset retry status so that in the next round we can start retrying connections again
+            resetStates();
             return;
         }
 
         if (hsService != null) {
-            if (hsConnDevList.isEmpty()
+            if (hsConnDevList.isEmpty() && !mHeadsetRetrySet.contains(device)
                     && (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)
                     && (hsService.getConnectionState(device)
                                == BluetoothProfile.STATE_DISCONNECTED)) {
-                debugLog("Retrying connection to HS with device " + device);
+                debugLog("Retrying connection to Headset with device " + device);
+                mHeadsetRetrySet.add(device);
                 hsService.connect(device);
             }
         }
         if (a2dpService != null) {
-            if (a2dpConnDevList.isEmpty()
+            if (a2dpConnDevList.isEmpty() && !mA2dpRetrySet.contains(device)
                     && (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)
                     && (a2dpService.getConnectionState(device)
                                == BluetoothProfile.STATE_DISCONNECTED)) {
                 debugLog("Retrying connection to A2DP with device " + device);
+                mA2dpRetrySet.add(device);
                 a2dpService.connect(device);
             }
         }
@@ -369,27 +401,20 @@
                     && (panService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)
                     && (panService.getConnectionState(device)
                                == BluetoothProfile.STATE_DISCONNECTED)) {
-                debugLog("Retrying connection to HF with device " + device);
+                debugLog("Retrying connection to PAN with device " + device);
                 panService.connect(device);
             }
         }
     }
 
-    private void debugLog(String msg) {
-        if (DBG) Log.d(TAG, msg);
-    }
-
-    private void errorLog(String msg) {
-        Log.e(TAG, msg);
-    }
-
-    void setProfileAutoConnectionPriority(BluetoothDevice device, int profileId) {
+    private void setProfileAutoConnectionPriority(BluetoothDevice device, int profileId) {
         switch (profileId) {
             case BluetoothProfile.HEADSET:
                 HeadsetService hsService = mFactory.getHeadsetService();
-                List<BluetoothDevice> deviceList = hsService.getConnectedDevices();
-                if ((hsService != null) && (BluetoothProfile.PRIORITY_AUTO_CONNECT
-                                                   != hsService.getPriority(device))) {
+                if ((hsService != null)
+                        && (BluetoothProfile.PRIORITY_AUTO_CONNECT
+                                   != hsService.getPriority(device))) {
+                    List<BluetoothDevice> deviceList = hsService.getConnectedDevices();
                     adjustOtherHeadsetPriorities(hsService, deviceList);
                     hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
                 }
@@ -405,7 +430,7 @@
                 break;
 
             default:
-                Log.w(TAG, "Attempting to set Auto Connect priority on invalid profile");
+                Log.w(TAG, "Tried to set AutoConnect priority on invalid profile " + profileId);
                 break;
         }
     }
@@ -429,4 +454,16 @@
             }
         }
     }
+
+    private static void debugLog(String msg) {
+        if (DBG) Log.d(TAG, msg);
+    }
+
+    private static void warnLog(String msg) {
+        Log.w(TAG, msg);
+    }
+
+    private static void errorLog(String msg) {
+        Log.e(TAG, msg);
+    }
 }
diff --git a/src/com/android/bluetooth/gatt/AppScanStats.java b/src/com/android/bluetooth/gatt/AppScanStats.java
index 35bb51e..e65ad6b 100644
--- a/src/com/android/bluetooth/gatt/AppScanStats.java
+++ b/src/com/android/bluetooth/gatt/AppScanStats.java
@@ -50,6 +50,9 @@
 
     class LastScan {
         long duration;
+        long suspendDuration;
+        long suspendStartTime;
+        boolean isSuspended;
         long timestamp;
         boolean opportunistic;
         boolean timeout;
@@ -67,6 +70,9 @@
             this.filtered = filtered;
             this.results = 0;
             this.scannerId = scannerId;
+            this.suspendDuration = 0;
+            this.suspendStartTime = 0;
+            this.isSuspended = false;
         }
     }
 
@@ -90,6 +96,7 @@
     long maxScanTime = 0;
     long mScanStartTime = 0;
     long mTotalScanTime = 0;
+    long mTotalSuspendTime = 0;
     List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT);
     HashMap<Integer, LastScan> ongoingScans = new HashMap<Integer, LastScan>();
     long startTime = 0;
@@ -177,6 +184,10 @@
         stopTime = SystemClock.elapsedRealtime();
         long scanDuration = stopTime - scan.timestamp;
         scan.duration = scanDuration;
+        if (scan.isSuspended) {
+            scan.suspendDuration += stopTime - scan.suspendStartTime;
+            mTotalSuspendTime += scan.suspendDuration;
+        }
         ongoingScans.remove(scannerId);
         if (lastScans.size() >= NUM_SCAN_DURATIONS_KEPT) {
             lastScans.remove(0);
@@ -208,6 +219,26 @@
         }
     }
 
+    synchronized void recordScanSuspend(int scannerId) {
+        LastScan scan = getScanFromScannerId(scannerId);
+        if (scan == null || scan.isSuspended) {
+            return;
+        }
+        scan.suspendStartTime = SystemClock.elapsedRealtime();
+        scan.isSuspended = true;
+    }
+
+    synchronized void recordScanResume(int scannerId) {
+        LastScan scan = getScanFromScannerId(scannerId);
+        if (scan == null || !scan.isSuspended) {
+            return;
+        }
+        scan.isSuspended = false;
+        stopTime = SystemClock.elapsedRealtime();
+        scan.suspendDuration += stopTime - scan.suspendStartTime;
+        mTotalSuspendTime += scan.suspendDuration;
+    }
+
     synchronized void setScanTimeout(int scannerId) {
         if (!isScanning()) return;
 
@@ -299,6 +330,9 @@
                   maxScan + " / " +
                   avgScan + " / " +
                   totalScanTime + "\n");
+        if (mTotalSuspendTime != 0) {
+            sb.append("  Total time suspended             : " + mTotalSuspendTime + "ms\n");
+        }
         sb.append("  Total number of results            : " +
                   results + "\n");
 
@@ -319,6 +353,10 @@
                 sb.append(scan.results + " results");
                 sb.append(" (" + scan.scannerId + ")");
                 sb.append("\n");
+                if (scan.suspendDuration != 0) {
+                    sb.append("      └"
+                            + " Suspended Time: " + scan.suspendDuration + "ms\n");
+                }
             }
         }
 
@@ -333,9 +371,16 @@
                 if (scan.background) sb.append("Back ");
                 if (scan.timeout) sb.append("Forced ");
                 if (scan.filtered) sb.append("Filter ");
+                if (scan.isSuspended) sb.append("Suspended ");
                 sb.append(scan.results + " results");
                 sb.append(" (" + scan.scannerId + ")");
                 sb.append("\n");
+                if (scan.suspendStartTime != 0) {
+                    long duration = scan.suspendDuration
+                            + (scan.isSuspended ? (elapsedRt - scan.suspendStartTime) : 0);
+                    sb.append("      └"
+                            + " Suspended Time: " + duration + "ms\n");
+                }
             }
         }
 
diff --git a/src/com/android/bluetooth/gatt/ContextMap.java b/src/com/android/bluetooth/gatt/ContextMap.java
index a9965db..13c46a8 100644
--- a/src/com/android/bluetooth/gatt/ContextMap.java
+++ b/src/com/android/bluetooth/gatt/ContextMap.java
@@ -86,6 +86,12 @@
         /** Flag to signal that transport is congested */
         Boolean isCongested = false;
 
+        /** Whether the calling app has location permission */
+        boolean hasLocationPermisson;
+
+        /** Whether the calling app has peers mac address permission */
+        boolean hasPeersMacAddressPermission;
+
         /** Internal callback info queue, waiting to be send on congestion clear */
         private List<CallbackInfo> congestionQueue = new ArrayList<CallbackInfo>();
 
@@ -151,7 +157,7 @@
     /**
      * Add an entry to the application context list.
      */
-    void add(UUID uuid, WorkSource workSource, C callback, T info, GattService service) {
+    App add(UUID uuid, WorkSource workSource, C callback, T info, GattService service) {
         int appUid = Binder.getCallingUid();
         String appName = service.getPackageManager().getNameForUid(appUid);
         if (appName == null) {
@@ -164,8 +170,10 @@
                 appScanStats = new AppScanStats(appName, workSource, this, service);
                 mAppScanStats.put(appUid, appScanStats);
             }
-            mApps.add(new App(uuid, callback, info, appName, appScanStats));
+            App app = new App(uuid, callback, info, appName, appScanStats);
+            mApps.add(app);
             appScanStats.isRegistered = true;
+            return app;
         }
     }
 
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 9117a7d..9a99bcd 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -37,6 +37,7 @@
 import android.bluetooth.le.IScannerCallback;
 import android.bluetooth.le.PeriodicAdvertisingParameters;
 import android.bluetooth.le.ResultStorageDescriptor;
+import android.bluetooth.le.ScanCallback;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
@@ -59,6 +60,7 @@
 import com.android.bluetooth.util.NumberUtils;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -367,7 +369,8 @@
             service.unregisterClient(clientIf);
         }
 
-        public void registerScanner(IScannerCallback callback, WorkSource workSource) {
+        public void registerScanner(IScannerCallback callback, WorkSource workSource)
+                throws RemoteException {
             GattService service = getService();
             if (service == null) return;
             service.registerScanner(callback, workSource);
@@ -844,7 +847,7 @@
                 if (cbApp.callback != null) {
                     cbApp.linkToDeath(new ScannerDeathRecipient(scannerId));
                 } else {
-                    continuePiStartScan(scannerId, cbApp.info);
+                    continuePiStartScan(scannerId, cbApp);
                 }
             } else {
                 mScannerMap.remove(scannerId);
@@ -934,11 +937,17 @@
         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
     }
 
-    void onClientPhyRead(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
-        if (DBG) Log.d(TAG, "onClientPhyRead() - connId=" + connId + ", status=" + status);
+    void onClientPhyRead(int clientIf, String address, int txPhy, int rxPhy, int status)
+            throws RemoteException {
+        if (DBG)
+            Log.d(TAG, "onClientPhyRead() - address=" + address + ", status=" + status
+                            + ", clientIf=" + clientIf);
 
-        String address = mClientMap.addressByConnId(connId);
-        if (address == null) return;
+        Integer connId = mClientMap.connIdByAddress(clientIf, address);
+        if (connId == null) {
+            Log.d(TAG, "onClientPhyRead() - no connection to " + address);
+            return;
+        }
 
         ClientMap.App app = mClientMap.getByConnId(connId);
         if (app == null) return;
@@ -971,11 +980,15 @@
         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
     }
 
-    void onServerPhyRead(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
-        if (DBG) Log.d(TAG, "onServerPhyRead() - connId=" + connId + ", status=" + status);
+    void onServerPhyRead(int serverIf, String address, int txPhy, int rxPhy, int status)
+            throws RemoteException {
+        if (DBG) Log.d(TAG, "onServerPhyRead() - address=" + address + ", status=" + status);
 
-        String address = mServerMap.addressByConnId(connId);
-        if (address == null) return;
+        Integer connId = mServerMap.connIdByAddress(serverIf, address);
+        if (connId == null) {
+            Log.d(TAG, "onServerPhyRead() - no connection to " + address);
+            return;
+        }
 
         ServerMap.App app = mServerMap.getByConnId(connId);
         if (app == null) return;
@@ -1548,7 +1561,7 @@
         return deviceList;
     }
 
-    void registerScanner(IScannerCallback callback, WorkSource workSource) {
+    void registerScanner(IScannerCallback callback, WorkSource workSource) throws RemoteException {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
         UUID uuid = UUID.randomUUID();
@@ -1559,6 +1572,14 @@
         }
 
         mScannerMap.add(uuid, workSource, callback, null, this);
+        AppScanStats app = mScannerMap.getAppScanStatsByUid(Binder.getCallingUid());
+        if (app != null && app.isScanningTooFrequently()
+                && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) {
+            Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
+            callback.onScannerRegistered(ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY, -1);
+            return;
+        }
+
         mScanManager.registerScanner(uuid);
     }
 
@@ -1584,17 +1605,9 @@
                 this);
         scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage);
 
-        AppScanStats app = null;
-        app = mScannerMap.getAppScanStatsById(scannerId);
-
+        AppScanStats app = mScannerMap.getAppScanStatsById(scannerId);
         if (app != null) {
-            if (app.isScanningTooFrequently() &&
-                checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) {
-                Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
-                return;
-            }
             scanClient.stats = app;
-
             boolean isFilteredScan = (filters != null) && !filters.isEmpty();
             app.recordScanStart(settings, isFilteredScan, scannerId);
         }
@@ -1617,34 +1630,36 @@
         piInfo.settings = settings;
         piInfo.filters = filters;
         piInfo.callingPackage = callingPackage;
-        mScannerMap.add(uuid, null, null, piInfo, this);
+        ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
+        try {
+            app.hasLocationPermisson =
+                    Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage);
+        } catch (SecurityException se) {
+            // No need to throw here. Just mark as not granted.
+            app.hasLocationPermisson = false;
+        }
+        try {
+            app.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission(this);
+        } catch (SecurityException se) {
+            // No need to throw here. Just mark as not granted.
+            app.hasPeersMacAddressPermission = false;
+        }
         mScanManager.registerScanner(uuid);
     }
 
-    void continuePiStartScan(int scannerId, PendingIntentInfo piInfo) {
+    void continuePiStartScan(int scannerId, ScannerMap.App app) {
+        final PendingIntentInfo piInfo = app.info;
         final ScanClient scanClient =
                 new ScanClient(scannerId, piInfo.settings, piInfo.filters, null);
-        scanClient.hasLocationPermission =
-                true; // Utils.checkCallerHasLocationPermission(this, mAppOps,
-        // piInfo.callingPackage);
-        scanClient.hasPeersMacAddressPermission =
-                true; // Utils.checkCallerHasPeersMacAddressPermission(
-        // this);
+        scanClient.hasLocationPermission = app.hasLocationPermisson;
+        scanClient.hasPeersMacAddressPermission = app.hasPeersMacAddressPermission;
         scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, piInfo.callingPackage);
 
-        AppScanStats app = null;
-        app = mScannerMap.getAppScanStatsById(scannerId);
-
-        if (app != null) {
-            if (app.isScanningTooFrequently()
-                    && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) {
-                Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
-                return;
-            }
-            scanClient.stats = app;
-
+        AppScanStats scanStats = mScannerMap.getAppScanStatsById(scannerId);
+        if (scanStats != null) {
+            scanClient.stats = scanStats;
             boolean isFilteredScan = (piInfo.filters != null) && !piInfo.filters.isEmpty();
-            app.recordScanStart(piInfo.settings, isFilteredScan, scannerId);
+            scanStats.recordScanStart(piInfo.settings, isFilteredScan, scannerId);
         }
 
         mScanManager.startScan(scanClient);
@@ -1797,8 +1812,8 @@
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
         if (DBG) {
-            Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect
-                            + ", opportunistic=" + opportunistic + ", phy=" + phy);
+            Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect +
+                    ", opportunistic=" + opportunistic + ", phy=" + phy);
         }
         gattClientConnectNative(clientIf, address, isDirect, transport, opportunistic, phy);
     }
@@ -1822,7 +1837,7 @@
         }
 
         if (DBG) Log.d(TAG, "clientSetPreferredPhy() - address=" + address + ", connId=" + connId);
-        gattClientSetPreferredPhyNative(clientIf, connId, txPhy, rxPhy, phyOptions);
+        gattClientSetPreferredPhyNative(clientIf, address, txPhy, rxPhy, phyOptions);
     }
 
     void clientReadPhy(int clientIf, String address) {
@@ -1835,7 +1850,7 @@
         }
 
         if (DBG) Log.d(TAG, "clientReadPhy() - address=" + address + ", connId=" + connId);
-        gattClientReadPhyNative(clientIf, connId);
+        gattClientReadPhyNative(clientIf, address);
     }
 
     int numHwTrackFiltersAvailable() {
@@ -2373,7 +2388,7 @@
         }
 
         if (DBG) Log.d(TAG, "serverSetPreferredPhy() - address=" + address + ", connId=" + connId);
-        gattServerSetPreferredPhyNative(serverIf, connId, txPhy, rxPhy, phyOptions);
+        gattServerSetPreferredPhyNative(serverIf, address, txPhy, rxPhy, phyOptions);
     }
 
     void serverReadPhy(int serverIf, String address) {
@@ -2386,7 +2401,7 @@
         }
 
         if (DBG) Log.d(TAG, "serverReadPhy() - address=" + address + ", connId=" + connId);
-        gattServerReadPhyNative(serverIf, connId);
+        gattServerReadPhyNative(serverIf, address);
     }
 
     void addService(int serverIf, BluetoothGattService service) {
@@ -2694,9 +2709,9 @@
             int conn_id);
 
     private native void gattClientSetPreferredPhyNative(
-            int clientIf, int conn_id, int tx_phy, int rx_phy, int phy_options);
+            int clientIf, String address, int tx_phy, int rx_phy, int phy_options);
 
-    private native void gattClientReadPhyNative(int clientIf, int conn_id);
+    private native void gattClientReadPhyNative(int clientIf, String address);
 
     private native void gattClientRefreshNative(int clientIf, String address);
 
@@ -2746,9 +2761,9 @@
                                               int conn_id);
 
     private native void gattServerSetPreferredPhyNative(
-            int clientIf, int conn_id, int tx_phy, int rx_phy, int phy_options);
+            int clientIf, String address, int tx_phy, int rx_phy, int phy_options);
 
-    private native void gattServerReadPhyNative(int clientIf, int conn_id);
+    private native void gattServerReadPhyNative(int clientIf, String address);
 
     private native void gattServerAddServiceNative(int server_if, List<GattDbElement> service);
 
diff --git a/src/com/android/bluetooth/gatt/ScanManager.java b/src/com/android/bluetooth/gatt/ScanManager.java
index f7dc9f3..65f4f6d 100644
--- a/src/com/android/bluetooth/gatt/ScanManager.java
+++ b/src/com/android/bluetooth/gatt/ScanManager.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -34,6 +35,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.Log;
+import android.view.Display;
 
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.btservice.AdapterService;
@@ -69,7 +71,8 @@
     private static final int MSG_STOP_BLE_SCAN = 1;
     private static final int MSG_FLUSH_BATCH_RESULTS = 2;
     private static final int MSG_SCAN_TIMEOUT = 3;
-
+    private static final int MSG_SUSPEND_SCANS = 4;
+    private static final int MSG_RESUME_SCANS = 5;
     private static final String ACTION_REFRESH_BATCHED_SCAN =
             "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";
 
@@ -89,28 +92,42 @@
 
     private Set<ScanClient> mRegularScanClients;
     private Set<ScanClient> mBatchClients;
+    private Set<ScanClient> mSuspendedScanClients;
 
     private CountDownLatch mLatch;
 
+    private DisplayManager mDm;
+
     ScanManager(GattService service) {
         mRegularScanClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
         mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
+        mSuspendedScanClients =
+                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
         mService = service;
         mScanNative = new ScanNative();
         curUsedTrackableAdvertisements = 0;
+        mDm = (DisplayManager) mService.getSystemService(Context.DISPLAY_SERVICE);
     }
 
     void start() {
         HandlerThread thread = new HandlerThread("BluetoothScanManager");
         thread.start();
         mHandler = new ClientHandler(thread.getLooper());
+        if (mDm != null) {
+            mDm.registerDisplayListener(mDisplayListener, null);
+        }
     }
 
     void cleanup() {
         mRegularScanClients.clear();
         mBatchClients.clear();
+        mSuspendedScanClients.clear();
         mScanNative.cleanup();
 
+        if (mDm != null) {
+            mDm.unregisterDisplayListener(mDisplayListener);
+        }
+
         if (mHandler != null) {
             // Shut down the thread
             mHandler.removeCallbacksAndMessages(null);
@@ -215,6 +232,12 @@
                 case MSG_SCAN_TIMEOUT:
                     mScanNative.regularScanTimeout(client);
                     break;
+                case MSG_SUSPEND_SCANS:
+                    handleSuspendScans();
+                    break;
+                case MSG_RESUME_SCANS:
+                    handleResumeScans();
+                    break;
                 default:
                     // Shouldn't happen.
                     Log.e(TAG, "received an unkown message : " + msg.what);
@@ -223,6 +246,7 @@
 
         void handleStartScan(ScanClient client) {
             Utils.enforceAdminPermission(mService);
+            boolean isFiltered = (client.filters != null) && !client.filters.isEmpty();
             if (DBG) Log.d(TAG, "handling starting scan");
 
             if (!isScanSupported(client)) {
@@ -234,6 +258,15 @@
                 Log.e(TAG, "Scan already started");
                 return;
             }
+
+            if (!mScanNative.isOpportunisticScanClient(client) && !isScreenOn() && !isFiltered) {
+                Log.e(TAG,
+                        "Cannot start unfiltered scan in screen-off. This scan will be resumed later: "
+                                + client.scannerId);
+                mSuspendedScanClients.add(client);
+                return;
+            }
+
             // Begin scan operations.
             if (isBatchClient(client)) {
                 mBatchClients.add(client);
@@ -258,6 +291,10 @@
             Utils.enforceAdminPermission(mService);
             if (client == null) return;
 
+            if (mSuspendedScanClients.contains(client)) {
+                mSuspendedScanClients.remove(client);
+            }
+
             if (mRegularScanClients.contains(client)) {
                 mScanNative.stopRegularScan(client);
 
@@ -305,6 +342,30 @@
             return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES &&
                     settings.getReportDelayMillis() == 0;
         }
+
+        void handleSuspendScans() {
+            for (ScanClient client : mRegularScanClients) {
+                if (!mScanNative.isOpportunisticScanClient(client)
+                        && (client.filters == null || client.filters.isEmpty())) {
+                    /*Suspend unfiltered scans*/
+                    if (client.stats != null) {
+                        client.stats.recordScanSuspend(client.scannerId);
+                    }
+                    handleStopScan(client);
+                    mSuspendedScanClients.add(client);
+                }
+            }
+        }
+
+        void handleResumeScans() {
+            for (ScanClient client : mSuspendedScanClients) {
+                if (client.stats != null) {
+                    client.stats.recordScanResume(client.scannerId);
+                }
+                handleStartScan(client);
+            }
+            mSuspendedScanClients.clear();
+        }
     }
 
     /**
@@ -1163,4 +1224,38 @@
 
         private native void gattClientReadScanReportsNative(int client_if, int scan_type);
     }
+
+    private boolean isScreenOn() {
+        Display[] displays = mDm.getDisplays();
+
+        if (displays == null) {
+            return false;
+        }
+
+        for (Display display : displays) {
+            if (display.getState() == Display.STATE_ON) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+                @Override
+                public void onDisplayAdded(int displayId) {}
+
+                @Override
+                public void onDisplayRemoved(int displayId) {}
+
+                @Override
+                public void onDisplayChanged(int displayId) {
+                    if (isScreenOn()) {
+                        sendMessage(MSG_RESUME_SCANS, null);
+                    } else {
+                        sendMessage(MSG_SUSPEND_SCANS, null);
+                    }
+                }
+            };
 }
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 636ccf5..a7fa02a 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -812,31 +812,26 @@
                         break;
                     }
                     if (mConnectedDevicesList.size() >= max_hf_connections) {
-                        BluetoothDevice DisconnectConnectedDevice = null;
-                        IState CurrentAudioState = getCurrentState();
-                        Log.d(TAG, "Reach to max size, disconnect one of them first");
-                        /* TODO: Disconnect based on CoD */
-                        DisconnectConnectedDevice = mConnectedDevicesList.get(0);
-
+                        BluetoothDevice disconnectDevice = mConnectedDevicesList.get(0);
+                        Log.d(TAG, "Connected: Reach to max size, disconnect " + disconnectDevice);
                         broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
                                 BluetoothProfile.STATE_DISCONNECTED);
-
-                        if (!disconnectHfpNative(getByteAddress(DisconnectConnectedDevice))) {
+                        if (disconnectHfpNative(getByteAddress(disconnectDevice))) {
+                            broadcastConnectionState(disconnectDevice,
+                                    BluetoothProfile.STATE_DISCONNECTING,
+                                    BluetoothProfile.STATE_CONNECTED);
+                        } else {
+                            Log.w(TAG, "Connected: failed to disconnect " + disconnectDevice);
                             broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                                     BluetoothProfile.STATE_CONNECTING);
                             break;
-                        } else {
-                            broadcastConnectionState(DisconnectConnectedDevice,
-                                    BluetoothProfile.STATE_DISCONNECTING,
-                                    BluetoothProfile.STATE_CONNECTED);
                         }
-
                         synchronized (HeadsetStateMachine.this) {
                             mTargetDevice = device;
                             if (max_hf_connections == 1) {
                                 transitionTo(mPending);
                             } else {
-                                mMultiDisconnectDevice = DisconnectConnectedDevice;
+                                mMultiDisconnectDevice = disconnectDevice;
                                 transitionTo(mMultiHFPending);
                             }
                         }
@@ -1123,9 +1118,9 @@
                     mAudioState = BluetoothHeadset.STATE_AUDIO_CONNECTED;
                     setAudioParameters(device); /*Set proper Audio Paramters.*/
                     mAudioManager.setBluetoothScoOn(true);
+                    mActiveScoDevice = device;
                     broadcastAudioState(device, BluetoothHeadset.STATE_AUDIO_CONNECTED,
                             BluetoothHeadset.STATE_AUDIO_CONNECTING);
-                    mActiveScoDevice = device;
                     transitionTo(mAudioOn);
                     break;
                 case HeadsetHalConstants.AUDIO_STATE_CONNECTING:
@@ -1188,42 +1183,39 @@
                         deferMessage(obtainMessage(DISCONNECT, mCurrentDevice));
                         deferMessage(obtainMessage(CONNECT, device));
                         if (disconnectAudioNative(getByteAddress(mCurrentDevice))) {
-                            Log.d(TAG, "Disconnecting SCO audio for device=" + mCurrentDevice);
+                            Log.d(TAG, "AudioOn: disconnecting SCO, device=" + mCurrentDevice);
                         } else {
-                            Log.e(TAG, "disconnectAudioNative failed");
+                            Log.e(TAG, "AudioOn: disconnect SCO failed, device=" + mCurrentDevice);
                         }
                         break;
                     }
 
                     if (mConnectedDevicesList.size() >= max_hf_connections) {
-                        BluetoothDevice DisconnectConnectedDevice = null;
-                        IState CurrentAudioState = getCurrentState();
-                        Log.d(TAG, "Reach to max size, disconnect "
-                                        + "one of them first");
-                        DisconnectConnectedDevice = mConnectedDevicesList.get(0);
+                        BluetoothDevice disconnectDevice = mConnectedDevicesList.get(0);
+                        Log.d(TAG, "AudioOn: Reach to max size, disconnect " + disconnectDevice);
 
-                        if (mActiveScoDevice.equals(DisconnectConnectedDevice)) {
-                            DisconnectConnectedDevice = mConnectedDevicesList.get(1);
+                        if (mActiveScoDevice.equals(disconnectDevice)) {
+                            disconnectDevice = mConnectedDevicesList.get(1);
                         }
 
                         broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
                                 BluetoothProfile.STATE_DISCONNECTED);
 
-                        if (!disconnectHfpNative(getByteAddress(DisconnectConnectedDevice))) {
+                        if (disconnectHfpNative(getByteAddress(disconnectDevice))) {
+                            broadcastConnectionState(disconnectDevice,
+                                    BluetoothProfile.STATE_DISCONNECTING,
+                                    BluetoothProfile.STATE_CONNECTED);
+                        } else {
+                            Log.e(TAG, "AudioOn: Failed to disconnect " + disconnectDevice);
                             broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                                     BluetoothProfile.STATE_CONNECTING);
                             break;
-                        } else {
-                            broadcastConnectionState(DisconnectConnectedDevice,
-                                    BluetoothProfile.STATE_DISCONNECTING,
-                                    BluetoothProfile.STATE_CONNECTED);
                         }
 
                         synchronized (HeadsetStateMachine.this) {
                             mTargetDevice = device;
-                            mMultiDisconnectDevice = DisconnectConnectedDevice;
+                            mMultiDisconnectDevice = disconnectDevice;
                             transitionTo(mMultiHFPending);
-                            DisconnectConnectedDevice = null;
                         }
                     } else if (mConnectedDevicesList.size() < max_hf_connections) {
                         broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
@@ -2100,7 +2092,7 @@
             sco disconnect issued in AudioOn state. This was causing a mismatch in the
             Incall screen UI. */
 
-            if (getCurrentState() == mAudioOn && mCurrentDevice.equals(device)
+            if (mActiveScoDevice != null && mActiveScoDevice.equals(device)
                     && mAudioState != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                 return true;
             }
@@ -2110,6 +2102,7 @@
 
     public void setAudioRouteAllowed(boolean allowed) {
         mAudioRouteAllowed = allowed;
+        setScoAllowedNative(allowed);
     }
 
     public boolean getAudioRouteAllowed() {
@@ -3463,4 +3456,5 @@
     private native boolean phoneStateChangeNative(
             int numActive, int numHeld, int callState, String number, int type);
     private native boolean configureWBSNative(byte[] address, int condec_config);
+    private native boolean setScoAllowedNative(boolean value);
 }
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index ef5a12f..089f4a6 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -162,16 +162,30 @@
             // ({@link HeadsetClientStateMachine#SET_SPEAKER_VOLUME} in
             // {@link HeadsetClientStateMachine} for details.
             if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
-                Log.d(TAG, "Volume changed for stream: " +
-                    intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE));
+                if (DBG) {
+                    Log.d(TAG,
+                            "Volume changed for stream: "
+                                    + intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE));
+                }
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                 if (streamType == AudioManager.STREAM_VOICE_CALL) {
                     int streamValue = intent
                             .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
                     int hfVol = HeadsetClientStateMachine.amToHfVol(streamValue);
-                    Log.d(TAG, "Setting volume to audio manager: " + streamValue + " hands free: "
-                                    + hfVol);
+                    if (DBG) {
+                        Log.d(TAG,
+                                "Setting volume to audio manager: " + streamValue
+                                        + " hands free: " + hfVol);
+                    }
                     mAudioManager.setParameters("hfp_volume=" + hfVol);
+                    synchronized (this) {
+                        for (HeadsetClientStateMachine sm : mStateMachineMap.values()) {
+                            if (sm != null) {
+                                sm.sendMessage(
+                                        HeadsetClientStateMachine.SET_SPEAKER_VOLUME, streamValue);
+                            }
+                        }
+                    }
                 }
             }
         }
@@ -646,6 +660,25 @@
 
     boolean acceptCall(BluetoothDevice device, int flag) {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        /* Phonecalls from a single device are supported, hang up any calls on the other phone */
+        synchronized (this) {
+            for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry :
+                    mStateMachineMap.entrySet()) {
+                if (entry.getValue() == null || entry.getKey().equals(device)) {
+                    continue;
+                }
+                int connectionState = entry.getValue().getConnectionState(entry.getKey());
+                if (DBG) {
+                    Log.d(TAG, "Accepting a call on device " + device
+                                    + ". Possibly disconnecting on " + entry.getValue());
+                }
+                if (connectionState == BluetoothProfile.STATE_CONNECTED) {
+                    entry.getValue()
+                            .obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL)
+                            .sendToTarget();
+                }
+            }
+        }
         HeadsetClientStateMachine sm = getStateMachine(device);
         if (sm == null) {
             Log.e(TAG, "Cannot allocate SM for device " + device);
@@ -653,8 +686,7 @@
         }
 
         int connectionState = sm.getConnectionState(device);
-        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
-                connectionState != BluetoothProfile.STATE_CONNECTING) {
+        if (connectionState != BluetoothProfile.STATE_CONNECTED) {
             return false;
         }
         Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL);
@@ -872,19 +904,22 @@
         return sm;
     }
 
-    // Check if any of the state machines are currently holding the SCO audio stream
-    // This function is *only* called from the SMs which are themselves run the same thread and
-    // hence we do not need synchronization here
-    boolean isScoAvailable() {
-        for (BluetoothDevice bd : mStateMachineMap.keySet()) {
-            HeadsetClientStateMachine sm = mStateMachineMap.get(bd);
-            int audioState = sm.getAudioState(bd);
-            if (audioState != BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED) {
-                Log.w(TAG, "Device " + bd + " audio state " + audioState + " not disconnected");
-                return false;
+    // Check if any of the state machines have routed the SCO audio stream.
+    synchronized boolean isScoRouted() {
+        for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry :
+                mStateMachineMap.entrySet()) {
+            if (entry.getValue() != null) {
+                int audioState = entry.getValue().getAudioState(entry.getKey());
+                if (audioState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTED) {
+                    if (DBG) {
+                        Log.d(TAG, "Device " + entry.getKey() + " audio state " + audioState
+                                        + " Connected");
+                    }
+                    return true;
+                }
             }
         }
-        return true;
+        return false;
     }
 
     @Override
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 632789a..9ff30f7 100755
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -104,6 +104,8 @@
 
     // Timeouts.
     static final int CONNECTING_TIMEOUT_MS = 10000;  // 10s
+    static final int ROUTING_DELAY_MS = 250;
+    static final int SCO_DISCONNECT_TIMEOUT_MS = 750;
 
     static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec.
     static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec.
@@ -112,6 +114,9 @@
     private long OUTGOING_TIMEOUT_MILLI = 10 * 1000; // 10 seconds
     private long QUERY_CURRENT_CALLS_WAIT_MILLIS = 2 * 1000; // 2 seconds
 
+    // Keep track of audio routing across all devices.
+    private static boolean sAudioIsRouted = true;
+
     private final Disconnected mDisconnected;
     private final Connecting mConnecting;
     private final Connected mConnected;
@@ -145,7 +150,7 @@
     // indicator
     private Pair<Integer, Object> mPendingAction;
 
-    private final AudioManager mAudioManager;
+    private static AudioManager sAudioManager;
     private int mAudioState;
     private boolean mAudioWbs;
     private final BluetoothAdapter mAdapter;
@@ -460,6 +465,8 @@
                     action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1;
                 } else if (getCall(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) != null) {
                     action = HeadsetClientHalConstants.CALL_ACTION_CHLD_3;
+                } else if (flag == BluetoothHeadsetClient.CALL_ACCEPT_NONE) {
+                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
                 } else {
                     action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
                 }
@@ -475,11 +482,8 @@
         }
 
         if (flag == BluetoothHeadsetClient.CALL_ACCEPT_HOLD) {
-            // HFP is disabled when a call is put on hold to ensure correct audio routing for
-            // cellular calls accepted while an HFP call is in progress. Reenable HFP when the HFP
-            // call is put off hold.
-            Log.d(TAG,"hfp_enable=true");
-            mAudioManager.setParameters("hfp_enable=true");
+            // When unholding a call over Bluetooth make sure to route audio.
+            routeHfpAudio(true);
         }
 
         if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) {
@@ -555,11 +559,6 @@
             action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
         }
 
-        // Set HFP enable to false in case the call is being held to accept a cellular call. This
-        // allows the cellular call's audio to be correctly routed.
-        Log.d(TAG,"hfp_enable=false");
-        mAudioManager.setParameters("hfp_enable=false");
-
         if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) {
             addQueuedAction(HOLD_CALL, action);
         } else {
@@ -669,7 +668,11 @@
         mService = context;
 
         mAdapter = BluetoothAdapter.getDefaultAdapter();
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        if (sAudioManager == null) {
+            sAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+            // Initialize hfp_enable into a known state.
+            routeHfpAudio(false);
+        }
         mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
         mAudioWbs = false;
 
@@ -680,8 +683,8 @@
         mIndicatorNetworkSignal = 0;
         mIndicatorBatteryLevel = 0;
 
-        mMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
-        mMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
+        mMaxAmVcVol = sAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
+        mMinAmVcVol = sAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
 
         mOperatorName = null;
         mSubscriberInfo = null;
@@ -714,10 +717,22 @@
         return hfcsm;
     }
 
+    static synchronized void routeHfpAudio(boolean enable) {
+        if (DBG) {
+            Log.d(TAG, "hfp_enable=" + enable);
+        }
+        if (enable && !sAudioIsRouted) {
+            sAudioManager.setParameters("hfp_enable=true");
+        } else if (!enable) {
+            sAudioManager.setParameters("hfp_enable=false");
+        }
+        sAudioIsRouted = enable;
+    }
+
     public void doQuit() {
         Log.d(TAG, "doQuit");
-        if (mAudioManager != null) {
-            mAudioManager.setParameters("hfp_enable=false");
+        if (sAudioManager != null) {
+            routeHfpAudio(false);
         }
         quitNow();
     }
@@ -988,13 +1003,13 @@
                     }
                     transitionTo(mConnected);
 
-                    int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+                    int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                     sendMessage(
                             obtainMessage(HeadsetClientStateMachine.SET_SPEAKER_VOLUME, amVol, 0));
                     // Mic is either in ON state (full volume) or OFF state. There is no way in
                     // Android to change the MIC volume.
                     sendMessage(obtainMessage(HeadsetClientStateMachine.SET_MIC_VOLUME,
-                            mAudioManager.isMicrophoneMute() ? 0 : 15, 0));
+                            sAudioManager.isMicrophoneMute() ? 0 : 15, 0));
 
                     // query subscriber info
                     sendMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO);
@@ -1036,12 +1051,15 @@
     }
 
     class Connected extends State {
+        int mCommandedSpeakerVolume = -1;
+
         @Override
         public void enter() {
             if (DBG) {
                 Log.d(TAG, "Enter Connected: " + getCurrentMessage().what);
             }
             mAudioWbs = false;
+            mCommandedSpeakerVolume = -1;
         }
 
         @Override
@@ -1065,7 +1083,6 @@
                     }
 
                     NativeInterface.connectNative(getByteAddress(device));
-                    // deferMessage(message);
                     break;
                 case DISCONNECT:
                     BluetoothDevice dev = (BluetoothDevice) message.obj;
@@ -1083,11 +1100,8 @@
                     break;
 
                 case CONNECT_AUDIO:
-                    if (!mService.isScoAvailable()
-                            || !NativeInterface.connectAudioNative(
-                                       getByteAddress(mCurrentDevice))) {
-                        Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice
-                                        + " isScoAvailable " + mService.isScoAvailable());
+                    if (!NativeInterface.connectAudioNative(getByteAddress(mCurrentDevice))) {
+                        Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice);
                         broadcastAudioState(mCurrentDevice,
                                 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED,
                                 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
@@ -1109,11 +1123,15 @@
                     // This message should always contain the volume in AudioManager max normalized.
                     int amVol = message.arg1;
                     int hfVol = amToHfVol(amVol);
-                    Log.d(TAG,"HF volume is set to " + hfVol);
-                    mAudioManager.setParameters("hfp_volume=" + hfVol);
-                    // We do not set the volume in native because multiple devices might be
-                    // connected and it does not make sense to synchronize them. Car becomes the
-                    // master in such case.
+                    if (amVol != mCommandedSpeakerVolume) {
+                        Log.d(TAG, "Volume" + amVol + ":" + mCommandedSpeakerVolume);
+                        // Volume was changed by a 3rd party
+                        mCommandedSpeakerVolume = -1;
+                        if (NativeInterface.setVolumeNative(getByteAddress(mCurrentDevice),
+                                    HeadsetClientHalConstants.VOLUME_TYPE_SPK, hfVol)) {
+                            addQueuedAction(SET_SPEAKER_VOLUME);
+                        }
+                    }
                     break;
                 case DIAL_NUMBER:
                     // Add the call as an outgoing call.
@@ -1294,15 +1312,13 @@
                             break;
                         case StackEvent.EVENT_TYPE_VOLUME_CHANGED:
                             if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) {
-                                Log.d(TAG, "AM volume set to " +
-                                      hfToAmVol(event.valueInt2));
-                                mAudioManager.setStreamVolume(
-                                    AudioManager.STREAM_VOICE_CALL,
-                                    hfToAmVol(event.valueInt2),
-                                    AudioManager.FLAG_SHOW_UI);
-                            } else if (event.valueInt ==
-                                    HeadsetClientHalConstants.VOLUME_TYPE_MIC) {
-                                mAudioManager.setMicrophoneMute(event.valueInt2 == 0);
+                                mCommandedSpeakerVolume = hfToAmVol(event.valueInt2);
+                                Log.d(TAG, "AM volume set to " + mCommandedSpeakerVolume);
+                                sAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
+                                        +mCommandedSpeakerVolume, AudioManager.FLAG_SHOW_UI);
+                            } else if (event.valueInt
+                                    == HeadsetClientHalConstants.VOLUME_TYPE_MIC) {
+                                sAudioManager.setMicrophoneMute(event.valueInt2 == 0);
                             }
                             break;
                         case StackEvent.EVENT_TYPE_CMD_RESULT:
@@ -1398,12 +1414,21 @@
                     // for routing and volume purposes.
                     // NOTE: All calls here are routed via the setParameters which changes the
                     // routing at the Audio HAL level.
+
+                    if (mService.isScoRouted()) {
+                        StackEvent event =
+                                new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+                        event.valueInt = state;
+                        event.device = device;
+                        sendMessageDelayed(StackEvent.STACK_EVENT, event, ROUTING_DELAY_MS);
+                        break;
+                    }
+
                     mAudioState = BluetoothHeadsetClient.STATE_AUDIO_CONNECTED;
 
                     // We need to set the volume after switching into HFP mode as some Audio HALs
                     // reset the volume to a known-default on mode switch.
-                    final int amVol =
-                            mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+                    final int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                     final int hfVol = amToHfVol(amVol);
 
                     if (DBG) {
@@ -1413,19 +1438,19 @@
                         if (DBG) {
                             Log.d(TAG,"Setting sampling rate as 16000");
                         }
-                        mAudioManager.setParameters("hfp_set_sampling_rate=16000");
+                        sAudioManager.setParameters("hfp_set_sampling_rate=16000");
                     }
                     else {
                         if (DBG) {
                             Log.d(TAG,"Setting sampling rate as 8000");
                         }
-                        mAudioManager.setParameters("hfp_set_sampling_rate=8000");
+                        sAudioManager.setParameters("hfp_set_sampling_rate=8000");
                     }
                     if (DBG) {
                         Log.d(TAG, "hf_volume " + hfVol);
                     }
-                    mAudioManager.setParameters("hfp_enable=true");
-                    mAudioManager.setParameters("hfp_volume=" + hfVol);
+                    routeHfpAudio(true);
+                    sAudioManager.setParameters("hfp_volume=" + hfVol);
                     transitionTo(mAudioOn);
                     break;
 
@@ -1495,12 +1520,14 @@
                      * Machines state changing
                      */
                     if (NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) {
-                        if (DBG) {
-                            Log.d(TAG,"hfp_enable=false");
-                        }
-                        mAudioManager.setParameters("hfp_enable=false");
+                        routeHfpAudio(false);
                     }
                     break;
+
+                case HOLD_CALL:
+                    holdCall();
+                    break;
+
                 case StackEvent.STACK_EVENT:
                     StackEvent event = (StackEvent) message.obj;
                     if (DBG) {
@@ -1561,15 +1588,13 @@
 
             switch (state) {
                 case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED:
+                    removeMessages(DISCONNECT_AUDIO);
                     mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
                     // Audio focus may still be held by the entity controlling the actual call
                     // (such as Telecom) and hence this will still keep the call around, there
                     // is not much we can do here since dropping the call without user consent
                     // even if the audio connection snapped may not be a good idea.
-                    if (DBG) {
-                        Log.d(TAG, "hfp_enable=false");
-                    }
-                    mAudioManager.setParameters("hfp_enable=false");
+                    routeHfpAudio(false);
                     broadcastAudioState(device, BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED,
                             BluetoothHeadsetClient.STATE_AUDIO_CONNECTED);
                     transitionTo(mConnected);
diff --git a/src/com/android/bluetooth/hfpclient/NativeInterface.java b/src/com/android/bluetooth/hfpclient/NativeInterface.java
index d22bd64..a9b3115 100644
--- a/src/com/android/bluetooth/hfpclient/NativeInterface.java
+++ b/src/com/android/bluetooth/hfpclient/NativeInterface.java
@@ -311,9 +311,11 @@
             Log.d(TAG, "onVolumeChange: address " + address + " event "  + event);
         }
         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
-        // Ignore volume changes from the Phone. This is to avoid the scenario where we may have two
-        // phones connected each tries to set different volumes.
-        Log.w(TAG, "onVolumeChange: Ignoring message: " + event);
+        if (service != null) {
+            service.messageFromNative(event);
+        } else {
+            Log.w(TAG, "onVolumeChange: Ignoring message because service not available: " + event);
+        }
     }
 
     private void onCmdResult(int type, int cme, byte[] address) {
diff --git a/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java b/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java
index bd143b1..954b8b8 100644
--- a/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java
+++ b/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java
@@ -73,11 +73,6 @@
 
     @Override
     public void onUnhold() {
-        if (getPrimaryConnection().getConnectionService()
-                .getAllConnections().size() > 1) {
-            Log.w(TAG, "Ignoring unhold; call hold on the foreground call");
-            return;
-        }
         Log.d(TAG, "onUnhold");
         mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD);
     }
diff --git a/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java b/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java
index 749bb75..0aca701 100644
--- a/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java
+++ b/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java
@@ -38,6 +38,7 @@
     private BluetoothHeadsetClient mHeadsetProfile;
 
     private BluetoothHeadsetClientCall mCurrentCall;
+    private int mPreviousCallState = -1;
     private boolean mClosed;
     private boolean mClosing = false;
     private boolean mLocalDisconnect;
@@ -81,6 +82,7 @@
             return;
         }
 
+        mHeadsetProfile.connectAudio(device);
         setInitializing();
         setDialing();
         finishInitializing();
@@ -161,12 +163,19 @@
                 setRinging();
                 break;
             case BluetoothHeadsetClientCall.CALL_STATE_TERMINATED:
-                // TODO Use more specific causes
-                close(mLocalDisconnect ? DisconnectCause.LOCAL : DisconnectCause.REMOTE);
+                if (mPreviousCallState == BluetoothHeadsetClientCall.CALL_STATE_INCOMING
+                        || mPreviousCallState == BluetoothHeadsetClientCall.CALL_STATE_WAITING) {
+                    close(DisconnectCause.MISSED);
+                } else if (mLocalDisconnect) {
+                    close(DisconnectCause.LOCAL);
+                } else {
+                    close(DisconnectCause.REMOTE);
+                }
                 break;
             default:
                 Log.wtf(TAG, "Unexpected phone state " + state);
         }
+        mPreviousCallState = state;
     }
 
     public synchronized void close(int cause) {
@@ -256,6 +265,7 @@
         if (!mClosed) {
             mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE);
         }
+        mHeadsetProfile.connectAudio(mDevice);
     }
 
     @Override
diff --git a/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java b/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
index ee7f16a..f891b90 100644
--- a/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
+++ b/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
@@ -192,15 +192,15 @@
             // (represented as unknown call in telecom since). Since BluetoothHeadsetClientCall is a
             // parcelable we simply pack the entire object in there.
             Bundle b = new Bundle();
-            if (call.getState() == BluetoothHeadsetClientCall.CALL_STATE_DIALING ||
-                call.getState() == BluetoothHeadsetClientCall.CALL_STATE_ALERTING ||
-                call.getState() == BluetoothHeadsetClientCall.CALL_STATE_ACTIVE ||
-                call.getState() == BluetoothHeadsetClientCall.CALL_STATE_WAITING) {
+            if (call.getState() == BluetoothHeadsetClientCall.CALL_STATE_DIALING
+                    || call.getState() == BluetoothHeadsetClientCall.CALL_STATE_ALERTING
+                    || call.getState() == BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) {
                 // This is an outgoing call. Even if it is an active call we do not have a way of
                 // putting that parcelable in a seaprate field.
                 b.putParcelable(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, call);
                 mTelecomManager.addNewUnknownCall(mPhoneAccount.getAccountHandle(), b);
-            } else if (call.getState() == BluetoothHeadsetClientCall.CALL_STATE_INCOMING) {
+            } else if (call.getState() == BluetoothHeadsetClientCall.CALL_STATE_INCOMING
+                    || call.getState() == BluetoothHeadsetClientCall.CALL_STATE_WAITING) {
                 // This is an incoming call.
                 b.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, call);
                 mTelecomManager.addNewIncomingCall(mPhoneAccount.getAccountHandle(), b);
diff --git a/src/com/android/bluetooth/mapclient/MnsService.java b/src/com/android/bluetooth/mapclient/MnsService.java
index 7b3419e..1078cf1 100644
--- a/src/com/android/bluetooth/mapclient/MnsService.java
+++ b/src/com/android/bluetooth/mapclient/MnsService.java
@@ -50,26 +50,49 @@
 
     static private MapClientService mContext;
     private volatile boolean mShutdown = false;         // Used to interrupt socket accept thread
+    private int mSdpHandle = -1;
 
     MnsService(MapClientService context) {
         if (VDBG) Log.v(TAG, "MnsService()");
         mContext = context;
         mAcceptThread = new SocketAcceptor();
         mServerSockets = ObexServerSockets.create(mAcceptThread);
-        SdpManager.getDefaultManager().createMapMnsRecord(
-                "MAP Message Notification Service", mServerSockets.getRfcommChannel(), -1,
-                MNS_VERSION, MNS_FEATURE_BITS);
+        SdpManager sdpManager = SdpManager.getDefaultManager();
+        if (sdpManager == null) {
+            Log.e(TAG, "SdpManager is null");
+            return;
+        }
+        mSdpHandle = sdpManager.createMapMnsRecord("MAP Message Notification Service",
+                mServerSockets.getRfcommChannel(), -1, MNS_VERSION, MNS_FEATURE_BITS);
     }
 
     void stop() {
         if (VDBG) Log.v(TAG, "stop()");
         mShutdown = true;
+        cleanUpSdpRecord();
         if (mServerSockets != null) {
             mServerSockets.shutdown(false);
             mServerSockets = null;
         }
     }
 
+    private void cleanUpSdpRecord() {
+        if (mSdpHandle < 0) {
+            Log.e(TAG, "cleanUpSdpRecord, SDP record never created");
+            return;
+        }
+        int sdpHandle = mSdpHandle;
+        mSdpHandle = -1;
+        SdpManager sdpManager = SdpManager.getDefaultManager();
+        if (sdpManager == null) {
+            Log.e(TAG, "cleanUpSdpRecord failed, sdpManager is null, sdpHandle=" + sdpHandle);
+            return;
+        }
+        Log.i(TAG, "cleanUpSdpRecord, mSdpHandle=" + sdpHandle);
+        if (!sdpManager.removeSdpRecord(sdpHandle)) {
+            Log.e(TAG, "cleanUpSdpRecord, removeSdpRecord failed, sdpHandle=" + sdpHandle);
+        }
+    }
 
     private class SocketAcceptor implements IObexConnectionHandler {
 
diff --git a/src/com/android/bluetooth/opp/BluetoothOppService.java b/src/com/android/bluetooth/opp/BluetoothOppService.java
index b68936a..7f94820 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppService.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppService.java
@@ -226,14 +226,6 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case STOP_LISTENER:
-                    if (mAdapter != null && mOppSdpHandle >= 0
-                            && SdpManager.getDefaultManager() != null) {
-                        if (D) Log.d(TAG, "Removing SDP record mOppSdpHandle :" + mOppSdpHandle);
-                        boolean status =
-                                SdpManager.getDefaultManager().removeSdpRecord(mOppSdpHandle);
-                        Log.d(TAG, "RemoveSDPrecord returns " + status);
-                        mOppSdpHandle = -1;
-                    }
                     stopListeners();
                     mListenStarted = false;
                     //Stop Active INBOUND Transfer
@@ -365,8 +357,10 @@
                             + " mServerSocket:" + mServerSocket);
             return;
         }
-        sdpManager.createOppOpsRecord("OBEX Object Push", mServerSocket.getRfcommChannel(),
-                mServerSocket.getL2capPsm(), 0x0102, SUPPORTED_OPP_FORMAT);
+        mOppSdpHandle =
+                sdpManager.createOppOpsRecord("OBEX Object Push", mServerSocket.getRfcommChannel(),
+                        mServerSocket.getL2capPsm(), 0x0102, SUPPORTED_OPP_FORMAT);
+        if (D) Log.d(TAG, "mOppSdpHandle :" + mOppSdpHandle);
     }
 
     @Override
@@ -1063,6 +1057,12 @@
     }
 
     private void stopListeners() {
+        if (mAdapter != null && mOppSdpHandle >= 0 && SdpManager.getDefaultManager() != null) {
+            if (D) Log.d(TAG, "Removing SDP record mOppSdpHandle :" + mOppSdpHandle);
+            boolean status = SdpManager.getDefaultManager().removeSdpRecord(mOppSdpHandle);
+            Log.d(TAG, "RemoveSDPrecord returns " + status);
+            mOppSdpHandle = -1;
+        }
         if (mServerSocket != null) {
             mServerSocket.shutdown(false);
             mServerSocket = null;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java b/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
index 21fad6b..fd47318 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
@@ -39,6 +39,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.ContentResolver;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -118,11 +119,12 @@
 
         final String sortOrder = BluetoothShare.TIMESTAMP + " DESC";
 
-        mTransferCursor = managedQuery(BluetoothShare.CONTENT_URI, new String[] {
-                "_id", BluetoothShare.FILENAME_HINT, BluetoothShare.STATUS,
-                BluetoothShare.TOTAL_BYTES, BluetoothShare._DATA, BluetoothShare.TIMESTAMP,
-                BluetoothShare.VISIBILITY, BluetoothShare.DESTINATION, BluetoothShare.DIRECTION
-        }, selection, sortOrder);
+        mTransferCursor = getContentResolver().query(BluetoothShare.CONTENT_URI,
+                new String[] {"_id", BluetoothShare.FILENAME_HINT, BluetoothShare.STATUS,
+                        BluetoothShare.TOTAL_BYTES, BluetoothShare._DATA, BluetoothShare.TIMESTAMP,
+                        BluetoothShare.VISIBILITY, BluetoothShare.DESTINATION,
+                        BluetoothShare.DIRECTION},
+                selection, null, sortOrder);
 
         // only attach everything to the listbox if we can access
         // the transfer database. Otherwise, just show it empty
@@ -193,6 +195,14 @@
     }
 
     @Override
+    protected void onDestroy() {
+        if (mTransferCursor != null) {
+            mTransferCursor.close();
+        }
+        super.onDestroy();
+    }
+
+    @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
         if (mTransferCursor != null) {
             mContextMenu = true;
diff --git a/src/com/android/bluetooth/pan/PanService.java b/src/com/android/bluetooth/pan/PanService.java
index 391ea3a..a978693 100755
--- a/src/com/android/bluetooth/pan/PanService.java
+++ b/src/com/android/bluetooth/pan/PanService.java
@@ -472,6 +472,7 @@
         // will fail until the caller explicitly calls BluetoothPan#disconnect.
         if (prevState == BluetoothProfile.STATE_DISCONNECTED && state == BluetoothProfile.STATE_DISCONNECTING) {
             Log.d(TAG, "Ignoring state change from " + prevState + " to " + state);
+            mPanDevices.remove(device);
             return;
         }
 
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java b/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
index d91d9a2..325a386 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
@@ -217,6 +217,7 @@
         final int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX);
         final String callLogTypeStr;
         switch (callLogType) {
+            case Calls.REJECTED_TYPE:
             case Calls.INCOMING_TYPE: {
                 callLogTypeStr = VCARD_PROPERTY_CALLTYPE_INCOMING;
                 break;
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
index d112bfd..01f8be9 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java
@@ -763,7 +763,7 @@
                 for (int pos = appParamValue.listStartOffset;
                         pos < listSize && itemsFound < requestSize; pos++) {
                     currentValue = nameList.get(pos);
-                    if (D) Log.d(TAG, "currentValue=" + currentValue);
+                    if (V) Log.d(TAG, "currentValue=" + currentValue);
                     if (currentValue.equals(compareValue)) {
                         itemsFound++;
                         if (currentValue.contains(","))
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
index 7743d9b..7e1164e 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapService.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
@@ -437,17 +437,43 @@
             mWakeLock = null;
         }
 
+        // Step 1: clean up active server session
         if (mServerSession != null) {
             mServerSession.close();
             mServerSession = null;
         }
-
+        // Step 2: clean up existing connection socket
         closeConnectionSocket();
+        // Step 3: clean up SDP record
+        cleanUpSdpRecord();
+        // Step 4: clean up existing server socket(s)
         closeServerSocket();
+        if (mServerSockets != null) {
+            mServerSockets.shutdown(false);
+            mServerSockets = null;
+        }
         if (mSessionStatusHandler != null) mSessionStatusHandler.removeCallbacksAndMessages(null);
         if (VERBOSE) Log.v(TAG, "Pbap Service closeService out");
     }
 
+    private void cleanUpSdpRecord() {
+        if (mSdpHandle < 0) {
+            if (VERBOSE) Log.v(TAG, "cleanUpSdpRecord, SDP record never created");
+            return;
+        }
+        int sdpHandle = mSdpHandle;
+        mSdpHandle = -1;
+        SdpManager sdpManager = SdpManager.getDefaultManager();
+        if (sdpManager == null) {
+            Log.e(TAG, "cleanUpSdpRecord failed, sdpManager is null, sdpHandle=" + sdpHandle);
+            return;
+        }
+        Log.i(TAG, "cleanUpSdpRecord, mSdpHandle=" + sdpHandle);
+        if (!sdpManager.removeSdpRecord(sdpHandle)) {
+            Log.e(TAG, "cleanUpSdpRecord, removeSdpRecord failed, sdpHandle=" + sdpHandle);
+        }
+    }
+
     private final void startObexServerSession() throws IOException {
         if (VERBOSE) Log.v(TAG, "Pbap Service startObexServerSession");
 
@@ -935,6 +961,10 @@
         }
     }
 
+    /**
+     * Start server side socket listeners. Caller should make sure that adapter is in a ready state
+     * and SDP record is cleaned up. Otherwise, this method will fail.
+     */
     synchronized private void startSocketListeners() {
         if (DEBUG) Log.d(TAG, "startsocketListener");
         if (mServerSession != null) {
@@ -952,17 +982,10 @@
                 Log.e(TAG, "Failed to start the listeners");
                 return;
             }
-            SdpManager sdpManager = SdpManager.getDefaultManager();
-            if (sdpManager == null) {
-                Log.e(TAG, "Failed to start the listeners sdp null ");
+            if (mSdpHandle >= 0) {
+                Log.e(TAG, "SDP handle was not cleaned up, mSdpHandle=" + mSdpHandle);
                 return;
             }
-            if (mAdapter != null && mSdpHandle >= 0) {
-                Log.d(TAG, "Removing SDP record for PBAP with SDP handle:" + mSdpHandle);
-                boolean status = sdpManager.removeSdpRecord(mSdpHandle);
-                Log.d(TAG, "RemoveSDPrecord returns " + status);
-                mSdpHandle = -1;
-            }
             mSdpHandle = SdpManager.getDefaultManager().createPbapPseRecord(
                     "OBEX Phonebook Access Server", mServerSockets.getRfcommChannel(),
                     mServerSockets.getL2capPsm(), SDP_PBAP_SERVER_VERSION,
@@ -1053,8 +1076,13 @@
      */
     @Override
     public synchronized void onAcceptFailed() {
+        // Clean up SDP record first
+        cleanUpSdpRecord();
         // Force socket listener to restart
-        mServerSockets = null;
+        if (mServerSockets != null) {
+            mServerSockets.shutdown(false);
+            mServerSockets = null;
+        }
         if (!mInterrupted && mAdapter != null && mAdapter.isEnabled()) {
             startSocketListeners();
         }
diff --git a/src/com/android/bluetooth/sap/SapServer.java b/src/com/android/bluetooth/sap/SapServer.java
index a66fc46..8f8da2d 100644
--- a/src/com/android/bluetooth/sap/SapServer.java
+++ b/src/com/android/bluetooth/sap/SapServer.java
@@ -115,13 +115,15 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(SAP_DISCONNECT_ACTION);
+        mIntentReceiver = new SapServerBroadcastReceiver();
         mContext.registerReceiver(mIntentReceiver, filter);
     }
 
     /**
      * This handles the response from RIL.
      */
-    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mIntentReceiver;
+    private class SapServerBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             if(intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
@@ -148,8 +150,7 @@
                 if(disconnectType == SapMessage.DISC_RFCOMM) {
                     // At timeout we need to close the RFCOMM socket to complete shutdown
                     shutdown();
-                } else if( mState != SAP_STATE.DISCONNECTED
-                    && mState != SAP_STATE.DISCONNECTING ) {
+                } else if (mState != SAP_STATE.DISCONNECTED && mState != SAP_STATE.DISCONNECTING) {
                     // The user pressed disconnect - initiate disconnect sequence.
                     sendDisconnectInd(disconnectType);
                 }
@@ -157,7 +158,7 @@
                 Log.w(TAG, "RIL-BT received unexpected Intent: " + intent.getAction());
             }
         }
-    };
+    }
 
     /**
      * Set RIL driver in test mode - only possible if SapMessage is build with TEST == true
diff --git a/tests/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java b/tests/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
index 3a3edf9..70825ff 100644
--- a/tests/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
+++ b/tests/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
@@ -42,7 +42,7 @@
         assertTrue(mService != null);
 
         // At this point Adapter Service should have started
-        AdapterService inst = AdapterService.getAdapterService();
+        AdapterService inst = mock(AdapterService.class);
         assertTrue(inst != null);
 
         // Try getting the Bluetooth adapter
diff --git a/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java b/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
index a8b2c59..68adb29 100644
--- a/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
+++ b/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
@@ -18,6 +18,7 @@
 import com.android.bluetooth.btservice.AdapterService;
 
 import static org.mockito.Mockito.*;
+
 import org.mockito.ArgumentCaptor;
 
 public class HeadsetClientStateMachineTest extends AndroidTestCase {
@@ -25,7 +26,7 @@
 
     @Override
     protected void setUp() throws Exception {
-        AdapterService inst = AdapterService.getAdapterService();
+        AdapterService inst = mock(AdapterService.class);
         assertTrue(inst != null);
         mAdapter = BluetoothAdapter.getDefaultAdapter();
     }
diff --git a/tests/src/com/android/bluetooth/pbapclient/PbapParserTest.java b/tests/src/com/android/bluetooth/pbapclient/PbapParserTest.java
index 5007238..93b02b3 100644
--- a/tests/src/com/android/bluetooth/pbapclient/PbapParserTest.java
+++ b/tests/src/com/android/bluetooth/pbapclient/PbapParserTest.java
@@ -81,11 +81,11 @@
         processor.setResults(pbapVCardList.getList());
 
         // Verify that these entries aren't in the call log to start.
-        assertFalse(verifyCallLog("555-0002", "1483232460000", "3"));
-
+        // EST is default Time Zone
+        assertFalse(verifyCallLog("555-0002", "1483250460000", "3"));
         // Finish processing the data and verify entries were added to the call log.
         processor.onPullComplete();
-        assertTrue(verifyCallLog("555-0002", "1483232460000", "3"));
+        assertTrue(verifyCallLog("555-0002", "1483250460000", "3"));
     }
 
     // testUnknownCall should parse two calls with no phone number.
@@ -102,13 +102,14 @@
         processor.setResults(pbapVCardList.getList());
 
         // Verify that these entries aren't in the call log to start.
-        assertFalse(verifyCallLog("", "1483232520000", "3"));
-        assertFalse(verifyCallLog("", "1483232580000", "3"));
+        // EST is default Time Zone
+        assertFalse(verifyCallLog("", "1483250520000", "3"));
+        assertFalse(verifyCallLog("", "1483250580000", "3"));
 
         // Finish processing the data and verify entries were added to the call log.
         processor.onPullComplete();
-        assertTrue(verifyCallLog("", "1483232520000", "3"));
-        assertTrue(verifyCallLog("", "1483232580000", "3"));
+        assertTrue(verifyCallLog("", "1483250520000", "3"));
+        assertTrue(verifyCallLog("", "1483250580000", "3"));
     }
 
     // Find Entries in call log with type matching number and date.