From 972fc68c7e077d959fcbe75ca5fe11a3bd3d8b07 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Wed, 4 May 2011 18:48:56 +0200 Subject: [PATCH] Android: implement headphone detection thus enabling pause on unplug. Listen to headphone plug events. There are currently two glitches with this: - Android takes a while until it reports the unplug event, so there will be some delay until playback gets paused. This is an Android limitation. - Rockbox debounces headphone state changes for one second. Therefore playback will shortly be routed to the speaker on unplug until Rockbox does the actual pause. --- android/src/org/rockbox/RockboxService.java | 21 +++++++++++++++ firmware/drivers/button.c | 2 +- firmware/export/config/android.h | 2 + firmware/target/hosted/android/button-android.c | 32 +++++++++++++++++++++- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/android/src/org/rockbox/RockboxService.java b/android/src/org/rockbox/RockboxService.java index 0ffeec7..ed47442 100644 --- a/android/src/org/rockbox/RockboxService.java +++ b/android/src/org/rockbox/RockboxService.java @@ -64,10 +64,13 @@ public class RockboxService extends Service private static volatile boolean rockbox_running; private Activity current_activity = null; private IntentFilter itf; + private IntentFilter ifh; private BroadcastReceiver batt_monitor; + private BroadcastReceiver headphone_monitor; private RunForegroundManager fg_runner; private MediaButtonReceiver mMediaButtonReceiver; private int battery_level; + private int headphone_state; private ResultReceiver resultReceiver; public static final int RESULT_INVOKING_MAIN = 0; @@ -349,6 +352,24 @@ public class RockboxService extends Service registerReceiver(batt_monitor, itf); } + + private void initHeadphoneMonitor() + { + ifh = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + headphone_monitor = new BroadcastReceiver() + { + @Override + public void onReceive(Context context, Intent intent) + { + int state = intent.getIntExtra("state", -1); + LOG("headphone state:" + state); + headphone_state = state; + } + }; + registerReceiver(headphone_monitor, ifh); + } + + void startForeground() { fg_runner.startForeground(); diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index f8e4a35..e477ffa 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -177,7 +177,7 @@ static void button_tick(void) /* Use the autoresetting oneshot to debounce the detection signal */ phones_present = !phones_present; timeout_register(&hp_detect_timeout, btn_detect_callback, - HZ, phones_present); + HZ/10, phones_present); } #endif diff --git a/firmware/export/config/android.h b/firmware/export/config/android.h index 69a758d..41ecacf 100644 --- a/firmware/export/config/android.h +++ b/firmware/export/config/android.h @@ -84,6 +84,8 @@ #define HAVE_SW_TONE_CONTROLS +#define HAVE_HEADPHONE_DETECTION + /* Define current usage levels. */ #define CURRENT_NORMAL 88 /* 18 hours from a 1600 mAh battery */ #define CURRENT_BACKLIGHT 30 /* TBD */ diff --git a/firmware/target/hosted/android/button-android.c b/firmware/target/hosted/android/button-android.c index ed1e125..26f57d4 100644 --- a/firmware/target/hosted/android/button-android.c +++ b/firmware/target/hosted/android/button-android.c @@ -30,6 +30,10 @@ #include "touchscreen.h" extern JNIEnv *env_ptr; +extern jclass RockboxService_class; +extern jobject RockboxService_instance; + +static jfieldID _headphone_state; static int last_y, last_x; static int last_btns; @@ -83,7 +87,7 @@ Java_org_rockbox_RockboxFramebuffer_buttonHandler(JNIEnv*env, jclass class, } if (!button) - { + { button = key_to_button(keycode); } @@ -102,12 +106,26 @@ Java_org_rockbox_RockboxFramebuffer_buttonHandler(JNIEnv*env, jclass class, last_btns &= (~button); return false; } - + return true; } void button_init_device(void) { + jmethodID initHeadphoneMonitor = (*env_ptr)->GetMethodID(env_ptr, + RockboxService_class, + "initHeadphoneMonitor", + "()V"); + /* start the monitor */ + (*env_ptr)->CallVoidMethod(env_ptr, + RockboxService_instance, + initHeadphoneMonitor); + + /* cache the headphone state field id */ + _headphone_state = (*env_ptr)->GetFieldID(env_ptr, + RockboxService_class, + "headphone_state", + "I"); } int button_read_device(int *data) @@ -125,3 +143,13 @@ int button_read_device(int *data) return btn; } + + +/* Tell if anything is in the jack. */ +bool headphones_inserted(void) +{ + int state = (*env_ptr)->GetIntField(env_ptr, RockboxService_instance, _headphone_state); + /* 0 is disconnected, 1 and 2 are connected */ + return (state == 0) ? false : true; +} + -- 1.7.4.4