summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin F. Haggerty <haggertk@lineageos.org>2020-06-01 20:43:45 -0600
committerKevin F. Haggerty <haggertk@lineageos.org>2020-06-01 20:43:45 -0600
commitcf38327eba534b6354b44e4d29a3fef8190b481e (patch)
tree84195c87dacf64c2d7df6be202f9f62a62258aba
parent837b47f2b5613cb2e6235229831f9c80ec28c741 (diff)
parent906df07061fcf46aac856894fb6d68b2ccccfa2c (diff)
downloadandroid_packages_apps_Bluetooth-lineage-17.1.tar.gz
android_packages_apps_Bluetooth-lineage-17.1.tar.bz2
android_packages_apps_Bluetooth-lineage-17.1.zip
Merge tag 'android-10.0.0_r37' into staging/lineage-17.1_merge-android-10.0.0_r37lineage-17.1
Android 10.0.0 Release 37 (QQ3A.200605.001) * tag 'android-10.0.0_r37': (37 commits) Import translations. DO NOT MERGE Revert "PBAP server, send favorite contacts" Import translations. DO NOT MERGE Delete call logs when calls are made without PBAP Set Browsing bit to 0 in PbapSupportedFeatures Prevent phone's bd_addr from appearing in Accounts Return an empty list when the requested node is not in the tree AvrcpController Test update AVRCP Controller Media Controller not ready Allow subsequent requests for media keys to replay the silent audio sample HFP Client call status update PBAP server, send favorite contacts AVRCP Controller Disable Automatic Focus Request A2DP Sink: Focus gain while transient loss AVRCP Controller State without Browsing Add bluetooth prefs for Android Automotive MAP Client disconnect state machine if MAS client disconnected MAP Client close connection on MNS disconnect MAP Client Only connect MNS in connected state MAP Client BMessage parser length ... Change-Id: I1398f4ffe79e4ac0a37765927e4afd2e05ee0908
-rw-r--r--Android.mk1
-rw-r--r--AndroidManifest.xml10
-rw-r--r--res/values-af/strings.xml1
-rw-r--r--res/values-am/strings.xml1
-rw-r--r--res/values-ar/strings.xml9
-rw-r--r--res/values-as/strings.xml1
-rw-r--r--res/values-az/strings.xml1
-rw-r--r--res/values-b+sr+Latn/strings.xml1
-rw-r--r--res/values-be/strings.xml1
-rw-r--r--res/values-bg/strings.xml1
-rw-r--r--res/values-bn/strings.xml1
-rw-r--r--res/values-bs/strings.xml1
-rw-r--r--res/values-ca/strings.xml1
-rw-r--r--res/values-cs/strings.xml1
-rw-r--r--res/values-da/strings.xml1
-rw-r--r--res/values-de/strings.xml1
-rw-r--r--res/values-el/strings.xml1
-rw-r--r--res/values-en-rAU/strings.xml1
-rw-r--r--res/values-en-rCA/strings.xml1
-rw-r--r--res/values-en-rGB/strings.xml1
-rw-r--r--res/values-en-rIN/strings.xml1
-rw-r--r--res/values-en-rXC/strings.xml1
-rw-r--r--res/values-es-rUS/strings.xml1
-rw-r--r--res/values-es/strings.xml3
-rw-r--r--res/values-et/strings.xml1
-rw-r--r--res/values-eu/strings.xml1
-rw-r--r--res/values-fa/strings.xml1
-rw-r--r--res/values-fi/strings.xml1
-rw-r--r--res/values-fr-rCA/strings.xml1
-rw-r--r--res/values-fr/strings.xml1
-rw-r--r--res/values-gl/strings.xml1
-rw-r--r--res/values-gu/strings.xml1
-rw-r--r--res/values-hi/strings.xml1
-rw-r--r--res/values-hr/strings.xml1
-rw-r--r--res/values-hu/strings.xml1
-rw-r--r--res/values-hy/strings.xml1
-rw-r--r--res/values-in/strings.xml1
-rw-r--r--res/values-is/strings.xml1
-rw-r--r--res/values-it/strings.xml1
-rw-r--r--res/values-iw/strings.xml1
-rw-r--r--res/values-ja/strings.xml1
-rw-r--r--res/values-ka/strings.xml1
-rw-r--r--res/values-kk/strings.xml1
-rw-r--r--res/values-kk/strings_pbap.xml4
-rw-r--r--res/values-km/strings.xml3
-rw-r--r--res/values-kn/strings.xml1
-rw-r--r--res/values-ko/strings.xml1
-rw-r--r--res/values-ky/strings.xml5
-rw-r--r--res/values-lo/strings.xml1
-rw-r--r--res/values-lt/strings.xml1
-rw-r--r--res/values-lv/strings.xml1
-rw-r--r--res/values-mk/strings.xml1
-rw-r--r--res/values-ml/strings.xml3
-rw-r--r--res/values-mn/strings.xml1
-rw-r--r--res/values-mr/strings.xml1
-rw-r--r--res/values-ms/strings.xml1
-rw-r--r--res/values-my/strings.xml1
-rw-r--r--res/values-nb/strings.xml1
-rw-r--r--res/values-ne/strings.xml1
-rw-r--r--res/values-nl/strings.xml1
-rw-r--r--res/values-or/strings.xml1
-rw-r--r--res/values-pa/strings.xml1
-rw-r--r--res/values-pl/strings.xml1
-rw-r--r--res/values-pt-rPT/strings.xml1
-rw-r--r--res/values-pt/strings.xml1
-rw-r--r--res/values-ro/strings.xml1
-rw-r--r--res/values-ru/strings.xml1
-rw-r--r--res/values-si/strings.xml1
-rw-r--r--res/values-sk/strings.xml1
-rw-r--r--res/values-sl/strings.xml1
-rw-r--r--res/values-sq/strings.xml1
-rw-r--r--res/values-sr/strings.xml1
-rw-r--r--res/values-sv/strings.xml1
-rw-r--r--res/values-sw/strings.xml1
-rw-r--r--res/values-ta/strings.xml1
-rw-r--r--res/values-te/strings.xml1
-rw-r--r--res/values-th/strings.xml1
-rw-r--r--res/values-tl/strings.xml1
-rw-r--r--res/values-tr/strings.xml1
-rw-r--r--res/values-uk/strings.xml1
-rw-r--r--res/values-ur/strings.xml1
-rw-r--r--res/values-uz/strings.xml1
-rw-r--r--res/values-vi/strings.xml3
-rw-r--r--res/values-zh-rCN/strings.xml1
-rw-r--r--res/values-zh-rHK/strings.xml1
-rw-r--r--res/values-zh-rTW/strings.xml1
-rw-r--r--res/values-zu/strings.xml1
-rw-r--r--res/values/strings.xml1
-rw-r--r--res/xml/authenticator.xml3
-rw-r--r--src/com/android/bluetooth/BluetoothPrefs.java40
-rw-r--r--src/com/android/bluetooth/a2dpsink/A2dpSinkService.java3
-rw-r--r--src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java63
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java37
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java138
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java104
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java106
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/BrowseTree.java9
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/PlayerApplicationSettings.java201
-rw-r--r--src/com/android/bluetooth/btservice/AdapterService.java1
-rw-r--r--src/com/android/bluetooth/hfp/HeadsetStateMachine.java26
-rw-r--r--src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java2
-rw-r--r--src/com/android/bluetooth/mapclient/MceStateMachine.java28
-rw-r--r--src/com/android/bluetooth/mapclient/MnsObexServer.java4
-rw-r--r--src/com/android/bluetooth/mapclient/MnsService.java6
-rw-r--r--src/com/android/bluetooth/mapclient/obex/BmessageParser.java6
-rw-r--r--src/com/android/bluetooth/mapclient/obex/ObexTime.java43
-rw-r--r--src/com/android/bluetooth/pan/PanService.java13
-rw-r--r--src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java2
-rw-r--r--src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java66
-rw-r--r--src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java124
-rw-r--r--src/com/android/bluetooth/pbapclient/PbapClientService.java36
-rw-r--r--tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandlerTest.java15
-rw-r--r--tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java165
-rw-r--r--tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java96
-rw-r--r--tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java30
-rw-r--r--tests/unit/src/com/android/bluetooth/mapclient/ObexTimeTest.java114
-rw-r--r--tests/unit/src/com/android/bluetooth/pan/PanServiceTest.java13
117 files changed, 1236 insertions, 378 deletions
diff --git a/Android.mk b/Android.mk
index a34d2a34f..1f73091ad 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,6 +29,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.core_core \
+ androidx.legacy_legacy-support-v4 \
androidx.lifecycle_lifecycle-livedata \
androidx.room_room-runtime \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b524f7b54..99272a426 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -316,6 +316,16 @@
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
+
+ <activity
+ android:name=".BluetoothPrefs"
+ android:exported="@bool/profile_supported_a2dp_sink"
+ android:enabled="@bool/profile_supported_a2dp_sink">
+ <intent-filter>
+ <action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
+ </intent-filter>
+ </activity>
+
<service
android:process="@string/process"
android:name = ".avrcp.AvrcpTargetService"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 060fd9013..f011684cf 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-oudio is ontkoppel"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-oudio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Lêers groter as 4 GB kan nie oorgedra word nie"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Koppel aan Bluetooth"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index dbf4aadd6..0d2f87cc5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"የብሉቱዝ ኦዲዮ ግንኙነት ተቋርጧል"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"የብሉቱዝ ኦዲዮ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"ከ4 ጊባ በላይ የሆኑ ፋይሎች ሊዛወሩ አይችሉም"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ከብሉቱዝ ጋር ተገናኝ"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1525a71f5..2d4e70d29 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -26,10 +26,10 @@
<string name="airplane_error_title" msgid="2683839635115739939">"وضع الطائرة"</string>
<string name="airplane_error_msg" msgid="8698965595254137230">"لا يمكنك استخدام البلوتوث في وضع الطائرة."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
- <string name="bt_enable_line1" msgid="7203551583048149">"لإستخدام خدمات البلوتوث، يجب تشغيل البلوتوث أولاً."</string>
- <string name="bt_enable_line2" msgid="4341936569415937994">"هل تريد تشغيل البلوتوث الآن؟"</string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"لإستخدام خدمات البلوتوث، يجب تفعيل البلوتوث أولاً."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"هل تريد تفعيل البلوتوث الآن؟"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"إلغاء"</string>
- <string name="bt_enable_ok" msgid="3432462749994538265">"تشغيل"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"تفعيل"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"نقل الملف"</string>
<string name="incoming_file_confirm_content" msgid="2752605552743148036">"هل تقبل الملف الوارد؟"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"رفض"</string>
@@ -77,7 +77,7 @@
<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>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"جارٍ تفعيل البلوتوث..."</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>
@@ -142,4 +142,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"انقطع الاتصال بالبث الصوتي عبر البلوتوث."</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"بث صوتي عبر البلوتوث"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"يتعذّر نقل الملفات التي يزيد حجمها عن 4 غيغابايت"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"الاتصال ببلوتوث"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index fd6ab371a..a5f682ce6 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ব্লুটুথ অডিঅ\'ৰ সৈতে সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ব্লুটুথ অডিঅ\'"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"৪ জি. বি. তকৈ ডাঙৰ ফাইল স্থানান্তৰ কৰিব নোৱাৰি"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ব্লুটুথৰ সৈতে সংযোগ কৰক"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 4abf91f83..ea55d1771 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio ilə bağlantı kəsildi"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB-dən böyük olan faylları köçürmək mümkün deyil"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth\'a qoşulun"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 4d999f36a..9ad26e1e8 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Veza sa Bluetooth audijom je prekinuta"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Ne mogu da se prenose datoteke veće od 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Poveži sa Bluetooth-om"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 0026ea6d8..3c9dbd6cd 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-аўдыя адключана"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-аўдыя"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Немагчыма перадаць файлы, большыя за 4 ГБ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Падключыцца да Bluetooth"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 1566a37dc..4b57342d2 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Аудиовръзката през Bluetooth е прекратена"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Аудио през Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Файловете с размер над 4 ГБ не могат да бъдат прехвърлени"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Свързване с Bluetooth"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 352f359c0..be016492a 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ব্লুটুথ অডিওর সংযোগ বিচ্ছিন্ন হয়েছে"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ব্লুটুথ অডিও"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"৪GB থেকে বড় ফটো ট্রান্সফার করা যাবে না"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ব্লুটুথের সাথে কানেক্ট করুন"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 7f6eca1e4..3c7dec44d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio je isključen"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Nije moguće prenijeti fajlove veće od 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Poveži se na Bluetooth"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index e24b808d3..bddf09672 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Àudio per Bluetooth desconnectat"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Àudio per Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"No es poden transferir fitxers més grans de 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connecta el Bluetooth"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 3e76d2bb4..9adb80c78 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth Audio – odpojeno"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Soubory větší než 4 GB nelze přenést"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Připojit k Bluetooth"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 25819a183..25cf3d7be 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-lyden blev afbrudt"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-lyd"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"File, der er større end 4 GB, kan ikke overføres"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Opret forbindelse til Bluetooth"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c9e655490..4ffe47022 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-Audio-Verbindung aufgehoben"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Dateien mit mehr als 4 GB können nicht übertragen werden"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Mit Bluetooth verbinden"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1506bd2e7..e249a3889 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Ο ήχος Bluetooth αποσυνδέθηκε"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Ήχος Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Δεν είναι δυνατή η μεταφορά αρχείων που ξεπερνούν τα 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Σύνδεση σε Bluetooth"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index ddca4979a..8dcbab466 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio disconnected"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Files bigger than 4 GB cannot be transferred"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connect to Bluetooth"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index e549cb6d4..07202ef21 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio disconnected"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Files bigger than 4 GB cannot be transferred"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connect to Bluetooth"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index ddca4979a..8dcbab466 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio disconnected"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Files bigger than 4 GB cannot be transferred"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connect to Bluetooth"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index ddca4979a..8dcbab466 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio disconnected"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Files bigger than 4 GB cannot be transferred"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connect to Bluetooth"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 02178d43d..8bbc66c7c 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎Bluetooth audio disconnected‎‏‎‎‏‎"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎Bluetooth Audio‎‏‎‎‏‎"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎Files bigger than 4GB cannot be transferred‎‏‎‎‏‎"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎Connect to Bluetooth‎‏‎‎‏‎"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 4a4eaaaa3..eb95310b4 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio Bluetooth desconectado"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"No se pueden transferir los archivos de más de 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Conectarse a Bluetooth"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index a9e448c41..a67ba6b4f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -122,7 +122,7 @@
<string name="transfer_menu_open" msgid="3368984869083107200">"Abrir"</string>
<string name="transfer_menu_clear" msgid="5854038118831427492">"Borrar de la lista"</string>
<string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Borrar"</string>
- <string name="bluetooth_a2dp_sink_queue_name" msgid="6864149958708669766">"Está Sonando"</string>
+ <string name="bluetooth_a2dp_sink_queue_name" msgid="6864149958708669766">"Reproduciendo"</string>
<string name="bluetooth_map_settings_save" msgid="7635491847388074606">"Guardar"</string>
<string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"Cancelar"</string>
<string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Selecciona las cuentas que quieras compartir por Bluetooth. Tendrás que aceptar cualquier acceso a las cuentas al establecer conexión."</string>
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio por Bluetooth desconectado"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio por Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"No se pueden transferir archivos de más de 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Conectarse a un dispositivo Bluetooth"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index dbc425adb..334174fbc 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetoothi heli ühendus on katkestatud"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetoothi heli"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Faile, mis on üle 4 GB, ei saa üle kanda"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Ühenda Bluetoothiga"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index cc6e417f0..72e609650 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Deskonektatu da Bluetooth bidezko audioa"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth bidezko audioa"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Ezin dira transferitu 4 GB baino gehiagoko fitxategiak"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Konektatu Bluetooth-era"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c95558eac..e2c1b75c9 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ارتباط بلوتوث صوتی قطع شد"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"بلوتوث‌ صوتی"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"فایل‌های بزرگ‌تر از ۴ گیگابایت نمی‌توانند منتقل شوند"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"اتصال به بلوتوث"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 0fbc55c5a..f1792c634 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-ääni katkaistu"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-ääni"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Yli 4 Gt:n kokoisia tiedostoja ei voi siirtää."</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Muodosta Bluetooth-yhteys"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index b881cfcbd..4a62f98eb 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio Bluetooth déconnecté"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Les fichiers dépassant 4 Go ne peuvent pas être transférés"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connexion au Bluetooth"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 06fe2093c..e0caaee4f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio Bluetooth déconnecté"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Impossible de transférer les fichiers supérieurs à 4 Go"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Se connecter au Bluetooth"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9dedefde2..1f2b1d0ca 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Desconectouse o audio por Bluetooth"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio por Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Non se poden transferir ficheiros de máis de 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Conectar ao Bluetooth"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index d6e10005a..4195292df 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"બ્લૂટૂથ ઑડિઓ ડિસ્કનેક્ટ થયું"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"બ્લૂટૂથ ઑડિઓ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB કરતા મોટી ફાઇલ ટ્રાન્સફર કરી શકાતી નથી"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"બ્લૂટૂથ સાથે કનેક્ટ કરો"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index d01d1377a..cb0bb5f7d 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ब्लूटूथ ऑडियो डिसकनेक्ट किया गया"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ब्लूटूथ ऑडियो"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 जीबी से बड़ी फ़ाइलें ट्रांसफ़र नहीं की जा सकतीं"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ब्लूटूथ से कनेक्ट करें"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d05c7b338..581e1a875 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Veza Bluetooth Audija prekinuta"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Datoteke veće od 4 GB ne mogu se prenijeti"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Povezivanje s Bluetoothom"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 4fa442f44..ff93e444d 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audió leválasztva"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth audió"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"A 4 GB-nál nagyobb fájlokat nem lehet átvinni"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Csatlakozás Bluetooth-eszközhöz"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index bf6fbf3b8..1fb6d74fb 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth աուդիոն անջատված է"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth աուդիո"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 ԳԲ-ից մեծ ֆայլերը հնարավոր չէ փոխանցել"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Միանալ Bluetooth-ին"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 15722dab8..01c4fe10d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth audio terputus"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"File yang berukuran lebih dari 4GB tidak dapat ditransfer"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Hubungkan ke Bluetooth"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 624638903..65db6e918 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-hljóð aftengt"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-hljóð"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Ekki er hægt að flytja skrár sem eru stærri en 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Tengjast við Bluetooth"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index e4a486f33..27cefda39 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio Bluetooth disconnesso"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Impossibile trasferire file con dimensioni superiori a 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Connettiti a Bluetooth"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 415bd1077..11446ff3b 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"‏אודיו Bluetooth מנותק"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"‏אודיו Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"‏לא ניתן להעביר קבצים שגדולים מ-GB‏ 4"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"‏התחברות באמצעות Bluetooth"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 6171772a0..7688d485a 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth オーディオは接続を解除されています"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth オーディオ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 GB を超えるファイルは転送できません"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth に接続する"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 4983eaaf6..92b632919 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth აუდიო გათიშულია"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth აუდიო"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 გბაიტზე დიდი მოცულობის ფაილების გადატანა ვერ მოხერხდება"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth-თან დაკავშირება"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 82de8a6a4..811187fa3 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth дыбысы ажыратылды"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth aудиосы"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Көлемі 4 ГБ-тан асатын файлдар тасымалданбайды"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth-ге қосылу"</string>
</resources>
diff --git a/res/values-kk/strings_pbap.xml b/res/values-kk/strings_pbap.xml
index 29ff2212d..11893b9ab 100644
--- a/res/values-kk/strings_pbap.xml
+++ b/res/values-kk/strings_pbap.xml
@@ -4,9 +4,7 @@
<string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"%1$s үшін сессия кілтін теру"</string>
<string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Bluetooth сессия кілті қажет"</string>
<string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"%1$s арқылы байланыс қабылдау уақыты өтіп кетті"</string>
- <!-- String.format failed for translation -->
- <!-- no translation found for pbap_authentication_timeout_message (4166979525521902687) -->
- <skip />
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"%1$s арқылы сессия кілтін енгізу уақыты өтіп кетті"</string>
<string name="auth_notif_ticker" msgid="1575825798053163744">"Obex растау талабы"</string>
<string name="auth_notif_title" msgid="7599854855681573258">"Сессия кілті"</string>
<string name="auth_notif_message" msgid="6667218116427605038">"%1$s үшін сессия кілтін теру"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index f4b7e7a5c..1db467c4d 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -122,7 +122,7 @@
<string name="transfer_menu_open" msgid="3368984869083107200">"បើក"</string>
<string name="transfer_menu_clear" msgid="5854038118831427492">"សម្អាត​ពី​បញ្ជី"</string>
<string name="transfer_clear_dlg_title" msgid="2953444575556460386">"សម្អាត"</string>
- <string name="bluetooth_a2dp_sink_queue_name" msgid="6864149958708669766">"Now Playing"</string>
+ <string name="bluetooth_a2dp_sink_queue_name" msgid="6864149958708669766">"ឥឡូវកំពុងចាក់"</string>
<string name="bluetooth_map_settings_save" msgid="7635491847388074606">"រក្សាទុក"</string>
<string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"បោះបង់"</string>
<string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"ជ្រើសគណនីដែលអ្នកចង់ចែករំលែកតាមរយៈប៊្លូធូស។ អ្នកនៅតែត្រូវទទួលយកលទ្ធភាពចូលដំណើរការទាំងឡាយទៅកាន់គណនីនេះដដែល នៅពេលភ្ជាប់។"</string>
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"សំឡេងប៊្លូធូសត្រូវបានផ្តាច់"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"សំឡេងប៊្លូធូស"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"ឯកសារ​ដែល​មាន​ទំហំ​ធំ​ជាង 4 GB មិន​អាចផ្ទេរ​បាន​ទេ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ភ្ជាប់​ប៊្លូធូស"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 0f0e06f92..1d87823c1 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB ಗಿಂತ ದೊಡ್ಡದಾದ ಫೈಲ್‌ಗಳನ್ನು ವರ್ಗಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ಬ್ಲೂಟೂತ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f5eeca948..3977271cc 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"블루투스 오디오가 연결 해제됨"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"블루투스 오디오"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB보다 큰 파일은 전송할 수 없습니다"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"블루투스에 연결"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 0ed4aa9bd..f02c8748a 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/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>
@@ -125,7 +125,7 @@
<string name="bluetooth_a2dp_sink_queue_name" msgid="6864149958708669766">"Азыр эмне ойноп жатат?"</string>
<string name="bluetooth_map_settings_save" msgid="7635491847388074606">"Сактоо"</string>
<string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"Жокко чыгаруу"</string>
- <string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Bluetooth аркылуу бөлүшө турган каттоо эсептерин тандаңыз. Туташкан сайын каттоо эсептерине кирүү мүмкүнчүлүгүн ырастап турушуңуз керек."</string>
+ <string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Bluetooth аркылуу бөлүшө турган каттоо эсептерин тандаңыз. Туташкан сайын аккаунттарына кирүү мүмкүнчүлүгүн ырастап турушуңуз керек."</string>
<string name="bluetooth_map_settings_count" msgid="4557473074937024833">"Калган көзөнөктөр:"</string>
<string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"Колдонмонун сүрөтчөсү"</string>
<string name="bluetooth_map_settings_title" msgid="7420332483392851321">"Bluetooth билдирүү бөлүшүү жөндөөлөрү"</string>
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth аудио ажыратылды"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth аудио"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4Гб чоң файлдарды өткөрүү мүмкүн эмес"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth\'га туташуу"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index bebe622a8..3257841eb 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ຕັດການເຊື່ອມຕໍ່ສຽງ Bluetooth ແລ້ວ"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ສຽງ Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"ບໍ່ສາມາດໂອນຍ້າຍໄຟລ໌ທີ່ໃຫຍກວ່າ 4GB ໄດ້"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ເຊື່ອມຕໍ່ກັບ Bluetooth"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 5d0f75990..42562f4ad 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"„Bluetooth“ garsas atjungtas"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"„Bluetooth“ garsas"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Negalima perkelti didesnių nei 4 GB failų"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Prisijungti prie „Bluetooth“"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 062a0195e..6edd98470 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Pārtraukts savienojums ar Bluetooth audio"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Nevar pārsūtīt failus, kas lielāki par 4 GB."</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Izveidot savienojumu ar Bluetooth"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 011c39dfb..5045b56db 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Аудиото преку Bluetooth е исклучено"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Аудио преку Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Не може да се пренесуваат датотеки поголеми од 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Поврзи се со Bluetooth"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 08e907f4f..716bf1dd5 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -20,7 +20,7 @@
<string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"BluetoothShare മാനേജർ ആക്‌സസ്സുചെയ്യാനും ഫയലുകൾ കൈമാറാൻ അത് ഉപയോഗിക്കാനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"വൈറ്റ്‌ലിസ്റ്റ് ബ്ലൂടൂത്ത് ഉപകരണ ആക്‌സസ്സ്."</string>
<string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"ഒരു ബ്ലൂടൂത്ത് ഉപകരണം താൽക്കാലികമായി വൈറ്റ്‌ലിസ്റ്റുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു, അത് ഉപയോക്താവിന്റെ സ്ഥിരീകരണമില്ലാതെ ഈ ഉപകരണത്തിലേക്ക് ഫയലുകൾ അയയ്‌ക്കാൻ ആ ഉപകരണത്തെ അനുവദിക്കുന്നു."</string>
- <string name="bt_share_picker_label" msgid="6268100924487046932">"ബ്ലൂടൂത്ത്"</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
<string name="unknown_device" msgid="9221903979877041009">"അജ്ഞാത ഉപകരണം"</string>
<string name="unknownNumber" msgid="4994750948072751566">"അറിയില്ല"</string>
<string name="airplane_error_title" msgid="2683839635115739939">"ഫ്ലൈറ്റ് മോഡ്"</string>
@@ -132,4 +132,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth ഓഡിയോ വിച്ഛേദിച്ചു"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth ഓഡിയോ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB-യിൽ കൂടുതലുള്ള ഫയലുകൾ കൈമാറാനാവില്ല"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth-ലേക്ക് കണക്‌റ്റ് ചെയ്യുക"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index aec448c75..60f238a72 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth аудиог салгасан"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Аудио"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4ГБ-с дээш хэмжээтэй файлыг шилжүүлэх боломжгүй"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth-тэй холбогдох"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 4db5d0aa8..43e0a545c 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ब्लूटूथ ऑडिओ डिस्कनेक्ट केला"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ब्लूटूथ ऑडिओ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 GB हून मोठ्या फायली ट्रान्सफर करता येणार नाहीत"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ब्लूटूथशी कनेक्ट करा"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index ab9c7a934..a0071ca53 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio Bluetooth diputuskan sambungannya"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Fail lebih besar daripada 4GB tidak boleh dipindahkan"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Sambung ke Bluetooth"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 7e7763a23..eb35b0f85 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ဘလူးတုသ်အသံ မချိတ်ဆက်ထားပါ"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ဘလူးတုသ် အသံ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB ထက်ပိုကြီးသည့် ဖိုင်များကို လွှဲပြောင်းမရနိုင်ပါ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ဘလူးတုသ်သို့ ချိတ်ဆက်ရန်"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index e0418b1b4..d6f9e7705 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-lyd er frakoblet"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-lyd"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Filer som er større enn 4 GB, kan ikke overføres"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Koble til Bluetooth"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 639df71d3..6f9ab5888 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ब्लुटुथ सम्बन्धी अडियो यन्त्रलाई विच्छेद गरियो"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ब्लुटुथको अडियो"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"४ जि.बि. भन्दा ठूला फाइलहरूलाई स्थानान्तरण गर्न सकिँदैन"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ब्लुटुथमा जोड्नुहोस्"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 920737897..8f496201b 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-audio ontkoppeld"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Bestanden groter dan 4 GB kunnen niet worden overgedragen"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Verbinding maken met bluetooth"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 8819773e2..94ad0410e 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ବ୍ଲୁଟୂଥ୍‍‌ ଅଡିଓ ବିଚ୍ଛିନ୍ନ କରାଗଲା"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ବ୍ଲୁଟୂଥ୍‍‌ ଅଡିଓ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GBରୁ ବଡ଼ ଫାଇଲ୍‌ଗୁଡ଼ିକୁ ଟ୍ରାନ୍ସଫର୍‌ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ବ୍ଲୁଟୁଥ୍ ସହ ସଂଯୋଗ କରନ୍ତୁ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 07cab6a78..71c771b2a 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਡਿਸਕਨੈਕਟ ਕੀਤੀ ਗਈ"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"ਬਲੂਟੁੱਥ ਆਡੀਓ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB ਤੋਂ ਵਧੇਰੇ ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਟ੍ਰਾਂਸਫ਼ਰ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"ਬਲੂਟੁੱਥ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 8c4869f4c..3cfbe0d5f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Dźwięk Bluetooth odłączony"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Dźwięk Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Nie można przenieść plików przekraczających 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Nawiązywanie połączeń przez Bluetooth"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 09e6781d3..9eae5c975 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Áudio Bluetooth desligado"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Áudio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Não é possível transferir os ficheiros com mais de 4 GB."</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Ligar ao Bluetooth"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 8472432ec..b4a775e33 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Áudio Bluetooth desconectado"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Áudio Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Não é possível transferir arquivos maiores que 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Conectar ao Bluetooth"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 67f117d40..fadc4a6d5 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audio prin Bluetooth deconectat"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audio prin Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Fișierele mai mari de 4 GB nu pot fi transferate"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Conectați-vă la Bluetooth"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 87c1492aa..6625b8346 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Звук через Bluetooth отключен"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Звук через Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Можно перенести только файлы размером до 4 ГБ."</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Подключиться по Bluetooth"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index ed6e3551a..bbe1e0053 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"බ්ලූටූත් ශ්‍රව්‍යය විසන්ධි කරන ලදී"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"බ්ලූටූත් ශ්‍රව්‍යය"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GBට වඩා විශාල ගොනු මාරු කළ නොහැකිය"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"බ්ලූටූත් වෙත සබඳින්න"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index d189d0da2..e28a7920d 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Rozhranie Bluetooth Audio je odpojené"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Súbory väčšie ako 4 GB sa nedajú preniesť"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Pripojiť k zariadeniu Bluetooth"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 912ba37e9..d681fb27e 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Zvok prek Bluetootha ni povezan"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Zvok prek Bluetootha"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Datotek, večjih od 4 GB, ni mogoče prenesti"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Povezovanje z Bluetoothom"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1a95dcd6a..5d1aff31b 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Audioja e \"bluetooth-it\" e shkëputur"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Audioja e \"bluetooth-it\""</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Skedarët më të mëdhenj se 4 GB nuk mund të transferohen"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Lidhu me Bluetooth"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6bdf67a61..25fc24fba 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -136,4 +136,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Веза са Bluetooth аудијом је прекинута"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth аудио"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Не могу да се преносе датотеке веће од 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Повежи са Bluetooth-ом"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 7c1609fbb..f243475b0 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth-ljud är frånkopplat"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth-ljud"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Det går inte att överföra filer som är större än 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Anslut till Bluetooth"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 39f803ef6..edc03d96d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Imeondoa sauti ya Bluetooth"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Sauti ya Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Haiwezi kutuma faili zinazozidi GB 4"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Unganisha kwenye Bluetooth"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index e584f9ff7..67d872f9e 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"புளூடூத் ஆடியோ துண்டிக்கப்பட்டது"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"புளூடூத் ஆடியோ"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4ஜி.பை.க்கு மேலிருக்கும் ஃபைல்களை இடமாற்ற முடியாது"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"புளூடூத் உடன் இணை"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 7aaeaa459..e7f777546 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"బ్లూటూత్ ఆడియో డిస్‌కనెక్ట్ చేయబడింది"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"బ్లూటూత్ ఆడియో"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4GB కన్నా పెద్ద ఫైళ్లు బదిలీ చేయబడవు"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"బ్లూటూత్‌కు కనెక్ట్ చేయి"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 8cfec4fe8..48023cdf5 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"ยกเลิกการเชื่อมต่อ Bluetooth Audio แล้ว"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"โอนไฟล์ที่มีขนาดใหญ่กว่า 4 GB ไม่ได้"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"เชื่อมต่อบลูทูธ"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 1f50cebbe..3820800f6 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Nadiskonekta ang Bluetooth audio"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Hindi maililipat ang mga file na mas malaki sa 4GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Kumonekta sa Bluetooth"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 71ce9a4a5..e1a0bfb88 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth ses bağlantısı kesildi"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Ses"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 GB\'tan büyük dosyalar aktarılamaz"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetooth\'a bağlan"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index e357d1357..f7d6fbdd8 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -138,4 +138,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Аудіо Bluetooth від’єднано"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth Audio"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Не можна перенести файли, більші за 4 ГБ"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Підключитися до Bluetooth"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index cc13746bf..e944fb8c2 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"بلوٹوتھ آڈیو غیر منسلک ہے"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"بلوٹوتھ آڈیو"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"‏4GB سے بڑی فائلیں منتقل نہیں کی جا سکتیں"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"بلوٹوتھ سے منسلک کریں"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index dac670b6b..cadb8be49 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Bluetooth orqali ovoz o‘chirildi"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Bluetooth orqali ovoz"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"4 GBdan katta hajmli videolar o‘tkazilmaydi"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Bluetoothga ulanish"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 4a40dfe12..e0653c096 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -128,10 +128,11 @@
<string name="bluetooth_map_settings_intro" msgid="6482369468223987562">"Chọn tài khoản mà bạn muốn chia sẻ qua Bluetooth. Bạn vẫn phải chấp nhận mọi quyền truy cập vào tài khoản khi kết nối."</string>
<string name="bluetooth_map_settings_count" msgid="4557473074937024833">"Số khe cắm còn lại:"</string>
<string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"Biểu tượng ứng dụng"</string>
- <string name="bluetooth_map_settings_title" msgid="7420332483392851321">"Cài đặt chia sẻ thư qua Bluetooth"</string>
+ <string name="bluetooth_map_settings_title" msgid="7420332483392851321">"Cài đặt cách chia sẻ thư qua Bluetooth"</string>
<string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"Không chọn được tài khoản. Còn lại 0 khe cắm"</string>
<string name="bluetooth_connected" msgid="6718623220072656906">"Đã kết nối âm thanh Bluetooth"</string>
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Đã ngắt kết nối âm thanh Bluetooth"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Âm thanh Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Không thể chuyển những tệp lớn hơn 4 GB"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Kết nối với Bluetooth"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 489853755..a5f6d2dad 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"蓝牙音频已断开连接"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"蓝牙音频"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"无法传输 4GB 以上的文件"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"连接到蓝牙"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index dfb352a71..2881ffe3c 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"已與藍牙音訊解除連接"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"藍牙音訊"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"無法轉移 4 GB 以上的檔案"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"連接藍牙"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 046dfc682..c8ece0167 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"已中斷與藍牙音訊的連線"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"藍牙音訊"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"無法轉移大於 4GB 的檔案"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"使用藍牙連線"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 1bc0fe622..da08ed2a9 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -134,4 +134,5 @@
<string name="bluetooth_disconnected" msgid="3318303728981478873">"Umsindo we-Bluetooth unqanyuliwe"</string>
<string name="a2dp_sink_mbs_label" msgid="7566075853395412558">"Umsindo we-Bluetooth"</string>
<string name="bluetooth_opp_file_limit_exceeded" msgid="8894450394309084519">"Amafayela amakhulu kuno-4GB awakwazi ukudluliselwa"</string>
+ <string name="bluetooth_connect_action" msgid="4009848433321657090">"Xhumeka ku-Bluetooth"</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 016bb615b..b7dcaf2a9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -249,4 +249,5 @@
<string name="bluetooth_disconnected">Bluetooth audio disconnected"</string>
<string name="a2dp_sink_mbs_label">Bluetooth Audio</string>
<string name="bluetooth_opp_file_limit_exceeded">Files bigger than 4GB cannot be transferred</string>
+ <string name="bluetooth_connect_action">Connect to Bluetooth</string>
</resources>
diff --git a/res/xml/authenticator.xml b/res/xml/authenticator.xml
index b719fec4f..ab08a6103 100644
--- a/res/xml/authenticator.xml
+++ b/res/xml/authenticator.xml
@@ -17,5 +17,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:icon="@mipmap/bt_share"
android:smallIcon="@mipmap/bt_share"
- android:accountType="@string/pbap_account_type"
- android:label="@string/pbap_account_type" />
+ android:accountType="@string/pbap_account_type" />
diff --git a/src/com/android/bluetooth/BluetoothPrefs.java b/src/com/android/bluetooth/BluetoothPrefs.java
new file mode 100644
index 000000000..2c7c87aaa
--- /dev/null
+++ b/src/com/android/bluetooth/BluetoothPrefs.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.bluetooth;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Activity that routes to Bluetooth settings when launched
+ */
+public class BluetoothPrefs extends Activity {
+
+ public static final String BLUETOOTH_SETTING_ACTION = "android.settings.BLUETOOTH_SETTINGS";
+ public static final String BLUETOOTH_SETTING_CATEGORY = "android.intent.category.DEFAULT";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent launchIntent = new Intent();
+ launchIntent.setAction(BLUETOOTH_SETTING_ACTION);
+ launchIntent.addCategory(BLUETOOTH_SETTING_CATEGORY);
+ startActivity(launchIntent);
+ finish();
+ }
+}
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
index e41def075..5271cc791 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
@@ -413,7 +413,8 @@ public class A2dpSinkService extends ProfileService {
if (state == StackEvent.AUDIO_STATE_STARTED) {
mA2dpSinkStreamHandler.obtainMessage(
A2dpSinkStreamHandler.SRC_STR_START).sendToTarget();
- } else if (state == StackEvent.AUDIO_STATE_STOPPED) {
+ } else if (state == StackEvent.AUDIO_STATE_STOPPED
+ || state == StackEvent.AUDIO_STATE_REMOTE_SUSPEND) {
mA2dpSinkStreamHandler.obtainMessage(
A2dpSinkStreamHandler.SRC_STR_STOP).sendToTarget();
}
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
index 5e3b3567c..5aa3cbbd5 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
@@ -17,6 +17,7 @@
package com.android.bluetooth.a2dpsink;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClientCall;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
@@ -24,10 +25,9 @@ import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaPlayer;
-import android.media.session.PlaybackState;
-
import android.os.Handler;
import android.os.Message;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import com.android.bluetooth.R;
@@ -183,8 +183,9 @@ public class A2dpSinkStreamHandler extends Handler {
break;
case AUDIO_FOCUS_CHANGE:
+ mAudioFocus = (int) message.obj;
// message.obj is the newly granted audio focus.
- switch ((int) message.obj) {
+ switch (mAudioFocus) {
case AudioManager.AUDIOFOCUS_GAIN:
removeMessages(DELAYED_PAUSE);
// Begin playing audio, if we paused the remote, send a play now.
@@ -228,7 +229,7 @@ public class A2dpSinkStreamHandler extends Handler {
case DELAYED_PAUSE:
if (BluetoothMediaBrowserService.getPlaybackState()
- == PlaybackState.STATE_PLAYING && !inCallFromStreamingDevice()) {
+ == PlaybackStateCompat.STATE_PLAYING && !inCallFromStreamingDevice()) {
sendAvrcpPause();
mSentPause = true;
mStreamAvailable = false;
@@ -245,12 +246,9 @@ public class A2dpSinkStreamHandler extends Handler {
*/
private void requestAudioFocusIfNone() {
if (DBG) Log.d(TAG, "requestAudioFocusIfNone()");
- if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
+ if (mAudioFocus != AudioManager.AUDIOFOCUS_GAIN) {
requestAudioFocus();
}
- // On the off change mMediaPlayer errors out and dies, we want to make sure we retry this.
- // This function immediately exits if we have a MediaPlayer object.
- requestMediaKeyFocus();
}
private synchronized int requestAudioFocus() {
@@ -277,8 +275,11 @@ public class A2dpSinkStreamHandler extends Handler {
}
/**
- * Creates a MediaPlayer that plays a silent audio sample so that MediaSessionService will be
- * aware of the fact that Bluetooth is playing audio.
+ * Plays a silent audio sample so that MediaSessionService will be aware of the fact that
+ * Bluetooth is playing audio.
+ *
+ * Creates a new MediaPlayer if one does not already exist. Repeat calls to this function are
+ * safe and will result in the silent audio sample again.
*
* This allows the MediaSession in AVRCP Controller to be routed media key events, if we've
* chosen to use it.
@@ -286,25 +287,25 @@ public class A2dpSinkStreamHandler extends Handler {
private synchronized void requestMediaKeyFocus() {
if (DBG) Log.d(TAG, "requestMediaKeyFocus()");
- if (mMediaPlayer != null) return;
-
- AudioAttributes attrs = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_MEDIA)
- .build();
-
- mMediaPlayer = MediaPlayer.create(mContext, R.raw.silent, attrs,
- mAudioManager.generateAudioSessionId());
if (mMediaPlayer == null) {
- Log.e(TAG, "Failed to initialize media player. You may not get media key events");
- return;
- }
+ AudioAttributes attrs = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .build();
+
+ mMediaPlayer = MediaPlayer.create(mContext, R.raw.silent, attrs,
+ mAudioManager.generateAudioSessionId());
+ if (mMediaPlayer == null) {
+ Log.e(TAG, "Failed to initialize media player. You may not get media key events");
+ return;
+ }
- mMediaPlayer.setLooping(false);
- mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
- Log.e(TAG, "Silent media player error: " + what + ", " + extra);
- releaseMediaKeyFocus();
- return false;
- });
+ mMediaPlayer.setLooping(false);
+ mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
+ Log.e(TAG, "Silent media player error: " + what + ", " + extra);
+ releaseMediaKeyFocus();
+ return false;
+ });
+ }
mMediaPlayer.start();
BluetoothMediaBrowserService.setActive(true);
@@ -313,7 +314,6 @@ public class A2dpSinkStreamHandler extends Handler {
private synchronized void abandonAudioFocus() {
if (DBG) Log.d(TAG, "abandonAudioFocus()");
stopFluorideStreaming();
- releaseMediaKeyFocus();
mAudioManager.abandonAudioFocus(mAudioFocusListener);
mAudioFocus = AudioManager.AUDIOFOCUS_NONE;
}
@@ -336,9 +336,11 @@ public class A2dpSinkStreamHandler extends Handler {
private void startFluorideStreaming() {
mA2dpSinkService.informAudioFocusStateNative(STATE_FOCUS_GRANTED);
mA2dpSinkService.informAudioTrackGainNative(1.0f);
+ requestMediaKeyFocus();
}
private void stopFluorideStreaming() {
+ releaseMediaKeyFocus();
mA2dpSinkService.informAudioFocusStateNative(STATE_FOCUS_LOST);
}
@@ -362,7 +364,10 @@ public class A2dpSinkStreamHandler extends Handler {
}
HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService();
if (targetDevice != null && headsetClientService != null) {
- return headsetClientService.getCurrentCalls(targetDevice).size() > 0;
+ List<BluetoothHeadsetClientCall> currentCalls =
+ headsetClientService.getCurrentCalls(targetDevice);
+ if (currentCalls == null) return false;
+ return currentCalls.size() > 0;
}
return false;
}
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
index 64e63df00..56684cd7c 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
@@ -172,9 +172,11 @@ public class AvrcpControllerService extends ProfileService {
}
}
+ // If we don't find a node in the tree then do not have any way to browse for the contents.
+ // Return an empty list instead.
if (requestedNode == null) {
if (DBG) Log.d(TAG, "Didn't find a node");
- return null;
+ return new ArrayList(0);
} else {
if (!requestedNode.isCached()) {
if (DBG) Log.d(TAG, "node is not cached");
@@ -412,9 +414,10 @@ public class AvrcpControllerService extends ProfileService {
if (stateMachine != null) {
PlayerApplicationSettings supportedSettings =
PlayerApplicationSettings.makeSupportedSettings(playerAttribRsp);
+ stateMachine.sendMessage(
+ AvrcpControllerStateMachine.MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS,
+ supportedSettings);
}
- /* Do nothing */
-
}
private synchronized void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp,
@@ -426,10 +429,12 @@ public class AvrcpControllerService extends ProfileService {
AvrcpControllerStateMachine stateMachine = getStateMachine(device);
if (stateMachine != null) {
- PlayerApplicationSettings desiredSettings =
+ PlayerApplicationSettings currentSettings =
PlayerApplicationSettings.makeSettings(playerAttribRsp);
+ stateMachine.sendMessage(
+ AvrcpControllerStateMachine.MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS,
+ currentSettings);
}
- /* Do nothing */
}
// Browsing related JNI callbacks.
@@ -711,7 +716,7 @@ public class AvrcpControllerService extends ProfileService {
/**
* Send button press commands to addressed device
*
- * @param keyCode key code as defined in AVRCP specification
+ * @param keyCode key code as defined in AVRCP specification
* @param keyState 0 = key pressed, 1 = key released
* @return command was sent
*/
@@ -720,7 +725,7 @@ public class AvrcpControllerService extends ProfileService {
/**
* Send group navigation commands
*
- * @param keyCode next/previous
+ * @param keyCode next/previous
* @param keyState state
* @return command was sent
*/
@@ -741,7 +746,7 @@ public class AvrcpControllerService extends ProfileService {
* Send response to set absolute volume
*
* @param absVol new volume
- * @param label label
+ * @param label label
*/
public native void sendAbsVolRspNative(byte[] address, int absVol, int label);
@@ -749,8 +754,8 @@ public class AvrcpControllerService extends ProfileService {
* Register for any volume level changes
*
* @param rspType type of response
- * @param absVol current volume
- * @param label label
+ * @param absVol current volume
+ * @param label label
*/
public native void sendRegisterAbsVolRspNative(byte[] address, byte rspType, int absVol,
int label);
@@ -764,7 +769,7 @@ public class AvrcpControllerService extends ProfileService {
* Fetch the current now playing list
*
* @param start first index to retrieve
- * @param end last index to retrieve
+ * @param end last index to retrieve
*/
public native void getNowPlayingListNative(byte[] address, int start, int end);
@@ -772,7 +777,7 @@ public class AvrcpControllerService extends ProfileService {
* Fetch the current folder's listing
*
* @param start first index to retrieve
- * @param end last index to retrieve
+ * @param end last index to retrieve
*/
public native void getFolderListNative(byte[] address, int start, int end);
@@ -780,7 +785,7 @@ public class AvrcpControllerService extends ProfileService {
* Fetch the listing of players
*
* @param start first index to retrieve
- * @param end last index to retrieve
+ * @param end last index to retrieve
*/
public native void getPlayerListNative(byte[] address, int start, int end);
@@ -788,15 +793,15 @@ public class AvrcpControllerService extends ProfileService {
* Change the current browsed folder
*
* @param direction up/down
- * @param uid folder unique id
+ * @param uid folder unique id
*/
public native void changeFolderPathNative(byte[] address, byte direction, long uid);
/**
* Play item with provided uid
*
- * @param scope scope of item to played
- * @param uid song unique id
+ * @param scope scope of item to played
+ * @param uid song unique id
* @param uidCounter counter
*/
public native void playItemNative(byte[] address, byte scope, long uid, int uidCounter);
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 66571c4e7..c319364c1 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -24,10 +24,10 @@ import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Message;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.util.SparseArray;
@@ -42,6 +42,7 @@ import com.android.internal.util.StateMachine;
import java.util.ArrayList;
import java.util.List;
+
/**
* Provides Bluetooth AVRCP Controller State Machine responsible for all remote control connections
* and interactions with a remote controlable device.
@@ -76,11 +77,15 @@ class AvrcpControllerStateMachine extends StateMachine {
static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 214;
static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 215;
static final int MESSAGE_PROCESS_NOW_PLAYING_CONTENTS_CHANGED = 216;
+ static final int MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS = 217;
+ static final int MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS = 218;
//300->399 Events for Browsing
static final int MESSAGE_GET_FOLDER_ITEMS = 300;
static final int MESSAGE_PLAY_ITEM = 301;
static final int MSG_AVRCP_PASSTHRU = 302;
+ static final int MSG_AVRCP_SET_SHUFFLE = 303;
+ static final int MSG_AVRCP_SET_REPEAT = 304;
static final int MESSAGE_INTERNAL_ABS_VOL_TIMEOUT = 404;
@@ -218,26 +223,19 @@ class AvrcpControllerStateMachine extends StateMachine {
mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
BluetoothMediaBrowserService.notifyChanged(mService
.sBrowseTree.mRootNode);
- BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
mBrowsingConnected = true;
}
synchronized void onBrowsingDisconnected() {
if (!mBrowsingConnected) return;
- mAddressedPlayer.setPlayStatus(PlaybackState.STATE_ERROR);
+ mAddressedPlayer.setPlayStatus(PlaybackStateCompat.STATE_ERROR);
mAddressedPlayer.updateCurrentTrack(null);
mBrowseTree.mNowPlayingNode.setCached(false);
BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
- PlaybackState.Builder pbb = new PlaybackState.Builder();
- pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN,
- 1.0f).setActions(0);
- pbb.setErrorMessage(mService.getString(R.string.bluetooth_disconnected));
- BluetoothMediaBrowserService.notifyChanged(pbb.build());
mService.sBrowseTree.mRootNode.removeChild(
mBrowseTree.mRootNode);
BluetoothMediaBrowserService.notifyChanged(mService
.sBrowseTree.mRootNode);
- BluetoothMediaBrowserService.trackChanged(null);
mBrowsingConnected = false;
}
@@ -298,8 +296,9 @@ class AvrcpControllerStateMachine extends StateMachine {
@Override
public void enter() {
if (mMostRecentState == BluetoothProfile.STATE_CONNECTING) {
- broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
} else {
logD("ReEnteringConnected");
}
@@ -315,14 +314,14 @@ class AvrcpControllerStateMachine extends StateMachine {
removeMessages(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT);
sendMessageDelayed(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT,
ABS_VOL_TIMEOUT_MILLIS);
- setAbsVolume(msg.arg1, msg.arg2);
+ handleAbsVolumeRequest(msg.arg1, msg.arg2);
return true;
case MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION:
mVolumeNotificationLabel = msg.arg1;
mService.sendRegisterAbsVolRspNative(mDeviceAddress,
NOTIFICATION_RSP_TYPE_INTERIM,
- getAbsVolumeResponse(), mVolumeNotificationLabel);
+ getAbsVolume(), mVolumeNotificationLabel);
return true;
case MESSAGE_GET_FOLDER_ITEMS:
@@ -338,6 +337,14 @@ class AvrcpControllerStateMachine extends StateMachine {
passThru(msg.arg1);
return true;
+ case MSG_AVRCP_SET_REPEAT:
+ setRepeat(msg.arg1);
+ return true;
+
+ case MSG_AVRCP_SET_SHUFFLE:
+ setShuffle(msg.arg1);
+ return true;
+
case MESSAGE_PROCESS_TRACK_CHANGED:
mAddressedPlayer.updateCurrentTrack((MediaMetadata) msg.obj);
BluetoothMediaBrowserService.trackChanged((MediaMetadata) msg.obj);
@@ -347,11 +354,14 @@ class AvrcpControllerStateMachine extends StateMachine {
mAddressedPlayer.setPlayStatus(msg.arg1);
BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
if (mAddressedPlayer.getPlaybackState().getState()
- == PlaybackState.STATE_PLAYING
- && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
- && !shouldRequestFocus()) {
+ == PlaybackStateCompat.STATE_PLAYING
+ && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE) {
+ if (shouldRequestFocus()) {
+ mSessionCallbacks.onPrepare();
+ } else {
sendMessage(MSG_AVRCP_PASSTHRU,
AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
+ }
}
return true;
@@ -378,6 +388,18 @@ class AvrcpControllerStateMachine extends StateMachine {
}
return true;
+ case MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS:
+ mAddressedPlayer.setSupportedPlayerApplicationSettings(
+ (PlayerApplicationSettings) msg.obj);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ return true;
+
+ case MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS:
+ mAddressedPlayer.setCurrentPlayerApplicationSettings(
+ (PlayerApplicationSettings) msg.obj);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ return true;
+
case DISCONNECT:
transitionTo(mDisconnecting);
return true;
@@ -435,6 +457,20 @@ class AvrcpControllerStateMachine extends StateMachine {
return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND)
|| (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF);
}
+
+ private void setRepeat(int repeatMode) {
+ mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
+ new byte[]{PlayerApplicationSettings.REPEAT_STATUS}, new byte[]{
+ PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
+ PlayerApplicationSettings.REPEAT_STATUS, repeatMode)});
+ }
+
+ private void setShuffle(int shuffleMode) {
+ mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
+ new byte[]{PlayerApplicationSettings.SHUFFLE_STATUS}, new byte[]{
+ PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
+ PlayerApplicationSettings.SHUFFLE_STATUS, shuffleMode)});
+ }
}
// Handle the get folder listing action
@@ -554,7 +590,7 @@ class AvrcpControllerStateMachine extends StateMachine {
case MESSAGE_GET_FOLDER_ITEMS:
if (!mBrowseNode.equals(msg.obj)) {
if (shouldAbort(mBrowseNode.getScope(),
- ((BrowseTree.BrowseNode) msg.obj).getScope())) {
+ ((BrowseTree.BrowseNode) msg.obj).getScope())) {
mAbort = true;
}
deferMessage(msg);
@@ -576,8 +612,8 @@ class AvrcpControllerStateMachine extends StateMachine {
* necessary.
*
* @return true: a new folder in the same scope
- * a new player while fetching contents of a folder
- * false: other cases, specifically Now Playing while fetching a folder
+ * a new player while fetching contents of a folder
+ * false: other cases, specifically Now Playing while fetching a folder
*/
private boolean shouldAbort(int currentScope, int fetchScope) {
if ((currentScope == fetchScope)
@@ -674,31 +710,60 @@ class AvrcpControllerStateMachine extends StateMachine {
@Override
public void enter() {
onBrowsingDisconnected();
+ BluetoothMediaBrowserService.trackChanged(null);
+ BluetoothMediaBrowserService.addressedPlayerChanged(null);
broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING);
transitionTo(mDisconnected);
}
}
+ /**
+ * Handle a request to align our local volume with the volume of a remote device. If
+ * we're assuming the source volume is fixed then a response of ABS_VOL_MAX will always be
+ * sent and no volume adjustment action will be taken on the sink side.
+ *
+ * @param absVol A volume level based on a domain of [0, ABS_VOL_MAX]
+ * @param label Volume notification label
+ */
+ private void handleAbsVolumeRequest(int absVol, int label) {
+ logD("handleAbsVolumeRequest: absVol = " + absVol + ", label = " + label);
+ if (mIsVolumeFixed) {
+ logD("Source volume is assumed to be fixed, responding with max volume");
+ absVol = ABS_VOL_BASE;
+ } else {
+ mVolumeChangedNotificationsToIgnore++;
+ removeMessages(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT);
+ sendMessageDelayed(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT,
+ ABS_VOL_TIMEOUT_MILLIS);
+ setAbsVolume(absVol);
+ }
+ mService.sendAbsVolRspNative(mDeviceAddress, absVol, label);
+ }
+
+ /**
+ * Align our volume with a requested absolute volume level
+ *
+ * @param absVol A volume level based on a domain of [0, ABS_VOL_MAX]
+ */
+ private void setAbsVolume(int absVol) {
+ int maxLocalVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int curLocalVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ int reqLocalVolume = (maxLocalVolume * absVol) / ABS_VOL_BASE;
+ logD("setAbsVolme: absVol = " + absVol + ", reqLocal = " + reqLocalVolume
+ + ", curLocal = " + curLocalVolume + ", maxLocal = " + maxLocalVolume);
- private void setAbsVolume(int absVol, int label) {
- int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
- int newIndex = (maxVolume * absVol) / ABS_VOL_BASE;
- logD(" setAbsVolume =" + absVol + " maxVol = " + maxVolume
- + " cur = " + currIndex + " new = " + newIndex);
/*
* In some cases change in percentage is not sufficient enough to warrant
* change in index values which are in range of 0-15. For such cases
* no action is required
*/
- if (newIndex != currIndex) {
- mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newIndex,
+ if (reqLocalVolume != curLocalVolume) {
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, reqLocalVolume,
AudioManager.FLAG_SHOW_UI);
}
- mService.sendAbsVolRspNative(mDeviceAddress, getAbsVolumeResponse(), label);
}
- private int getAbsVolumeResponse() {
+ private int getAbsVolume() {
if (mIsVolumeFixed) {
return ABS_VOL_BASE;
}
@@ -708,7 +773,7 @@ class AvrcpControllerStateMachine extends StateMachine {
return newIndex;
}
- MediaSession.Callback mSessionCallbacks = new MediaSession.Callback() {
+ MediaSessionCompat.Callback mSessionCallbacks = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
logD("onPlay");
@@ -781,6 +846,19 @@ class AvrcpControllerStateMachine extends StateMachine {
BrowseTree.BrowseNode node = mBrowseTree.findBrowseNodeByID(mediaId);
sendMessage(MESSAGE_PLAY_ITEM, node);
}
+
+ @Override
+ public void onSetRepeatMode(int repeatMode) {
+ logD("onSetRepeatMode");
+ sendMessage(MSG_AVRCP_SET_REPEAT, repeatMode);
+ }
+
+ @Override
+ public void onSetShuffleMode(int shuffleMode) {
+ logD("onSetShuffleMode");
+ sendMessage(MSG_AVRCP_SET_SHUFFLE, shuffleMode);
+
+ }
};
protected void broadcastConnectionStateChanged(int currentState) {
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java
index bed38d905..4736acffa 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java
@@ -17,8 +17,9 @@
package com.android.bluetooth.avrcpcontroller;
import android.media.MediaMetadata;
-import android.media.session.PlaybackState;
import android.os.SystemClock;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import java.util.Arrays;
@@ -41,27 +42,31 @@ class AvrcpPlayer {
public static final int FEATURE_PREVIOUS = 48;
public static final int FEATURE_BROWSING = 59;
- private int mPlayStatus = PlaybackState.STATE_NONE;
- private long mPlayTime = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
+ private int mPlayStatus = PlaybackStateCompat.STATE_NONE;
+ private long mPlayTime = PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN;
private long mPlayTimeUpdate = 0;
private float mPlaySpeed = 1;
private int mId;
private String mName = "";
private int mPlayerType;
- private byte[] mPlayerFeatures;
- private long mAvailableActions;
+ private byte[] mPlayerFeatures = new byte[16];
+ private long mAvailableActions = PlaybackStateCompat.ACTION_PREPARE;
private MediaMetadata mCurrentTrack;
- private PlaybackState mPlaybackState;
+ private PlaybackStateCompat mPlaybackStateCompat;
+ private PlayerApplicationSettings mSupportedPlayerApplicationSettings =
+ new PlayerApplicationSettings();
+ private PlayerApplicationSettings mCurrentPlayerApplicationSettings;
AvrcpPlayer() {
mId = INVALID_ID;
//Set Default Actions in case Player data isn't available.
- mAvailableActions = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY
- | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS
- | PlaybackState.ACTION_STOP;
- PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder()
+ mAvailableActions = PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY
+ | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+ | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
+ | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_PREPARE;
+ PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder()
.setActions(mAvailableActions);
- mPlaybackState = playbackStateBuilder.build();
+ mPlaybackStateCompat = playbackStateBuilder.build();
}
AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) {
@@ -70,10 +75,10 @@ class AvrcpPlayer {
mPlayStatus = playStatus;
mPlayerType = playerType;
mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length);
- updateAvailableActions();
- PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder()
+ PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder()
.setActions(mAvailableActions);
- mPlaybackState = playbackStateBuilder.build();
+ mPlaybackStateCompat = playbackStateBuilder.build();
+ updateAvailableActions();
}
public int getId() {
@@ -87,7 +92,8 @@ class AvrcpPlayer {
public void setPlayTime(int playTime) {
mPlayTime = playTime;
mPlayTimeUpdate = SystemClock.elapsedRealtime();
- mPlaybackState = new PlaybackState.Builder(mPlaybackState).setState(mPlayStatus, mPlayTime,
+ mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat).setState(
+ mPlayStatus, mPlayTime,
mPlaySpeed).build();
}
@@ -97,30 +103,48 @@ class AvrcpPlayer {
public void setPlayStatus(int playStatus) {
mPlayTime += mPlaySpeed * (SystemClock.elapsedRealtime()
- - mPlaybackState.getLastPositionUpdateTime());
+ - mPlaybackStateCompat.getLastPositionUpdateTime());
mPlayStatus = playStatus;
switch (mPlayStatus) {
- case PlaybackState.STATE_STOPPED:
+ case PlaybackStateCompat.STATE_STOPPED:
mPlaySpeed = 0;
break;
- case PlaybackState.STATE_PLAYING:
+ case PlaybackStateCompat.STATE_PLAYING:
mPlaySpeed = 1;
break;
- case PlaybackState.STATE_PAUSED:
+ case PlaybackStateCompat.STATE_PAUSED:
mPlaySpeed = 0;
break;
- case PlaybackState.STATE_FAST_FORWARDING:
+ case PlaybackStateCompat.STATE_FAST_FORWARDING:
mPlaySpeed = 3;
break;
- case PlaybackState.STATE_REWINDING:
+ case PlaybackStateCompat.STATE_REWINDING:
mPlaySpeed = -3;
break;
}
- mPlaybackState = new PlaybackState.Builder(mPlaybackState).setState(mPlayStatus, mPlayTime,
+ mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat).setState(
+ mPlayStatus, mPlayTime,
mPlaySpeed).build();
}
+ public void setSupportedPlayerApplicationSettings(
+ PlayerApplicationSettings playerApplicationSettings) {
+ mSupportedPlayerApplicationSettings = playerApplicationSettings;
+ updateAvailableActions();
+ }
+
+ public void setCurrentPlayerApplicationSettings(
+ PlayerApplicationSettings playerApplicationSettings) {
+ Log.d(TAG, "Settings changed");
+ mCurrentPlayerApplicationSettings = playerApplicationSettings;
+ MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
+ session.setRepeatMode(mCurrentPlayerApplicationSettings.getSetting(
+ PlayerApplicationSettings.REPEAT_STATUS));
+ session.setShuffleMode(mCurrentPlayerApplicationSettings.getSetting(
+ PlayerApplicationSettings.SHUFFLE_STATUS));
+ }
+
public int getPlayStatus() {
return mPlayStatus;
}
@@ -131,17 +155,22 @@ class AvrcpPlayer {
return (mPlayerFeatures[byteNumber] & bitMask) == bitMask;
}
- public PlaybackState getPlaybackState() {
+ public boolean supportsSetting(int settingType, int settingValue) {
+ return mSupportedPlayerApplicationSettings.supportsSetting(settingType, settingValue);
+ }
+
+ public PlaybackStateCompat getPlaybackState() {
if (DBG) {
Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);
}
- return mPlaybackState;
+ return mPlaybackStateCompat;
}
public synchronized void updateCurrentTrack(MediaMetadata update) {
if (update != null) {
long trackNumber = update.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
- mPlaybackState = new PlaybackState.Builder(mPlaybackState).setActiveQueueItemId(
+ mPlaybackStateCompat = new PlaybackStateCompat.Builder(
+ mPlaybackStateCompat).setActiveQueueItemId(
trackNumber - 1).build();
}
mCurrentTrack = update;
@@ -153,26 +182,37 @@ class AvrcpPlayer {
private void updateAvailableActions() {
if (supportsFeature(FEATURE_PLAY)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_PLAY;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PLAY;
}
if (supportsFeature(FEATURE_STOP)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_STOP;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_STOP;
}
if (supportsFeature(FEATURE_PAUSE)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_PAUSE;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PAUSE;
}
if (supportsFeature(FEATURE_REWIND)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_REWIND;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_REWIND;
}
if (supportsFeature(FEATURE_FAST_FORWARD)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_FAST_FORWARD;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_FAST_FORWARD;
}
if (supportsFeature(FEATURE_FORWARD)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_NEXT;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
}
if (supportsFeature(FEATURE_PREVIOUS)) {
- mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
+ mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
}
+ if (mSupportedPlayerApplicationSettings.supportsSetting(
+ PlayerApplicationSettings.REPEAT_STATUS)) {
+ mAvailableActions |= PlaybackStateCompat.ACTION_SET_REPEAT_MODE;
+ }
+ if (mSupportedPlayerApplicationSettings.supportsSetting(
+ PlayerApplicationSettings.SHUFFLE_STATUS)) {
+ mAvailableActions |= PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE;
+ }
+ mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat)
+ .setActions(mAvailableActions).build();
+
if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions);
}
}
diff --git a/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java b/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
index 304d5a2c9..a0b1224ee 100644
--- a/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
+++ b/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
@@ -16,15 +16,22 @@
package com.android.bluetooth.avrcpcontroller;
+import android.app.PendingIntent;
+import android.content.Intent;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
import android.os.Bundle;
-import android.service.media.MediaBrowserService;
+import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
+import androidx.media.MediaBrowserServiceCompat;
+
+import com.android.bluetooth.BluetoothPrefs;
import com.android.bluetooth.R;
import java.util.ArrayList;
@@ -37,45 +44,48 @@ import java.util.List;
* The applications are expected to use MediaBrowser (see API) and all the music
* browsing/playback/metadata can be controlled via MediaBrowser and MediaController.
*
- * The current behavior of MediaSession exposed by this service is as follows:
- * 1. MediaSession is active (i.e. SystemUI and other overview UIs can see updates) when device is
- * connected and first starts playing. Before it starts playing we do not active the session.
+ * The current behavior of MediaSessionCompat exposed by this service is as follows:
+ * 1. MediaSessionCompat is active (i.e. SystemUI and other overview UIs can see updates) when
+ * device is connected and first starts playing. Before it starts playing we do not activate the
+ * session.
* 1.1 The session is active throughout the duration of connection.
* 2. The session is de-activated when the device disconnects. It will be connected again when (1)
* happens.
*/
-public class BluetoothMediaBrowserService extends MediaBrowserService {
+public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
private static final String TAG = "BluetoothMediaBrowserService";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;
- private MediaSession mSession;
+ private MediaSessionCompat mSession;
// Browsing related structures.
- private List<MediaSession.QueueItem> mMediaQueue = new ArrayList<>();
+ private List<MediaSessionCompat.QueueItem> mMediaQueue = new ArrayList<>();
+
+ // Error messaging extras
+ public static final String ERROR_RESOLUTION_ACTION_INTENT =
+ "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+ public static final String ERROR_RESOLUTION_ACTION_LABEL =
+ "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
/**
- * Initialize this BluetoothMediaBrowserService, creating our MediaSession, MediaPlayer and
- * MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
+ * Initialize this BluetoothMediaBrowserService, creating our MediaSessionCompat, MediaPlayer
+ * and MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
*/
@Override
public void onCreate() {
if (DBG) Log.d(TAG, "onCreate");
super.onCreate();
- // Create and configure the MediaSession
- mSession = new MediaSession(this, TAG);
+ // Create and configure the MediaSessionCompat
+ mSession = new MediaSessionCompat(this, TAG);
setSessionToken(mSession.getSessionToken());
- mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
- | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+ | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mSession.setQueueTitle(getString(R.string.bluetooth_a2dp_sink_queue_name));
mSession.setQueue(mMediaQueue);
- PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder();
- playbackStateBuilder.setState(PlaybackState.STATE_ERROR,
- PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f).setActions(0);
- playbackStateBuilder.setErrorMessage(getString(R.string.bluetooth_disconnected));
- mSession.setPlaybackState(playbackStateBuilder.build());
+ setErrorPlaybackState();
sBluetoothMediaBrowserService = this;
}
@@ -89,11 +99,30 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
}
}
+ private void setErrorPlaybackState() {
+ Bundle extras = new Bundle();
+ extras.putString(ERROR_RESOLUTION_ACTION_LABEL,
+ getString(R.string.bluetooth_connect_action));
+ Intent launchIntent = new Intent();
+ launchIntent.setAction(BluetoothPrefs.BLUETOOTH_SETTING_ACTION);
+ launchIntent.addCategory(BluetoothPrefs.BLUETOOTH_SETTING_CATEGORY);
+ PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
+ launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ extras.putParcelable(ERROR_RESOLUTION_ACTION_INTENT, pendingIntent);
+ PlaybackStateCompat errorState = new PlaybackStateCompat.Builder()
+ .setErrorMessage(getString(R.string.bluetooth_disconnected))
+ .setExtras(extras)
+ .setState(PlaybackStateCompat.STATE_ERROR, 0, 0)
+ .build();
+ mSession.setPlaybackState(errorState);
+ }
+
@Override
public synchronized void onLoadChildren(final String parentMediaId,
- final Result<List<MediaItem>> result) {
+ final Result<List<MediaBrowserCompat.MediaItem>> result) {
if (DBG) Log.d(TAG, "onLoadChildren parentMediaId=" + parentMediaId);
- List<MediaItem> contents = getContents(parentMediaId);
+ List<MediaBrowserCompat.MediaItem> contents =
+ MediaBrowserCompat.MediaItem.fromMediaItemList(getContents(parentMediaId));
if (contents == null) {
result.detach();
} else {
@@ -112,7 +141,8 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
mMediaQueue.clear();
if (songList != null) {
for (MediaItem song : songList) {
- mMediaQueue.add(new MediaSession.QueueItem(song.getDescription(),
+ mMediaQueue.add(new MediaSessionCompat.QueueItem(
+ MediaDescriptionCompat.fromMediaDescription(song.getDescription()),
mMediaQueue.size()));
}
}
@@ -129,8 +159,11 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
}
}
- static synchronized void addressedPlayerChanged(MediaSession.Callback callback) {
+ static synchronized void addressedPlayerChanged(MediaSessionCompat.Callback callback) {
if (sBluetoothMediaBrowserService != null) {
+ if (callback == null) {
+ sBluetoothMediaBrowserService.setErrorPlaybackState();
+ }
sBluetoothMediaBrowserService.mSession.setCallback(callback);
} else {
Log.w(TAG, "addressedPlayerChanged Unavailable");
@@ -139,13 +172,14 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
static synchronized void trackChanged(MediaMetadata mediaMetadata) {
if (sBluetoothMediaBrowserService != null) {
- sBluetoothMediaBrowserService.mSession.setMetadata(mediaMetadata);
+ sBluetoothMediaBrowserService.mSession.setMetadata(
+ MediaMetadataCompat.fromMediaMetadata(mediaMetadata));
} else {
Log.w(TAG, "trackChanged Unavailable");
}
}
- static synchronized void notifyChanged(PlaybackState playbackState) {
+ static synchronized void notifyChanged(PlaybackStateCompat playbackState) {
Log.d(TAG, "notifyChanged PlaybackState" + playbackState);
if (sBluetoothMediaBrowserService != null) {
sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState);
@@ -181,19 +215,19 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
*/
public static synchronized int getPlaybackState() {
if (sBluetoothMediaBrowserService != null) {
- PlaybackState currentPlaybackState =
+ PlaybackStateCompat currentPlaybackState =
sBluetoothMediaBrowserService.mSession.getController().getPlaybackState();
if (currentPlaybackState != null) {
return currentPlaybackState.getState();
}
}
- return PlaybackState.STATE_ERROR;
+ return PlaybackStateCompat.STATE_ERROR;
}
/**
* Get object for controlling playback
*/
- public static synchronized MediaController.TransportControls getTransportControls() {
+ public static synchronized MediaControllerCompat.TransportControls getTransportControls() {
if (sBluetoothMediaBrowserService != null) {
return sBluetoothMediaBrowserService.mSession.getController().getTransportControls();
} else {
@@ -212,4 +246,16 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
Log.w(TAG, "setActive Unavailable");
}
}
+
+ /**
+ * Get Media session for updating state
+ */
+ public static synchronized MediaSessionCompat getSession() {
+ if (sBluetoothMediaBrowserService != null) {
+ return sBluetoothMediaBrowserService.mSession;
+ } else {
+ Log.w(TAG, "getSession Unavailable");
+ return null;
+ }
+ }
}
diff --git a/src/com/android/bluetooth/avrcpcontroller/BrowseTree.java b/src/com/android/bluetooth/avrcpcontroller/BrowseTree.java
index accea2a70..923282d34 100644
--- a/src/com/android/bluetooth/avrcpcontroller/BrowseTree.java
+++ b/src/com/android/bluetooth/avrcpcontroller/BrowseTree.java
@@ -100,7 +100,7 @@ public class BrowseTree {
}
BrowseNode getTrackFromNowPlayingList(int trackNumber) {
- return mNowPlayingNode.mChildren.get(trackNumber);
+ return mNowPlayingNode.getChild(trackNumber);
}
// Each node of the tree is represented by Folder ID, Folder Name and the children.
@@ -218,6 +218,13 @@ public class BrowseTree {
return mChildren;
}
+ synchronized BrowseNode getChild(int index) {
+ if (index < 0 || index >= mChildren.size()) {
+ return null;
+ }
+ return mChildren.get(index);
+ }
+
synchronized BrowseNode getParent() {
return mParent;
}
diff --git a/src/com/android/bluetooth/avrcpcontroller/PlayerApplicationSettings.java b/src/com/android/bluetooth/avrcpcontroller/PlayerApplicationSettings.java
index c34a2d7d0..362548e5f 100644
--- a/src/com/android/bluetooth/avrcpcontroller/PlayerApplicationSettings.java
+++ b/src/com/android/bluetooth/avrcpcontroller/PlayerApplicationSettings.java
@@ -16,12 +16,11 @@
package com.android.bluetooth.avrcpcontroller;
-import android.bluetooth.BluetoothAvrcpPlayerSettings;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
+import android.util.SparseArray;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
/*
* Contains information Player Application Setting extended from BluetootAvrcpPlayerSettings
@@ -32,10 +31,10 @@ class PlayerApplicationSettings {
/*
* Values for SetPlayerApplicationSettings from AVRCP Spec V1.6 Appendix F.
*/
- private static final byte JNI_ATTRIB_EQUALIZER_STATUS = 0x01;
- private static final byte JNI_ATTRIB_REPEAT_STATUS = 0x02;
- private static final byte JNI_ATTRIB_SHUFFLE_STATUS = 0x03;
- private static final byte JNI_ATTRIB_SCAN_STATUS = 0x04;
+ static final byte EQUALIZER_STATUS = 0x01;
+ static final byte REPEAT_STATUS = 0x02;
+ static final byte SHUFFLE_STATUS = 0x03;
+ static final byte SCAN_STATUS = 0x04;
private static final byte JNI_EQUALIZER_STATUS_OFF = 0x01;
private static final byte JNI_EQUALIZER_STATUS_ON = 0x02;
@@ -55,18 +54,17 @@ class PlayerApplicationSettings {
private static final byte JNI_STATUS_INVALID = -1;
-
/*
* Hash map of current settings.
*/
- private Map<Integer, Integer> mSettings = new HashMap<Integer, Integer>();
+ private SparseArray<Integer> mSettings = new SparseArray<>();
/*
* Hash map of supported values, a setting should be supported by the remote in order to enable
* in mSettings.
*/
- private Map<Integer, ArrayList<Integer>> mSupportedValues =
- new HashMap<Integer, ArrayList<Integer>>();
+ private SparseArray<ArrayList<Integer>> mSupportedValues =
+ new SparseArray<ArrayList<Integer>>();
/* Convert from JNI array to Java classes. */
static PlayerApplicationSettings makeSupportedSettings(byte[] btAvrcpAttributeList) {
@@ -82,8 +80,7 @@ class PlayerApplicationSettings {
supportedValues.add(
mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++]));
}
- newObj.mSupportedValues.put(mapBTAttribIdToAvrcpPlayerSettings(attrId),
- supportedValues);
+ newObj.mSupportedValues.put(attrId, supportedValues);
}
} catch (ArrayIndexOutOfBoundsException exception) {
Log.e(TAG, "makeSupportedSettings attributeList index error.");
@@ -91,25 +88,13 @@ class PlayerApplicationSettings {
return newObj;
}
- public BluetoothAvrcpPlayerSettings getAvrcpSettings() {
- int supportedSettings = 0;
- for (Integer setting : mSettings.keySet()) {
- supportedSettings |= setting;
- }
- BluetoothAvrcpPlayerSettings result = new BluetoothAvrcpPlayerSettings(supportedSettings);
- for (Integer setting : mSettings.keySet()) {
- result.addSettingValue(setting, mSettings.get(setting));
- }
- return result;
- }
-
static PlayerApplicationSettings makeSettings(byte[] btAvrcpAttributeList) {
PlayerApplicationSettings newObj = new PlayerApplicationSettings();
try {
for (int i = 0; i < btAvrcpAttributeList.length; ) {
byte attrId = btAvrcpAttributeList[i++];
- newObj.mSettings.put(mapBTAttribIdToAvrcpPlayerSettings(attrId),
+ newObj.mSettings.put(attrId,
mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++]));
}
} catch (ArrayIndexOutOfBoundsException exception) {
@@ -123,177 +108,69 @@ class PlayerApplicationSettings {
mSupportedValues = updates.mSupportedValues;
}
- public void setValues(BluetoothAvrcpPlayerSettings updates) {
- int supportedSettings = updates.getSettings();
- for (int i = 1; i <= BluetoothAvrcpPlayerSettings.SETTING_SCAN; i++) {
- if ((i & supportedSettings) > 0) {
- mSettings.put(i, updates.getSettingValue(i));
- }
- }
+ public boolean supportsSetting(int settingType, int settingValue) {
+ if (null == mSupportedValues.get(settingType)) return false;
+ return mSupportedValues.valueAt(settingType).contains(settingValue);
}
- /*
- * Check through all settings to ensure that they are all available to be set and then check
- * that the desired value is in fact supported by our remote player.
- */
- public boolean supportsSettings(BluetoothAvrcpPlayerSettings settingsToCheck) {
- int settingSubset = settingsToCheck.getSettings();
- int supportedSettings = 0;
- for (Integer setting : mSupportedValues.keySet()) {
- supportedSettings |= setting;
- }
- try {
- if ((supportedSettings & settingSubset) == settingSubset) {
- for (Integer settingId : mSettings.keySet()) {
- // The setting is in both settings to check and supported settings but the
- // value is not supported.
- if ((settingId & settingSubset) == settingId && (!mSupportedValues.get(
- settingId).contains(settingsToCheck.getSettingValue(settingId)))) {
- return false;
- }
- }
- return true;
- }
- } catch (NullPointerException e) {
- Log.e(TAG,
- "supportsSettings received a supported setting that has no supported values.");
- }
- return false;
+ public boolean supportsSetting(int settingType) {
+ return (null != mSupportedValues.get(settingType));
}
- // Convert currently desired settings into an attribute array to pass to the native layer to
- // enable them.
- public ArrayList<Byte> getNativeSettings() {
- int i = 0;
- ArrayList<Byte> attribArray = new ArrayList<Byte>();
- for (Integer settingId : mSettings.keySet()) {
- switch (settingId) {
- case BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER:
- attribArray.add(JNI_ATTRIB_EQUALIZER_STATUS);
- attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId,
- mSettings.get(settingId)));
- break;
- case BluetoothAvrcpPlayerSettings.SETTING_REPEAT:
- attribArray.add(JNI_ATTRIB_REPEAT_STATUS);
- attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId,
- mSettings.get(settingId)));
- break;
- case BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE:
- attribArray.add(JNI_ATTRIB_SHUFFLE_STATUS);
- attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId,
- mSettings.get(settingId)));
- break;
- case BluetoothAvrcpPlayerSettings.SETTING_SCAN:
- attribArray.add(JNI_ATTRIB_SCAN_STATUS);
- attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId,
- mSettings.get(settingId)));
- break;
- default:
- Log.w(TAG, "Unknown setting found in getNativeSettings: " + settingId);
- }
- }
- return attribArray;
+ public int getSetting(int settingType) {
+ if (null == mSettings.get(settingType)) return -1;
+ return mSettings.get(settingType);
}
// Convert a native Attribute Id/Value pair into the AVRCP equivalent value.
private static int mapAttribIdValtoAvrcpPlayerSetting(byte attribId, byte attribVal) {
- if (attribId == JNI_ATTRIB_EQUALIZER_STATUS) {
- switch (attribVal) {
- case JNI_EQUALIZER_STATUS_OFF:
- return BluetoothAvrcpPlayerSettings.STATE_OFF;
- case JNI_EQUALIZER_STATUS_ON:
- return BluetoothAvrcpPlayerSettings.STATE_ON;
- }
- } else if (attribId == JNI_ATTRIB_REPEAT_STATUS) {
+ if (attribId == REPEAT_STATUS) {
switch (attribVal) {
case JNI_REPEAT_STATUS_ALL_TRACK_REPEAT:
- return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
+ return PlaybackStateCompat.REPEAT_MODE_ALL;
case JNI_REPEAT_STATUS_GROUP_REPEAT:
- return BluetoothAvrcpPlayerSettings.STATE_GROUP;
+ return PlaybackStateCompat.REPEAT_MODE_GROUP;
case JNI_REPEAT_STATUS_OFF:
- return BluetoothAvrcpPlayerSettings.STATE_OFF;
+ return PlaybackStateCompat.REPEAT_MODE_NONE;
case JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT:
- return BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK;
- }
- } else if (attribId == JNI_ATTRIB_SCAN_STATUS) {
- switch (attribVal) {
- case JNI_SCAN_STATUS_ALL_TRACK_SCAN:
- return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
- case JNI_SCAN_STATUS_GROUP_SCAN:
- return BluetoothAvrcpPlayerSettings.STATE_GROUP;
- case JNI_SCAN_STATUS_OFF:
- return BluetoothAvrcpPlayerSettings.STATE_OFF;
+ return PlaybackStateCompat.REPEAT_MODE_ONE;
}
- } else if (attribId == JNI_ATTRIB_SHUFFLE_STATUS) {
+ } else if (attribId == SHUFFLE_STATUS) {
switch (attribVal) {
case JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE:
- return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
+ return PlaybackStateCompat.SHUFFLE_MODE_ALL;
case JNI_SHUFFLE_STATUS_GROUP_SHUFFLE:
- return BluetoothAvrcpPlayerSettings.STATE_GROUP;
+ return PlaybackStateCompat.SHUFFLE_MODE_GROUP;
case JNI_SHUFFLE_STATUS_OFF:
- return BluetoothAvrcpPlayerSettings.STATE_OFF;
+ return PlaybackStateCompat.SHUFFLE_MODE_NONE;
}
}
- return BluetoothAvrcpPlayerSettings.STATE_INVALID;
+ return JNI_STATUS_INVALID;
}
// Convert an AVRCP Setting/Value pair into the native equivalent value;
- private static byte mapAvrcpPlayerSettingstoBTattribVal(int mSetting, int mSettingVal) {
- if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER) {
- switch (mSettingVal) {
- case BluetoothAvrcpPlayerSettings.STATE_OFF:
- return JNI_EQUALIZER_STATUS_OFF;
- case BluetoothAvrcpPlayerSettings.STATE_ON:
- return JNI_EQUALIZER_STATUS_ON;
- }
- } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_REPEAT) {
+ static byte mapAvrcpPlayerSettingstoBTattribVal(int mSetting, int mSettingVal) {
+ if (mSetting == REPEAT_STATUS) {
switch (mSettingVal) {
- case BluetoothAvrcpPlayerSettings.STATE_OFF:
+ case PlaybackStateCompat.REPEAT_MODE_NONE:
return JNI_REPEAT_STATUS_OFF;
- case BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK:
+ case PlaybackStateCompat.REPEAT_MODE_ONE:
return JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT;
- case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
+ case PlaybackStateCompat.REPEAT_MODE_ALL:
return JNI_REPEAT_STATUS_ALL_TRACK_REPEAT;
- case BluetoothAvrcpPlayerSettings.STATE_GROUP:
+ case PlaybackStateCompat.REPEAT_MODE_GROUP:
return JNI_REPEAT_STATUS_GROUP_REPEAT;
}
- } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE) {
+ } else if (mSetting == SHUFFLE_STATUS) {
switch (mSettingVal) {
- case BluetoothAvrcpPlayerSettings.STATE_OFF:
+ case PlaybackStateCompat.SHUFFLE_MODE_NONE:
return JNI_SHUFFLE_STATUS_OFF;
- case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
+ case PlaybackStateCompat.SHUFFLE_MODE_ALL:
return JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE;
- case BluetoothAvrcpPlayerSettings.STATE_GROUP:
+ case PlaybackStateCompat.SHUFFLE_MODE_GROUP:
return JNI_SHUFFLE_STATUS_GROUP_SHUFFLE;
}
- } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SCAN) {
- switch (mSettingVal) {
- case BluetoothAvrcpPlayerSettings.STATE_OFF:
- return JNI_SCAN_STATUS_OFF;
- case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
- return JNI_SCAN_STATUS_ALL_TRACK_SCAN;
- case BluetoothAvrcpPlayerSettings.STATE_GROUP:
- return JNI_SCAN_STATUS_GROUP_SCAN;
- }
}
return JNI_STATUS_INVALID;
}
-
- // convert a native Attribute Id into the AVRCP Setting equivalent value;
- private static int mapBTAttribIdToAvrcpPlayerSettings(byte attribId) {
- switch (attribId) {
- case JNI_ATTRIB_EQUALIZER_STATUS:
- return BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER;
- case JNI_ATTRIB_REPEAT_STATUS:
- return BluetoothAvrcpPlayerSettings.SETTING_REPEAT;
- case JNI_ATTRIB_SHUFFLE_STATUS:
- return BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE;
- case JNI_ATTRIB_SCAN_STATUS:
- return BluetoothAvrcpPlayerSettings.SETTING_SCAN;
- default:
- return BluetoothAvrcpPlayerSettings.STATE_INVALID;
- }
- }
-
}
-
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 009e42cef..a65bcfdf9 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -1559,7 +1559,6 @@ public class AdapterService extends Service {
if (service == null) {
return false;
}
- service.disable();
return service.factoryReset();
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 989043a7d..e92688f8c 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -1196,6 +1196,21 @@ public class HeadsetStateMachine extends StateMachine {
}
}
+ class MyAudioServerStateCallback extends AudioManager.AudioServerStateCallback {
+ @Override
+ public void onAudioServerDown() {
+ logi("onAudioServerDown");
+ }
+
+ @Override
+ public void onAudioServerUp() {
+ logi("onAudioServerUp restoring audio parameters");
+ setAudioParameters();
+ }
+ }
+
+ MyAudioServerStateCallback mAudioServerStateCallback = new MyAudioServerStateCallback();
+
class AudioOn extends ConnectedBase {
@Override
int getAudioStateInt() {
@@ -1214,10 +1229,21 @@ public class HeadsetStateMachine extends StateMachine {
mHeadsetService.setActiveDevice(mDevice);
}
setAudioParameters();
+
+ mSystemInterface.getAudioManager().setAudioServerStateCallback(
+ mHeadsetService.getMainExecutor(), mAudioServerStateCallback);
+
broadcastStateTransitions();
}
@Override
+ public void exit() {
+ super.exit();
+
+ mSystemInterface.getAudioManager().clearAudioServerStateCallback();
+ }
+
+ @Override
public boolean processMessage(Message message) {
switch (message.what) {
case CONNECT: {
diff --git a/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java b/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
index 05af73e08..b567371f1 100644
--- a/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
+++ b/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
@@ -224,7 +224,7 @@ public class HfpClientDeviceBlock {
if (DBG) {
Log.d(mTAG, "prevConn " + prevConn.isClosing() + " new call " + newCall.getState());
}
- if (prevConn.isClosing()
+ if (prevConn.isClosing() && prevConn.getCall().getState() != newCall.getState()
&& newCall.getState() != BluetoothHeadsetClientCall.CALL_STATE_TERMINATED) {
return true;
}
diff --git a/src/com/android/bluetooth/mapclient/MceStateMachine.java b/src/com/android/bluetooth/mapclient/MceStateMachine.java
index 0a428b418..9b86aaef1 100644
--- a/src/com/android/bluetooth/mapclient/MceStateMachine.java
+++ b/src/com/android/bluetooth/mapclient/MceStateMachine.java
@@ -42,7 +42,6 @@ package com.android.bluetooth.mapclient;
import android.app.Activity;
import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothProfile;
@@ -59,6 +58,7 @@ import android.util.Log;
import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.map.BluetoothMapbMessageMime;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IState;
import com.android.internal.util.State;
@@ -69,7 +69,6 @@ import com.android.vcard.VCardProperty;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -347,7 +346,9 @@ final class MceStateMachine extends StateMachine {
void setDefaultMessageType(SdpMasRecord sdpMasRecord) {
int supportedMessageTypes = sdpMasRecord.getSupportedMessageTypes();
synchronized (mDefaultMessageType) {
- if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_CDMA) > 0) {
+ if ((supportedMessageTypes & SdpMasRecord.MessageType.MMS) > 0) {
+ mDefaultMessageType = Bmessage.Type.MMS;
+ } else if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_CDMA) > 0) {
mDefaultMessageType = Bmessage.Type.SMS_CDMA;
} else if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_GSM) > 0) {
mDefaultMessageType = Bmessage.Type.SMS_GSM;
@@ -473,6 +474,11 @@ final class MceStateMachine extends StateMachine {
}
break;
+ case MSG_MAS_DISCONNECTED:
+ deferMessage(message);
+ transitionTo(mDisconnecting);
+ break;
+
case MSG_OUTBOUND_MESSAGE:
mMasClient.makeRequest(
new RequestPushMessage(FOLDER_OUTBOX, (Bmessage) message.obj, null,
@@ -625,9 +631,12 @@ final class MceStateMachine extends StateMachine {
}
ArrayList<com.android.bluetooth.mapclient.Message> messageListing = request.getList();
if (messageListing != null) {
- for (com.android.bluetooth.mapclient.Message msg : messageListing) {
+ // Message listings by spec arrive ordered newest first but we wish to broadcast as
+ // oldest first. Iterate in reverse order so we initiate requests oldest first.
+ for (int i = messageListing.size() - 1; i >= 0; i--) {
+ com.android.bluetooth.mapclient.Message msg = messageListing.get(i);
if (DBG) {
- Log.d(TAG, "getting message ");
+ Log.d(TAG, "getting message for handle " + msg.getHandle());
}
// A message listing coming from the server should always have up to date data
mMessages.put(msg.getHandle(), new MessageMetadata(msg.getHandle(),
@@ -665,6 +674,7 @@ final class MceStateMachine extends StateMachine {
switch (message.getType()) {
case SMS_CDMA:
case SMS_GSM:
+ case MMS:
if (DBG) {
Log.d(TAG, "Body: " + message.getBodyContent());
}
@@ -705,6 +715,12 @@ final class MceStateMachine extends StateMachine {
intent.putExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME,
originator.getDisplayName());
}
+ if (message.getType() == Bmessage.Type.MMS) {
+ BluetoothMapbMessageMime mmsBmessage = new BluetoothMapbMessageMime();
+ mmsBmessage.parseMsgPart(message.getBodyContent());
+ intent.putExtra(android.content.Intent.EXTRA_TEXT,
+ mmsBmessage.getMessageAsText());
+ }
// Only send to the current default SMS app if one exists
String defaultMessagingPackage = Telephony.Sms.getDefaultSmsPackage(mService);
if (defaultMessagingPackage != null) {
@@ -712,8 +728,6 @@ final class MceStateMachine extends StateMachine {
}
mService.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS);
break;
-
- case MMS:
case EMAIL:
default:
Log.e(TAG, "Received unhandled type" + message.getType().toString());
diff --git a/src/com/android/bluetooth/mapclient/MnsObexServer.java b/src/com/android/bluetooth/mapclient/MnsObexServer.java
index 53cd79bb2..33ba1ea74 100644
--- a/src/com/android/bluetooth/mapclient/MnsObexServer.java
+++ b/src/com/android/bluetooth/mapclient/MnsObexServer.java
@@ -90,6 +90,10 @@ class MnsObexServer extends ServerRequestHandler {
if (VDBG) {
Log.v(TAG, "onDisconnect");
}
+ MceStateMachine currentStateMachine = mStateMachineReference.get();
+ if (currentStateMachine != null) {
+ currentStateMachine.disconnect();
+ }
}
@Override
diff --git a/src/com/android/bluetooth/mapclient/MnsService.java b/src/com/android/bluetooth/mapclient/MnsService.java
index c1ab39e00..b3317df90 100644
--- a/src/com/android/bluetooth/mapclient/MnsService.java
+++ b/src/com/android/bluetooth/mapclient/MnsService.java
@@ -17,6 +17,7 @@
package com.android.bluetooth.mapclient;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
@@ -129,6 +130,11 @@ public class MnsService {
Log.e(TAG, "Error: NO statemachine for device: " + device.getAddress()
+ " (name: " + device.getName());
return false;
+ } else if (stateMachine.getState() != BluetoothProfile.STATE_CONNECTED) {
+ Log.e(TAG, "Error: statemachine for device: " + device.getAddress()
+ + " (name: " + device.getName() + ") is not currently CONNECTED : "
+ + stateMachine.getCurrentState());
+ return false;
}
MnsObexServer srv = new MnsObexServer(stateMachine, sServerSockets);
BluetoothObexTransport transport = new BluetoothObexTransport(socket);
diff --git a/src/com/android/bluetooth/mapclient/obex/BmessageParser.java b/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
index 2705e3429..5b844dce5 100644
--- a/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
+++ b/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
@@ -309,6 +309,12 @@ class BmessageParser {
String remng = mParser.remaining();
byte[] data = remng.getBytes();
+ if (offset < 0 || offset > data.length) {
+ /* Handle possible exception for incorrect LENGTH value
+ * from MSE while parsing end of props */
+ throw new ParseException("Invalid LENGTH value", mParser.pos());
+ }
+
/* restart parsing from after 'message'<CRLF> */
mParser = new BmsgTokenizer(new String(data, offset, data.length - offset), restartPos);
diff --git a/src/com/android/bluetooth/mapclient/obex/ObexTime.java b/src/com/android/bluetooth/mapclient/obex/ObexTime.java
index 42a32c10f..cc58a5144 100644
--- a/src/com/android/bluetooth/mapclient/obex/ObexTime.java
+++ b/src/com/android/bluetooth/mapclient/obex/ObexTime.java
@@ -29,8 +29,17 @@ public final class ObexTime {
public ObexTime(String time) {
/*
- * match OBEX time string: YYYYMMDDTHHMMSS with optional UTF offset
- * +/-hhmm
+ * Match OBEX time string: YYYYMMDDTHHMMSS with optional UTF offset +/-hhmm
+ *
+ * Matched groups are numberes as follows:
+ *
+ * YYYY MM DD T HH MM SS + hh mm
+ * ^^^^ ^^ ^^ ^^ ^^ ^^ ^ ^^ ^^
+ * 1 2 3 4 5 6 8 9 10
+ * |---7---|
+ *
+ * All groups are guaranteed to be numeric so conversion will always succeed (except group 8
+ * which is either + or -)
*/
Pattern p = Pattern.compile(
"(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})(([+-])(\\d{2})(\\d{2})" + ")?");
@@ -39,20 +48,26 @@ public final class ObexTime {
if (m.matches()) {
/*
- * matched groups are numberes as follows: YYYY MM DD T HH MM SS +
- * hh mm ^^^^ ^^ ^^ ^^ ^^ ^^ ^ ^^ ^^ 1 2 3 4 5 6 8 9 10 all groups
- * are guaranteed to be numeric so conversion will always succeed
- * (except group 8 which is either + or -)
+ * MAP spec says to default to "Local Time basis" for a message listing timestamp. We'll
+ * use the system default timezone and assume it knows best what our local timezone is.
+ * The builder defaults to the default locale and timezone if none is provided.
*/
+ Calendar.Builder builder = new Calendar.Builder();
- Calendar cal = Calendar.getInstance();
- cal.set(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)) - 1,
- Integer.parseInt(m.group(3)), Integer.parseInt(m.group(4)),
- Integer.parseInt(m.group(5)), Integer.parseInt(m.group(6)));
+ /* Note that Calendar months are zero-based */
+ builder.setDate(Integer.parseInt(m.group(1)), /* year */
+ Integer.parseInt(m.group(2)) - 1, /* month */
+ Integer.parseInt(m.group(3))); /* day of month */
+
+ /* Note the MAP timestamp doesn't have milliseconds and we're explicitly setting to 0 */
+ builder.setTimeOfDay(Integer.parseInt(m.group(4)), /* hours */
+ Integer.parseInt(m.group(5)), /* minutes */
+ Integer.parseInt(m.group(6)), /* seconds */
+ 0); /* milliseconds */
/*
- * if 7th group is matched then we have UTC offset information
- * included
+ * If 7th group is matched then we're no longer using "Local Time basis" and instead
+ * have a UTC based timestamp and offset information included
*/
if (m.group(7) != null) {
int ohh = Integer.parseInt(m.group(9));
@@ -68,10 +83,10 @@ public final class ObexTime {
TimeZone tz = TimeZone.getTimeZone("UTC");
tz.setRawOffset(offset);
- cal.setTimeZone(tz);
+ builder.setTimeZone(tz);
}
- mDate = cal.getTime();
+ mDate = builder.build().getTime();
}
}
diff --git a/src/com/android/bluetooth/pan/PanService.java b/src/com/android/bluetooth/pan/PanService.java
index aa5a1fd31..92eab7787 100644
--- a/src/com/android/bluetooth/pan/PanService.java
+++ b/src/com/android/bluetooth/pan/PanService.java
@@ -40,6 +40,7 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
+import com.android.internal.annotations.VisibleForTesting;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -67,6 +68,9 @@ public class PanService extends ProfileService {
private String mNapIfaceAddr;
private boolean mNativeAvailable;
+ @VisibleForTesting
+ UserManager mUserManager;
+
private static final int MESSAGE_CONNECT = 1;
private static final int MESSAGE_DISCONNECT = 2;
private static final int MESSAGE_CONNECT_STATE_CHANGED = 11;
@@ -116,6 +120,8 @@ public class PanService extends ProfileService {
initializeNative();
mNativeAvailable = true;
+ mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
+
mNetworkFactory =
new BluetoothTetheringNetworkFactory(getBaseContext(), getMainLooper(), this);
setPanService(this);
@@ -137,6 +143,9 @@ public class PanService extends ProfileService {
cleanupNative();
mNativeAvailable = false;
}
+
+ mUserManager = null;
+
if (mPanDevices != null) {
int[] desiredStates = {BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_DISCONNECTING};
@@ -319,6 +328,10 @@ public class PanService extends ProfileService {
public boolean connect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (mUserManager.isGuestUser()) {
+ Log.w(TAG, "Guest user does not have the permission to change the WiFi network");
+ return false;
+ }
if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
Log.e(TAG, "Pan Device not disconnected: " + device);
return false;
diff --git a/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java b/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java
index 34ab7d52c..a5b3fbfea 100644
--- a/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java
+++ b/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java
@@ -73,7 +73,7 @@ final class BluetoothPbapRequestPullPhoneBook extends BluetoothPbapRequest {
oap.add(OAP_TAGID_FORMAT, format);
/*
- * maxListCount is a special case which is handled in
+ * maxListCount == 0 is a special case which is handled in
* BluetoothPbapRequestPullPhoneBookSize
*/
if (maxListCount > 0) {
diff --git a/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java b/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java
new file mode 100644
index 000000000..f0706610f
--- /dev/null
+++ b/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.util.Log;
+
+import javax.obex.HeaderSet;
+
+final class BluetoothPbapRequestPullPhoneBookSize extends BluetoothPbapRequest {
+
+ private static final boolean VDBG = Utils.VDBG;
+
+ private static final String TAG = "BtPbapReqPullPhoneBookSize";
+
+ private static final String TYPE = "x-bt/phonebook";
+
+ private int mSize;
+
+ BluetoothPbapRequestPullPhoneBookSize(String pbName, long filter) {
+ mHeaderSet.setHeader(HeaderSet.NAME, pbName);
+
+ mHeaderSet.setHeader(HeaderSet.TYPE, TYPE);
+
+ ObexAppParameters oap = new ObexAppParameters();
+ // Set MaxListCount in the request to 0 to get PhonebookSize in the response.
+ // If a vCardSelector is present in the request, then the result shall
+ // contain the number of items that satisfy the selector’s criteria.
+ // See PBAP v1.2.3, Sec. 5.1.4.5.
+ oap.add(OAP_TAGID_MAX_LIST_COUNT, (short) 0);
+ if (filter != 0) {
+ oap.add(OAP_TAGID_FILTER, filter);
+ }
+ oap.addToHeaderSet(mHeaderSet);
+ }
+
+ @Override
+ protected void readResponseHeaders(HeaderSet headerset) {
+ if (VDBG) {
+ Log.v(TAG, "readResponseHeaders");
+ }
+
+ ObexAppParameters oap = ObexAppParameters.fromHeaderSet(headerset);
+
+ if (oap.exists(OAP_TAGID_PHONEBOOK_SIZE)) {
+ mSize = oap.getShort(OAP_TAGID_PHONEBOOK_SIZE);
+ }
+ }
+
+ public int getSize() {
+ return mSize;
+ }
+}
diff --git a/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java b/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java
index 914b5b163..4e4a240f1 100644
--- a/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java
+++ b/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java
@@ -32,8 +32,10 @@ import android.util.Log;
import com.android.bluetooth.BluetoothObexTransport;
import com.android.bluetooth.R;
+import com.android.vcard.VCardEntry;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import javax.obex.ClientSession;
@@ -46,6 +48,15 @@ import javax.obex.ResponseCodes;
* controlling state machine.
*/
class PbapClientConnectionHandler extends Handler {
+ // Tradeoff: larger BATCH_SIZE leads to faster download rates, while smaller
+ // BATCH_SIZE is less prone to IO Exceptions if there is a download in
+ // progress when Bluetooth stack is torn down.
+ private static final int DEFAULT_BATCH_SIZE = 250;
+
+ // Upper limit on the indices of the vcf cards/entries, inclusive,
+ // i.e., valid indices are [0, 1, ... , UPPER_LIMIT]
+ private static final int UPPER_LIMIT = 65535;
+
static final String TAG = "PbapClientConnHandler";
static final boolean DBG = Utils.DBG;
static final boolean VDBG = Utils.VDBG;
@@ -88,16 +99,26 @@ class PbapClientConnectionHandler extends Handler {
private static final long PBAP_FILTER_NICKNAME = 1 << 23;
private static final int PBAP_SUPPORTED_FEATURE =
- PBAP_FEATURE_DEFAULT_IMAGE_FORMAT | PBAP_FEATURE_BROWSING | PBAP_FEATURE_DOWNLOADING;
+ PBAP_FEATURE_DEFAULT_IMAGE_FORMAT | PBAP_FEATURE_DOWNLOADING;
private static final long PBAP_REQUESTED_FIELDS =
PBAP_FILTER_VERSION | PBAP_FILTER_FN | PBAP_FILTER_N | PBAP_FILTER_PHOTO
| PBAP_FILTER_ADR | PBAP_FILTER_EMAIL | PBAP_FILTER_TEL | PBAP_FILTER_NICKNAME;
private static final int L2CAP_INVALID_PSM = -1;
public static final String PB_PATH = "telecom/pb.vcf";
+ public static final String FAV_PATH = "telecom/fav.vcf";
public static final String MCH_PATH = "telecom/mch.vcf";
public static final String ICH_PATH = "telecom/ich.vcf";
public static final String OCH_PATH = "telecom/och.vcf";
+ public static final String SIM_PB_PATH = "SIM1/telecom/pb.vcf";
+ public static final String SIM_MCH_PATH = "SIM1/telecom/mch.vcf";
+ public static final String SIM_ICH_PATH = "SIM1/telecom/ich.vcf";
+ public static final String SIM_OCH_PATH = "SIM1/telecom/och.vcf";
+
+ // PBAP v1.2.3 Sec. 7.1.2
+ private static final int SUPPORTED_REPOSITORIES_LOCALPHONEBOOK = 1 << 0;
+ private static final int SUPPORTED_REPOSITORIES_SIMCARD = 1 << 1;
+ private static final int SUPPORTED_REPOSITORIES_FAVORITES = 1 << 3;
public static final int PBAP_V1_2 = 0x0102;
public static final byte VCARD_TYPE_21 = 0;
@@ -239,29 +260,25 @@ class PbapClientConnectionHandler extends Handler {
break;
case MSG_DOWNLOAD:
- try {
- mAccountCreated = addAccount(mAccount);
- if (!mAccountCreated) {
- Log.e(TAG, "Account creation failed.");
- return;
- }
- // Start at contact 1 to exclued Owner Card PBAP 1.1 sec 3.1.5.2
- BluetoothPbapRequestPullPhoneBook request =
- new BluetoothPbapRequestPullPhoneBook(PB_PATH, mAccount,
- PBAP_REQUESTED_FIELDS, VCARD_TYPE_30, 0, 1);
- request.execute(mObexSession);
- PhonebookPullRequest processor =
- new PhonebookPullRequest(mPbapClientStateMachine.getContext(),
- mAccount);
- processor.setResults(request.getList());
- processor.onPullComplete();
- HashMap<String, Integer> callCounter = new HashMap<>();
- downloadCallLog(MCH_PATH, callCounter);
- downloadCallLog(ICH_PATH, callCounter);
- downloadCallLog(OCH_PATH, callCounter);
- } catch (IOException e) {
- Log.w(TAG, "DOWNLOAD_CONTACTS Failure" + e.toString());
+ mAccountCreated = addAccount(mAccount);
+ if (!mAccountCreated) {
+ Log.e(TAG, "Account creation failed.");
+ return;
}
+ if (isRepositorySupported(SUPPORTED_REPOSITORIES_FAVORITES)) {
+ downloadContacts(FAV_PATH);
+ }
+ if (isRepositorySupported(SUPPORTED_REPOSITORIES_LOCALPHONEBOOK)) {
+ downloadContacts(PB_PATH);
+ }
+ if (isRepositorySupported(SUPPORTED_REPOSITORIES_SIMCARD)) {
+ downloadContacts(SIM_PB_PATH);
+ }
+
+ HashMap<String, Integer> callCounter = new HashMap<>();
+ downloadCallLog(MCH_PATH, callCounter);
+ downloadCallLog(ICH_PATH, callCounter);
+ downloadCallLog(OCH_PATH, callCounter);
break;
default:
@@ -369,6 +386,59 @@ class PbapClientConnectionHandler extends Handler {
}
}
+ void downloadContacts(String path) {
+ try {
+ PhonebookPullRequest processor =
+ new PhonebookPullRequest(mPbapClientStateMachine.getContext(),
+ mAccount);
+
+ // Download contacts in batches of size DEFAULT_BATCH_SIZE
+ BluetoothPbapRequestPullPhoneBookSize requestPbSize =
+ new BluetoothPbapRequestPullPhoneBookSize(path,
+ PBAP_REQUESTED_FIELDS);
+ requestPbSize.execute(mObexSession);
+
+ int numberOfContactsRemaining = requestPbSize.getSize();
+ int startOffset = 0;
+ if (PB_PATH.equals(path)) {
+ // PBAP v1.2.3, Sec 3.1.5. The first contact in pb is owner card 0.vcf, which we
+ // do not want to download. The other phonebook objects (e.g., fav) don't have an
+ // owner card, so they don't need an offset.
+ startOffset = 1;
+ // "-1" because Owner Card 0.vcf is also included in /pb, but not in /fav.
+ numberOfContactsRemaining -= 1;
+ }
+
+ while ((numberOfContactsRemaining > 0) && (startOffset <= UPPER_LIMIT)) {
+ int numberOfContactsToDownload =
+ Math.min(Math.min(DEFAULT_BATCH_SIZE, numberOfContactsRemaining),
+ UPPER_LIMIT - startOffset + 1);
+ BluetoothPbapRequestPullPhoneBook request =
+ new BluetoothPbapRequestPullPhoneBook(path, mAccount,
+ PBAP_REQUESTED_FIELDS, VCARD_TYPE_30,
+ numberOfContactsToDownload, startOffset);
+ request.execute(mObexSession);
+ ArrayList<VCardEntry> vcards = request.getList();
+ if (path == FAV_PATH) {
+ // mark each vcard as a favorite
+ for (VCardEntry v : vcards) {
+ v.setStarred(true);
+ }
+ }
+ processor.setResults(vcards);
+ processor.onPullComplete();
+
+ startOffset += numberOfContactsToDownload;
+ numberOfContactsRemaining -= numberOfContactsToDownload;
+ }
+ if ((startOffset > UPPER_LIMIT) && (numberOfContactsRemaining > 0)) {
+ Log.w(TAG, "Download contacts incomplete, index exceeded upper limit.");
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Download contacts failure" + e.toString());
+ }
+ }
+
void downloadCallLog(String path, HashMap<String, Integer> callCounter) {
try {
BluetoothPbapRequestPullPhoneBook request =
@@ -419,4 +489,12 @@ class PbapClientConnectionHandler extends Handler {
Log.d(TAG, "Call Logs could not be deleted, they may not exist yet.");
}
}
+
+ private boolean isRepositorySupported(int mask) {
+ if (mPseRec == null) {
+ if (VDBG) Log.v(TAG, "No PBAP Server SDP Record");
+ return false;
+ }
+ return (mask & mPseRec.getSupportedRepositories()) != 0;
+ }
}
diff --git a/src/com/android/bluetooth/pbapclient/PbapClientService.java b/src/com/android/bluetooth/pbapclient/PbapClientService.java
index f150cddec..02b1e7a51 100644
--- a/src/com/android/bluetooth/pbapclient/PbapClientService.java
+++ b/src/com/android/bluetooth/pbapclient/PbapClientService.java
@@ -19,9 +19,11 @@ package com.android.bluetooth.pbapclient;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetoothPbapClient;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -31,6 +33,7 @@ import android.util.Log;
import com.android.bluetooth.R;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService;
import com.android.bluetooth.sdp.SdpManager;
import java.util.ArrayList;
@@ -71,6 +74,9 @@ public class PbapClientService extends ProfileService {
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
// delay initial download until after the user is unlocked to add an account.
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ // To remove call logs when PBAP was never connected while calls were made,
+ // we also listen for HFP to become disconnected.
+ filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
try {
registerReceiver(mPbapBroadcastReceiver, filter);
} catch (Exception e) {
@@ -128,6 +134,21 @@ public class PbapClientService extends ProfileService {
}
}
+ private void removeHfpCallLog(String accountName, Context context) {
+ if (DBG) Log.d(TAG, "Removing call logs from " + accountName);
+ // Delete call logs belonging to accountName==BD_ADDR that also match
+ // component name "hfpclient".
+ ComponentName componentName = new ComponentName(context, HfpClientConnectionService.class);
+ String selectionFilter = CallLog.Calls.PHONE_ACCOUNT_ID + "=? AND "
+ + CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME + "=?";
+ String[] selectionArgs = new String[]{accountName, componentName.flattenToString()};
+ try {
+ getContentResolver().delete(CallLog.Calls.CONTENT_URI, selectionFilter, selectionArgs);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
+ }
+ }
+
private void registerSdpRecord() {
SdpManager sdpManager = SdpManager.getDefaultManager();
if (sdpManager == null) {
@@ -171,6 +192,21 @@ public class PbapClientService extends ProfileService {
for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
stateMachine.resumeDownload();
}
+ } else if (action.equals(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED)) {
+ // PbapClientConnectionHandler has code to remove calllogs when PBAP disconnects.
+ // However, if PBAP was never connected/enabled in the first place, and calls are
+ // made over HFP, these calllogs will not be removed when the device disconnects.
+ // This code ensures callogs are still removed in this case.
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+
+ if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ if (DBG) {
+ Log.d(TAG, "Received intent to disconnect HFP with " + device);
+ }
+ // HFP client stores entries in calllog.db by BD_ADDR and component name
+ removeHfpCallLog(device.getAddress(), context);
+ }
}
}
}
diff --git a/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandlerTest.java b/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandlerTest.java
index c759a8a1f..b8fbbb9ef 100644
--- a/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandlerTest.java
+++ b/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandlerTest.java
@@ -195,6 +195,21 @@ public class A2dpSinkStreamHandlerTest {
}
@Test
+ public void testFocusRerequest() {
+ // Focus was lost transiently, expect streaming to stop.
+ testSnkPlay();
+ mStreamHandler.handleMessage(
+ mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT));
+ verify(mMockAudioManager, times(0)).abandonAudioFocus(any());
+ verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(0);
+ verify(mMockA2dpSink, times(1)).informAudioTrackGainNative(0);
+ mStreamHandler.handleMessage(
+ mStreamHandler.obtainMessage(A2dpSinkStreamHandler.REQUEST_FOCUS, true));
+ verify(mMockAudioManager, times(2)).requestAudioFocus(any());
+ }
+
+ @Test
public void testFocusGainTransient() {
// Focus was lost then regained.
testSnkPlay();
diff --git a/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java b/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
index 4fedc889a..907f0dcdc 100644
--- a/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
@@ -23,9 +23,11 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.media.AudioManager;
-import android.media.session.MediaController;
import android.os.Looper;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -34,6 +36,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
@@ -66,15 +69,23 @@ public class AvrcpControllerStateMachineTest {
private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class);
private byte[] mTestAddress = new byte[]{00, 01, 02, 03, 04, 05};
- @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
+ @Rule public final ServiceTestRule mAvrcpServiceRule = new ServiceTestRule();
+ @Rule public final ServiceTestRule mA2dpServiceRule = new ServiceTestRule();
@Mock
- private AdapterService mAdapterService;
+ private AdapterService mAvrcpAdapterService;
+
+ @Mock
+ private AdapterService mA2dpAdapterService;
+
@Mock
private AudioManager mAudioManager;
@Mock
private AvrcpControllerService mAvrcpControllerService;
+ @Mock
+ private Resources mMockResources;
+
AvrcpControllerStateMachine mAvrcpStateMachine;
@Before
@@ -90,9 +101,14 @@ public class AvrcpControllerStateMachineTest {
// Setup mocks and test assets
MockitoAnnotations.initMocks(this);
- TestUtils.setAdapterService(mAdapterService);
- TestUtils.startService(mServiceRule, AvrcpControllerService.class);
- doReturn(mTargetContext.getResources()).when(mAvrcpControllerService).getResources();
+ TestUtils.setAdapterService(mAvrcpAdapterService);
+ TestUtils.startService(mAvrcpServiceRule, AvrcpControllerService.class);
+ TestUtils.clearAdapterService(mAvrcpAdapterService);
+ TestUtils.setAdapterService(mA2dpAdapterService);
+ TestUtils.startService(mA2dpServiceRule, A2dpSinkService.class);
+ when(mMockResources.getBoolean(R.bool.a2dp_sink_automatically_request_audio_focus))
+ .thenReturn(true);
+ doReturn(mMockResources).when(mAvrcpControllerService).getResources();
doReturn(15).when(mAudioManager).getStreamMaxVolume(anyInt());
doReturn(8).when(mAudioManager).getStreamVolume(anyInt());
doReturn(true).when(mAudioManager).isVolumeFixed();
@@ -113,7 +129,7 @@ public class AvrcpControllerStateMachineTest {
if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_avrcp_controller)) {
return;
}
- TestUtils.clearAdapterService(mAdapterService);
+ TestUtils.clearAdapterService(mA2dpAdapterService);
}
/**
@@ -141,6 +157,10 @@ public class AvrcpControllerStateMachineTest {
IsInstanceOf.instanceOf(AvrcpControllerStateMachine.Disconnected.class));
Assert.assertEquals(mAvrcpStateMachine.getState(), BluetoothProfile.STATE_DISCONNECTED);
verify(mAvrcpControllerService).removeStateMachine(eq(mAvrcpStateMachine));
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+ Assert.assertEquals(PlaybackStateCompat.STATE_ERROR,
+ BluetoothMediaBrowserService.getPlaybackState());
}
/**
@@ -149,6 +169,11 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testControlOnly() {
int numBroadcastsSent = setUpConnectedState(true, false);
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+ Assert.assertNotNull(transportControls);
+ Assert.assertEquals(PlaybackStateCompat.STATE_NONE,
+ BluetoothMediaBrowserService.getPlaybackState());
StackEvent event =
StackEvent.connectionStateChanged(false, false);
mAvrcpStateMachine.disconnect();
@@ -166,6 +191,8 @@ public class AvrcpControllerStateMachineTest {
IsInstanceOf.instanceOf(AvrcpControllerStateMachine.Disconnected.class));
Assert.assertEquals(mAvrcpStateMachine.getState(), BluetoothProfile.STATE_DISCONNECTED);
verify(mAvrcpControllerService).removeStateMachine(eq(mAvrcpStateMachine));
+ Assert.assertEquals(PlaybackStateCompat.STATE_ERROR,
+ BluetoothMediaBrowserService.getPlaybackState());
}
/**
@@ -176,6 +203,8 @@ public class AvrcpControllerStateMachineTest {
Assert.assertEquals(0, mAvrcpControllerService.sBrowseTree.mRootNode.getChildrenCount());
int numBroadcastsSent = setUpConnectedState(false, true);
Assert.assertEquals(1, mAvrcpControllerService.sBrowseTree.mRootNode.getChildrenCount());
+ Assert.assertEquals(PlaybackStateCompat.STATE_NONE,
+ BluetoothMediaBrowserService.getPlaybackState());
StackEvent event =
StackEvent.connectionStateChanged(false, false);
mAvrcpStateMachine.disconnect();
@@ -193,6 +222,10 @@ public class AvrcpControllerStateMachineTest {
IsInstanceOf.instanceOf(AvrcpControllerStateMachine.Disconnected.class));
Assert.assertEquals(mAvrcpStateMachine.getState(), BluetoothProfile.STATE_DISCONNECTED);
verify(mAvrcpControllerService).removeStateMachine(eq(mAvrcpStateMachine));
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+ Assert.assertEquals(PlaybackStateCompat.STATE_ERROR,
+ BluetoothMediaBrowserService.getPlaybackState());
}
/**
@@ -221,7 +254,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testPlay() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Play
@@ -240,7 +273,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testPause() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Pause
@@ -259,7 +292,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testStop() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Stop
@@ -278,7 +311,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testNext() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Next
@@ -298,7 +331,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testPrevious() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Previous
@@ -318,7 +351,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testFastForward() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//FastForward
@@ -339,7 +372,7 @@ public class AvrcpControllerStateMachineTest {
@Test
public void testRewind() throws Exception {
setUpConnectedState(true, true);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
//Rewind
@@ -355,6 +388,69 @@ public class AvrcpControllerStateMachineTest {
}
/**
+ * Test media browser skip to queue item
+ */
+ @Test
+ public void testSkipToQueueInvalid() throws Exception {
+ byte scope = 1;
+ int minSize = 0;
+ int maxSize = 255;
+ setUpConnectedState(true, true);
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+
+ //Play an invalid item below start
+ transportControls.skipToQueueItem(minSize - 1);
+ verify(mAvrcpControllerService,
+ timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(0)).playItemNative(
+ eq(mTestAddress), eq(scope), anyLong(), anyInt());
+
+ //Play an invalid item beyond end
+ transportControls.skipToQueueItem(maxSize + 1);
+ verify(mAvrcpControllerService,
+ timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(0)).playItemNative(
+ eq(mTestAddress), eq(scope), anyLong(), anyInt());
+ }
+
+ /**
+ * Test media browser shuffle command
+ */
+ @Test
+ public void testShuffle() throws Exception {
+ byte[] shuffleSetting = new byte[]{3};
+ byte[] shuffleMode = new byte[]{2};
+
+ setUpConnectedState(true, true);
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+
+ //Shuffle
+ transportControls.setShuffleMode(1);
+ verify(mAvrcpControllerService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
+ .setPlayerApplicationSettingValuesNative(
+ eq(mTestAddress), eq((byte) 1), eq(shuffleSetting), eq(shuffleMode));
+ }
+
+ /**
+ * Test media browser repeat command
+ */
+ @Test
+ public void testRepeat() throws Exception {
+ byte[] repeatSetting = new byte[]{2};
+ byte[] repeatMode = new byte[]{3};
+
+ setUpConnectedState(true, true);
+ MediaControllerCompat.TransportControls transportControls =
+ BluetoothMediaBrowserService.getTransportControls();
+
+ //Shuffle
+ transportControls.setRepeatMode(2);
+ verify(mAvrcpControllerService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
+ .setPlayerApplicationSettingValuesNative(
+ eq(mTestAddress), eq((byte) 1), eq(repeatSetting), eq(repeatMode));
+ }
+
+ /**
* Test media browsing
* Verify that a browse tree is created with the proper root
* Verify that a player can be fetched and added to the browse tree
@@ -483,7 +579,7 @@ public class AvrcpControllerStateMachineTest {
BrowseTree.BrowseNode playerNodes = mAvrcpStateMachine.findNode(results.getID());
mAvrcpStateMachine.requestContents(results);
- MediaController.TransportControls transportControls =
+ MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
transportControls.play();
verify(mAvrcpControllerService,
@@ -507,6 +603,45 @@ public class AvrcpControllerStateMachineTest {
}
/**
+ * Test playback does not request focus when another app is playing music.
+ */
+ @Test
+ public void testPlaybackWhileMusicPlaying() {
+ when(mMockResources.getBoolean(R.bool.a2dp_sink_automatically_request_audio_focus))
+ .thenReturn(false);
+ Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
+ doReturn(true).when(mAudioManager).isMusicActive();
+ setUpConnectedState(true, true);
+ mAvrcpStateMachine.sendMessage(
+ AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
+ PlaybackStateCompat.STATE_PLAYING);
+ TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
+ verify(mAvrcpControllerService,
+ timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).sendPassThroughCommandNative(
+ eq(mTestAddress), eq(AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE), eq(KEY_DOWN));
+ TestUtils.waitForLooperToFinishScheduledTask(
+ A2dpSinkService.getA2dpSinkService().getMainLooper());
+ Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
+ }
+
+ /**
+ * Test playback requests focus while nothing is playing music.
+ */
+ @Test
+ public void testPlaybackWhileIdle() {
+ Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
+ doReturn(false).when(mAudioManager).isMusicActive();
+ setUpConnectedState(true, true);
+ mAvrcpStateMachine.sendMessage(
+ AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
+ PlaybackStateCompat.STATE_PLAYING);
+ TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
+ TestUtils.waitForLooperToFinishScheduledTask(
+ A2dpSinkService.getA2dpSinkService().getMainLooper());
+ Assert.assertEquals(AudioManager.AUDIOFOCUS_GAIN, A2dpSinkService.getFocusState());
+ }
+
+ /**
* Setup Connected State
*
* @return number of times mAvrcpControllerService.sendBroadcastAsUser() has been invoked
diff --git a/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java b/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
new file mode 100644
index 000000000..acd05ed02
--- /dev/null
+++ b/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.bluetooth.mapclient;
+
+import static org.mockito.Mockito.*;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BmessageTest {
+ private static final String TAG = BmessageTest.class.getSimpleName();
+ private static final String SIMPLE_MMS_MESSAGE =
+ "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+ + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+ + "BEGIN:BBODY\r\nLENGTH:39\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+ + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+ private static final String NO_END_MESSAGE =
+ "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+ + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+ + "BEGIN:BBODY\r\nLENGTH:39\r\nBEGIN:MSG\r\nThis is a new msg\r\n";
+
+ private static final String WRONG_LENGTH_MESSAGE =
+ "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+ + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+ + "BEGIN:BBODY\r\nLENGTH:200\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+ + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+ private static final String NO_BODY_MESSAGE =
+ "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+ + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+ + "BEGIN:BBODY\r\nLENGTH:\r\n";
+
+ private static final String NEGATIVE_LENGTH_MESSAGE =
+ "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+ + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+ + "BEGIN:BBODY\r\nLENGTH:-1\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+ + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+ @Test
+ public void testNormalMessages() {
+ Bmessage message = BmessageParser.createBmessage(SIMPLE_MMS_MESSAGE);
+ Assert.assertNotNull(message);
+ }
+
+ @Test
+ public void testParseWrongLengthMessage() {
+ Bmessage message = BmessageParser.createBmessage(WRONG_LENGTH_MESSAGE);
+ Assert.assertNull(message);
+ }
+
+ @Test
+ public void testParseNoEndMessage() {
+ Bmessage message = BmessageParser.createBmessage(NO_END_MESSAGE);
+ Assert.assertNull(message);
+ }
+
+ @Test
+ public void testParseReallyLongMessage() {
+ String testMessage = new String(new char[68048]).replace('\0', 'A');
+ Bmessage message = BmessageParser.createBmessage(testMessage);
+ Assert.assertNull(message);
+ }
+
+ @Test
+ public void testNoBodyMessage() {
+ Bmessage message = BmessageParser.createBmessage(NO_BODY_MESSAGE);
+ Assert.assertNull(message);
+ }
+
+ @Test
+ public void testNegativeLengthMessage() {
+ Bmessage message = BmessageParser.createBmessage(NEGATIVE_LENGTH_MESSAGE);
+ Assert.assertNull(message);
+ }
+}
diff --git a/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java b/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
index 70854d8d1..ccfd9f810 100644
--- a/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
@@ -150,6 +150,36 @@ public class MapClientStateMachineTest {
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
}
+ /**
+ * Test transition from STATE_CONNECTING --> (receive MSG_MAS_CONNECTED) --> STATE_CONNECTED
+ * --> (receive MSG_MAS_DISCONNECTED) --> STATE_DISCONNECTED
+ */
+ @Test
+ public void testStateTransitionFromConnectedWithMasDisconnected() {
+ Log.i(TAG, "in testStateTransitionFromConnectedWithMasDisconnected");
+
+ setupSdpRecordReceipt();
+ Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
+ mMceStateMachine.sendMessage(msg);
+
+ // Wait until the message is processed and a broadcast request is sent to
+ // to MapClientService to change
+ // state from STATE_CONNECTING to STATE_CONNECTED
+ verify(mMockMapClientService,
+ timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
+ mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
+ Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
+
+ msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED);
+ mMceStateMachine.sendMessage(msg);
+ verify(mMockMapClientService,
+ timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(4)).sendBroadcast(
+ mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
+
+ Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState());
+ }
+
+
/**
* Test receiving an empty event report
*/
diff --git a/tests/unit/src/com/android/bluetooth/mapclient/ObexTimeTest.java b/tests/unit/src/com/android/bluetooth/mapclient/ObexTimeTest.java
new file mode 100644
index 000000000..5ef2d455b
--- /dev/null
+++ b/tests/unit/src/com/android/bluetooth/mapclient/ObexTimeTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.bluetooth.mapclient;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+@RunWith(AndroidJUnit4.class)
+public class ObexTimeTest {
+ private static final String TAG = ObexTimeTest.class.getSimpleName();
+
+ private static final String VALID_TIME_STRING = "20190101T121314";
+ private static final String VALID_TIME_STRING_WITH_OFFSET_POS = "20190101T121314+0130";
+ private static final String VALID_TIME_STRING_WITH_OFFSET_NEG = "20190101T121314-0130";
+
+ private static final String INVALID_TIME_STRING_OFFSET_EXTRA_DIGITS = "20190101T121314-99999";
+ private static final String INVALID_TIME_STRING_BAD_DELIMITER = "20190101Q121314";
+
+ // MAP message listing times, per spec, use "local time basis" if UTC offset isn't given. The
+ // ObexTime class parses using the current default timezone (assumed to be the "local timezone")
+ // in the case that UTC isn't provided. However, the Date class assumes UTC ALWAYS when
+ // initializing off of a long value. We have to take that into account when determining our
+ // expected results for time strings that don't have an offset.
+ private static final long LOCAL_TIMEZONE_OFFSET = TimeZone.getDefault().getRawOffset();
+
+ // If you are a positive offset from GMT then GMT is in the "past" and you need to subtract that
+ // offset from the time. If you are negative then GMT is in the future and you need to add that
+ // offset to the time.
+ private static final long VALID_TS = 1546344794000L; // Jan 01, 2019 at 12:13:14 GMT
+ private static final long TS_OFFSET = 5400000L; // 1 Hour, 30 minutes -> milliseconds
+ private static final long VALID_TS_LOCAL_TZ = VALID_TS - LOCAL_TIMEZONE_OFFSET;
+ private static final long VALID_TS_OFFSET_POS = VALID_TS - TS_OFFSET;
+ private static final long VALID_TS_OFFSET_NEG = VALID_TS + TS_OFFSET;
+
+ private static final Date VALID_DATE_LOCAL_TZ = new Date(VALID_TS_LOCAL_TZ);
+ private static final Date VALID_DATE_WITH_OFFSET_POS = new Date(VALID_TS_OFFSET_POS);
+ private static final Date VALID_DATE_WITH_OFFSET_NEG = new Date(VALID_TS_OFFSET_NEG);
+
+ @Test
+ public void createWithValidDateTimeString_TimestampCorrect() {
+ ObexTime timestamp = new ObexTime(VALID_TIME_STRING);
+ Assert.assertEquals("Parsed timestamp must match expected", VALID_DATE_LOCAL_TZ,
+ timestamp.getTime());
+ }
+
+ @Test
+ public void createWithValidDateTimeStringWithPosOffset_TimestampCorrect() {
+ ObexTime timestamp = new ObexTime(VALID_TIME_STRING_WITH_OFFSET_POS);
+ Assert.assertEquals("Parsed timestamp must match expected", VALID_DATE_WITH_OFFSET_POS,
+ timestamp.getTime());
+ }
+
+ @Test
+ public void createWithValidDateTimeStringWithNegOffset_TimestampCorrect() {
+ ObexTime timestamp = new ObexTime(VALID_TIME_STRING_WITH_OFFSET_NEG);
+ Assert.assertEquals("Parsed timestamp must match expected", VALID_DATE_WITH_OFFSET_NEG,
+ timestamp.getTime());
+ }
+
+ @Test
+ public void createWithValidDate_TimestampCorrect() {
+ ObexTime timestamp = new ObexTime(VALID_DATE_LOCAL_TZ);
+ Assert.assertEquals("ObexTime created with a date must return the same date",
+ VALID_DATE_LOCAL_TZ, timestamp.getTime());
+ }
+
+ @Test
+ public void printValidTime_TimestampMatchesInput() {
+ ObexTime timestamp = new ObexTime(VALID_TIME_STRING);
+ Assert.assertEquals("Timestamp as a string must match the input string", VALID_TIME_STRING,
+ timestamp.toString());
+ }
+
+ @Test
+ public void createWithInvalidDelimiterString_TimestampIsNull() {
+ ObexTime timestamp = new ObexTime(INVALID_TIME_STRING_BAD_DELIMITER);
+ Assert.assertEquals("Parsed timestamp was invalid and must result in a null object", null,
+ timestamp.getTime());
+ }
+
+ @Test
+ public void createWithInvalidOffsetString_TimestampIsNull() {
+ ObexTime timestamp = new ObexTime(INVALID_TIME_STRING_OFFSET_EXTRA_DIGITS);
+ Assert.assertEquals("Parsed timestamp was invalid and must result in a null object", null,
+ timestamp.getTime());
+ }
+
+ @Test
+ public void printInvalidTime_ReturnsNull() {
+ ObexTime timestamp = new ObexTime(INVALID_TIME_STRING_BAD_DELIMITER);
+ Assert.assertEquals("Invalid timestamps must return null for toString()", null,
+ timestamp.toString());
+ }
+}
diff --git a/tests/unit/src/com/android/bluetooth/pan/PanServiceTest.java b/tests/unit/src/com/android/bluetooth/pan/PanServiceTest.java
index 6d4574f11..3573f847a 100644
--- a/tests/unit/src/com/android/bluetooth/pan/PanServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/pan/PanServiceTest.java
@@ -15,8 +15,12 @@
*/
package com.android.bluetooth.pan;
+import static org.mockito.Mockito.when;
+
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.os.UserManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -47,6 +51,7 @@ public class PanServiceTest {
@Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
@Mock private AdapterService mAdapterService;
+ @Mock private UserManager mMockUserManager;
@Before
public void setUp() throws Exception {
@@ -61,6 +66,7 @@ public class PanServiceTest {
// Try getting the Bluetooth adapter
mAdapter = BluetoothAdapter.getDefaultAdapter();
Assert.assertNotNull(mAdapter);
+ mService.mUserManager = mMockUserManager;
}
@After
@@ -78,4 +84,11 @@ public class PanServiceTest {
public void testInitialize() {
Assert.assertNotNull(PanService.getPanService());
}
+
+ @Test
+ public void testGuestUserConnect() {
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0);
+ when(mMockUserManager.isGuestUser()).thenReturn(true);
+ Assert.assertFalse(mService.connect(device));
+ }
}