1
0
Fork 0
forked from len0rd/rockbox

Code style changes in the java part (whitespaces and braces) to match Rockbox coding style.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28065 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Thomas Martitz 2010-09-12 19:56:13 +00:00
parent 54c838d2ae
commit 282adacb54
5 changed files with 549 additions and 528 deletions

View file

@ -29,7 +29,8 @@ import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
public class RockboxActivity extends Activity { public class RockboxActivity extends Activity
{
/** Called when the activity is first created. */ /** Called when the activity is first created. */
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
@ -49,71 +50,75 @@ public class RockboxActivity extends Activity {
* *
* In order to get the fb, we need to let the Service start up * In order to get the fb, we need to let the Service start up
* run, we can wait in a separate thread for fb to get ready * run, we can wait in a separate thread for fb to get ready
* This thread waits for the fb to become ready */ * This thread waits for the fb to become ready */
new Thread(new Runnable() new Thread(new Runnable()
{ {
public void run() { public void run()
try { {
while (RockboxService.fb == null) try {
Thread.sleep(250); while (RockboxService.fb == null)
} catch (InterruptedException e) { Thread.sleep(250);
} catch (Exception e) { } catch (InterruptedException e) {
LOG(e.toString()); } catch (Exception e) {
} LOG(e.toString());
/* drawing needs to happen in ui thread */ }
runOnUiThread(new Runnable() /* drawing needs to happen in ui thread */
{ @Override runOnUiThread(new Runnable()
public void run() { { @Override
setContentView(RockboxService.fb); public void run() {
RockboxService.fb.invalidate(); setContentView(RockboxService.fb);
} RockboxService.fb.invalidate();
}); }
} });
}
}).start(); }).start();
} }
public void onResume() public void onResume()
{ {
super.onResume(); super.onResume();
if (RockboxService.fb != null) if (RockboxService.fb != null)
{ {
try { try {
setContentView(RockboxService.fb); setContentView(RockboxService.fb);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
/* we are already using the View, /* we are already using the View,
* need to remove it and re-attach it */ * need to remove it and re-attach it */
ViewGroup g = (ViewGroup)RockboxService.fb.getParent(); ViewGroup g = (ViewGroup)RockboxService.fb.getParent();
g.removeView(RockboxService.fb); g.removeView(RockboxService.fb);
setContentView(RockboxService.fb); setContentView(RockboxService.fb);
} }
RockboxService.fb.resume(); RockboxService.fb.resume();
} }
} }
/* this is also called when the backlight goes off, /* this is also called when the backlight goes off,
* which is nice * which is nice
*/ */
@Override @Override
protected void onPause() { protected void onPause()
super.onPause(); {
RockboxService.fb.suspend(); super.onPause();
RockboxService.fb.suspend();
} }
@Override @Override
protected void onStop() { protected void onStop()
super.onStop(); {
RockboxService.fb.suspend(); super.onStop();
RockboxService.fb.suspend();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy()
super.onDestroy(); {
RockboxService.fb.suspend(); super.onDestroy();
RockboxService.fb.suspend();
} }
private void LOG(CharSequence text) private void LOG(CharSequence text)
{ {
Log.d("Rockbox", (String) text); Log.d("Rockbox", (String) text);
} }
} }

View file

