summaryrefslogtreecommitdiffstats
path: root/android/src
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-08-02 20:34:47 +0000
committerThomas Martitz <kugel@rockbox.org>2010-08-02 20:34:47 +0000
commit240923a801382c86545d10be167a15892a556fb6 (patch)
tree3c0e07ec3abf0c493a0b24b0b57e8bbd0200f7f6 /android/src
parent850efead04f10488b478a0f255a2464a01156a7f (diff)
downloadrockbox-240923a801382c86545d10be167a15892a556fb6.tar.gz
rockbox-240923a801382c86545d10be167a15892a556fb6.zip
Rockbox as an application: Commit current Android port progress.
General state is: Rockbox is usable (plays music, saves configuration, touchscreen works too). Problems: - Playing music in the background (i.e. when switching to another app) doesn't work reliably, but I'm working on that now. - no cabbiev2 (only some preliminary files for it), no other default theme. - screen flickers sometimes if the updates are too frequent - no multi screen apk/package - strange behavior when a phone call comes in The java files (and the eclipse project) resides in android/, which is also supposed to be the build folder. I've put a small README in there for instructions. There are some steps needed after the make part, which are described there, and which eclipse mostly handles. But there ought to be some script/makefile rules which do that instead in the future. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27668 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'android/src')
-rw-r--r--android/src/org/rockbox/RockboxActivity.java148
-rw-r--r--android/src/org/rockbox/RockboxFramebuffer.java98
-rw-r--r--android/src/org/rockbox/RockboxPCM.java155
-rw-r--r--android/src/org/rockbox/RockboxTimer.java93
4 files changed, 494 insertions, 0 deletions
diff --git a/android/src/org/rockbox/RockboxActivity.java b/android/src/org/rockbox/RockboxActivity.java
new file mode 100644
index 0000000000..791cad90ff
--- /dev/null
+++ b/android/src/org/rockbox/RockboxActivity.java
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+package org.rockbox;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
+
+public class RockboxActivity extends Activity {
+ /** Called when the activity is first created. */
+ public RockboxFramebuffer fb;
+ private Thread rb;
+ static final int BUFFER = 2048;
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LOG("start rb");
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
+ ,WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ fb = new RockboxFramebuffer(this);
+ if (true) {
+ try
+ {
+ BufferedOutputStream dest = null;
+ BufferedInputStream is = null;
+ ZipEntry entry;
+ File file = new File("/data/data/org.rockbox/lib/libmisc.so");
+ /* use arbitary file to determine whether extracting is needed */
+ 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));
+ 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(Exception e) {
+ e.printStackTrace();
+ }}
+ Rect r = new Rect();
+ fb.getDrawingRect(r);
+ LOG(r.left + " " + r.top + " " + r.right + " " + r.bottom);
+ rb = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ main();
+ }
+ },"Rockbox thread");
+ System.loadLibrary("rockbox");
+ rb.setDaemon(false);
+ setContentView(fb);
+ }
+
+ private void LOG(CharSequence text)
+ {
+ Log.d("RockboxBootloader", (String) text);
+ }
+
+ public synchronized void onStart()
+ {
+ super.onStart();
+ if (!rb.isAlive())
+ rb.start();
+ }
+
+ public void onPause()
+ {
+ super.onPause();
+ }
+
+ public void onResume()
+ {
+ super.onResume();
+ switch (rb.getState()) {
+ case BLOCKED: LOG("BLOCKED"); break;
+ case RUNNABLE: LOG("RUNNABLE"); break;
+ case NEW: LOG("NEW"); break;
+ case TERMINATED: LOG("TERMINATED"); break;
+ case TIMED_WAITING: LOG("TIMED_WAITING"); break;
+ case WAITING: LOG("WAITING"); break;
+ }
+ }
+
+
+ private native void main();
+} \ No newline at end of file
diff --git a/android/src/org/rockbox/RockboxFramebuffer.java b/android/src/org/rockbox/RockboxFramebuffer.java
new file mode 100644
index 0000000000..f947806bb4
--- /dev/null
+++ b/android/src/org/rockbox/RockboxFramebuffer.java
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+package org.rockbox;
+
+import java.nio.ByteBuffer;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class RockboxFramebuffer extends View
+{
+ private Bitmap btm;
+ private ByteBuffer native_buf;
+ private Handler update_handler;
+ private Runnable cb;
+
+
+ public RockboxFramebuffer(Context c)
+ {
+ super(c);
+ update_handler = new Handler();
+ cb = new Runnable() {
+ public void run()
+ {
+ btm.copyPixelsFromBuffer(native_buf);
+ invalidate();
+ }
+ };
+ btm = null;
+ }
+
+ 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()
+ {
+ update_handler.post(cb);
+ }
+
+ private void LOG(CharSequence text)
+ {
+ Log.d("RockboxBootloader", (String) text);
+ }
+
+ public boolean onTouchEvent(MotionEvent me)
+ {
+ LOG("onTouchEvent");
+ switch (me.getAction())
+ {
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ touchHandler(0);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_DOWN:
+ touchHandler(1);
+ break;
+
+ }
+ pixelHandler((int)me.getX(), (int)me.getY());
+ return true;
+ }
+
+ public native void pixelHandler(int x, int y);
+ public native void touchHandler(int down);
+}
diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java
new file mode 100644
index 0000000000..f098df6991
--- /dev/null
+++ b/android/src/org/rockbox/RockboxPCM.java
@@ -0,0 +1,155 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+package org.rockbox;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.util.Log;
+
+public class RockboxPCM extends AudioTrack
+{
+ byte[] raw_data;
+
+ private void LOG(CharSequence text)
+ {
+ Log.d("RockboxBootloader", (String) text);
+ }
+
+ public RockboxPCM()
+ {
+ super(AudioManager.STREAM_MUSIC,
+ 44100,
+ /* should be CHANNEL_OUT_STEREO in 2.0 and above */
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO,
+ AudioFormat.ENCODING_PCM_16BIT,
+ 24<<10,
+ AudioTrack.MODE_STREAM);
+ int buf_len = 24<<10;
+
+ raw_data = new byte[buf_len*2];
+ for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte) 0x00;
+ /* fill with silence */
+ write(raw_data, 0, raw_data.length);
+ if (getState() == AudioTrack.STATE_INITIALIZED)
+ {
+ if (setNotificationMarkerPosition(bytes2frames(buf_len*2)/4) != AudioTrack.SUCCESS)
+ LOG("setNotificationMarkerPosition Error");
+ setPlaybackPositionUpdateListener(new PCMListener(buf_len*2));
+ }
+ }
+
+
+
+ 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);
+ }
+
+ @SuppressWarnings("unused")
+ private void play_pause(boolean pause) {
+ LOG("play_pause()");
+ if (pause)
+ pause();
+ else
+ {
+ if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
+ {
+ for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte) 0x00;
+ LOG("Writing silence");
+ /* fill with silence */
+ write(raw_data, 0, raw_data.length);
+ }
+ play();
+ }
+ LOG("play_pause() return");
+ }
+
+ @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);
+ }
+
+ public native void pcmSamplesToByteArray(byte[] dest);
+
+ private class PCMListener implements OnPlaybackPositionUpdateListener {
+ int max_len;
+ byte[] buf;
+ public PCMListener(int len) {
+ max_len = len;
+ buf = new byte[len/2];
+ }
+ @Override
+ public void onMarkerReached(AudioTrack track) {
+ // push new data to the hardware
+ int result = 1;
+ pcmSamplesToByteArray(buf);
+ //LOG("Trying to write " + buf.length + " bytes");
+ result = track.write(buf, 0, buf.length);
+ if (result > 0)
+ {
+ //LOG(result + " bytes written");
+ track.setPlaybackPositionUpdateListener(this);
+ track.setNotificationMarkerPosition(bytes2frames(max_len)/4);
+ switch(track.getPlayState())
+ {
+ case AudioTrack.PLAYSTATE_PLAYING:
+ //LOG("State PLAYING");
+ break;
+ case AudioTrack.PLAYSTATE_PAUSED:
+ LOG("State PAUSED");
+ break;
+ case AudioTrack.PLAYSTATE_STOPPED:
+ LOG("State STOPPED");
+ break;
+ }
+ }
+ else
+ {
+ LOG("Error in onMarkerReached");
+ track.stop();
+ }
+ }
+
+ @Override
+ public void onPeriodicNotification(AudioTrack track) {
+ // TODO Auto-generated method stub
+
+ }
+ }
+}
diff --git a/android/src/org/rockbox/RockboxTimer.java b/android/src/org/rockbox/RockboxTimer.java
new file mode 100644
index 0000000000..c7239b4ee6
--- /dev/null
+++ b/android/src/org/rockbox/RockboxTimer.java
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+package org.rockbox;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import android.util.Log;
+
+public class RockboxTimer extends Timer
+{
+ RockboxTimerTask task;
+ long interval;
+
+ private class RockboxTimerTask extends TimerTask {
+ private RockboxTimer t;
+ public RockboxTimerTask(RockboxTimer parent) {
+ super();
+ t = parent;
+ }
+
+ @Override
+ public void run() {
+ timerTask();
+ synchronized(t) {
+ t.notify();
+ }
+ }
+ }
+
+ public void pause()
+ {
+ cancel();
+ }
+ public void resume()
+ {
+ try {
+ schedule(task, 0, interval);
+ } catch (IllegalStateException e) {
+ /* not an error */
+ } catch (Exception e) {
+ LOG(e.toString());
+ }
+ }
+
+ public RockboxTimer(long period_inverval_in_ms)
+ {
+ super("tick timer", false);
+ task = new RockboxTimerTask(this);
+ schedule(task, 0, period_inverval_in_ms);
+ interval = period_inverval_in_ms;
+ }
+
+ private void LOG(CharSequence text)
+ {
+ Log.d("RockboxBootloader", (String) text);
+ }
+
+
+ /* methods called from native, keep them simple */
+ public void java_wait_for_interrupt()
+ {
+ synchronized(this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ /* wakeup and return */
+ } catch (Exception e) {
+ LOG(e.toString());
+ }
+ }
+ }
+ public native void timerTask();
+}