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.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue