summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com>2016-12-09 12:47:52 +0530
committerAnjaneedevi Kapparapu <akappa@codeaurora.org>2016-12-09 12:52:23 +0530
commitb6fb5c31b88156417c57e9cc17f87ca22e69b495 (patch)
tree64229ba844aa7011e3875dc48e9f60a4a0225360
parent8edd1a3a518f3858ba517de3bf010a5054de161f (diff)
parent42db863c7055834c96a7c02a4389d55a7cb4968e (diff)
downloadandroid_packages_apps_Bluetooth-b6fb5c31b88156417c57e9cc17f87ca22e69b495.tar.gz
android_packages_apps_Bluetooth-b6fb5c31b88156417c57e9cc17f87ca22e69b495.tar.bz2
android_packages_apps_Bluetooth-b6fb5c31b88156417c57e9cc17f87ca22e69b495.zip
To Backport the N-Mr1 Changes
To Backport the N-Mr1 Changes Merge remote-tracking branch 'origin/bt.lnx.2.1.c1-rel' into bt.lnx.2.1.c1-dev Change-Id: Id00f000afbc330b368fa2b19d6c9fe468e86f1d6 CRs-Fixed: 1099415
-rw-r--r--jni/com_android_bluetooth_a2dp.cpp7
-rw-r--r--jni/com_android_bluetooth_hfp.cpp1
-rw-r--r--res/values-ca/strings.xml2
-rw-r--r--res/values-fa/strings.xml2
-rw-r--r--res/values-fa/strings_pbap.xml2
-rw-r--r--res/values-hy-rAM/strings.xml4
-rw-r--r--res/values-lt/strings.xml2
-rw-r--r--res/values-my-rMM/strings.xml12
-rw-r--r--res/values-ro/strings.xml2
-rw-r--r--res/values/config.xml17
-rw-r--r--src/com/android/bluetooth/OolConnManager.java9
-rw-r--r--src/com/android/bluetooth/avrcp/Avrcp.java438
-rw-r--r--src/com/android/bluetooth/btservice/AdapterService.java56
-rw-r--r--src/com/android/bluetooth/btservice/RemoteDevices.java60
-rw-r--r--src/com/android/bluetooth/btservice/bluetooth.proto3
-rw-r--r--src/com/android/bluetooth/gatt/AdvertiseManager.java2
-rw-r--r--src/com/android/bluetooth/gatt/ContextMap.java16
-rw-r--r--src/com/android/bluetooth/gatt/GattService.java47
-rw-r--r--src/com/android/bluetooth/gatt/HandleMap.java2
-rw-r--r--src/com/android/bluetooth/gatt/ScanManager.java31
-rw-r--r--src/com/android/bluetooth/hfp/HeadsetHalConstants.java4
-rwxr-xr-x[-rw-r--r--]src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java1
-rw-r--r--src/com/android/bluetooth/hid/HidService.java6
-rwxr-xr-xsrc/com/android/bluetooth/map/BluetoothMapContent.java16
-rwxr-xr-xsrc/com/android/bluetooth/map/BluetoothMapContentObserver.java87
-rw-r--r--src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java9
-rw-r--r--src/com/android/bluetooth/map/BluetoothMapObexServer.java40
-rwxr-xr-xsrc/com/android/bluetooth/map/BluetoothMapService.java1
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java40
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java6
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java1
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppService.java48
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppTransfer.java23
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppUtility.java3
-rwxr-xr-xsrc/com/android/bluetooth/pan/PanService.java4
-rw-r--r--src/com/android/bluetooth/pbap/BluetoothPbapReceiver.java11
-rw-r--r--src/com/android/bluetooth/sdp/SdpManager.java2
-rw-r--r--src/com/android/bluetooth/util/Interop.java87
38 files changed, 887 insertions, 217 deletions
diff --git a/jni/com_android_bluetooth_a2dp.cpp b/jni/com_android_bluetooth_a2dp.cpp
index 717e27e90..48649d23e 100644
--- a/jni/com_android_bluetooth_a2dp.cpp
+++ b/jni/com_android_bluetooth_a2dp.cpp
@@ -208,6 +208,11 @@ static void initNative(JNIEnv *env, jobject object, jint maxA2dpConnections,
mCallbacksObj = NULL;
}
+ if ((mCallbacksObj = env->NewGlobalRef(object)) == NULL) {
+ ALOGE("Failed to allocate Global Ref for A2DP Callbacks");
+ return;
+ }
+
if ( (sBluetoothA2dpInterface = (btav_interface_t *)
btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {
ALOGE("Failed to get Bluetooth A2DP Interface");
@@ -221,8 +226,6 @@ static void initNative(JNIEnv *env, jobject object, jint maxA2dpConnections,
sBluetoothA2dpInterface = NULL;
return;
}
-
- mCallbacksObj = env->NewGlobalRef(object);
}
static void cleanupNative(JNIEnv *env, jobject object) {
diff --git a/jni/com_android_bluetooth_hfp.cpp b/jni/com_android_bluetooth_hfp.cpp
index 839a3d670..beacfa886 100644
--- a/jni/com_android_bluetooth_hfp.cpp
+++ b/jni/com_android_bluetooth_hfp.cpp
@@ -726,7 +726,6 @@ static jboolean cindResponseNative(JNIEnv *env, jobject object,
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-
static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str,
jbyteArray address) {
jbyte *addr;
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 53ce8179f..ed31bb1b1 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -27,7 +27,7 @@
<string name="airplane_error_msg" msgid="8698965595254137230">"No pots utilitzar Bluetooth en mode d\'avió."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
<string name="bt_enable_line1" msgid="7203551583048149">"Per utilitzar serveis Bluetooth, primer cal que activeu el Bluetooth."</string>
- <string name="bt_enable_line2" msgid="4341936569415937994">"Voleu activar el Bluetooth ara?"</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Vols activar el Bluetooth ara?"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancel·la"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activa"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferència del fitxer"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 9e390dd9a..bdffe8634 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -99,7 +99,7 @@
<string name="status_no_sd_card" product="default" msgid="5760944071743325592">"‏هیچ کارت SD موجود نیست. برای ذخیره فایل‌های منتقل شده، یک کارت SD در گوشی قرار دهید."</string>
<string name="status_connection_error" msgid="947681831523219891">"اتصال ناموفق بود."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"درخواست به درستی انجام نمی‌شود."</string>
- <string name="status_unknown_error" msgid="8156660554237824912">"خطای ناشناخته."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"خطای ناشناس."</string>
<string name="btopp_live_folder" msgid="7967791481444474554">"بلوتوث دریافت شد"</string>
<string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> دریافت کامل شد."</string>
<string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> ارسال کامل شد."</string>
diff --git a/res/values-fa/strings_pbap.xml b/res/values-fa/strings_pbap.xml
index 945d4426a..0667ebbee 100644
--- a/res/values-fa/strings_pbap.xml
+++ b/res/values-fa/strings_pbap.xml
@@ -5,7 +5,7 @@
<string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"به کلید جلسه بلوتوث نیاز است"</string>
<string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"‏هنگام پذیرش اتصال به %1$s وقفه زمانی ایجاد شده است"</string>
<string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"‏هنگام ورود کلید جلسه با %1$s وقفه زمانی ایجاد شده است"</string>
- <string name="auth_notif_ticker" msgid="1575825798053163744">"‏درخواست راستی‌آزمایی Obex"</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>
<string name="defaultname" msgid="4821590500649090078">"کیت خودرو"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index ed242a940..efef63b5c 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -23,8 +23,8 @@
<string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
<string name="unknown_device" msgid="9221903979877041009">"Անհայտ սարք"</string>
<string name="unknownNumber" msgid="4994750948072751566">"Անհայտ"</string>
- <string name="airplane_error_title" msgid="2683839635115739939">"Ինքնաթիռային ռեժիմ"</string>
- <string name="airplane_error_msg" msgid="8698965595254137230">"Դուք չեք կարող օգտվել Bluetooth-ից ինքնաթիռային ռեժիմում:"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Ինքնաթիռի ռեժիմ"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Դուք չեք կարող օգտվել Bluetooth-ից Ինքնաթիռի ռեժիմում:"</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
<string name="bt_enable_line1" msgid="7203551583048149">"Bluetooth ծառայություններից օգտվելու համար նախ պետք է միացնեք Bluetooth-ը:"</string>
<string name="bt_enable_line2" msgid="4341936569415937994">"Միացնե՞լ Bluetooth-ը հիմա:"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index a7ae86f1d..69cf285a1 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Pasiekti atsisiuntimo tvarkyklę."</string>
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Pasiekti atsisiuntimo tvarkytuvę."</string>
<string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Leidžiama programai pasiekti „BluetoothShare“ tvarkyklę ir naudoti ją failams perkelti."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Į baltąjį sąrašą įtraukto „Bluetooth“ įrenginio prieiga."</string>
<string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Leidžiama programai laikinai į baltąjį sąrašą įtraukti „Bluetooth“ įrenginį, suteikiant jam galimybę siųsti failus į šį įrenginį be naudotojo patvirtinimo."</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index a71b29839..2bbb0106f 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -19,7 +19,7 @@
<string name="permlab_bluetoothShareManager" msgid="311492132450338925">"ဒေါင်းလုပ်မန်နေဂျာကို အသုံးပြုနိုင်မည်"</string>
<string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"အပလီကေးရှင်းအား ဘလူးတုသ်မျှဝေမှု မန်နေဂျာကို အသုံးပြုခွင့်ပေးပြီး ဖိုင်လွှဲရန် အသုံးပြုပါ"</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"ဘလူးတုသ်ယာယီခွင့်ပြုစာရင်းကို အသုံးပြုခွင့်"</string>
- <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"အပလီကေးရှင်းအား ဘလူးတုသ်စက်ကို ယာယီခွင့်ပြုစာရင်းထဲ ထည့်ရန်ခွင့်ပြုကာ အသုံးပြုသူ၏ အတည်ပြုချက်မရယူပဲ ဖိုင်များကို စက်ထဲသို့ ပို့ခွင့်ပြုမည်"</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"အက်ပ်အား ဘလူးတုသ်စက်ကို ယာယီခွင့်ပြုစာရင်းထဲ ထည့်ရန်ခွင့်ပြုကာ အသုံးပြုသူ၏ အတည်ပြုချက်မရယူပဲ ဖိုင်များကို စက်ထဲသို့ ပို့ခွင့်ပြုမည်"</string>
<string name="bt_share_picker_label" msgid="6268100924487046932">"ဘလူးတုသ်"</string>
<string name="unknown_device" msgid="9221903979877041009">"မသိသော စက်"</string>
<string name="unknownNumber" msgid="4994750948072751566">"အကြောင်းအရာ မသိရှိ"</string>
@@ -28,7 +28,7 @@
<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_cancel" msgid="1988832367505151727">"မလုပ်တော့ပါ"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"မလုပ်တော့"</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>
@@ -120,12 +120,12 @@
<string name="transfer_menu_clear_all" msgid="790017462957873132">"စာရင်းကို ဖယ်ရှားရန်"</string>
<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_map_settings_save" msgid="7635491847388074606">"သိမ်းဆည်းရန်"</string>
- <string name="bluetooth_map_settings_cancel" msgid="9205350798049865699">"မလုပ်တော့ပါ"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"ရှင်းရန်"</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>
<string name="bluetooth_map_settings_count" msgid="4557473074937024833">"ကျန်နေသည့် အပေါက်များ:"</string>
- <string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"အက်ပ် အိုင်ကွန်"</string>
+ <string name="bluetooth_map_settings_app_icon" msgid="7105805610929114707">"အပလီကေးရှင်း သင်္ကေတ"</string>
<string name="bluetooth_map_settings_title" msgid="7420332483392851321">"ဘလူးတုသ် စာ မျှဝေရေး ဆက်တင်များ"</string>
<string name="bluetooth_map_settings_no_account_slots_left" msgid="1796029082612965251">"ရွေးထားသည့် အကောင့်ကို မရွေးနိုင်ပါ။ သုည အပေါက်များ ကျန်နေ"</string>
<string name="bluetooth_connected" msgid="6718623220072656906">"ဘလူးတုသ်အသံ ချိတ်ဆက်ပြီးပါပြီ"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 9a4a53648..85423d718 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -82,7 +82,7 @@
<string name="bt_toast_2" msgid="8602553334099066582">"Fișierul nu poate fi primit."</string>
<string name="bt_toast_3" msgid="6707884165086862518">"Primirea fișierului de la „<xliff:g id="SENDER">%1$s</xliff:g>” a fost anulată"</string>
<string name="bt_toast_4" msgid="4678812947604395649">"Se trimite fișierul către „<xliff:g id="RECIPIENT">%1$s</xliff:g>”"</string>
- <string name="bt_toast_5" msgid="2846870992823019494">"Se trimit <xliff:g id="NUMBER">%1$s</xliff:g> (de) fișiere către „<xliff:g id="RECIPIENT">%2$s</xliff:g>”"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"Se trimit <xliff:g id="NUMBER">%1$s</xliff:g> fișiere către „<xliff:g id="RECIPIENT">%2$s</xliff:g>”"</string>
<string name="bt_toast_6" msgid="1855266596936622458">"Trimiterea fișierului către „<xliff:g id="RECIPIENT">%1$s</xliff:g>” a fost anulată"</string>
<string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"Nu există spațiu suficient pe stocarea USB pentru a salva fișierul de la „<xliff:g id="SENDER">%1$s</xliff:g>”"</string>
<string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"Nu există suficient spațiu pe cardul SD pentru a salva fișierul de la „<xliff:g id="SENDER">%1$s</xliff:g>”"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index dcbe20837..90e513d36 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -35,14 +35,25 @@
of the location permissions. -->
<bool name="strict_location_check">true</bool>
- <!-- Specifies the min/max connection interval parameters for high priority
- and low power GATT configurations. These values are in multiples of
- 1.25ms. -->
+ <!-- Specifies the min/max connection interval parameters for high priority,
+ balanced and low power GATT configurations. These values are in
+ multiples of 1.25ms. -->
<integer name="gatt_high_priority_min_interval">9</integer>
<integer name="gatt_high_priority_max_interval">12</integer>
+ <!-- Default specs recommended interval is 30 (24 * 1.25) -> 50 (40 * 1.25)
+ ms. -->
+ <integer name="gatt_balanced_priority_min_interval">24</integer>
+ <integer name="gatt_balanced_priority_max_interval">40</integer>
<integer name="gatt_low_power_min_interval">80</integer>
<integer name="gatt_low_power_max_interval">100</integer>
+ <!-- Specifies latency parameters for high priority, balanced and low power
+ GATT configurations. These values represents the number of packets a
+ slave device is allowed to skip. -->
+ <integer name="gatt_high_priority_latency">0</integer>
+ <integer name="gatt_balanced_priority_latency">0</integer>
+ <integer name="gatt_low_power_latency">2</integer>
+
<bool name="headset_client_initial_audio_route_allowed">true</bool>
<!-- For AVRCP absolute volume feature. If the threshold is non-zero,
diff --git a/src/com/android/bluetooth/OolConnManager.java b/src/com/android/bluetooth/OolConnManager.java
index 034e9da57..c0b56e143 100644
--- a/src/com/android/bluetooth/OolConnManager.java
+++ b/src/com/android/bluetooth/OolConnManager.java
@@ -40,6 +40,7 @@ public class OolConnManager {
static int channel = 0;
static boolean sdpDone = false;
static String mAddress;
+ public static boolean interruptSdp = false;
public static BluetoothSocket CreateL2capConnection(BluetoothDevice remBtDev,UUID uuid ) {
@@ -66,7 +67,7 @@ public class OolConnManager {
int waitCount = 0;
int channelNo = -1;
- while(!sdpDone && waitCount < 100) {
+ while(!sdpDone && waitCount < 100 && (!interruptSdp)) {
try {
Thread.sleep(100);
@@ -77,6 +78,7 @@ public class OolConnManager {
}
waitCount = 0;
sdpDone = false;
+ interruptSdp = false;
Log.d(TAG,"returning l2c channel as "+channel);
channelNo = channel;
@@ -86,8 +88,9 @@ public class OolConnManager {
public static void saveOppSdpRecord(SdpOppOpsRecord sdpRec, BluetoothDevice btDevice) {
- Log.v(TAG,"saveOppSdpRecord"+ btDevice.getAddress());
- if ((mAddress != null) && mAddress.equalsIgnoreCase(btDevice.getAddress())) {
+ Log.i(TAG, "saveOppSdpRecord" + btDevice.getAddress() + " sdpRec:" + sdpRec);
+ if (sdpRec != null && (mAddress != null) && mAddress.
+ equalsIgnoreCase(btDevice.getAddress())) {
channel = sdpRec.getL2capPsm();
sdpDone = true;
Log.d(TAG,"saveOppSdpRecord channel "+ channel);
diff --git a/src/com/android/bluetooth/avrcp/Avrcp.java b/src/com/android/bluetooth/avrcp/Avrcp.java
index 50c7ece8c..8d7a77dc7 100644
--- a/src/com/android/bluetooth/avrcp/Avrcp.java
+++ b/src/com/android/bluetooth/avrcp/Avrcp.java
@@ -123,6 +123,7 @@ public final class Avrcp {
private static boolean updatePlayTime;
private static boolean updateValues;
private int mAddressedPlayerId;
+ private int mBrowsedPlayerId;
/* BTRC features */
public static final int BTRC_FEAT_METADATA = 0x01;
@@ -439,6 +440,7 @@ public final class Avrcp {
maxAvrcpConnections = maxConnections;
deviceFeatures = new DeviceDependentFeature[maxAvrcpConnections];
mAddressedPlayerId = INVALID_ADDRESSED_PLAYER_ID;
+ mBrowsedPlayerId = INVALID_ADDRESSED_PLAYER_ID;
for(int i = 0; i < maxAvrcpConnections; i++) {
deviceFeatures[i] = new DeviceDependentFeature();
}
@@ -716,7 +718,7 @@ public final class Avrcp {
featureMasks2[FEATURE_MASK_REWIND_OFFSET] | FEATURE_MASK_REWIND_MASK;
featureMasks2[FEATURE_MASK_FAST_FWD_OFFSET] =
featureMasks2[FEATURE_MASK_FAST_FWD_OFFSET] | FEATURE_MASK_FAST_FWD_MASK;
- mediaPlayerInfo1 = new MediaPlayerInfo ((short)0x0001,
+ mediaPlayerInfo1 = new MediaPlayerInfo ((short)0x0000,
MAJOR_TYPE_AUDIO,
SUB_TYPE_NONE,
(byte)PlaybackState.STATE_PAUSED,
@@ -726,7 +728,7 @@ public final class Avrcp {
"com.android.music",
true,
featureMasks);
- mediaPlayerInfo2 = new MediaPlayerInfo ((short)0x0000,
+ mediaPlayerInfo2 = new MediaPlayerInfo ((short)0x0001,
MAJOR_TYPE_AUDIO,
SUB_TYPE_NONE,
(byte)PlaybackState.STATE_PAUSED,
@@ -820,42 +822,6 @@ public final class Avrcp {
}
@Override
- public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
- Log.v(TAG, "onClientFolderInfoBrowsedPlayer: stringUri: " + stringUri);
- if (stringUri != null) {
- String[] ExternalPath = stringUri.split("/");
- if (ExternalPath.length < 4) {
- Log.d(TAG, "Wrong entries.");
- mHandler.obtainMessage(MSG_UPDATE_BROWSED_PLAYER_FOLDER, 0, INTERNAL_ERROR,
- null).sendToTarget();
- return;
- }
- Uri uri = Uri.parse(stringUri);
- Log.v(TAG, "URI received: " + uri);
- String[] SplitPath = new String[ExternalPath.length - 3];
- for (int count = 2; count < (ExternalPath.length - 1); count++) {
- SplitPath[count - 2] = ExternalPath[count];
- Log.d(TAG, "SplitPath[" + (count - 2) + "] = " + SplitPath[count - 2]);
- }
- Log.v(TAG, "folderDepth: " + SplitPath.length);
- for (int count = 0; count < SplitPath.length; count++) {
- Log.v(TAG, "folderName: " + SplitPath[count]);
- }
- mMediaUriStatic = uri;
- if (mHandler != null) {
- // Don't send the complete path to CK as few gets confused by that
- // Send only the name of the root folder
- mHandler.obtainMessage(MSG_UPDATE_BROWSED_PLAYER_FOLDER, NUM_ROOT_ELEMENTS,
- OPERATION_SUCCESSFUL, SplitPath).sendToTarget();
- }
- } else {
- mHandler.obtainMessage(MSG_UPDATE_BROWSED_PLAYER_FOLDER, 0, INTERNAL_ERROR,
- null).sendToTarget();
- }
- Log.d(TAG, "Exit onUpdateFolderInfoBrowsedPlayer()");
- }
-
- @Override
public void onUpdateNowPlayingEntries(long[] playList) {
Log.v(TAG, "onClientUpdateNowPlayingEntries");
if (mHandler != null) {
@@ -1023,11 +989,6 @@ public final class Avrcp {
updateAddressedMediaPlayer(msg.arg1);
break;
- case MSG_UPDATE_BROWSED_PLAYER_FOLDER:
- Log.v(TAG, "MSG_UPDATE_BROWSED_PLAYER_FOLDER");
- updateBrowsedPlayerFolder(msg.arg1, msg.arg2, (String [])msg.obj);
- break;
-
case MSG_UPDATE_NOW_PLAYING_CONTENT_CHANGED:
Log.v(TAG, "MSG_UPDATE_NOW_PLAYING_CONTENT_CHANGED");
updateNowPlayingContentChanged();
@@ -1082,6 +1043,19 @@ public final class Avrcp {
deviceFeatures[deviceIndex].mVolumeMapping.clear();
if ((deviceFeatures[deviceIndex].mFeatures &
+ BTRC_FEAT_BROWSE) != 0)
+ {
+ Log.v(TAG,"BTRC_FEAT_BROWSE support is present on remote side");
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
+ deviceFeatures[deviceIndex].mMediaUri = Uri.parse("content://media/external/audio/media");
+ Log.v(TAG," update current path to root folder before browse");
+ deviceFeatures[deviceIndex].isBrowsingSupported = true;
+ mBrowserDevice = device;
+ Log.v(TAG,"Browsing supported by remote : mBrowserDevice = " + mBrowserDevice);
+ }
+
+ if ((deviceFeatures[deviceIndex].mFeatures &
BTRC_FEAT_AVRC_UI_UPDATE) != 0)
{
int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
@@ -1597,8 +1571,8 @@ public final class Avrcp {
for (int i = 0; i < msg.arg1; ++i) {
attrIds[i] = itemAttr.mAttrList.get(i).intValue();
}
- processGetItemAttr((byte)msg.arg2, itemAttr.mUid, (byte)msg.arg1,
- attrIds, itemAttr.mSize, itemAttr.mAddress);
+ processGetItemAttrInternal((byte)msg.arg2, itemAttr.mUid, (byte)msg.arg1,
+ attrIds, itemAttr.mSize, itemAttr.mAddress);
break;
case MESSAGE_GET_FOLDER_ITEMS:
FolderListEntries folderListEntries = (FolderListEntries)msg.obj;
@@ -1936,7 +1910,22 @@ public final class Avrcp {
long TrackNumberRsp = -1L;
try {
TrackNumberRsp = Long.parseLong(mMediaAttributes.getString
- (MediaAttributes.ATTR_MEDIA_NUMBER));
+ (MediaAttributes.ATTR_MEDIA_NUMBER));
+ //if (deviceFeatures[i].isBrowsingSupported) {//Track num
+ if (((deviceFeatures[i].mFeatures & BTRC_FEAT_BROWSE) != 0) &&
+ (deviceFeatures[i].mCurrentPath != PATH_INVALID)) {//Track num
+ Log.e(TAG,"TRACK_CHANGE_NOTIFICATION device suppports browsing");
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo di = rccIterator.next();
+ if (di.IsPlayerBrowsable() && (di.GetPlayerFocus() == true)) {
+ TrackNumberRsp = Long.parseLong(mMediaAttributes.getString
+ (MediaAttributes.ATTR_TRACK_NUM));
+ }
+ }
+ }
+ }
} catch (Exception e) {
Log.e(TAG, "sendTrackChangedRsp Exception e" + e);
TrackNumberRsp = -1L;
@@ -2005,27 +1994,6 @@ public final class Avrcp {
updateResetNotification(PLAYER_STATUS_CHANGED_NOTIFICATION);
}
- void updateBrowsedPlayerFolder(int numOfItems, int status, String[] folderNames) {
- Log.v(TAG, "updateBrowsedPlayerFolder: numOfItems = " + numOfItems
- + " status = " + status);
- if (mBrowserDevice == null) {
- Log.e(TAG,"mBrowserDevice is null for music player called api");
- }
- BluetoothDevice device = mBrowserDevice;
- int deviceIndex = getIndexForDevice(device);
- if (deviceIndex == INVALID_DEVICE_INDEX) {
- Log.e(TAG,"invalid index for device");
- return;
- }
- deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
- deviceFeatures[deviceIndex].mCurrentPathUid = null;
- deviceFeatures[deviceIndex].mMediaUri = mMediaUriStatic;
- mMediaUriStatic = null;
-
- setBrowsedPlayerRspNative((byte)status, 0x0, numOfItems, 0x0, CHAR_SET_UTF8,
- folderNames, getByteAddress(device));
- }
-
void updateNowPlayingContentChanged() {
Log.v(TAG, "updateNowPlayingContentChanged");
for (int i = 0; i < maxAvrcpConnections; i++) {
@@ -2090,6 +2058,11 @@ public final class Avrcp {
}
Log.v(TAG, "updateNowPlayingEntriesReceived");
+ if (mCachedRequest.mIsGetItemAttr) {
+ Log.v(TAG,"calling processGetItemAttrdummy");
+ processGetItemAttrdummy(playList);
+ return;
+ }
if (!mCachedRequest.mIsGetFolderItems) {
Log.v(TAG, "getTotalNumberOfItemsRspNative for NowPlaying List");
@@ -2186,13 +2159,22 @@ public final class Avrcp {
ArrayList<Integer> mAttrList;
int mSize;
boolean mIsGetFolderItems;
+ boolean mIsGetItemAttr;
+ long mUid;
+ byte mScope;
+ String mDeviceAddress;
public CachedRequest(long start, long end, byte attrCnt, int[] attrs,
- int size, boolean isGetFolderItems) {
+ int size, boolean isGetFolderItems, long uid, byte scope,
+ String deviceAddress, boolean isGetItemAttr) {
mStart = start;
mEnd = end;
mAttrCnt = attrCnt;
mSize = size;
mIsGetFolderItems = isGetFolderItems;
+ mUid = uid;
+ mScope = scope;
+ mDeviceAddress = deviceAddress;
+ mIsGetItemAttr = isGetItemAttr;
mAttrList = new ArrayList<Integer>();
for (int i = 0; i < attrCnt; ++i) {
mAttrList.add(new Integer(attrs[i]));
@@ -2236,6 +2218,7 @@ public final class Avrcp {
private String coverArt;
private String tracknum;
+ private static final int ATTR_TRACK_NUM = 0;
private static final int ATTR_TITLE = 1;
private static final int ATTR_ARTIST_NAME = 2;
private static final int ATTR_ALBUM_NAME = 3;
@@ -2253,12 +2236,12 @@ public final class Avrcp {
artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST));
albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM));
- mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
+ /* playlist array starts with 0*/
+ mediaNumber = longStringOrBlank((data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER) + 1L));
mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE));
playingTimeMs = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DURATION));
tracknum = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DISC_NUMBER));
-
// Try harder for the title.
title = data.getString(MediaMetadata.METADATA_KEY_TITLE);
@@ -2300,6 +2283,8 @@ public final class Avrcp {
return new String();
switch (attrId) {
+ case ATTR_TRACK_NUM:
+ return tracknum;
case ATTR_TITLE:
return title;
case ATTR_ARTIST_NAME:
@@ -2409,6 +2394,9 @@ public final class Avrcp {
private void processSetBrowsedPlayer(int playerId, String deviceAddress) {
String packageName = null;
+ int folder_depth = 0;
+ long num_attributes = 0;
+ ArrayList <String> folderPath = new ArrayList<String>();
byte retError = INVALID_PLAYER_ID;
BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
int deviceIndex = getIndexForDevice(device);
@@ -2416,10 +2404,7 @@ public final class Avrcp {
Log.v(TAG,"device entry not present, bailing out");
return;
}
- /* Following gets updated if SetBrowsed Player succeeds */
- deviceFeatures[deviceIndex].mCurrentPath = PATH_INVALID;
- deviceFeatures[deviceIndex].mMediaUri = Uri.EMPTY;
- deviceFeatures[deviceIndex].mCurrentPathUid = null;
+
if (DEBUG)
Log.v(TAG, "processSetBrowsedPlayer: PlayerID: " + playerId);
if (mMediaPlayers.size() > 0) {
@@ -2452,15 +2437,200 @@ public final class Avrcp {
}
}
}
- if (packageName != null) {
- mMediaController.getTransportControls().setRemoteControlClientBrowsedPlayer();
- mBrowserDevice = device;
- } else {
+ if (packageName == null) {
if (DEBUG)
Log.v(TAG, "player not available for browse");
setBrowsedPlayerRspNative(retError ,
0x0, 0x0, 0x0, 0x0,
null, getByteAddress(device));
+ } else {
+ String CurrentPath = deviceFeatures[deviceIndex].mCurrentPath;
+ String CurrentPathUid = deviceFeatures[deviceIndex].mCurrentPathUid;
+ Uri CurrentUri = deviceFeatures[deviceIndex].mMediaUri;
+ long folderUid = (CurrentPathUid != null) ? Long.valueOf(CurrentPathUid):(long)0;
+ retError = OPERATION_SUCCESSFUL;
+ folderPath.add(PATH_ROOT);
+
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ROOT)) {
+ num_attributes = NUM_ROOT_ELEMENTS;
+ folder_depth = 0;
+
+ } else if (CurrentPath.equals(PATH_TITLES)) {
+ folderPath.add(CurrentPath);
+ num_attributes = getNumItems(PATH_TITLES,
+ MediaStore.Audio.Media.TITLE, deviceIndex);
+
+ } else if (CurrentPath.equals(PATH_ALBUMS)) {
+ folderPath.add(CurrentPath);
+ if (CurrentPathUid == null) {
+ num_attributes = getNumItems(PATH_ALBUMS,
+ MediaStore.Audio.Media.ALBUM_ID, deviceIndex);
+ } else {
+ Cursor cursor = null;
+ try {
+ cursor = mContext.getContentResolver().query(CurrentUri,
+ mCursorCols, MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
+ MediaStore.Audio.Media.ALBUM_ID + "=" + folderUid, null,
+ MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
+ if (cursor != null) {
+ num_attributes = cursor.getCount();
+ String FolderName;
+ cursor.moveToFirst();
+ FolderName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
+ Log.i(TAG,"ALBUM =" + FolderName);
+ folderPath.add(FolderName);
+ } else {
+ Log.i(TAG, "Error: could not fetch the elements");
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ }
+ }
+ catch(Exception e) {
+ Log.e(TAG, "Exception e" + e);
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ } else if (CurrentPath.equals(PATH_ARTISTS)) {
+ folderPath.add(CurrentPath);
+ if (CurrentPathUid == null) {
+ num_attributes = getNumItems(PATH_ARTISTS,
+ MediaStore.Audio.Media.ARTIST_ID, deviceIndex);
+ } else {
+ Cursor cursor = null;
+ try {
+ cursor = mContext.getContentResolver().query(CurrentUri,
+ mCursorCols, MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
+ MediaStore.Audio.Media.ARTIST_ID + "=" + folderUid, null,
+ MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
+ if (cursor != null) {
+ num_attributes = cursor.getCount();
+ String FolderName;
+ cursor.moveToFirst();
+ FolderName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
+ Log.i(TAG,"ARTIST =" + FolderName);
+ folderPath.add(FolderName);
+ } else {
+ Log.i(TAG, "Error: could not fetch the elements");
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Exception e" + e);
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ } else if (CurrentPath.equals(PATH_PLAYLISTS)) {
+ folderPath.add(CurrentPath);
+ if (CurrentPathUid == null) {
+ num_attributes = getNumPlaylistItems();
+ } else {
+ Cursor cursor = null;
+ String[] playlistMemberCols = new String[] {
+ MediaStore.Audio.Playlists.Members._ID,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.DATA,
+ MediaStore.Audio.Media.ALBUM,
+ MediaStore.Audio.Media.ARTIST,
+ MediaStore.Audio.Media.DURATION,
+ MediaStore.Audio.Playlists.Members.PLAY_ORDER,
+ MediaStore.Audio.Playlists.Members.AUDIO_ID,
+ MediaStore.Audio.Media.IS_MUSIC
+ };
+ try {
+ Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
+ folderUid);
+ StringBuilder where = new StringBuilder();
+ where.append(MediaStore.Audio.Media.TITLE + " != ''");
+ cursor = mContext.getContentResolver().query(uri, playlistMemberCols,
+ where.toString(), null,
+ MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
+ if (cursor != null) {
+ num_attributes = cursor.getCount();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ Cursor tempcursor = null;
+ String[] cols = new String[] {
+ MediaStore.Audio.Playlists._ID,
+ MediaStore.Audio.Playlists.NAME
+ };
+ try {
+ tempcursor = mContext.getContentResolver().query(
+ MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
+ cols, MediaStore.Audio.Playlists._ID + "=" + folderUid,
+ null, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER);
+ if (tempcursor != null) {
+ tempcursor.moveToFirst();
+ String FolderName;
+ FolderName = tempcursor.getString(tempcursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME));
+ Log.i(TAG,"PLAYLIST = " + FolderName);
+ folderPath.add(FolderName);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ retError = INTERNAL_ERROR;
+ setBrowsedPlayerRspNative(retError,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
+ } finally {
+ if (tempcursor != null) {
+ tempcursor.close();
+ }
+ }
+ }
+
+ } else {
+ folderPath.clear();
+ retError = INTERNAL_ERROR;
+ num_attributes = 0;
+ }
+ folder_depth = folderPath.size() - 1;
+ String [] folderNames = new String[folderPath.size()];
+ folderNames = folderPath.toArray(folderNames);
+ Log.i(TAG,"SetBrowsedplayer for playerid = " + playerId + " and status code" + retError);
+ for (int i = 0; i < folderPath.size(); i++) {
+ Log.i(TAG,"folderNames[" + i + "] = " + folderNames[i]);
+ }
+ setBrowsedPlayerRspNative(retError ,
+ 0x0, (int)num_attributes, folder_depth, (int)CHAR_SET_UTF8,
+ folderNames, getByteAddress(device));
+ }
+
+ if (retError == OPERATION_SUCCESSFUL) {
+ mBrowsedPlayerId = playerId;
+ Log.i(TAG,"Set Browsed player id = " + mBrowsedPlayerId);
+ } else {
+ mBrowsedPlayerId = INVALID_ADDRESSED_PLAYER_ID;
+ Log.i(TAG,"Set Browsed player failed with error = " + retError);
}
}
@@ -3157,7 +3327,8 @@ public final class Avrcp {
}
if (mMediaController != null) {
mMediaController.getTransportControls().getRemoteControlClientNowPlayingEntries();
- mCachedRequest = new CachedRequest((long)0, (long)0, (byte)0, null, (int)0, false);
+ mCachedRequest = new CachedRequest((long)0, (long)0, (byte)0, null, (int)0, false,
+ (long)0, (byte)0, null, false);
} else {
Log.e(TAG, "processGetNowPlayingTotalItems fails: mMediaController is null");
getTotalNumberOfItemsRspNative((byte)INTERNAL_ERROR, virtualFileTotalItems,
@@ -3394,9 +3565,42 @@ public final class Avrcp {
MediaStore.Audio.Media.IS_PODCAST,
MediaStore.Audio.Media.BOOKMARK
};
+ private void processGetItemAttrInternal(byte scope, long uid, byte numAttr, int[] attrs,
+ int size, String deviceAddress) {
+ boolean cachereq = false;
+ Log.v(TAG,"processGetItemAttrInternal uid = " + uid);
+ for (int i = 0; i < numAttr; i++) {
+ if (attrs[i] == MEDIA_ATTR_TRACK_NUM ||
+ attrs[i] == MEDIA_ATTR_NUM_TRACKS)
+ cachereq = true;
+ }
+ if (scope == SCOPE_NOW_PLAYING && cachereq) {
+ Log.v(TAG,"scope now playing, caching req");
+ mMediaController.getTransportControls().getRemoteControlClientNowPlayingEntries();
+ mCachedRequest = new CachedRequest((long)0, (long)0, numAttr, attrs, size, false,
+ uid, scope, deviceAddress, true);
+ }
+ else
+ processGetItemAttr(scope, uid, numAttr, attrs, size, deviceAddress, null);
+ }
+ private void processGetItemAttrdummy(long [] playlist) {
+ byte scope = mCachedRequest.mScope;
+ long uid = mCachedRequest.mUid;
+ byte numAttr = mCachedRequest.mAttrCnt;
+ int[] attrs = new int[numAttr];
+ int size = mCachedRequest.mSize;
+ String deviceAddress = mCachedRequest.mDeviceAddress;
+ for (int i = 0; i < numAttr; ++i)
+ attrs[i] = mCachedRequest.mAttrList.get(i).intValue();
+
+ Log.v(TAG,"processGetItemAttrdummy");
+ processGetItemAttr(scope, uid, numAttr, attrs, size, deviceAddress, playlist);
+ mCachedRequest.mIsGetItemAttr = false;
+ //mCachedGetItemAttrReq = null;
+ }
private void processGetItemAttr(byte scope, long uid, byte numAttr, int[] attrs,
- int size, String deviceAddress) {
+ int size, String deviceAddress, long[] playlist) {
if (DEBUG)
Log.v(TAG, "processGetItemAttr: scope: " + scope + " uid:" + uid +
" numAttr:" + numAttr + " size: " + size);
@@ -3440,6 +3644,31 @@ public final class Avrcp {
validAttrib ++;
}
}
+ if (scope == SCOPE_NOW_PLAYING && playlist != null) {
+ long arraylength = playlist.length;
+ Log.i(TAG,"arraylength = " + arraylength);
+ for (int i = 0; i < numAttr; ++i) {
+ if (attrs[i] == MEDIA_ATTR_NUM_TRACKS)
+ textArray[i] = String.valueOf(arraylength);
+ if (attrs[i] == MEDIA_ATTR_TRACK_NUM) {
+ for (int j = 0; j < playlist.length; ++j) {
+ cursor = mContext.getContentResolver().query(
+ deviceFeatures[deviceIndex].mMediaUri, mCursorCols,
+ MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" +
+ playlist[j], null, null);
+ if (cursor != null) {
+ cursor.moveToFirst();
+ long muid = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
+ Log.i(TAG,"uid = " + uid + "muid = " + muid);
+ if (muid == uid) {
+ textArray[i] = String.valueOf(j+1); //j starts from 0
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
getItemAttrRspNative(numAttr ,attrs ,
textArray, size, getByteAddress(device));
}
@@ -3660,6 +3889,15 @@ public final class Avrcp {
attIds[count] = 0;
}
+ if (!deviceFeatures[deviceIndex].isBrowsingSupported || mBrowsedPlayerId != 0) {
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds, size,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ Log.v(TAG, "Browsed player is yet not set");
+ return;
+ }
+
if (DEBUG)
Log.v(TAG, "mCurrentPath: " +
deviceFeatures[deviceIndex].mCurrentPath);
@@ -4428,7 +4666,8 @@ public final class Avrcp {
}
}
mMediaController.getTransportControls().getRemoteControlClientNowPlayingEntries();
- mCachedRequest = new CachedRequest(start, end, numAttr, attrs, size, true);
+ mCachedRequest = new CachedRequest(start, end, numAttr, attrs, size, true, (long)0,
+ (byte)0, null, false);
}
}
@@ -4660,12 +4899,34 @@ public final class Avrcp {
try {
TrackNumberRsp = Long.parseLong(mMediaAttributes.getString
- (MediaAttributes.ATTR_MEDIA_NUMBER));
+ (MediaAttributes.ATTR_MEDIA_NUMBER));
+ if ((((deviceFeatures[deviceIndex].mFeatures & BTRC_FEAT_BROWSE) != 0) &&
+ (deviceFeatures[deviceIndex].mCurrentPath != PATH_INVALID)) ||
+ ((deviceFeatures[deviceIndex].mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) &&
+ (((deviceFeatures[deviceIndex].mFeatures & BTRC_FEAT_BROWSE) != 0) &&
+ deviceFeatures[deviceIndex].mCurrentPath == PATH_INVALID))) {
+ /* First time when media playback is resumed after AVRCP connection,
+ * track changed rsp is not sent, So send track num for interim resp
+ * if browse channel is not connected yet to avoid metadata not getting
+ * updated properly.
+ */
+ Log.e(TAG,"sendTrackChangedRsp: device supports browsing");
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo di = rccIterator.next();
+ if (di.IsPlayerBrowsable() && (di.GetPlayerFocus() == true)) {
+ TrackNumberRsp = Long.parseLong(mMediaAttributes.getString
+ (MediaAttributes.ATTR_TRACK_NUM));
+ Log.e(TAG,"sendTrackChangedRsp: in focus tracnum = " + TrackNumberRsp);
+ }
+ }
+ }
+ }
} catch (Exception e) {
Log.e(TAG, "sendTrackChangedRsp Exception e" + e);
TrackNumberRsp = -1;
}
-
/* track is stored in big endian format */
for (int i = 0; i < TRACK_ID_SIZE; ++i) {
track[i] = (byte) (TrackNumberRsp >> (56 - 8 * i));
@@ -4783,16 +5044,17 @@ public final class Avrcp {
int playStatus = PLAYSTATUS_ERROR;
switch (state.getState()) {
case PlaybackState.STATE_PLAYING:
- case PlaybackState.STATE_BUFFERING:
playStatus = PLAYSTATUS_PLAYING;
break;
case PlaybackState.STATE_STOPPED:
+ case PlaybackState.STATE_CONNECTING:
case PlaybackState.STATE_NONE:
playStatus = PLAYSTATUS_STOPPED;
break;
case PlaybackState.STATE_PAUSED:
+ case PlaybackState.STATE_BUFFERING:
playStatus = PLAYSTATUS_PAUSED;
break;
@@ -4832,6 +5094,14 @@ public final class Avrcp {
return;
}
long playPositionMs = getPlayPosition(deviceFeatures[i].mCurrentDevice);
+ int currPlayStatus = convertPlayStateToPlayStatus(deviceFeatures[i].mCurrentPlayState);
+
+ // Some remote devices are going to bad state when sending play position
+ // as ffff for non-playing state
+ if (playPositionMs == -1L && currPlayStatus != PLAYSTATUS_PLAYING) {
+ if (DEBUG) Log.d(TAG, " Don't send invalid play position notification for non-playing state");
+ return;
+ }
// mNextPosMs is set to -1 when the previous position was invalid
// so this will be true if the new position is valid & old was invalid.
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 09f03808f..f4d029796 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -89,7 +89,8 @@ import android.os.SystemProperties;
public class AdapterService extends Service {
private static final String TAG = "BluetoothAdapterService";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
+ private static final boolean VERBOSE = false;
private static final boolean TRACE_REF = false;
private static final int MIN_ADVT_INSTANCES_FOR_MA = 5;
private static final int MIN_OFFLOADED_FILTERS = 10;
@@ -539,6 +540,8 @@ public class AdapterService extends Service {
mProfileObserver = new ProfileObserver(getApplicationContext(), this, new Handler());
mProfileObserver.start();
mVendor.init();
+
+ setAdapterService(this);
}
@Override
@@ -594,9 +597,6 @@ public class AdapterService extends Service {
// Ignore.
}
- //FIXME: Set static instance here???
- setAdapterService(this);
-
//Start Gatt service
setGattProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
}
@@ -1643,7 +1643,10 @@ public class AdapterService extends Service {
Log.i(TAG,"A2dp Multicast is Ongoing, ignore discovery");
return false;
}
-
+ if (mAdapterProperties.isDiscovering()) {
+ Log.i(TAG,"discovery already active, ignore startDiscovery");
+ return false;
+ }
return startDiscoveryNative();
}
@@ -1651,6 +1654,10 @@ public class AdapterService extends Service {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
+ if (!mAdapterProperties.isDiscovering()) {
+ Log.i(TAG,"discovery not active, ignore cancelDiscovery");
+ return false;
+ }
return cancelDiscoveryNative();
}
@@ -1754,6 +1761,12 @@ public class AdapterService extends Service {
}
}
+ private void cancelDiscoveryforautoConnect(){
+ if (mAdapterProperties.isDiscovering() == true) {
+ cancelDiscovery();
+ }
+ }
+
private void autoConnectHeadset(){
HeadsetService hsService = HeadsetService.getHeadsetService();
@@ -1763,6 +1776,7 @@ public class AdapterService extends Service {
}
for (BluetoothDevice device : bondedDevices) {
if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
+ cancelDiscoveryforautoConnect();
debugLog("autoConnectHeadset() - Connecting HFP with " + device.toString());
hsService.connect(device);
}
@@ -1777,6 +1791,7 @@ public class AdapterService extends Service {
}
for (BluetoothDevice device : bondedDevices) {
if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
+ cancelDiscoveryforautoConnect();
debugLog("autoConnectA2dp() - Connecting A2DP with " + device.toString());
a2dpSservice.connect(device);
}
@@ -1792,9 +1807,10 @@ public class AdapterService extends Service {
for (BluetoothDevice device : bondedDevices) {
if (headsetClientService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT){
- debugLog("autoConnectHeadsetClient() - Connecting Headset Client with " +
- device.toString());
- headsetClientService.connect(device);
+ cancelDiscoveryforautoConnect();
+ debugLog("autoConnectHeadsetClient() - Connecting Headset Client with " +
+ device.toString());
+ headsetClientService.connect(device);
}
}
}
@@ -1808,6 +1824,7 @@ public class AdapterService extends Service {
for (BluetoothDevice device : bondedDevices) {
if (a2dpSinkService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ cancelDiscoveryforautoConnect();
debugLog("autoConnectA2dpSink() - Connecting A2DP Sink with " + device.toString());
a2dpSinkService.connect(device);
}
@@ -1822,6 +1839,7 @@ public class AdapterService extends Service {
}
for (BluetoothDevice device : bondedDevices) {
if (pbapClientService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ cancelDiscoveryforautoConnect();
debugLog("autoConnectPbapClient() - Connecting PBAP Client with " +
device.toString());
pbapClientService.connect(device);
@@ -2101,9 +2119,9 @@ public class AdapterService extends Service {
case BluetoothProfile.A2DP:
A2dpService a2dpService = A2dpService.getA2dpService();
- deviceList = a2dpService.getConnectedDevices();
if ((a2dpService != null) &&
(BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
+ deviceList = a2dpService.getConnectedDevices();
adjustOtherSinkPriorities(a2dpService, deviceList);
a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
}
@@ -2662,11 +2680,12 @@ public class AdapterService extends Service {
}
}
- debugLog("energyInfoCallback() status = " + status +
- "tx_time = " + tx_time + "rx_time = " + rx_time +
- "idle_time = " + idle_time + "energy_used = " + energy_used +
- "ctrl_state = " + ctrl_state +
- "traffic = " + Arrays.toString(data));
+ verboseLog("energyInfoCallback() status = " + status +
+ "tx_time = " + tx_time + "rx_time = " + rx_time +
+ "idle_time = " + idle_time +
+ "energy_used = " + energy_used +
+ "ctrl_state = " + ctrl_state +
+ "traffic = " + Arrays.toString(data));
}
private int getIdleCurrentMa() {
@@ -2712,8 +2731,8 @@ public class AdapterService extends Service {
enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
if (args.length > 0) {
- debugLog("dumpsys arguments, check for protobuf output: " +
- TextUtils.join(" ", args));
+ verboseLog("dumpsys arguments, check for protobuf output: "
+ + TextUtils.join(" ", args));
if (args[0].startsWith("--proto")) {
if (args[0].equals("--proto-java-bin")) {
dumpJava(fd);
@@ -2761,6 +2780,7 @@ public class AdapterService extends Service {
private void dumpJava(FileDescriptor fd) {
BluetoothProto.BluetoothLog log = new BluetoothProto.BluetoothLog();
+ log.setNumBondedDevices(getBondedDevices().length);
for (ProfileService profile : mProfiles) {
profile.dumpProto(log);
@@ -2788,6 +2808,10 @@ public class AdapterService extends Service {
if (DBG) Log.d(TAG, msg);
}
+ private void verboseLog(String msg) {
+ if (VERBOSE) Log.v(TAG, msg);
+ }
+
private void errorLog(String msg) {
Log.e(TAG, msg);
}
diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java
index 19089a742..94c469d8f 100644
--- a/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -30,12 +30,15 @@ import com.android.bluetooth.Utils;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.ArrayList;
import java.util.HashMap;
-
+import java.util.LinkedList;
+import java.util.Queue;
final class RemoteDevices {
private static final boolean DBG = false;
private static final String TAG = "BluetoothRemoteDevices";
+ // Maximum number of device properties to remember
+ private static final int MAX_DEVICE_QUEUE_SIZE = 200;
private static BluetoothAdapter mAdapter;
private static AdapterService mAdapterService;
@@ -45,13 +48,15 @@ final class RemoteDevices {
private static final int UUID_INTENT_DELAY = 6000;
private static final int MESSAGE_UUID_INTENT = 1;
- private HashMap<BluetoothDevice, DeviceProperties> mDevices;
+ private HashMap<String, DeviceProperties> mDevices;
+ private Queue<String> mDeviceQueue;
RemoteDevices(AdapterService service) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mAdapterService = service;
mSdpTracker = new ArrayList<BluetoothDevice>();
- mDevices = new HashMap<BluetoothDevice, DeviceProperties>();
+ mDevices = new HashMap<String, DeviceProperties>();
+ mDeviceQueue = new LinkedList<String>();
}
@@ -61,6 +66,9 @@ final class RemoteDevices {
if (mDevices != null)
mDevices.clear();
+
+ if (mDeviceQueue != null)
+ mDeviceQueue.clear();
}
@Override
@@ -70,28 +78,36 @@ final class RemoteDevices {
DeviceProperties getDeviceProperties(BluetoothDevice device) {
synchronized (mDevices) {
- return mDevices.get(device);
+ return mDevices.get(device.getAddress());
}
}
BluetoothDevice getDevice(byte[] address) {
- synchronized (mDevices) {
- for (BluetoothDevice dev : mDevices.keySet()) {
- if (dev.getAddress().equals(Utils.getAddressStringFromByte(address))) {
- return dev;
- }
- }
- }
- return null;
+ DeviceProperties prop = mDevices.get(Utils.getAddressStringFromByte(address));
+ if (prop == null)
+ return null;
+ return prop.getDevice();
}
DeviceProperties addDeviceProperties(byte[] address) {
synchronized (mDevices) {
DeviceProperties prop = new DeviceProperties();
- BluetoothDevice device =
- mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
+ prop.mDevice = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
prop.mAddress = address;
- mDevices.put(device, prop);
+ String key = Utils.getAddressStringFromByte(address);
+ DeviceProperties pv = mDevices.put(key, prop);
+
+ if (pv == null) {
+ mDeviceQueue.offer(key);
+ if (mDeviceQueue.size() > MAX_DEVICE_QUEUE_SIZE) {
+ String deleteKey = mDeviceQueue.poll();
+ for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
+ if (device.getAddress().equals(deleteKey)) return prop;
+ }
+ debugLog("Removing device " + deleteKey + " from property map");
+ mDevices.remove(deleteKey);
+ }
+ }
return prop;
}
}
@@ -105,6 +121,7 @@ final class RemoteDevices {
private int mDeviceType;
private String mAlias;
private int mBondState;
+ private BluetoothDevice mDevice;
DeviceProperties() {
mBondState = BluetoothDevice.BOND_NONE;
@@ -147,6 +164,15 @@ final class RemoteDevices {
}
/**
+ * @return the mDevice
+ */
+ BluetoothDevice getDevice() {
+ synchronized (mObject) {
+ return mDevice;
+ }
+ }
+
+ /**
* @return mRssi
*/
short getRssi() {
@@ -235,6 +261,7 @@ final class RemoteDevices {
BluetoothDevice bdDevice = getDevice(address);
DeviceProperties device;
if (bdDevice == null) {
+ debugLog("Added new device property");
device = addDeviceProperties(address);
bdDevice = getDevice(address);
} else {
@@ -244,11 +271,12 @@ final class RemoteDevices {
for (int j = 0; j < types.length && device != null; j++) {
type = types[j];
val = values[j];
- if(val.length <= 0)
+ if (val.length <= 0)
errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice
+ ", value is empty for type: " + type);
else {
synchronized(mObject) {
+ debugLog("Property type: " + type);
switch (type) {
case AbstractionLayer.BT_PROPERTY_BDNAME:
device.mName = new String(val);
diff --git a/src/com/android/bluetooth/btservice/bluetooth.proto b/src/com/android/bluetooth/btservice/bluetooth.proto
index 11311ea58..77ded7807 100644
--- a/src/com/android/bluetooth/btservice/bluetooth.proto
+++ b/src/com/android/bluetooth/btservice/bluetooth.proto
@@ -25,6 +25,9 @@ message BluetoothLog {
// Scan event information.
repeated ScanEvent scan_event = 4;
+
+ // Number of bonded devices.
+ optional int32 num_bonded_devices = 5;
}
// The information about the device.
diff --git a/src/com/android/bluetooth/gatt/AdvertiseManager.java b/src/com/android/bluetooth/gatt/AdvertiseManager.java
index 058bf4b59..3fb4aa945 100644
--- a/src/com/android/bluetooth/gatt/AdvertiseManager.java
+++ b/src/com/android/bluetooth/gatt/AdvertiseManager.java
@@ -194,7 +194,7 @@ class AdvertiseManager {
private void handleStartAdvertising(AdvertiseClient client) {
Utils.enforceAdminPermission(mService);
int clientIf = client.clientIf;
- if (mAdvertiseClients.contains(clientIf)) {
+ if (mAdvertiseClients.contains(client)) {
postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
return;
}
diff --git a/src/com/android/bluetooth/gatt/ContextMap.java b/src/com/android/bluetooth/gatt/ContextMap.java
index e3044d586..024572792 100644
--- a/src/com/android/bluetooth/gatt/ContextMap.java
+++ b/src/com/android/bluetooth/gatt/ContextMap.java
@@ -190,6 +190,7 @@ import com.android.bluetooth.btservice.BluetoothProto;
while (i.hasNext()) {
App entry = i.next();
if (entry.id == id) {
+ removeConnectionsByAppId(id);
entry.unlinkToDeath();
entry.appScanStats.isRegistered = false;
i.remove();
@@ -205,7 +206,7 @@ import com.android.bluetooth.btservice.BluetoothProto;
void addConnection(int id, int connId, String address) {
synchronized (mConnections) {
App entry = getById(id);
- if (entry != null){
+ if (entry != null) {
mConnections.add(new Connection(connId, address, id));
}
}
@@ -228,6 +229,19 @@ import com.android.bluetooth.btservice.BluetoothProto;
}
/**
+ * Remove all connections for a given application ID.
+ */
+ void removeConnectionsByAppId(int appId) {
+ Iterator<Connection> i = mConnections.iterator();
+ while (i.hasNext()) {
+ Connection connection = i.next();
+ if (connection.appId == appId) {
+ i.remove();
+ }
+ }
+ }
+
+ /**
* Get an application context by ID.
*/
App getById(int id) {
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index e1e5e5728..f8bef759d 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -237,6 +237,7 @@ public class GattService extends ProfileService {
boolean permissionCheck(int connId, int handle) {
List<BluetoothGattService> db = gattClientDatabases.get(connId);
+ if (db == null) return true;
for (BluetoothGattService service : db) {
for (BluetoothGattCharacteristic characteristic: service.getCharacteristics()) {
@@ -759,7 +760,15 @@ public class GattService extends ProfileService {
void onSearchCompleted(int connId, int status) throws RemoteException {
if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
// Gatt DB is ready!
- gattClientGetGattDbNative(connId);
+
+ // This callback was called from the jni_workqueue thread. If we make request to the stack
+ // on the same thread, it might cause deadlock. Schedule request on a new thread instead.
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ gattClientGetGattDbNative(connId);
+ }
+ });
+ t.start();
}
GattDbElement GetSampleGattDbElement() {
@@ -1391,9 +1400,20 @@ public class GattService extends ProfileService {
}
void unregAll() {
- for(ClientMap.App app:mClientMap.mApps){
- if (DBG) Log.d(TAG, "unreg:" + app.id);
- unregisterClient(app.id);
+ int clientCount = mClientMap.mApps.size();
+ int counter = 0;
+ while ((counter < clientCount) && (mClientMap.mApps.size() > 0)) {
+ if (DBG) Log.d(TAG, "unreg client:" + mClientMap.mApps.get(0).id);
+ unregisterClient(mClientMap.mApps.get(0).id);
+ counter ++;
+ }
+
+ int serverCount = mServerMap.mApps.size();
+ counter = 0;
+ while ((counter < serverCount) && (mServerMap.mApps.size() > 0)) {
+ if (DBG) Log.d(TAG, "unreg server:" + mServerMap.mApps.get(0).id);
+ unregisterServer(mServerMap.mApps.get(0).id);
+ counter ++;
}
}
@@ -1627,12 +1647,11 @@ public class GattService extends ProfileService {
void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- // Default spec recommended interval is 30->50 ms
- int minInterval = 24; // 24 * 1.25ms = 30ms
- int maxInterval = 40; // 40 * 1.25ms = 50ms
+ int minInterval;
+ int maxInterval;
// Slave latency
- int latency = 0;
+ int latency;
// Link supervision timeout is measured in N * 10ms
int timeout = 2000; // 20s
@@ -1642,12 +1661,22 @@ public class GattService extends ProfileService {
case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval);
maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval);
+ latency = getResources().getInteger(R.integer.gatt_high_priority_latency);
break;
case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval);
maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval);
- latency = 2;
+ latency = getResources().getInteger(R.integer.gatt_low_power_latency);
+ break;
+
+ default:
+ // Using the values for CONNECTION_PRIORITY_BALANCED.
+ minInterval =
+ getResources().getInteger(R.integer.gatt_balanced_priority_min_interval);
+ maxInterval =
+ getResources().getInteger(R.integer.gatt_balanced_priority_max_interval);
+ latency = getResources().getInteger(R.integer.gatt_balanced_priority_latency);
break;
}
diff --git a/src/com/android/bluetooth/gatt/HandleMap.java b/src/com/android/bluetooth/gatt/HandleMap.java
index 4a2063984..27a7a7194 100644
--- a/src/com/android/bluetooth/gatt/HandleMap.java
+++ b/src/com/android/bluetooth/gatt/HandleMap.java
@@ -69,7 +69,6 @@ class HandleMap {
this.type = type;
this.handle = handle;
this.uuid = uuid;
- this.instance = instance;
this.serviceHandle = serviceHandle;
}
@@ -78,7 +77,6 @@ class HandleMap {
this.type = type;
this.handle = handle;
this.uuid = uuid;
- this.instance = instance;
this.serviceHandle = serviceHandle;
this.charHandle = charHandle;
}
diff --git a/src/com/android/bluetooth/gatt/ScanManager.java b/src/com/android/bluetooth/gatt/ScanManager.java
index 7712997db..9ed405901 100644
--- a/src/com/android/bluetooth/gatt/ScanManager.java
+++ b/src/com/android/bluetooth/gatt/ScanManager.java
@@ -40,11 +40,13 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.internal.app.IBatteryStats;
import java.util.ArrayDeque;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -95,8 +97,8 @@ public class ScanManager {
private CountDownLatch mLatch;
ScanManager(GattService service) {
- mRegularScanClients = new HashSet<ScanClient>();
- mBatchClients = new HashSet<ScanClient>();
+ mRegularScanClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
+ mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
mService = service;
mScanNative = new ScanNative();
curUsedTrackableAdvertisements = 0;
@@ -238,11 +240,11 @@ public class ScanManager {
if (!mScanNative.isOpportunisticScanClient(client)) {
mScanNative.configureRegularScanParams();
- if (!mScanNative.isFirstMatchScanClient(client)) {
+ if (!mScanNative.isExemptFromScanDowngrade(client)) {
Message msg = mHandler.obtainMessage(MSG_SCAN_TIMEOUT);
msg.obj = client;
// Only one timeout message should exist at any time
- mHandler.removeMessages(SCAN_TIMEOUT_MS);
+ mHandler.removeMessages(MSG_SCAN_TIMEOUT);
mHandler.sendMessageDelayed(msg, SCAN_TIMEOUT_MS);
}
}
@@ -261,10 +263,6 @@ public class ScanManager {
if (client == null) return;
if (mRegularScanClients.contains(client)) {
- // The ScanClient passed in just holds the clientIf. We retrieve the real client,
- // which may have workSource set.
- client = mScanNative.getRegularScanClient(client.clientIf);
- if (client == null) return;
mScanNative.stopRegularScan(client);
@@ -278,7 +276,11 @@ public class ScanManager {
// Update BatteryStats with this workload.
try {
- mBatteryStats.noteBleScanStopped(client.workSource);
+ // The ScanClient passed in just holds the clientIf. We retrieve the real client,
+ // which may have workSource set.
+ ScanClient workClient = mScanNative.getRegularScanClient(client.clientIf);
+ if (workClient != null)
+ mBatteryStats.noteBleScanStopped(workClient.workSource);
} catch (RemoteException e) {
/* ignore */
}
@@ -534,6 +536,12 @@ public class ScanManager {
}
}
+ private boolean isExemptFromScanDowngrade(ScanClient client) {
+ return isOpportunisticScanClient(client)
+ || isFirstMatchScanClient(client)
+ || !shouldUseAllPassFilter(client);
+ }
+
private boolean isOpportunisticScanClient(ScanClient client) {
return client.settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
}
@@ -683,8 +691,9 @@ public class ScanManager {
void regularScanTimeout() {
for (ScanClient client : mRegularScanClients) {
- if (!isOpportunisticScanClient(client) && !isFirstMatchScanClient(client)) {
- logd("clientIf set to scan opportunisticly: " + client.clientIf);
+ if (!isExemptFromScanDowngrade(client)) {
+ Log.w(TAG, "Moving scan client to opportunistic (clientIf "
+ + client.clientIf + ")");
setOpportunisticScanClient(client);
client.stats.setScanTimeout();
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetHalConstants.java b/src/com/android/bluetooth/hfp/HeadsetHalConstants.java
index 0742917c1..dee633f2d 100644
--- a/src/com/android/bluetooth/hfp/HeadsetHalConstants.java
+++ b/src/com/android/bluetooth/hfp/HeadsetHalConstants.java
@@ -64,4 +64,8 @@ final public class HeadsetHalConstants {
final static int CALL_STATE_INCOMING = 4;
final static int CALL_STATE_WAITING = 5;
final static int CALL_STATE_IDLE = 6;
+
+ // Match up with bthf_hf_ind_type_t of bt_hf.h
+ final static int HF_INDICATOR_ENHANCED_DRIVER_SAFETY = 1;
+ final static int HF_INDICATOR_BATTERY_LEVEL_STATUS = 2;
}
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 05806fa59..76ef46301 100644..100755
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -339,6 +339,7 @@ final class HeadsetClientStateMachine extends StateMachine {
Log.d(TAG, "Enter sendCallChangedIntent()");
Log.d(TAG, "sendCallChangedIntent " + c);
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CALL_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c);
mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
Log.d(TAG, "Exit sendCallChangedIntent()");
diff --git a/src/com/android/bluetooth/hid/HidService.java b/src/com/android/bluetooth/hid/HidService.java
index ba6ca2ca4..23178d04b 100644
--- a/src/com/android/bluetooth/hid/HidService.java
+++ b/src/com/android/bluetooth/hid/HidService.java
@@ -109,6 +109,12 @@ public class HidService extends ProfileService {
}
if(mInputDevices != null) {
+ for (BluetoothDevice device: mInputDevices.keySet()) {
+ int inputDeviceState = getConnectionState(device);
+ if (inputDeviceState != BluetoothProfile.STATE_DISCONNECTED) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
+ }
+ }
mInputDevices.clear();
}
clearHidService();
diff --git a/src/com/android/bluetooth/map/BluetoothMapContent.java b/src/com/android/bluetooth/map/BluetoothMapContent.java
index 2370a4d35..4f42bfb58 100755
--- a/src/com/android/bluetooth/map/BluetoothMapContent.java
+++ b/src/com/android/bluetooth/map/BluetoothMapContent.java
@@ -950,10 +950,14 @@ public class BluetoothMapContent {
address = c.getString(c.getColumnIndex(Sms.ADDRESS));
}
if ((address == null) && msgType == Sms.MESSAGE_TYPE_DRAFT) {
- //Fetch address for Drafts folder from "canonical_address" table
+ // Fetch address for Drafts folder from "canonical_address" table
int threadIdInd = c.getColumnIndex(Sms.THREAD_ID);
String threadIdStr = c.getString(threadIdInd);
- address = getCanonicalAddressSms(mResolver, Integer.valueOf(threadIdStr));
+ // If a draft message has no recipient, it has no thread ID
+ // hence threadIdStr could possibly be null
+ if (threadIdStr != null) {
+ address = getCanonicalAddressSms(mResolver, Integer.valueOf(threadIdStr));
+ }
if(V) Log.v(TAG, "threadId = " + threadIdStr + " adress:" + address +"\n");
}
} else if (fi.mMsgType == FilterInfo.TYPE_MMS) {
@@ -961,7 +965,7 @@ public class BluetoothMapContent {
address = getAddressMms(mResolver, id, MMS_TO);
} else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) {
/* Might be another way to handle addresses */
- address = getRecipientAddressingEmail(e, c,fi);
+ address = getRecipientAddressingEmail(e, c, fi);
}
if (V) Log.v(TAG, "setRecipientAddressing: " + address);
if(address == null)
@@ -1603,7 +1607,8 @@ public class BluetoothMapContent {
} else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) {
where = Sms.TYPE + " = 2 AND " + Sms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) {
- where = Sms.TYPE + " = 3 AND " + Sms.THREAD_ID + " <> -1";
+ where = Sms.TYPE + " = 3 AND " +
+ "(" + Sms.THREAD_ID + " IS NULL OR " + Sms.THREAD_ID + " <> -1 )";
} else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) {
where = Sms.THREAD_ID + " = -1";
}
@@ -1620,7 +1625,8 @@ public class BluetoothMapContent {
} else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) {
where = Mms.MESSAGE_BOX + " = 2 AND " + Mms.THREAD_ID + " <> -1";
} else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) {
- where = Mms.MESSAGE_BOX + " = 3 AND " + Mms.THREAD_ID + " <> -1";
+ where = Mms.MESSAGE_BOX + " = 3 AND " +
+ "(" + Mms.THREAD_ID + " IS NULL OR " + Mms.THREAD_ID + " <> -1 )";
} else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) {
where = Mms.THREAD_ID + " = -1";
}
diff --git a/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
index 878f5bedf..c70408ccb 100755
--- a/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
+++ b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
@@ -37,6 +37,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserManager;
import android.provider.Telephony;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
@@ -172,7 +173,9 @@ public class BluetoothMapContentObserver {
public static final String EXTRA_MESSAGE_SENT_TIMESTAMP = "timestamp";
private SmsBroadcastReceiver mSmsBroadcastReceiver = new SmsBroadcastReceiver();
+ private CeBroadcastReceiver mCeBroadcastReceiver = new CeBroadcastReceiver();
+ private boolean mStorageUnlocked = false;
private boolean mInitialized = false;
@@ -480,6 +483,12 @@ public class BluetoothMapContentObserver {
Log.w(TAG, "onChange() with URI == null - not handled.");
return;
}
+
+ if (!mStorageUnlocked) {
+ Log.v(TAG, "Ignore events until storage is completely unlocked");
+ return;
+ }
+
if (V) Log.d(TAG, "onChange on thread: " + Thread.currentThread().getId()
+ " Uri: " + uri.toString() + " selfchange: " + selfChange);
@@ -1184,9 +1193,10 @@ public class BluetoothMapContentObserver {
private void initMsgList() throws RemoteException {
if (V) Log.d(TAG, "initMsgList");
+ UserManager manager = UserManager.get(mContext);
+ if (manager == null || !manager.isUserUnlocked()) return;
- if(mEnableSmsMms) {
-
+ if (mEnableSmsMms) {
HashMap<Long, Msg> msgListSms = new HashMap<Long, Msg>();
Cursor c = mResolver.query(Sms.CONTENT_URI,
@@ -2361,21 +2371,19 @@ public class BluetoothMapContentObserver {
/* Approved MAP spec errata 3445 states that read status initiated
* by the MCE shall change the MSE read status. */
if (type == TYPE.SMS_GSM || type == TYPE.SMS_CDMA) {
- Uri uri = Sms.Inbox.CONTENT_URI;
+ Uri uri = ContentUris.withAppendedId(Sms.CONTENT_URI, handle);
ContentValues contentValues = new ContentValues();
contentValues.put(Sms.READ, statusValue);
contentValues.put(Sms.SEEN, statusValue);
- String where = Sms._ID+"="+handle;
String values = contentValues.toString();
- if (D) Log.d(TAG, " -> SMS Uri: " + uri.toString() +
- " Where " + where + " values " + values);
+ if (D) Log.d(TAG, " -> SMS Uri: " + uri.toString() + " values " + values);
synchronized(getMsgListSms()) {
Msg msg = getMsgListSms().get(handle);
if(msg != null) { // This will always be the case
msg.flagRead = statusValue;
}
}
- count = mResolver.update(uri, contentValues, where, null);
+ count = mResolver.update(uri, contentValues, null, null);
if (D) Log.d(TAG, " -> "+count +" rows updated!");
} else if (type == TYPE.MMS) {
@@ -2455,8 +2463,16 @@ public class BluetoothMapContentObserver {
long folderId = -1;
if (recipientList == null) {
- if (D) Log.d(TAG, "empty recipient list");
- return -1;
+ if (folderElement.getName().equalsIgnoreCase(BluetoothMapContract.FOLDER_NAME_DRAFT)) {
+ BluetoothMapbMessage.vCard empty =
+ new BluetoothMapbMessage.vCard("", "", null, null, 0);
+ recipientList = new ArrayList<BluetoothMapbMessage.vCard>();
+ recipientList.add(empty);
+ Log.w(TAG, "Added empty recipient to draft message");
+ } else {
+ Log.e(TAG, "Trying to send a message with no recipients");
+ return -1;
+ }
}
if ( msg.getType().equals(TYPE.EMAIL) ) {
@@ -3190,6 +3206,52 @@ public class BluetoothMapContentObserver {
}
}
+ private class CeBroadcastReceiver extends BroadcastReceiver {
+ public void register() {
+ UserManager manager = UserManager.get(mContext);
+ if (manager == null || manager.isUserUnlocked()) {
+ mStorageUnlocked = true;
+ return;
+ }
+
+ Handler handler = new Handler(Looper.getMainLooper());
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ mContext.registerReceiver(this, intentFilter, null, handler);
+ }
+
+ public void unregister() {
+ try {
+ mContext.unregisterReceiver(this);
+ } catch (IllegalArgumentException e) {
+ /* do nothing */
+ }
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "onReceive: action" + action);
+
+ if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
+ try {
+ initMsgList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error initializing SMS/MMS message lists.");
+ }
+
+ for (String folder : FOLDER_SMS_MAP.values()) {
+ Event evt = new Event(EVENT_TYPE_NEW, -1, folder, mSmsType);
+ sendEvent(evt);
+ }
+ mStorageUnlocked = true;
+ /* After unlock this BroadcastReceiver is never needed */
+ unregister();
+ } else {
+ Log.d(TAG, "onReceive: Unknown action " + action);
+ }
+ }
+ }
+
/**
* Handle MMS sent intents in disconnected(MNS) state, where we do not need to send any
* notifications.
@@ -3331,6 +3393,8 @@ public class BluetoothMapContentObserver {
private void resendPendingMessages() {
/* Send pending messages in outbox */
String where = "type = " + Sms.MESSAGE_TYPE_OUTBOX;
+ UserManager manager = UserManager.get(mContext);
+ if (manager == null || !manager.isUserUnlocked()) return;
Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null,
null);
try {
@@ -3398,6 +3462,11 @@ public class BluetoothMapContentObserver {
if (mSmsBroadcastReceiver != null) {
mSmsBroadcastReceiver.register();
}
+
+ if (mCeBroadcastReceiver != null) {
+ mCeBroadcastReceiver.register();
+ }
+
registerPhoneServiceStateListener();
mInitialized = true;
}
diff --git a/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java b/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java
index 88e5605de..832060e86 100644
--- a/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java
+++ b/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java
@@ -27,6 +27,7 @@ import android.util.Log;
import android.util.Xml;
import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+import com.android.bluetooth.util.Interop;
public class BluetoothMapMessageListingElement
implements Comparable<BluetoothMapMessageListingElement> {
@@ -276,9 +277,17 @@ public class BluetoothMapMessageListingElement
BluetoothMapUtils.getMapHandle(mCpHandle, mType));
if(mSubject != null){
String stripped = BluetoothMapUtils.stripInvalidChars(mSubject);
+
+ if (Interop.matchByAddress(Interop.INTEROP_MAP_ASCIIONLY,
+ BluetoothMapService.getRemoteDevice().getAddress())) {
+ stripped = stripped.replaceAll("[\\P{ASCII}&\"><]", "");
+ if (stripped.isEmpty()) stripped = "---";
+ }
+
xmlMsgElement.attribute(null, "subject",
stripped.substring(0, stripped.length() < 256 ? stripped.length() : 256));
}
+
if(mDateTime != 0)
xmlMsgElement.attribute(null, "datetime", this.getDateTimeString());
if(mSenderName != null)
diff --git a/src/com/android/bluetooth/map/BluetoothMapObexServer.java b/src/com/android/bluetooth/map/BluetoothMapObexServer.java
index f0c26b0de..00b290215 100644
--- a/src/com/android/bluetooth/map/BluetoothMapObexServer.java
+++ b/src/com/android/bluetooth/map/BluetoothMapObexServer.java
@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.os.UserManager;
import android.text.format.DateUtils;
import android.util.Log;
@@ -402,6 +403,11 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
return ResponseCodes.OBEX_HTTP_OK;
}
+ private boolean isUserUnlocked() {
+ UserManager manager = UserManager.get(mContext);
+ return (manager == null || manager.isUserUnlocked());
+ }
+
@Override
public int onPut(final Operation op) {
if (D) Log.d(TAG, "onPut(): enter");
@@ -431,26 +437,34 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
return ResponseCodes.OBEX_HTTP_OK;
}
return updateInbox();
- }else if(type.equals(TYPE_SET_NOTIFICATION_REGISTRATION)) {
+ } else if (type.equals(TYPE_SET_NOTIFICATION_REGISTRATION)) {
if(V) {
Log.d(TAG,"TYPE_SET_NOTIFICATION_REGISTRATION: NotificationStatus: "
+ appParams.getNotificationStatus());
}
return mObserver.setNotificationRegistration(appParams.getNotificationStatus());
- }else if(type.equals(TYPE_SET_NOTIFICATION_FILTER)) {
+ } else if (type.equals(TYPE_SET_NOTIFICATION_FILTER)) {
if(V) {
Log.d(TAG,"TYPE_SET_NOTIFICATION_FILTER: NotificationFilter: "
+ appParams.getNotificationFilter());
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
mObserver.setNotificationFilter(appParams.getNotificationFilter());
return ResponseCodes.OBEX_HTTP_OK;
- } else if(type.equals(TYPE_SET_MESSAGE_STATUS)) {
+ } else if (type.equals(TYPE_SET_MESSAGE_STATUS)) {
if(V) {
Log.d(TAG,"TYPE_SET_MESSAGE_STATUS: " +
"StatusIndicator: " + appParams.getStatusIndicator()
+ ", StatusValue: " + appParams.getStatusValue()
+ ", ExtentedData: " + "" ); // TODO: appParams.getExtendedImData());
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
return setMessageStatus(name, appParams);
} else if (type.equals(TYPE_MESSAGE)) {
if(V) {
@@ -458,6 +472,10 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
+ ", retry: " + appParams.getRetry()
+ ", charset: " + appParams.getCharset());
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
return pushMessage(op, name, appParams, mMessageVersion);
} else if (type.equals(TYPE_SET_OWNER_STATUS)) {
if(V) {
@@ -916,6 +934,10 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
Log.d(TAG,"FilterConvoId = " + ((tmpLongLong == null) ? "" :
Long.toHexString(tmpLongLong.getLeastSignificantBits()) ) );
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
// Block until all packets have been send.
return sendMessageListingRsp(op, appParams, name);
@@ -930,6 +952,10 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
Log.d(TAG,"FilterReadStatus = " + appParams.getFilterReadStatus());
Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient());
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
// Block until all packets have been send.
return sendConvoListingRsp(op, appParams,name);
} else if (type.equals(TYPE_GET_MAS_INSTANCE_INFORMATION)) {
@@ -947,6 +973,10 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
", Charset = " + appParams.getCharset() +
", FractionRequest = " + appParams.getFractionRequest());
}
+ if (!isUserUnlocked()) {
+ Log.e(TAG, "Storage locked, " + type + " failed");
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
// Block until all packets have been send.
return sendGetMessageRsp(op, name, appParams, mMessageVersion);
} else {
@@ -1028,8 +1058,8 @@ public class BluetoothMapObexServer extends ServerRequestHandler {
return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
}
Log.v(TAG,"sendMessageListingRsp: has sms " + folderToList.hasSmsMmsContent() +
- "has email " + folderToList.hasEmailContent() +
- "has IM " + folderToList.hasImContent() );
+ ", has email " + folderToList.hasEmailContent() +
+ ", has IM " + folderToList.hasImContent() );
}
try {
diff --git a/src/com/android/bluetooth/map/BluetoothMapService.java b/src/com/android/bluetooth/map/BluetoothMapService.java
index 552bb09eb..addebf0c5 100755
--- a/src/com/android/bluetooth/map/BluetoothMapService.java
+++ b/src/com/android/bluetooth/map/BluetoothMapService.java
@@ -867,6 +867,7 @@ public class BluetoothMapService extends ProfileService {
sendShutdownMessage();
}
mStartError = true;
+ setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED);
return true;
}
diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
index 2a51aa067..38873da12 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
@@ -42,31 +42,31 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver {
if (D) Log.d(TAG, "No device attached to handover intent.");
return;
}
+
+ String mimeType = intent.getType();
+ ArrayList<Uri> uris = new ArrayList<Uri>();
if (action.equals(Constants.ACTION_HANDOVER_SEND)) {
- String type = intent.getType();
Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM);
- if (stream != null && type != null) {
- // Save type/stream, will be used when adding transfer
- // session to DB.
- BluetoothOppManager.getInstance(context).saveSendingFileInfo(type,
- stream.toString(), true);
- } else {
- if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
- }
+ if (stream != null) uris.add(stream);
} else if (action.equals(Constants.ACTION_HANDOVER_SEND_MULTIPLE)) {
- ArrayList<Uri> uris = new ArrayList<Uri>();
- String mimeType = intent.getType();
uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
- if (mimeType != null && uris != null) {
- BluetoothOppManager.getInstance(context).saveSendingFileInfo(mimeType,
- uris, true);
- } else {
- if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
- return;
- }
}
- // we already know where to send to
- BluetoothOppManager.getInstance(context).startTransfer(device);
+
+ if (mimeType != null && uris != null && !uris.isEmpty()) {
+ final String finalType = mimeType;
+ final ArrayList<Uri> finalUris = uris;
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ BluetoothOppManager.getInstance(context).saveSendingFileInfo(finalType,
+ finalUris, true);
+ BluetoothOppManager.getInstance(context).startTransfer(device);
+ }
+ });
+ t.start();
+ } else {
+ if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
+ return;
+ }
} else if (action.equals(Constants.ACTION_WHITELIST_DEVICE)) {
BluetoothDevice device =
(BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
index 0f23bd382..59e7848b6 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
@@ -476,13 +476,13 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
outputStream.write(buffer, 0, readLength);
position += readLength;
+ /* check remote accept or reject */
+ responseCode = putOperation.getResponseCode();
mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
synchronized (this) {
mWaitingForRemote = false;
}
- /* check remote accept or reject */
- responseCode = putOperation.getResponseCode();
if (responseCode == ResponseCodes.OBEX_HTTP_CONTINUE
|| responseCode == ResponseCodes.OBEX_HTTP_OK) {
@@ -595,7 +595,7 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
} finally {
try {
if (outputStream != null) {
- outputStream.close();
+ outputStream.close();
}
// Close InputStream and remove SendFileInfo from map
diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
index 2a9cadb8b..f60f06cab 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
@@ -123,6 +123,7 @@ public class BluetoothOppSendFileInfo {
Log.e(TAG, "generateFileInfo: " + e);
return new BluetoothOppSendFileInfo(fileName, contentType, length, null, 0);
}
+
if (metadataCursor != null) {
try {
if (metadataCursor.moveToFirst()) {
diff --git a/src/com/android/bluetooth/opp/BluetoothOppService.java b/src/com/android/bluetooth/opp/BluetoothOppService.java
index 8c10ab7e9..89e5a0d4b 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppService.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppService.java
@@ -142,6 +142,8 @@ public class BluetoothOppService extends Service {
private ObexTransport mPendingConnection = null;
private int mOppSdpHandle = -1;
+ private boolean isScreenOff = false;
+
/*
* TODO No support for queue incoming from multiple devices.
* Make an array list of server session to support receiving queue from
@@ -167,6 +169,8 @@ public class BluetoothOppService extends Service {
mNotifier = new BluetoothOppNotification(this);
mNotifier.mNotificationMgr.cancelAll();
mNotifier.updateNotification();
+ mPowerManager = (PowerManager)getSystemService(POWER_SERVICE);
+ isScreenOff = !mPowerManager.isInteractive();
final ContentResolver contentResolver = getContentResolver();
new Thread("trimDatabase") {
@@ -176,6 +180,8 @@ public class BluetoothOppService extends Service {
}.start();
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mBluetoothReceiver, filter);
synchronized (BluetoothOppService.this) {
@@ -262,8 +268,19 @@ public class BluetoothOppService extends Service {
mTransfer =null;
}
synchronized (BluetoothOppService.this) {
+ if (D) Log.d(TAG, "STOP_LISTENER :" + mUpdateThread);
if (mUpdateThread == null) {
stopSelf();
+ } else {
+ try {
+ mUpdateThread.interrupt();
+ mUpdateThread.join();
+ if (D) Log.d(TAG, "Stop after join");
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted", e);
+ }
+ mUpdateThread = null;
+ stopSelf();
}
}
// Update Notification
@@ -466,6 +483,12 @@ public class BluetoothOppService extends Service {
break;
}
+ } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+ isScreenOff = true;
+ if (V) Log.v(TAG, "ACTION_SCREEN_OFF ");
+ } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+ isScreenOff = false;
+ if (V) Log.v(TAG, "ACTION_SCREEN_ON ");
}
}
};
@@ -475,7 +498,10 @@ public class BluetoothOppService extends Service {
mPendingUpdate = true;
if ((mUpdateThread == null) && (mAdapter != null)
&& mAdapter.isEnabled()) {
- mPowerManager = (PowerManager)getSystemService(POWER_SERVICE);
+ if (mPowerManager == null) {
+ mPowerManager = (PowerManager)getSystemService(POWER_SERVICE);
+ isScreenOff = !mPowerManager.isInteractive();
+ }
if (V) Log.v(TAG, "Starting a new thread");
mUpdateThread = new UpdateThread();
mUpdateThread.start();
@@ -484,8 +510,17 @@ public class BluetoothOppService extends Service {
}
private class UpdateThread extends Thread {
+ private boolean isInterrupted ;
public UpdateThread() {
super("Bluetooth Share Service");
+ isInterrupted = false;
+ }
+
+ @Override
+ public void interrupt() {
+ isInterrupted = true;
+ if (D) Log.d(TAG, "Interrupted :" + isInterrupted);
+ super.interrupt();
}
@Override
@@ -493,14 +528,15 @@ public class BluetoothOppService extends Service {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
boolean keepService = false;
- for (;;) {
+ for (; !isInterrupted;) {
synchronized (BluetoothOppService.this) {
if (mUpdateThread != this) {
throw new IllegalStateException(
"multiple UpdateThreads in BluetoothOppService");
}
if (V) Log.v(TAG, "pendingUpdate is " + mPendingUpdate + " keepUpdateThread is "
- + keepService + " sListenStarted is " + mListenStarted);
+ + keepService + " sListenStarted is " + mListenStarted + " isInterrupted :"
+ + isInterrupted + " isScreenOff:" + isScreenOff);
if (!mPendingUpdate) {
mUpdateThread = null;
if (!keepService && !mListenStarted) {
@@ -512,12 +548,12 @@ public class BluetoothOppService extends Service {
return;
}
try {
- if (!mPowerManager.isInteractive())
- Thread.sleep(10);
+ if (isScreenOff && !isInterrupted) {
+ Thread.sleep(1000);
+ }
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted", e);
}
-
mPendingUpdate = false;
}
Cursor cursor;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
index d74cbd67b..bc2510faf 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
@@ -416,8 +416,9 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
if (mConnectThread != null) {
try {
mConnectThread.interrupt();
- if (V) Log.v(TAG, "waiting for connect thread to terminate");
+ if (D) Log.v(TAG, "waiting for connect thread to terminate");
mConnectThread.join();
+ if (D) Log.d(TAG, "connect thread to terminated");
} catch (InterruptedException e) {
if (V) Log.v(TAG, "Interrupted waiting for connect thread to join");
}
@@ -435,6 +436,7 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
mHandlerThread = null;
}
}
+ if (V) Log.v(TAG, "exit stop :"+mConnectThread);
}
private void startObexSession() {
@@ -603,6 +605,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
private boolean mSdpInitiated = false;
+ private boolean isInterrupted = false;
+
/* create a TCP socket */
public SocketConnectThread(String host, int port, int dummy) {
super("Socket Connect Thread");
@@ -611,6 +615,7 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
this.device = null;
isConnected = false;
mSdpInitiated = false;
+ isInterrupted = false;
}
/* create a Rfcomm/L2CAP Socket */
@@ -623,6 +628,7 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
isConnected = false;
mRetry = retry;
mSdpInitiated = false;
+ isInterrupted = false;
}
/* create a Rfcomm/L2CAP Socket */
@@ -649,7 +655,10 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
}
public void interrupt() {
+ Log.d(TAG, "start interrupt :" + btSocket);
if (!Constants.USE_TCP_DEBUG) {
+ isInterrupted = true;
+ OolConnManager.interruptSdp= true;
if (btSocket != null) {
try {
btSocket.close();
@@ -664,6 +673,11 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
if (V) Log.v(TAG, "connectRfcommSocket");
try {
+ if (isInterrupted) {
+ Log.d(TAG, "connectRfcommSocket interrupted");
+ markConnectionFailed(btSocket);
+ return;
+ }
btSocket = device.createInsecureRfcommSocketToServiceRecord(BluetoothUuid.ObexObjectPush.getUuid());
} catch (IOException e1) {
Log.e(TAG, "Rfcomm socket create error",e1);
@@ -786,6 +800,13 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
l2cChannel = 0;
try {
l2cChannel = OolConnManager.getL2cPSM(device);
+ if (isInterrupted) {
+ Log.e(TAG, "btSocket connect interrupted ");
+ markConnectionFailed(btSocket);
+ return;
+ } else {
+ btSocket = device.createInsecureL2capSocket(l2cChannel);
+ }
if (l2cChannel > 0) {
Log.d(TAG, "Connecting to l2cap psm = " + l2cChannel);
btSocket = device.createInsecureL2capSocket(l2cChannel);
diff --git a/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
index 8294246f0..99777a5ae 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppUtility.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
@@ -367,6 +367,9 @@ public class BluetoothOppUtility {
static void putSendFileInfo(Uri uri, BluetoothOppSendFileInfo sendFileInfo) {
if (D) Log.d(TAG, "putSendFileInfo: uri=" + uri + " sendFileInfo=" + sendFileInfo);
+ if (sendFileInfo == BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR) {
+ Log.e(TAG, "putSendFileInfo: bad sendFileInfo, URI: " + uri);
+ }
sSendFileMap.put(uri, sendFileInfo);
}
diff --git a/src/com/android/bluetooth/pan/PanService.java b/src/com/android/bluetooth/pan/PanService.java
index 05f92ffe0..6a43b9342 100755
--- a/src/com/android/bluetooth/pan/PanService.java
+++ b/src/com/android/bluetooth/pan/PanService.java
@@ -440,8 +440,8 @@ public class PanService extends ProfileService {
if (prevState == state) return;
if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) {
if (state == BluetoothProfile.STATE_CONNECTED) {
- if((!mTetherOn)||(local_role == BluetoothPan.LOCAL_PANU_ROLE)){
- if(DBG) Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
+ if ((!mTetherOn) || (local_role == BluetoothPan.LOCAL_PANU_ROLE)) {
+ if (DBG) Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
+ " is PANU drop the connection");
mPanDevices.remove(device);
disconnectPanNative(Utils.getByteAddress(device));
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapReceiver.java b/src/com/android/bluetooth/pbap/BluetoothPbapReceiver.java
index a35ae5659..75388ee64 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapReceiver.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapReceiver.java
@@ -42,6 +42,8 @@ public class BluetoothPbapReceiver extends BroadcastReceiver {
private static final String TAG = "BluetoothPbapReceiver";
+ private static final boolean D = BluetoothPbapService.DEBUG;
+
private static final boolean V = Log.isLoggable(BluetoothPbapService.LOG_TAG, Log.VERBOSE);
@Override
@@ -52,12 +54,13 @@ public class BluetoothPbapReceiver extends BroadcastReceiver {
in.setClass(context, BluetoothPbapService.class);
String action = intent.getAction();
in.putExtra("action", action);
- Log.i(TAG, "Enter - onReceive for intent:" + action);
+ if (D) Log.d(TAG, "PbapReceiver onReceive action = " + action);
+
boolean startService = true;
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
in.putExtra(BluetoothAdapter.EXTRA_STATE, state);
- Log.i(TAG, "State :" + state);
+ if (D) Log.d(TAG, "state = " + state);
if ((state == BluetoothAdapter.STATE_TURNING_ON)
|| (state == BluetoothAdapter.STATE_OFF)) {
//FIX: We turn on PBAP after BluetoothAdapter.STATE_ON,
@@ -68,11 +71,13 @@ public class BluetoothPbapReceiver extends BroadcastReceiver {
// Don't forward intent unless device has bluetooth and bluetooth is enabled.
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null || !adapter.isEnabled()) {
+ if (D) Log.d(TAG, "BluetoothAdapter is not enabled (" +
+ adapter + "). Would not start service.");
startService = false;
}
}
if (startService) {
- if (V) Log.v(TAG, "Calling start service!!!! with action = " + in.getAction());
+ if (D) Log.d(TAG, "Calling start service with action = " + in.getAction());
context.startService(in);
}
Log.i(TAG, "Exit - onReceive for intent:" + action);
diff --git a/src/com/android/bluetooth/sdp/SdpManager.java b/src/com/android/bluetooth/sdp/SdpManager.java
index 86823a027..d6db4ed77 100644
--- a/src/com/android/bluetooth/sdp/SdpManager.java
+++ b/src/com/android/bluetooth/sdp/SdpManager.java
@@ -85,7 +85,7 @@ public class SdpManager {
static Object mTrackerLock = new Object();
/* The timeout to wait for reply from native. Should never fire. */
- private static final int SDP_INTENT_DELAY = 6000;
+ private static final int SDP_INTENT_DELAY = 11000;
private static final int MESSAGE_SDP_INTENT = 2;
// We need a reference to the adapter service, to be able to send intents
diff --git a/src/com/android/bluetooth/util/Interop.java b/src/com/android/bluetooth/util/Interop.java
new file mode 100644
index 000000000..4861c154e
--- /dev/null
+++ b/src/com/android/bluetooth/util/Interop.java
@@ -0,0 +1,87 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Centralized Bluetooth Interoperability workaround utilities and database.
+ * This is the Java version. An analagous native version can be found
+ * in /system/bt/devices/include/interop_database.h.
+ */
+public class Interop {
+
+ /**
+ * Simple interop entry consisting of a workarond id (see below)
+ * and a (partial or complete) Bluetooth device address string
+ * to match against.
+ */
+ private static class Entry {
+ String address;
+ int workaround_id;
+
+ public Entry(int workaround_id, String address) {
+ this.workaround_id = workaround_id;
+ this.address = address;
+ }
+ }
+
+ /**
+ * The actual "database" of interop entries.
+ */
+ private static List<Entry> entries = null;
+
+ /**
+ * Workaround ID for deivces which do not accept non-ASCII
+ * characters in SMS messages.
+ */
+ public static final int INTEROP_MAP_ASCIIONLY = 1;
+
+ /**
+ * Initializes the interop datbase with the relevant workaround
+ * entries.
+ * When adding entries, please provide a description for each
+ * device as to what problem the workaround addresses.
+ */
+ private static void lazyInitInteropDatabase() {
+ if (entries != null) return;
+ entries = new ArrayList<Entry>();
+
+ /** Mercedes Benz NTG 4.5 does not handle non-ASCII characters in SMS */
+ entries.add(new Entry(INTEROP_MAP_ASCIIONLY, "00:26:e8"));
+ }
+
+ /**
+ * Checks wheter a given device identified by |address| is a match
+ * for a given workaround identified by |workaround_id|.
+ * Return true if the address matches, false otherwise.
+ */
+ public static boolean matchByAddress(int workaround_id, String address) {
+ if (address == null || address.isEmpty()) return false;
+
+ lazyInitInteropDatabase();
+ for (Entry entry : entries) {
+ if (entry.workaround_id == workaround_id &&
+ entry.address.startsWith(address.toLowerCase())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}