@ -33,93 +33,92 @@ import android.view.View;
public class RockboxFramebuffer extends View public class RockboxFramebuffer extends View
{ {
private Bitmap btm; private Bitmap btm;
private ByteBuffer native_buf; private ByteBuffer native_buf;
public RockboxFramebuffer(Context c) public RockboxFramebuffer(Context c)
{ {
super(c); super(c);
btm = null; btm = null;
/* Needed so we can catch KeyEvents */ /* Needed so we can catch KeyEvents */
setFocusable(true); setFocusable(true);
requestFocus(); requestFocus();
} }
public void onDraw(Canvas c) public void onDraw(Canvas c)
{ {
if (btm != null) if (btm != null)
c.drawBitmap(btm, 0.0f, 0.0f, null); c.drawBitmap(btm, 0.0f, 0.0f, null);
} }
public void java_lcd_init(int lcd_width, int lcd_height, ByteBuffer native_fb) public void java_lcd_init(int lcd_width, int lcd_height, ByteBuffer native_fb)
{ {
btm = Bitmap.createBitmap(lcd_width, lcd_height, Bitmap.Config.RGB_565); btm = Bitmap.createBitmap(lcd_width, lcd_height, Bitmap.Config.RGB_565);
native_buf = native_fb; native_buf = native_fb;
} }
public void java_lcd_update() public void java_lcd_update()
{ {
btm.copyPixelsFromBuffer(native_buf); btm.copyPixelsFromBuffer(native_buf);
postInvalidate(); postInvalidate();
} }
public void java_lcd_update_rect(int x, int y, int w, int h) public void java_lcd_update_rect(int x, int y, int w, int h)
{ {
/* can't copy a partial buffer */ /* can't copy a partial buffer */
btm.copyPixelsFromBuffer(native_buf); btm.copyPixelsFromBuffer(native_buf);
postInvalidate(x, y, x+w, y+h);
}
postInvalidate(x, y, x+w, y+h); @SuppressWarnings("unused")
} private void LOG(CharSequence text)
{
Log.d("Rockbox", (String) text);
}
@SuppressWarnings("unused") public boolean onTouchEvent(MotionEvent me)
private void LOG(CharSequence text) {
{
Log.d("Rockbox", (String) text);
}
public boolean onTouchEvent(MotionEvent me)
{
int x = (int) me.getX(); int x = (int) me.getX();
int y = (int) me.getY(); int y = (int) me.getY();
switch (me.getAction()) switch (me.getAction())
{ {
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
touchHandler(false, x, y); touchHandler(false, x, y);
return true; return true;
case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
touchHandler(true, x, y); touchHandler(true, x, y);
return true; return true;
} }
return false; return false;
} }
public boolean onKeyDown(int keyCode, KeyEvent event) public boolean onKeyDown(int keyCode, KeyEvent event)
{ {
return buttonHandler(keyCode, true); return buttonHandler(keyCode, true);
} }
public boolean onKeyUp(int keyCode, KeyEvent event) public boolean onKeyUp(int keyCode, KeyEvent event)
{ {
return buttonHandler(keyCode, false); return buttonHandler(keyCode, false);
} }
/* the two below should only be called from the activity thread */ /* the two below should only be called from the activity thread */
public void suspend() public void suspend()
{ /* suspend, Rockbox will not make any lcd updates */ { /* suspend, Rockbox will not make any lcd updates */
set_lcd_active(0); set_lcd_active(0);
} }
public void resume() public void resume()
{ /* make updates again, the underlying function will { /* make updates again, the underlying function will
* send an event */ * send an event */
set_lcd_active(1); set_lcd_active(1);
} }
public native void set_lcd_active(int active); public native void set_lcd_active(int active);
public native void touchHandler(boolean down, int x, int y); public native void touchHandler(boolean down, int x, int y);
public native boolean buttonHandler(int keycode, boolean state); public native boolean buttonHandler(int keycode, boolean state);
} }

View file

@ -33,142 +33,148 @@ import android.util.Log;
public class RockboxPCM extends AudioTrack public class RockboxPCM extends AudioTrack
{ {
private byte[] raw_data; private byte[] raw_data;
private PCMListener l; private PCMListener l;
private HandlerThread ht; private HandlerThread ht;
private Handler h = null; private Handler h = null;
private static final int samplerate = 44100; private static final int samplerate = 44100;
/* should be CHANNEL_OUT_STEREO in 2.0 and above */ /* should be CHANNEL_OUT_STEREO in 2.0 and above */
private static final int channels = AudioFormat.CHANNEL_CONFIGURATION_STEREO; private static final int channels = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
private static final int encoding = AudioFormat.ENCODING_PCM_16BIT; private static final int encoding = AudioFormat.ENCODING_PCM_16BIT;
private static final int buf_len = getMinBufferSize(44100, channels, encoding); private static final int buf_len = getMinBufferSize(44100, channels, encoding);
private void LOG(CharSequence text) private void LOG(CharSequence text)
{ {
Log.d("Rockbox", (String) text); Log.d("Rockbox", (String) text);
} }
public RockboxPCM() public RockboxPCM()
{ {
super(AudioManager.STREAM_MUSIC, samplerate, channels, encoding, super(AudioManager.STREAM_MUSIC, samplerate, channels, encoding,
buf_len, AudioTrack.MODE_STREAM); buf_len, AudioTrack.MODE_STREAM);
ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO); ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO);
ht.start(); ht.start();
raw_data = new byte[buf_len]; /* in shorts */ raw_data = new byte[buf_len]; /* in shorts */
Arrays.fill(raw_data, (byte) 0); Arrays.fill(raw_data, (byte) 0);
l = new PCMListener(buf_len); l = new PCMListener(buf_len);
} }
int bytes2frames(int bytes) { private int bytes2frames(int bytes)
/* 1 sample is 2 bytes, 2 samples are 1 frame */ {
return (bytes/4); /* 1 sample is 2 bytes, 2 samples are 1 frame */
} return (bytes/4);
}
int frames2bytes(int frames) { private int frames2bytes(int frames)
/* 1 frame is 2 samples, 1 sample is 2 bytes */ {
return (frames*4); /* 1 frame is 2 samples, 1 sample is 2 bytes */
} return (frames*4);
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void play_pause(boolean pause) { private void play_pause(boolean pause) {
if (pause) if (pause)
{ {
pause(); pause();
} }
else else
{ {
if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED) if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
{ {
RockboxService.startForeground(); RockboxService.startForeground();
if (getState() == AudioTrack.STATE_INITIALIZED) if (getState() == AudioTrack.STATE_INITIALIZED)
{ {
if (h == null) if (h == null)
h = new Handler(ht.getLooper()); h = new Handler(ht.getLooper());
if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) != AudioTrack.SUCCESS) if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) != AudioTrack.SUCCESS)
LOG("setNotificationMarkerPosition Error"); LOG("setNotificationMarkerPosition Error");
else else
setPlaybackPositionUpdateListener(l, h); setPlaybackPositionUpdateListener(l, h);
} }
/* need to fill with silence before starting playback */ /* need to fill with silence before starting playback */
write(raw_data, frames2bytes(getPlaybackHeadPosition()), raw_data.length); write(raw_data, frames2bytes(getPlaybackHeadPosition()), raw_data.length);
} }
play(); play();
} }
} }
@Override @Override
public void stop() throws IllegalStateException public void stop() throws IllegalStateException
{ {
try { try {
super.stop(); super.stop();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
RockboxService.stopForeground(); RockboxService.stopForeground();
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void set_volume(int volume) private void set_volume(int volume)
{ {
/* volume comes from 0..-990 from Rockbox */ /* volume comes from 0..-990 from Rockbox */
/* TODO volume is in dB, but this code acts as if it were in %, convert? */ /* TODO volume is in dB, but this code acts as if it were in %, convert? */
float fvolume; float fvolume;
/* special case min and max volume to not suffer from floating point accuracy */ /* special case min and max volume to not suffer from floating point accuracy */
if (volume == 0) if (volume == 0)
fvolume = 1.0f; fvolume = 1.0f;
else if (volume == -990) else if (volume == -990)
fvolume = 0.0f; fvolume = 0.0f;
else else
fvolume = (volume + 990)/990.0f; fvolume = (volume + 990)/990.0f;
setStereoVolume(fvolume, fvolume); setStereoVolume(fvolume, fvolume);
} }
public native void pcmSamplesToByteArray(byte[] dest); public native void pcmSamplesToByteArray(byte[] dest);
private class PCMListener implements OnPlaybackPositionUpdateListener { private class PCMListener implements OnPlaybackPositionUpdateListener
int max_len; {
int refill_mark; private int max_len;
byte[] buf; private int refill_mark;
public PCMListener(int len) { private byte[] buf;
public PCMListener(int len)
{
max_len = len; max_len = len;
/* refill to 100% when reached the 25% */ /* refill to 100% when reached the 25% */
buf = new byte[max_len*3/4]; buf = new byte[max_len*3/4];
refill_mark = max_len - buf.length; refill_mark = max_len - buf.length;
} }
@Override @Override
public void onMarkerReached(AudioTrack track) { public void onMarkerReached(AudioTrack track)
/* push new data to the hardware */ {
RockboxPCM pcm = (RockboxPCM)track; /* push new data to the hardware */
int result = -1; RockboxPCM pcm = (RockboxPCM)track;
pcm.pcmSamplesToByteArray(buf); int result = -1;
result = track.write(buf, 0, buf.length); pcm.pcmSamplesToByteArray(buf);
if (result >= 0) result = track.write(buf, 0, buf.length);
{ if (result >= 0)
switch(track.getPlayState()) {
{ switch(track.getPlayState())
case AudioTrack.PLAYSTATE_PLAYING: {
case AudioTrack.PLAYSTATE_PAUSED: case AudioTrack.PLAYSTATE_PLAYING:
/* refill at 25% no matter of how many bytes we've written */ case AudioTrack.PLAYSTATE_PAUSED:
if (setNotificationMarkerPosition(bytes2frames(refill_mark)) != AudioTrack.SUCCESS) /* refill at 25% no matter of how many bytes we've written */
LOG("Error in onMarkerReached: Could not set notification marker"); if (setNotificationMarkerPosition(bytes2frames(refill_mark))
else /* recharge */ != AudioTrack.SUCCESS)
setPlaybackPositionUpdateListener(this, h); LOG("Error in onMarkerReached: Could not set notification marker");
break; else /* recharge */
case AudioTrack.PLAYSTATE_STOPPED: setPlaybackPositionUpdateListener(this, h);
LOG("State STOPPED"); break;
break; case AudioTrack.PLAYSTATE_STOPPED:
} LOG("State STOPPED");
} break;
else }
{ }
LOG("Error in onMarkerReached (result="+result+")"); else
stop(); {
} LOG("Error in onMarkerReached (result="+result+")");
} stop();
}
}
@Override @Override
public void onPeriodicNotification(AudioTrack track) { public void onPeriodicNotification(AudioTrack track)
// TODO Auto-generated method stub {
} }
} }
} }

View file

@ -48,78 +48,82 @@ import android.util.Log;
public class RockboxService extends Service public class RockboxService extends Service
{ {
/* this Service is really a singleton class */ /* this Service is really a singleton class */
public static RockboxFramebuffer fb = null; public static RockboxFramebuffer fb = null;
private static RockboxService instance; private static RockboxService instance;
private Notification notification; private Notification notification;
private static final Class<?>[] mStartForegroundSignature = new Class[] { private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class}; int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] { private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class}; boolean.class};
private NotificationManager mNM; private NotificationManager mNM;
private Method mStartForeground; private Method mStartForeground;
private Method mStopForeground; private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2]; private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1]; private Object[] mStopForegroundArgs = new Object[1];
private IntentFilter itf; private IntentFilter itf;
private BroadcastReceiver batt_monitor; private BroadcastReceiver batt_monitor;
private int battery_level; private int battery_level;
@Override
public void onCreate()
{
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
} catch (NoSuchMethodException e) {
/* Running on an older platform: fall back to old API */
mStartForeground = mStopForeground = null;
}
startservice();
instance = this;
}
private void do_start(Intent intent) @Override
{ public void onCreate()
LOG("Start Service"); {
/* Display a notification about us starting. We put an icon in the status bar. */ mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
create_notification(); try
} {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
}
catch (NoSuchMethodException e)
{
/* Running on an older platform: fall back to old API */
mStartForeground = mStopForeground = null;
}
startservice();
instance = this;
}
private void LOG(CharSequence text) private void do_start(Intent intent)
{ {
Log.d("Rockbox", (String) text); LOG("Start Service");
} /* Display a notification about us starting. We put an icon in the status bar. */
create_notification();
}
private void LOG(CharSequence text, Throwable tr) private void LOG(CharSequence text)
{ {
Log.d("Rockbox", (String) text, tr); Log.d("Rockbox", (String) text);
} }
public void onStart(Intent intent, int startId) { private void LOG(CharSequence text, Throwable tr)
do_start(intent); {
} Log.d("Rockbox", (String) text, tr);
}
public int onStartCommand(Intent intent, int flags, int startId) public void onStart(Intent intent, int startId) {
{ do_start(intent);
do_start(intent); }
return 1; /* old API compatibility: 1 == START_STICKY */
}
private void startservice() public int onStartCommand(Intent intent, int flags, int startId)
{ {
do_start(intent);
return 1; /* old API compatibility: 1 == START_STICKY */
}
private void startservice()
{
fb = new RockboxFramebuffer(this); fb = new RockboxFramebuffer(this);
final int BUFFER = 8*1024; final int BUFFER = 8*1024;
/* the following block unzips libmisc.so, which contains the files /* the following block unzips libmisc.so, which contains the files
* we ship, such as themes. It's needed to put it into a .so file * we ship, such as themes. It's needed to put it into a .so file
* because there's no other way to ship files and have access * because there's no other way to ship files and have access
* to them from native code * to them from native code
*/ */
try try
{ {
BufferedOutputStream dest = null; BufferedOutputStream dest = null;
BufferedInputStream is = null; BufferedInputStream is = null;
ZipEntry entry; ZipEntry entry;
@ -128,104 +132,107 @@ public class RockboxService extends Service
File file2 = new File("/data/data/org.rockbox/app_rockbox/rockbox/codecs/mpa.codec"); File file2 = new File("/data/data/org.rockbox/app_rockbox/rockbox/codecs/mpa.codec");
if (!file2.exists() || (file.lastModified() > file2.lastModified())) if (!file2.exists() || (file.lastModified() > file2.lastModified()))
{ {
ZipFile zipfile = new ZipFile(file); ZipFile zipfile = new ZipFile(file);
Enumeration<? extends ZipEntry> e = zipfile.entries(); Enumeration<? extends ZipEntry> e = zipfile.entries();
File folder; File folder;
while(e.hasMoreElements()) { while(e.hasMoreElements())
entry = (ZipEntry) e.nextElement(); {
LOG("Extracting: " +entry); entry = (ZipEntry) e.nextElement();
if (entry.isDirectory()) LOG("Extracting: " +entry);
{ if (entry.isDirectory())
folder = new File(entry.getName()); {
LOG("mkdir "+ entry); folder = new File(entry.getName());
try { LOG("mkdir "+ entry);
folder.mkdirs(); try {
} catch (SecurityException ex){ folder.mkdirs();
LOG(ex.getMessage()); } catch (SecurityException ex) {
} LOG(ex.getMessage());
continue; }
} continue;
is = new BufferedInputStream(zipfile.getInputStream(entry), BUFFER); }
int count; is = new BufferedInputStream(zipfile.getInputStream(entry), BUFFER);
byte data[] = new byte[BUFFER]; int count;
folder = new File(new File(entry.getName()).getParent()); byte data[] = new byte[BUFFER];
LOG("" + folder.getAbsolutePath()); folder = new File(new File(entry.getName()).getParent());
if (!folder.exists()) LOG("" + folder.getAbsolutePath());
folder.mkdirs(); if (!folder.exists())
FileOutputStream fos = new FileOutputStream(entry.getName()); folder.mkdirs();
dest = new BufferedOutputStream(fos, BUFFER); FileOutputStream fos = new FileOutputStream(entry.getName());
while ((count = is.read(data, 0, BUFFER)) != -1) { dest = new BufferedOutputStream(fos, BUFFER);
dest.write(data, 0, count); while ((count = is.read(data, 0, BUFFER)) != -1)
} dest.write(data, 0, count);
dest.flush(); dest.flush();
dest.close(); dest.close();
is.close(); is.close();
} }
} }
} catch(FileNotFoundException e) { } catch(FileNotFoundException e) {
LOG("FileNotFoundException when unzipping", e); LOG("FileNotFoundException when unzipping", e);
e.printStackTrace(); e.printStackTrace();
} catch(IOException e) { } catch(IOException e) {
LOG("IOException when unzipping", e); LOG("IOException when unzipping", e);
e.printStackTrace(); e.printStackTrace();
} }
System.loadLibrary("rockbox"); System.loadLibrary("rockbox");
Thread rb = new Thread(new Runnable() Thread rb = new Thread(new Runnable()
{ {
public void run() public void run()
{ {
main(); main();
} }
},"Rockbox thread"); },"Rockbox thread");
rb.setDaemon(false); rb.setDaemon(false);
rb.start(); rb.start();
} }
private native void main(); private native void main();
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent)
// TODO Auto-generated method stub {
return null; // TODO Auto-generated method stub
} return null;
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
/* /*
* Sets up the battery monitor which receives the battery level * Sets up the battery monitor which receives the battery level
* about each 30 seconds * about each 30 seconds
*/ */
private void initBatteryMonitor() private void initBatteryMonitor()
{ {
itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
batt_monitor = new BroadcastReceiver() batt_monitor = new BroadcastReceiver()
{ {
@Override @Override
public void onReceive(Context context, Intent intent) public void onReceive(Context context, Intent intent)
{ {
/* we get literally spammed with battery statuses /* we get literally spammed with battery statuses
* if we don't delay the re-attaching * if we don't delay the re-attaching
*/ */
TimerTask tk = new TimerTask() { TimerTask tk = new TimerTask()
public void run() { {
registerReceiver(batt_monitor, itf); public void run()
} {
}; registerReceiver(batt_monitor, itf);
Timer t = new Timer(); }
context.unregisterReceiver(this); };
int rawlevel = intent.getIntExtra("level", -1); Timer t = new Timer();
int scale = intent.getIntExtra("scale", -1); context.unregisterReceiver(this);
if (rawlevel >= 0 && scale > 0) int rawlevel = intent.getIntExtra("level", -1);
battery_level = (rawlevel * 100) / scale; int scale = intent.getIntExtra("scale", -1);
else if (rawlevel >= 0 && scale > 0)
battery_level = -1; battery_level = (rawlevel * 100) / scale;
/* query every 30s should be sufficient */ else
t.schedule(tk, 30000); battery_level = -1;
} /* query every 30s should be sufficient */
}; t.schedule(tk, 30000);
registerReceiver(batt_monitor, itf); }
} };
registerReceiver(batt_monitor, itf);
}
/* all below is heavily based on the examples found on /* all below is heavily based on the examples found on
* http://developer.android.com/reference/android/app/Service.html * http://developer.android.com/reference/android/app/Service.html
@ -233,7 +240,7 @@ public class RockboxService extends Service
private void create_notification() private void create_notification()
{ {
/* For now we'll use the same text for the ticker and the expanded notification */ /* For now we'll use the same text for the ticker and the expanded notification */
CharSequence text = getText(R.string.notification); CharSequence text = getText(R.string.notification);
/* Set the icon, scrolling text and timestamp */ /* Set the icon, scrolling text and timestamp */
notification = new Notification(R.drawable.icon, text, notification = new Notification(R.drawable.icon, text,
@ -247,89 +254,90 @@ public class RockboxService extends Service
notification.setLatestEventInfo(this, getText(R.string.notification), text, contentIntent); notification.setLatestEventInfo(this, getText(R.string.notification), text, contentIntent);
} }
public static void startForeground() public static void startForeground()
{ {
if (instance != null) if (instance != null)
{ {
/* /*
* Send the notification. * Send the notification.
* We use a layout id because it is a unique number. We use it later to cancel. * We use a layout id because it is a unique number. We use it later to cancel.
*/ */
instance.mNM.notify(R.string.notification, instance.notification); instance.mNM.notify(R.string.notification, instance.notification);
/* /*
* this call makes the service run as foreground, which * this call makes the service run as foreground, which
* provides enough cpu time to do music decoding in the * provides enough cpu time to do music decoding in the
* background * background
*/ */
instance.startForegroundCompat(R.string.notification, instance.notification); instance.startForegroundCompat(R.string.notification, instance.notification);
} }
} }
public static void stopForeground() public static void stopForeground()
{ {
if (instance.notification != null) if (instance.notification != null)
{ {
instance.stopForegroundCompat(R.string.notification); instance.stopForegroundCompat(R.string.notification);
instance.mNM.cancel(R.string.notification); instance.mNM.cancel(R.string.notification);
} }
} }
/** /**
* This is a wrapper around the new startForeground method, using the older * This is a wrapper around the new startForeground method, using the older
* APIs if it is not available. * APIs if it is not available.
*/ */
void startForegroundCompat(int id, Notification notification) void startForegroundCompat(int id, Notification notification)
{ {
if (mStartForeground != null) { if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification; mStartForegroundArgs[1] = notification;
try { try {
mStartForeground.invoke(this, mStartForegroundArgs); mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
/* Should not happen. */ /* Should not happen. */
LOG("Unable to invoke startForeground", e); LOG("Unable to invoke startForeground", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
/* Should not happen. */ /* Should not happen. */
LOG("Unable to invoke startForeground", e); LOG("Unable to invoke startForeground", e);
} }
return; return;
} }
/* Fall back on the old API.*/ /* Fall back on the old API.*/
setForeground(true); setForeground(true);
mNM.notify(id, notification); mNM.notify(id, notification);
} }
/** /**
* This is a wrapper around the new stopForeground method, using the older * This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available. * APIs if it is not available.
*/ */
void stopForegroundCompat(int id) void stopForegroundCompat(int id)
{ {
if (mStopForeground != null) { if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE; mStopForegroundArgs[0] = Boolean.TRUE;
try { try {
mStopForeground.invoke(this, mStopForegroundArgs); mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
/* Should not happen. */ /* Should not happen. */
LOG("Unable to invoke stopForeground", e); LOG("Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
/* Should not happen. */ /* Should not happen. */
LOG("Unable to invoke stopForeground", e); LOG("Unable to invoke stopForeground", e);
} }
return; return;
} }
/* Fall back on the old API. Note to cancel BEFORE changing the /* Fall back on the old API. Note to cancel BEFORE changing the
* foreground state, since we could be killed at that point. */ * foreground state, since we could be killed at that point. */
mNM.cancel(id); mNM.cancel(id);
setForeground(false); setForeground(false);
} }
@Override @Override
public void onDestroy() { public void onDestroy()
super.onDestroy(); {
/* Make sure our notification is gone. */ super.onDestroy();
stopForegroundCompat(R.string.notification); /* Make sure our notification is gone. */
} stopForegroundCompat(R.string.notification);
}
} }

View file

@ -30,70 +30,73 @@ import android.util.Log;
public class RockboxTimer extends Timer public class RockboxTimer extends Timer
{ {
RockboxTimerTask task; RockboxTimerTask task;
long interval; long interval;
private class RockboxTimerTask extends TimerTask { private class RockboxTimerTask extends TimerTask {
private RockboxTimer t; private RockboxTimer t;
private TelephonyManager tm; private TelephonyManager tm;
private int last_state; private int last_state;
public RockboxTimerTask(RockboxService s, RockboxTimer parent) { public RockboxTimerTask(RockboxService s, RockboxTimer parent) {
super(); super();
t = parent; t = parent;
tm = (TelephonyManager)s.getSystemService(Context.TELEPHONY_SERVICE); tm = (TelephonyManager)s.getSystemService(Context.TELEPHONY_SERVICE);
last_state = tm.getCallState(); last_state = tm.getCallState();
} }
@Override @Override
public void run() { public void run()
timerTask(); {
int state = tm.getCallState(); timerTask();
if (state != last_state) int state = tm.getCallState();
{ if (state != last_state)
switch (state) { {
case TelephonyManager.CALL_STATE_IDLE: switch (state)
postCallHungUp(); {
break; case TelephonyManager.CALL_STATE_IDLE:
case TelephonyManager.CALL_STATE_RINGING: postCallHungUp();
postCallIncoming(); break;
default: case TelephonyManager.CALL_STATE_RINGING:
break; postCallIncoming();
} default:
last_state = state; break;
} }
synchronized(t) { last_state = state;
t.notify(); }
} synchronized(t) {
} t.notify();
} }
}
}
public RockboxTimer(RockboxService instance, long period_inverval_in_ms) public RockboxTimer(RockboxService instance, long period_inverval_in_ms)
{ {
super("tick timer", false); super("tick timer");
task = new RockboxTimerTask(instance, this); task = new RockboxTimerTask(instance, this);
schedule(task, 0, period_inverval_in_ms); schedule(task, 0, period_inverval_in_ms);
interval = period_inverval_in_ms; interval = period_inverval_in_ms;
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void LOG(CharSequence text) private void LOG(CharSequence text)
{ {
Log.d("Rockbox", (String) text); Log.d("Rockbox", (String) text);
} }
/* methods called from native, keep them simple */ /* methods called from native, keep them simple */
public void java_wait_for_interrupt() public void java_wait_for_interrupt()
{ {
synchronized(this) { synchronized(this)
try { {
this.wait(); try {
} catch (InterruptedException e) { this.wait();
/* Not an error: wakeup and return */ } catch (InterruptedException e) {
} /* Not an error: wakeup and return */
} }
}
} }
public native void timerTask(); public native void timerTask();
private native void postCallIncoming(); private native void postCallIncoming();
private native void postCallHungUp(); private native void postCallHungUp();
} }