From ca4439ff65bdc93fc44f4cc1be52aab50217ce78 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 7 Aug 2010 21:30:22 +0000 Subject: [PATCH] Android port: handle incoming calls. Stop explicitely if a call comes in, and resume playback (if it was playing before the call) upon hang up. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27746 a1c6a512-1295-4272-9138-f99709370657 --- android/src/org/rockbox/RockboxTimer.java | 28 +++++++++++++++++-- apps/menu.c | 13 +++++++-- apps/misc.c | 19 +++++++++++++ firmware/export/kernel.h | 2 ++ .../target/hosted/android/kernel-android.c | 24 ++++++++++++++-- 5 files changed, 79 insertions(+), 7 deletions(-) diff --git a/android/src/org/rockbox/RockboxTimer.java b/android/src/org/rockbox/RockboxTimer.java index 6491e4ffe9..68a0e866fb 100644 --- a/android/src/org/rockbox/RockboxTimer.java +++ b/android/src/org/rockbox/RockboxTimer.java @@ -24,6 +24,8 @@ package org.rockbox; import java.util.Timer; import java.util.TimerTask; +import android.content.Context; +import android.telephony.TelephonyManager; import android.util.Log; public class RockboxTimer extends Timer @@ -33,24 +35,42 @@ public class RockboxTimer extends Timer private class RockboxTimerTask extends TimerTask { private RockboxTimer t; - public RockboxTimerTask(RockboxTimer parent) { + private TelephonyManager tm; + private int last_state; + public RockboxTimerTask(RockboxService s, RockboxTimer parent) { super(); t = parent; + tm = (TelephonyManager)s.getSystemService(Context.TELEPHONY_SERVICE); + last_state = tm.getCallState(); } @Override public void run() { timerTask(); + int state = tm.getCallState(); + if (state != last_state) + { + switch (state) { + case TelephonyManager.CALL_STATE_IDLE: + postCallHungUp(); + break; + case TelephonyManager.CALL_STATE_RINGING: + postCallIncoming(); + default: + break; + } + last_state = state; + } synchronized(t) { t.notify(); } } } - public RockboxTimer(long period_inverval_in_ms) + public RockboxTimer(RockboxService instance, long period_inverval_in_ms) { super("tick timer", false); - task = new RockboxTimerTask(this); + task = new RockboxTimerTask(instance, this); schedule(task, 0, period_inverval_in_ms); interval = period_inverval_in_ms; } @@ -75,4 +95,6 @@ public class RockboxTimer extends Timer } } public native void timerTask(); + private native void postCallIncoming(); + private native void postCallHungUp(); } diff --git a/apps/menu.c b/apps/menu.c index a88d725774..e6afec2d14 100644 --- a/apps/menu.c +++ b/apps/menu.c @@ -341,6 +341,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, const struct menu_item_ex *temp, *menu; int ret = 0, i; bool redraw_lists; + int old_audio_status = audio_status(); FOR_NB_SCREENS(i) viewportmanager_theme_enable(i, !hide_theme, NULL); @@ -380,6 +381,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, #endif while (!done) { + int new_old_audio_statusus; redraw_lists = false; if (!hide_theme) { @@ -389,6 +391,15 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, } action = get_action(CONTEXT_MAINMENU, list_do_action_timeout(&lists, HZ)); + + /* query audio status to see if it changed */ + new_old_audio_statusus = audio_status(); + if (old_audio_status != new_old_audio_statusus) + { /* force a redraw if anything changed the audio status + * from outside */ + redraw_lists = true; + old_audio_status = new_old_audio_statusus; + } /* HZ so the status bar redraws corectly */ if (menu_callback) @@ -410,8 +421,6 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, if (gui_synclist_do_button(&lists, &action, LIST_WRAP_UNLESS_HELD)) continue; - if (action == ACTION_NONE) - continue; #ifdef HAVE_QUICKSCREEN else if (action == ACTION_STD_QUICKSCREEN) { diff --git a/apps/misc.c b/apps/misc.c index ed6986180a..9fbdd433ef 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -517,6 +517,9 @@ static void unplug_change(bool inserted) long default_event_handler_ex(long event, void (*callback)(void *), void *parameter) { +#if CONFIG_PLATFORM & PLATFORM_ANDROID + static bool resume = false; +#endif switch(event) { case SYS_BATTERY_UPDATE: @@ -605,6 +608,22 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame case SYS_IAP_HANDLEPKT: iap_handlepkt(); return SYS_IAP_HANDLEPKT; +#endif +#if CONFIG_PLATFORM & PLATFORM_ANDROID + /* stop playback if we receive a call */ + case SYS_CALL_INCOMING: + resume = (audio_status() & AUDIO_STATUS_PLAY) != 0; + list_stop_handler(); + return SYS_CALL_INCOMING; + /* resume playback if needed */ + case SYS_CALL_HUNG_UP: + if (resume && playlist_resume() != -1) + { + playlist_start(global_status.resume_index, + global_status.resume_offset); + } + resume = false; + return SYS_CALL_HUNG_UP; #endif } return 0; diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 9ef5af8c0c..d256f31ab5 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h @@ -82,6 +82,8 @@ #define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0) #define SYS_IAP_PERIODIC MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 1) #define SYS_IAP_HANDLEPKT MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 2) +#define SYS_CALL_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3) +#define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4) #define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT) diff --git a/firmware/target/hosted/android/kernel-android.c b/firmware/target/hosted/android/kernel-android.c index 1a9b97b419..636c849c24 100644 --- a/firmware/target/hosted/android/kernel-android.c +++ b/firmware/target/hosted/android/kernel-android.c @@ -23,14 +23,17 @@ #include #include "config.h" #include "system.h" +#include "button.h" +#include "audio.h" extern JNIEnv *env_ptr; +extern jobject RockboxService_instance; + static jclass RockboxTimer_class; static jobject RockboxTimer_instance; static jmethodID java_wait_for_interrupt; static bool initialized = false; - /* * This is called from the separate Timer java thread. I have not added any * interrupt simulation to it (like the sdl counterpart does), @@ -49,6 +52,22 @@ Java_org_rockbox_RockboxTimer_timerTask(JNIEnv *env, jobject this) call_tick_tasks(); } +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxTimer_postCallIncoming(JNIEnv *env, jobject this) +{ + (void)env; + (void)this; + queue_broadcast(SYS_CALL_INCOMING, 0); +} + +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxTimer_postCallHungUp(JNIEnv *env, jobject this) +{ + (void)env; + (void)this; + queue_broadcast(SYS_CALL_HUNG_UP, 0); +} + void tick_start(unsigned int interval_in_ms) { JNIEnv e = *env_ptr; @@ -57,11 +76,12 @@ void tick_start(unsigned int interval_in_ms) jmethodID constructor = e->GetMethodID(env_ptr, RockboxTimer_class, "", - "(J)V"); + "(Lorg/rockbox/RockboxService;J)V"); /* the constructor will do the tick_start */ RockboxTimer_instance = e->NewObject(env_ptr, RockboxTimer_class, constructor, + RockboxService_instance, (jlong)interval_in_ms); /* get our wfi func also */