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:
parent
54c838d2ae
commit
282adacb54
5 changed files with 549 additions and 528 deletions
|
@ -29,7 +29,8 @@ import android.view.ViewGroup;
|
|||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class RockboxActivity extends Activity {
|
||||
public class RockboxActivity extends Activity
|
||||
{
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
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
|
||||
* 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()
|
||||
{
|
||||
public void run() {
|
||||
try {
|
||||
while (RockboxService.fb == null)
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (Exception e) {
|
||||
LOG(e.toString());
|
||||
}
|
||||
/* drawing needs to happen in ui thread */
|
||||
runOnUiThread(new Runnable()
|
||||
{ @Override
|
||||
public void run() {
|
||||
setContentView(RockboxService.fb);
|
||||
RockboxService.fb.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
while (RockboxService.fb == null)
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (Exception e) {
|
||||
LOG(e.toString());
|
||||
}
|
||||
/* drawing needs to happen in ui thread */
|
||||
runOnUiThread(new Runnable()
|
||||
{ @Override
|
||||
public void run() {
|
||||
setContentView(RockboxService.fb);
|
||||
RockboxService.fb.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
if (RockboxService.fb != null)
|
||||
{
|
||||
try {
|
||||
setContentView(RockboxService.fb);
|
||||
} catch (IllegalStateException e) {
|
||||
/* we are already using the View,
|
||||
* need to remove it and re-attach it */
|
||||
ViewGroup g = (ViewGroup)RockboxService.fb.getParent();
|
||||
g.removeView(RockboxService.fb);
|
||||
setContentView(RockboxService.fb);
|
||||
}
|
||||
RockboxService.fb.resume();
|
||||
}
|
||||
super.onResume();
|
||||
|
||||
if (RockboxService.fb != null)
|
||||
{
|
||||
try {
|
||||
setContentView(RockboxService.fb);
|
||||
} catch (IllegalStateException e) {
|
||||
/* we are already using the View,
|
||||
* need to remove it and re-attach it */
|
||||
ViewGroup g = (ViewGroup)RockboxService.fb.getParent();
|
||||
g.removeView(RockboxService.fb);
|
||||
setContentView(RockboxService.fb);
|
||||
}
|
||||
RockboxService.fb.resume();
|
||||
}
|
||||
}
|
||||
|
||||
/* this is also called when the backlight goes off,
|
||||
* which is nice
|
||||
*/
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
RockboxService.fb.suspend();
|
||||
protected void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
RockboxService.fb.suspend();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
RockboxService.fb.suspend();
|
||||
protected void onStop()
|
||||
{
|
||||
super.onStop();
|
||||
RockboxService.fb.suspend();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
RockboxService.fb.suspend();
|
||||
protected void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
RockboxService.fb.suspend();
|
||||
}
|
||||
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
}
|
|
@ -33,93 +33,92 @@ import android.view.View;
|
|||
|
||||
public class RockboxFramebuffer extends View
|
||||
{
|
||||
private Bitmap btm;
|
||||
private Bitmap btm;
|
||||
private ByteBuffer native_buf;
|
||||
|
||||
public RockboxFramebuffer(Context c)
|
||||
{
|
||||
super(c);
|
||||
btm = null;
|
||||
public RockboxFramebuffer(Context c)
|
||||
{
|
||||
super(c);
|
||||
btm = null;
|
||||
|
||||
/* Needed so we can catch KeyEvents */
|
||||
setFocusable(true);
|
||||
requestFocus();
|
||||
}
|
||||
/* Needed so we can catch KeyEvents */
|
||||
setFocusable(true);
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
public void onDraw(Canvas c)
|
||||
{
|
||||
if (btm != null)
|
||||
c.drawBitmap(btm, 0.0f, 0.0f, null);
|
||||
}
|
||||
|
||||
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);
|
||||
native_buf = native_fb;
|
||||
}
|
||||
|
||||
public void java_lcd_update()
|
||||
{
|
||||
btm.copyPixelsFromBuffer(native_buf);
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void java_lcd_update_rect(int x, int y, int w, int h)
|
||||
{
|
||||
/* can't copy a partial buffer */
|
||||
btm.copyPixelsFromBuffer(native_buf);
|
||||
public void onDraw(Canvas c)
|
||||
{
|
||||
if (btm != null)
|
||||
c.drawBitmap(btm, 0.0f, 0.0f, null);
|
||||
}
|
||||
|
||||
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);
|
||||
native_buf = native_fb;
|
||||
}
|
||||
|
||||
public void java_lcd_update()
|
||||
{
|
||||
btm.copyPixelsFromBuffer(native_buf);
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void java_lcd_update_rect(int x, int y, int w, int h)
|
||||
{
|
||||
/* can't copy a partial buffer */
|
||||
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")
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent me)
|
||||
{
|
||||
public boolean onTouchEvent(MotionEvent me)
|
||||
{
|
||||
int x = (int) me.getX();
|
||||
int y = (int) me.getY();
|
||||
|
||||
switch (me.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
touchHandler(false, x, y);
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
touchHandler(true, x, y);
|
||||
return true;
|
||||
}
|
||||
switch (me.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
touchHandler(false, x, y);
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
touchHandler(true, x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
return buttonHandler(keyCode, true);
|
||||
}
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
return buttonHandler(keyCode, true);
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
return buttonHandler(keyCode, false);
|
||||
}
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
return buttonHandler(keyCode, false);
|
||||
}
|
||||
|
||||
/* the two below should only be called from the activity thread */
|
||||
public void suspend()
|
||||
{ /* suspend, Rockbox will not make any lcd updates */
|
||||
set_lcd_active(0);
|
||||
}
|
||||
public void resume()
|
||||
{ /* make updates again, the underlying function will
|
||||
* send an event */
|
||||
set_lcd_active(1);
|
||||
}
|
||||
/* the two below should only be called from the activity thread */
|
||||
public void suspend()
|
||||
{ /* suspend, Rockbox will not make any lcd updates */
|
||||
set_lcd_active(0);
|
||||
}
|
||||
public void resume()
|
||||
{ /* make updates again, the underlying function will
|
||||
* send an event */
|
||||
set_lcd_active(1);
|
||||
}
|
||||
|
||||
public native void set_lcd_active(int active);
|
||||
public native void touchHandler(boolean down, int x, int y);
|
||||
public native boolean buttonHandler(int keycode, boolean state);
|
||||
public native void set_lcd_active(int active);
|
||||
public native void touchHandler(boolean down, int x, int y);
|
||||
public native boolean buttonHandler(int keycode, boolean state);
|
||||
}
|
||||
|
|
|
@ -33,142 +33,148 @@ import android.util.Log;
|
|||
|
||||
public class RockboxPCM extends AudioTrack
|
||||
{
|
||||
private byte[] raw_data;
|
||||
private PCMListener l;
|
||||
private HandlerThread ht;
|
||||
private Handler h = null;
|
||||
private static final int samplerate = 44100;
|
||||
private byte[] raw_data;
|
||||
private PCMListener l;
|
||||
private HandlerThread ht;
|
||||
private Handler h = null;
|
||||
private static final int samplerate = 44100;
|
||||
/* should be CHANNEL_OUT_STEREO in 2.0 and above */
|
||||
private static final int channels = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
||||
private static final int encoding = AudioFormat.ENCODING_PCM_16BIT;
|
||||
private static final int buf_len = getMinBufferSize(44100, channels, encoding);
|
||||
private static final int channels = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
||||
private static final int encoding = AudioFormat.ENCODING_PCM_16BIT;
|
||||
private static final int buf_len = getMinBufferSize(44100, channels, encoding);
|
||||
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
|
||||
public RockboxPCM()
|
||||
{
|
||||
super(AudioManager.STREAM_MUSIC, samplerate, channels, encoding,
|
||||
buf_len, AudioTrack.MODE_STREAM);
|
||||
ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO);
|
||||
ht.start();
|
||||
raw_data = new byte[buf_len]; /* in shorts */
|
||||
Arrays.fill(raw_data, (byte) 0);
|
||||
l = new PCMListener(buf_len);
|
||||
}
|
||||
public RockboxPCM()
|
||||
{
|
||||
super(AudioManager.STREAM_MUSIC, samplerate, channels, encoding,
|
||||
buf_len, AudioTrack.MODE_STREAM);
|
||||
ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO);
|
||||
ht.start();
|
||||
raw_data = new byte[buf_len]; /* in shorts */
|
||||
Arrays.fill(raw_data, (byte) 0);
|
||||
l = new PCMListener(buf_len);
|
||||
}
|
||||
|
||||
int bytes2frames(int bytes) {
|
||||
/* 1 sample is 2 bytes, 2 samples are 1 frame */
|
||||
return (bytes/4);
|
||||
}
|
||||
|
||||
int frames2bytes(int frames) {
|
||||
/* 1 frame is 2 samples, 1 sample is 2 bytes */
|
||||
return (frames*4);
|
||||
}
|
||||
private int bytes2frames(int bytes)
|
||||
{
|
||||
/* 1 sample is 2 bytes, 2 samples are 1 frame */
|
||||
return (bytes/4);
|
||||
}
|
||||
|
||||
private int frames2bytes(int frames)
|
||||
{
|
||||
/* 1 frame is 2 samples, 1 sample is 2 bytes */
|
||||
return (frames*4);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void play_pause(boolean pause) {
|
||||
if (pause)
|
||||
{
|
||||
pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
|
||||
{
|
||||
RockboxService.startForeground();
|
||||
if (getState() == AudioTrack.STATE_INITIALIZED)
|
||||
{
|
||||
if (h == null)
|
||||
h = new Handler(ht.getLooper());
|
||||
if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) != AudioTrack.SUCCESS)
|
||||
LOG("setNotificationMarkerPosition Error");
|
||||
else
|
||||
setPlaybackPositionUpdateListener(l, h);
|
||||
}
|
||||
/* need to fill with silence before starting playback */
|
||||
write(raw_data, frames2bytes(getPlaybackHeadPosition()), raw_data.length);
|
||||
}
|
||||
play();
|
||||
}
|
||||
private void play_pause(boolean pause) {
|
||||
if (pause)
|
||||
{
|
||||
pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
|
||||
{
|
||||
RockboxService.startForeground();
|
||||
if (getState() == AudioTrack.STATE_INITIALIZED)
|
||||
{
|
||||
if (h == null)
|
||||
h = new Handler(ht.getLooper());
|
||||
if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) != AudioTrack.SUCCESS)
|
||||
LOG("setNotificationMarkerPosition Error");
|
||||
else
|
||||
setPlaybackPositionUpdateListener(l, h);
|
||||
}
|
||||
/* need to fill with silence before starting playback */
|
||||
write(raw_data, frames2bytes(getPlaybackHeadPosition()), raw_data.length);
|
||||
}
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws IllegalStateException
|
||||
{
|
||||
try {
|
||||
super.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
RockboxService.stopForeground();
|
||||
try {
|
||||
super.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
RockboxService.stopForeground();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void set_volume(int volume)
|
||||
{
|
||||
/* volume comes from 0..-990 from Rockbox */
|
||||
/* TODO volume is in dB, but this code acts as if it were in %, convert? */
|
||||
float fvolume;
|
||||
/* special case min and max volume to not suffer from floating point accuracy */
|
||||
if (volume == 0)
|
||||
fvolume = 1.0f;
|
||||
else if (volume == -990)
|
||||
fvolume = 0.0f;
|
||||
else
|
||||
fvolume = (volume + 990)/990.0f;
|
||||
setStereoVolume(fvolume, fvolume);
|
||||
/* volume comes from 0..-990 from Rockbox */
|
||||
/* TODO volume is in dB, but this code acts as if it were in %, convert? */
|
||||
float fvolume;
|
||||
/* special case min and max volume to not suffer from floating point accuracy */
|
||||
if (volume == 0)
|
||||
fvolume = 1.0f;
|
||||
else if (volume == -990)
|
||||
fvolume = 0.0f;
|
||||
else
|
||||
fvolume = (volume + 990)/990.0f;
|
||||
setStereoVolume(fvolume, fvolume);
|
||||
}
|
||||
|
||||
public native void pcmSamplesToByteArray(byte[] dest);
|
||||
|
||||
private class PCMListener implements OnPlaybackPositionUpdateListener {
|
||||
int max_len;
|
||||
int refill_mark;
|
||||
byte[] buf;
|
||||
public PCMListener(int len) {
|
||||
private class PCMListener implements OnPlaybackPositionUpdateListener
|
||||
{
|
||||
private int max_len;
|
||||
private int refill_mark;
|
||||
private byte[] buf;
|
||||
public PCMListener(int len)
|
||||
{
|
||||
max_len = len;
|
||||
/* refill to 100% when reached the 25% */
|
||||
buf = new byte[max_len*3/4];
|
||||
refill_mark = max_len - buf.length;
|
||||
}
|
||||
@Override
|
||||
public void onMarkerReached(AudioTrack track) {
|
||||
/* push new data to the hardware */
|
||||
RockboxPCM pcm = (RockboxPCM)track;
|
||||
int result = -1;
|
||||
pcm.pcmSamplesToByteArray(buf);
|
||||
result = track.write(buf, 0, buf.length);
|
||||
if (result >= 0)
|
||||
{
|
||||
switch(track.getPlayState())
|
||||
{
|
||||
case AudioTrack.PLAYSTATE_PLAYING:
|
||||
case AudioTrack.PLAYSTATE_PAUSED:
|
||||
/* refill at 25% no matter of how many bytes we've written */
|
||||
if (setNotificationMarkerPosition(bytes2frames(refill_mark)) != AudioTrack.SUCCESS)
|
||||
LOG("Error in onMarkerReached: Could not set notification marker");
|
||||
else /* recharge */
|
||||
setPlaybackPositionUpdateListener(this, h);
|
||||
break;
|
||||
case AudioTrack.PLAYSTATE_STOPPED:
|
||||
LOG("State STOPPED");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Error in onMarkerReached (result="+result+")");
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onMarkerReached(AudioTrack track)
|
||||
{
|
||||
/* push new data to the hardware */
|
||||
RockboxPCM pcm = (RockboxPCM)track;
|
||||
int result = -1;
|
||||
pcm.pcmSamplesToByteArray(buf);
|
||||
result = track.write(buf, 0, buf.length);
|
||||
if (result >= 0)
|
||||
{
|
||||
switch(track.getPlayState())
|
||||
{
|
||||
case AudioTrack.PLAYSTATE_PLAYING:
|
||||
case AudioTrack.PLAYSTATE_PAUSED:
|
||||
/* refill at 25% no matter of how many bytes we've written */
|
||||
if (setNotificationMarkerPosition(bytes2frames(refill_mark))
|
||||
!= AudioTrack.SUCCESS)
|
||||
LOG("Error in onMarkerReached: Could not set notification marker");
|
||||
else /* recharge */
|
||||
setPlaybackPositionUpdateListener(this, h);
|
||||
break;
|
||||
case AudioTrack.PLAYSTATE_STOPPED:
|
||||
LOG("State STOPPED");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Error in onMarkerReached (result="+result+")");
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeriodicNotification(AudioTrack track) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onPeriodicNotification(AudioTrack track)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,78 +48,82 @@ import android.util.Log;
|
|||
|
||||
public class RockboxService extends Service
|
||||
{
|
||||
/* this Service is really a singleton class */
|
||||
public static RockboxFramebuffer fb = null;
|
||||
private static RockboxService instance;
|
||||
private Notification notification;
|
||||
private static final Class<?>[] mStartForegroundSignature = new Class[] {
|
||||
int.class, Notification.class};
|
||||
private static final Class<?>[] mStopForegroundSignature = new Class[] {
|
||||
boolean.class};
|
||||
/* this Service is really a singleton class */
|
||||
public static RockboxFramebuffer fb = null;
|
||||
private static RockboxService instance;
|
||||
private Notification notification;
|
||||
private static final Class<?>[] mStartForegroundSignature = new Class[] {
|
||||
int.class, Notification.class};
|
||||
private static final Class<?>[] mStopForegroundSignature = new Class[] {
|
||||
boolean.class};
|
||||
|
||||
private NotificationManager mNM;
|
||||
private Method mStartForeground;
|
||||
private Method mStopForeground;
|
||||
private Object[] mStartForegroundArgs = new Object[2];
|
||||
private Object[] mStopForegroundArgs = new Object[1];
|
||||
private IntentFilter itf;
|
||||
private BroadcastReceiver batt_monitor;
|
||||
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 NotificationManager mNM;
|
||||
private Method mStartForeground;
|
||||
private Method mStopForeground;
|
||||
private Object[] mStartForegroundArgs = new Object[2];
|
||||
private Object[] mStopForegroundArgs = new Object[1];
|
||||
private IntentFilter itf;
|
||||
private BroadcastReceiver batt_monitor;
|
||||
private int battery_level;
|
||||
|
||||
private void do_start(Intent intent)
|
||||
{
|
||||
LOG("Start Service");
|
||||
/* Display a notification about us starting. We put an icon in the status bar. */
|
||||
create_notification();
|
||||
}
|
||||
@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 LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
|
||||
private void LOG(CharSequence text, Throwable tr)
|
||||
{
|
||||
Log.d("Rockbox", (String) text, tr);
|
||||
}
|
||||
private void do_start(Intent intent)
|
||||
{
|
||||
LOG("Start Service");
|
||||
/* Display a notification about us starting. We put an icon in the status bar. */
|
||||
create_notification();
|
||||
}
|
||||
|
||||
public void onStart(Intent intent, int startId) {
|
||||
do_start(intent);
|
||||
}
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
|
||||
private void LOG(CharSequence text, Throwable tr)
|
||||
{
|
||||
Log.d("Rockbox", (String) text, tr);
|
||||
}
|
||||
|
||||
public int onStartCommand(Intent intent, int flags, int startId)
|
||||
{
|
||||
do_start(intent);
|
||||
return 1; /* old API compatibility: 1 == START_STICKY */
|
||||
}
|
||||
public void onStart(Intent intent, int startId) {
|
||||
do_start(intent);
|
||||
}
|
||||
|
||||
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);
|
||||
final int BUFFER = 8*1024;
|
||||
/* 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
|
||||
* because there's no other way to ship files and have access
|
||||
* to them from native code
|
||||
*/
|
||||
try
|
||||
{
|
||||
final int BUFFER = 8*1024;
|
||||
/* 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
|
||||
* because there's no other way to ship files and have access
|
||||
* to them from native code
|
||||
*/
|
||||
try
|
||||
{
|
||||
BufferedOutputStream dest = null;
|
||||
BufferedInputStream is = null;
|
||||
ZipEntry entry;
|
||||
|
@ -128,112 +132,115 @@ public class RockboxService extends Service
|
|||
File file2 = new File("/data/data/org.rockbox/app_rockbox/rockbox/codecs/mpa.codec");
|
||||
if (!file2.exists() || (file.lastModified() > file2.lastModified()))
|
||||
{
|
||||
ZipFile zipfile = new ZipFile(file);
|
||||
Enumeration<? extends ZipEntry> e = zipfile.entries();
|
||||
File folder;
|
||||
while(e.hasMoreElements()) {
|
||||
entry = (ZipEntry) e.nextElement();
|
||||
LOG("Extracting: " +entry);
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
folder = new File(entry.getName());
|
||||
LOG("mkdir "+ entry);
|
||||
try {
|
||||
folder.mkdirs();
|
||||
} catch (SecurityException ex){
|
||||
LOG(ex.getMessage());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
is = new BufferedInputStream(zipfile.getInputStream(entry), BUFFER);
|
||||
int count;
|
||||
byte data[] = new byte[BUFFER];
|
||||
folder = new File(new File(entry.getName()).getParent());
|
||||
LOG("" + folder.getAbsolutePath());
|
||||
if (!folder.exists())
|
||||
folder.mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(entry.getName());
|
||||
dest = new BufferedOutputStream(fos, BUFFER);
|
||||
while ((count = is.read(data, 0, BUFFER)) != -1) {
|
||||
dest.write(data, 0, count);
|
||||
}
|
||||
dest.flush();
|
||||
dest.close();
|
||||
is.close();
|
||||
}
|
||||
ZipFile zipfile = new ZipFile(file);
|
||||
Enumeration<? extends ZipEntry> e = zipfile.entries();
|
||||
File folder;
|
||||
while(e.hasMoreElements())
|
||||
{
|
||||
entry = (ZipEntry) e.nextElement();
|
||||
LOG("Extracting: " +entry);
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
folder = new File(entry.getName());
|
||||
LOG("mkdir "+ entry);
|
||||
try {
|
||||
folder.mkdirs();
|
||||
} catch (SecurityException ex) {
|
||||
LOG(ex.getMessage());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
is = new BufferedInputStream(zipfile.getInputStream(entry), BUFFER);
|
||||
int count;
|
||||
byte data[] = new byte[BUFFER];
|
||||
folder = new File(new File(entry.getName()).getParent());
|
||||
LOG("" + folder.getAbsolutePath());
|
||||
if (!folder.exists())
|
||||
folder.mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(entry.getName());
|
||||
dest = new BufferedOutputStream(fos, BUFFER);
|
||||
while ((count = is.read(data, 0, BUFFER)) != -1)
|
||||
dest.write(data, 0, count);
|
||||
dest.flush();
|
||||
dest.close();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
} catch(FileNotFoundException e) {
|
||||
LOG("FileNotFoundException when unzipping", e);
|
||||
e.printStackTrace();
|
||||
LOG("FileNotFoundException when unzipping", e);
|
||||
e.printStackTrace();
|
||||
} catch(IOException e) {
|
||||
LOG("IOException when unzipping", e);
|
||||
e.printStackTrace();
|
||||
LOG("IOException when unzipping", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.loadLibrary("rockbox");
|
||||
|
||||
Thread rb = new Thread(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
main();
|
||||
}
|
||||
},"Rockbox thread");
|
||||
rb.setDaemon(false);
|
||||
rb.start();
|
||||
}
|
||||
Thread rb = new Thread(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
main();
|
||||
}
|
||||
},"Rockbox thread");
|
||||
rb.setDaemon(false);
|
||||
rb.start();
|
||||
}
|
||||
|
||||
private native void main();
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public IBinder onBind(Intent intent)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
/*
|
||||
* Sets up the battery monitor which receives the battery level
|
||||
* about each 30 seconds
|
||||
*/
|
||||
private void initBatteryMonitor()
|
||||
{
|
||||
itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
batt_monitor = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
/* we get literally spammed with battery statuses
|
||||
* if we don't delay the re-attaching
|
||||
*/
|
||||
TimerTask tk = new TimerTask() {
|
||||
public void run() {
|
||||
registerReceiver(batt_monitor, itf);
|
||||
}
|
||||
};
|
||||
Timer t = new Timer();
|
||||
context.unregisterReceiver(this);
|
||||
int rawlevel = intent.getIntExtra("level", -1);
|
||||
int scale = intent.getIntExtra("scale", -1);
|
||||
if (rawlevel >= 0 && scale > 0)
|
||||
battery_level = (rawlevel * 100) / scale;
|
||||
else
|
||||
battery_level = -1;
|
||||
/* query every 30s should be sufficient */
|
||||
t.schedule(tk, 30000);
|
||||
}
|
||||
};
|
||||
registerReceiver(batt_monitor, itf);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
/*
|
||||
* Sets up the battery monitor which receives the battery level
|
||||
* about each 30 seconds
|
||||
*/
|
||||
private void initBatteryMonitor()
|
||||
{
|
||||
itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
batt_monitor = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
/* we get literally spammed with battery statuses
|
||||
* if we don't delay the re-attaching
|
||||
*/
|
||||
TimerTask tk = new TimerTask()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
registerReceiver(batt_monitor, itf);
|
||||
}
|
||||
};
|
||||
Timer t = new Timer();
|
||||
context.unregisterReceiver(this);
|
||||
int rawlevel = intent.getIntExtra("level", -1);
|
||||
int scale = intent.getIntExtra("scale", -1);
|
||||
if (rawlevel >= 0 && scale > 0)
|
||||
battery_level = (rawlevel * 100) / scale;
|
||||
else
|
||||
battery_level = -1;
|
||||
/* query every 30s should be sufficient */
|
||||
t.schedule(tk, 30000);
|
||||
}
|
||||
};
|
||||
registerReceiver(batt_monitor, itf);
|
||||
}
|
||||
|
||||
/* all below is heavily based on the examples found on
|
||||
* http://developer.android.com/reference/android/app/Service.html
|
||||
*/
|
||||
|
||||
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);
|
||||
/* Set the icon, scrolling text and timestamp */
|
||||
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);
|
||||
}
|
||||
|
||||
public static void startForeground()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
/*
|
||||
* Send the notification.
|
||||
* 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);
|
||||
/*
|
||||
* this call makes the service run as foreground, which
|
||||
* provides enough cpu time to do music decoding in the
|
||||
* background
|
||||
*/
|
||||
instance.startForegroundCompat(R.string.notification, instance.notification);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopForeground()
|
||||
{
|
||||
if (instance.notification != null)
|
||||
{
|
||||
instance.stopForegroundCompat(R.string.notification);
|
||||
instance.mNM.cancel(R.string.notification);
|
||||
}
|
||||
}
|
||||
public static void startForeground()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
/*
|
||||
* Send the notification.
|
||||
* 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);
|
||||
/*
|
||||
* this call makes the service run as foreground, which
|
||||
* provides enough cpu time to do music decoding in the
|
||||
* background
|
||||
*/
|
||||
instance.startForegroundCompat(R.string.notification, instance.notification);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopForeground()
|
||||
{
|
||||
if (instance.notification != null)
|
||||
{
|
||||
instance.stopForegroundCompat(R.string.notification);
|
||||
instance.mNM.cancel(R.string.notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new startForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void startForegroundCompat(int id, Notification notification)
|
||||
{
|
||||
if (mStartForeground != null) {
|
||||
mStartForegroundArgs[0] = Integer.valueOf(id);
|
||||
mStartForegroundArgs[1] = notification;
|
||||
try {
|
||||
mStartForeground.invoke(this, mStartForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke startForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke startForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* This is a wrapper around the new startForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void startForegroundCompat(int id, Notification notification)
|
||||
{
|
||||
if (mStartForeground != null) {
|
||||
mStartForegroundArgs[0] = Integer.valueOf(id);
|
||||
mStartForegroundArgs[1] = notification;
|
||||
try {
|
||||
mStartForeground.invoke(this, mStartForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke startForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke startForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fall back on the old API.*/
|
||||
setForeground(true);
|
||||
mNM.notify(id, notification);
|
||||
}
|
||||
/* Fall back on the old API.*/
|
||||
setForeground(true);
|
||||
mNM.notify(id, notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new stopForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void stopForegroundCompat(int id)
|
||||
{
|
||||
if (mStopForeground != null) {
|
||||
mStopForegroundArgs[0] = Boolean.TRUE;
|
||||
try {
|
||||
mStopForeground.invoke(this, mStopForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke stopForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke stopForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* This is a wrapper around the new stopForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void stopForegroundCompat(int id)
|
||||
{
|
||||
if (mStopForeground != null) {
|
||||
mStopForegroundArgs[0] = Boolean.TRUE;
|
||||
try {
|
||||
mStopForeground.invoke(this, mStopForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke stopForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
/* Should not happen. */
|
||||
LOG("Unable to invoke stopForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
setForeground(false);
|
||||
}
|
||||
/* 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);
|
||||
setForeground(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
/* Make sure our notification is gone. */
|
||||
stopForegroundCompat(R.string.notification);
|
||||
}
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
/* Make sure our notification is gone. */
|
||||
stopForegroundCompat(R.string.notification);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,70 +30,73 @@ import android.util.Log;
|
|||
|
||||
public class RockboxTimer extends Timer
|
||||
{
|
||||
RockboxTimerTask task;
|
||||
long interval;
|
||||
|
||||
private class RockboxTimerTask extends TimerTask {
|
||||
private RockboxTimer t;
|
||||
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();
|
||||
}
|
||||
RockboxTimerTask task;
|
||||
long interval;
|
||||
|
||||
private class RockboxTimerTask extends TimerTask {
|
||||
private RockboxTimer t;
|
||||
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(RockboxService instance, long period_inverval_in_ms)
|
||||
{
|
||||
super("tick timer", false);
|
||||
task = new RockboxTimerTask(instance, this);
|
||||
schedule(task, 0, period_inverval_in_ms);
|
||||
interval = period_inverval_in_ms;
|
||||
}
|
||||
@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(RockboxService instance, long period_inverval_in_ms)
|
||||
{
|
||||
super("tick timer");
|
||||
task = new RockboxTimerTask(instance, this);
|
||||
schedule(task, 0, period_inverval_in_ms);
|
||||
interval = period_inverval_in_ms;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
private void LOG(CharSequence text)
|
||||
{
|
||||
Log.d("Rockbox", (String) text);
|
||||
}
|
||||
|
||||
|
||||
/* methods called from native, keep them simple */
|
||||
public void java_wait_for_interrupt()
|
||||
{
|
||||
synchronized(this) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
/* Not an error: wakeup and return */
|
||||
}
|
||||
}
|
||||
synchronized(this)
|
||||
{
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
/* Not an error: wakeup and return */
|
||||
}
|
||||
}
|
||||
}
|
||||
public native void timerTask();
|
||||
private native void postCallIncoming();
|
||||
private native void postCallHungUp();
|
||||
public native void timerTask();
|
||||
private native void postCallIncoming();
|
||||
private native void postCallHungUp();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue