summaryrefslogtreecommitdiffstats
path: root/android/src
diff options
context:
space:
mode:
Diffstat (limited to 'android/src')
-rw-r--r--android/src/org/rockbox/Helper/Logger.java4
-rw-r--r--android/src/org/rockbox/Helper/MediaButtonReceiver.java1
-rw-r--r--android/src/org/rockbox/Helper/RunForegroundManager.java149
3 files changed, 88 insertions, 66 deletions
diff --git a/android/src/org/rockbox/Helper/Logger.java b/android/src/org/rockbox/Helper/Logger.java
index c0ef5f64ad..0620175ef9 100644
--- a/android/src/org/rockbox/Helper/Logger.java
+++ b/android/src/org/rockbox/Helper/Logger.java
@@ -36,6 +36,10 @@ public class Logger
{
Log.d(TAG, s);
}
+ public static void d(String s, Throwable t)
+ {
+ Log.d(TAG, s, t);
+ }
public static void e(String s)
{
diff --git a/android/src/org/rockbox/Helper/MediaButtonReceiver.java b/android/src/org/rockbox/Helper/MediaButtonReceiver.java
index eeeeef22cc..e74ec5c8c2 100644
--- a/android/src/org/rockbox/Helper/MediaButtonReceiver.java
+++ b/android/src/org/rockbox/Helper/MediaButtonReceiver.java
@@ -58,6 +58,7 @@ public class MediaButtonReceiver
/* Throwable includes Exception and the expected
* NoClassDefFoundError */
api = new OldApi(c);
+ Logger.i("MediaButtonReceiver: Falling back to compatibility API");
}
}
diff --git a/android/src/org/rockbox/Helper/RunForegroundManager.java b/android/src/org/rockbox/Helper/RunForegroundManager.java
index 7677444374..fbb6040005 100644
--- a/android/src/org/rockbox/Helper/RunForegroundManager.java
+++ b/android/src/org/rockbox/Helper/RunForegroundManager.java
@@ -1,22 +1,23 @@
package org.rockbox.Helper;
import java.lang.reflect.Method;
-
import org.rockbox.R;
import org.rockbox.RockboxActivity;
-
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
-import android.util.Log;
import android.widget.RemoteViews;
public class RunForegroundManager
{
+ /* all below is heavily based on the examples found on
+ * http://developer.android.com/reference/android/app/Service.html#setForeground(boolean)
+ */
private Notification mNotification;
private NotificationManager mNM;
+ private IRunForeground api;
private Service mCurrentService;
private Intent mWidgetUpdate;
@@ -37,17 +38,43 @@ public class RunForegroundManager
mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
mNotification.contentIntent = PendingIntent.getActivity(service, 0, intent, 0);
- initForegroundCompat();
+ try {
+ api = new NewForegroundApi(R.string.notification, mNotification);
+ } catch (Throwable t) {
+ /* Throwable includes Exception and the expected
+ * NoClassDefFoundError for Android 1.x */
+ try {
+ api = new OldForegroundApi();
+ Logger.i("RunForegroundManager: Falling back to compatibility API");
+ } catch (Exception e) {
+ Logger.e("Cannot run in foreground: No available API");
+ }
+ }
}
public void startForeground()
{
- startForegroundCompat(R.string.notification, mNotification);
+ /*
+ * Send the notification.
+ * We use a layout id because it is a unique number.
+ * We use it later to cancel.
+ */
+ mNM.notify(R.string.notification, mNotification);
+ /*
+ * this call makes the service run as foreground, which
+ * provides enough cpu time to do music decoding in the
+ * background
+ */
+ api.startForeground();
}
public void stopForeground()
{
- stopForegroundCompat(R.string.notification);
+ /* Note to cancel BEFORE changing the
+ * foreground state, since we could be killed at that point.
+ */
+ mNM.cancel(R.string.notification);
+ api.stopForeground();
mWidgetUpdate = null;
}
@@ -78,78 +105,68 @@ public class RunForegroundManager
public void finishNotification()
{
- Log.d("Rockbox", "TrackFinish");
+ Logger.d("TrackFinish");
Intent widgetUpdate = new Intent("org.rockbox.TrackFinish");
mCurrentService.sendBroadcast(widgetUpdate);
}
- /* Loosely based on http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification) */
- private static final Class<?>[] mSetForegroundSignature = new Class[] {boolean.class};
- private static final Class<?>[] mStartForegroundSignature = new Class[] {int.class, Notification.class};
- private static final Class<?>[] mStopForegroundSignature = new Class[] {boolean.class};
-
- private Method mSetForeground;
- private Method mStartForeground;
- private Method mStopForeground;
+ private interface IRunForeground
+ {
+ void startForeground();
+ void stopForeground();
+ }
- private void initForegroundCompat() {
- Class<?> serviceClass = mCurrentService.getClass();
- try {
- mStartForeground = serviceClass.getMethod("startForeground", mStartForegroundSignature);
- mStopForeground = serviceClass.getMethod("stopForeground", mStopForegroundSignature);
- } catch (NoSuchMethodException e) {
- // Running on an older platform.
- mStartForeground = mStopForeground = null;
- try {
- mSetForeground = serviceClass.getMethod("setForeground", mSetForegroundSignature);
- } catch (NoSuchMethodException e2) {
- throw new IllegalStateException("OS doesn't have Service.startForeground nor Service.setForeground!", e2);
- }
+ private class NewForegroundApi implements IRunForeground
+ {
+ int id;
+ Notification mNotification;
+ NewForegroundApi(int _id, Notification _notification)
+ {
+ id = _id;
+ mNotification = _notification;
}
- }
- private void invokeMethod(Method method, Object[] args) {
- try {
- method.invoke(mCurrentService, args);
- } catch (Exception e) {
- // Should not happen.
- Log.w("Rockbox", "Unable to invoke method", e);
+ public void startForeground()
+ {
+ mCurrentService.startForeground(id, mNotification);
}
- }
- /**
- * This is a wrapper around the new startForeground method, using the older
- * APIs if it is not available.
- */
- private void startForegroundCompat(int id, Notification notification) {
- // If we have the new startForeground API, then use it.
- if (mStartForeground != null) {
- Object[] startForeGroundArgs = new Object[] {Integer.valueOf(id), notification};
- invokeMethod(mStartForeground, startForeGroundArgs);
- } else {
- // Fall back on the old API.
- Object[] setForegroundArgs = new Object[] {Boolean.TRUE};
- invokeMethod(mSetForeground, setForegroundArgs);
- mNM.notify(id, notification);
+ public void stopForeground()
+ {
+ mCurrentService.stopForeground(true);
}
}
+
+ private class OldForegroundApi implements IRunForeground
+ {
+ /*
+ * Get the new API through reflection because it's unavailable
+ * in honeycomb
+ */
+ private Method mSetForeground;
+
+ public OldForegroundApi() throws SecurityException, NoSuchMethodException
+ {
+ mSetForeground = getClass().getMethod("setForeground",
+ new Class[] { boolean.class });
+ }
- /**
- * This is a wrapper around the new stopForeground method, using the older
- * APIs if it is not available.
- */
- private void stopForegroundCompat(int id) {
- // If we have the new stopForeground API, then use it.
- if (mStopForeground != null) {
- Object[] stopForegroundArgs = new Object[] {Boolean.TRUE};
- invokeMethod(mStopForeground, stopForegroundArgs);
- } else {
- // Fall back on the old API. Note to cancel BEFORE changing the
- // foreground state, since we could be killed at that point.
- mNM.cancel(id);
-
- Object[] setForegroundArgs = new Object[] {Boolean.FALSE};
- invokeMethod(mSetForeground, setForegroundArgs);
+ public void startForeground()
+ {
+ try {
+ mSetForeground.invoke(mCurrentService, Boolean.TRUE);
+ } catch (Exception e) {
+ Logger.e("startForeground compat error: " + e.getMessage());
+ e.printStackTrace();
+ }
}
+ public void stopForeground()
+ {
+ try {
+ mSetForeground.invoke(mCurrentService, Boolean.FALSE);
+ } catch (Exception e) {
+ Logger.e("stopForeground compat error: " + e.getMessage());
+ }
+ }
}
}