diff options
Diffstat (limited to 'android')
| -rw-r--r-- | android/.classpath | 7 | ||||
| -rw-r--r-- | android/.project | 33 | ||||
| -rw-r--r-- | android/AndroidManifest.xml | 18 | ||||
| -rw-r--r-- | android/README | 34 | ||||
| -rw-r--r-- | android/default.properties | 11 | ||||
| -rw-r--r-- | android/gen/org/rockbox/R.java | 22 | ||||
| -rw-r--r-- | android/res/drawable-hdpi/icon.png | bin | 0 -> 4147 bytes | |||
| -rw-r--r-- | android/res/drawable-ldpi/icon.png | bin | 0 -> 1723 bytes | |||
| -rw-r--r-- | android/res/drawable-mdpi/icon.png | bin | 0 -> 2574 bytes | |||
| -rw-r--r-- | android/res/layout/main.xml | 7 | ||||
| -rw-r--r-- | android/res/values/strings.xml | 5 | ||||
| -rw-r--r-- | android/src/org/rockbox/RockboxActivity.java | 148 | ||||
| -rw-r--r-- | android/src/org/rockbox/RockboxFramebuffer.java | 98 | ||||
| -rw-r--r-- | android/src/org/rockbox/RockboxPCM.java | 155 | ||||
| -rw-r--r-- | android/src/org/rockbox/RockboxTimer.java | 93 |
15 files changed, 631 insertions, 0 deletions
diff --git a/android/.classpath b/android/.classpath new file mode 100644 index 0000000..6efcbb7 --- /dev/null +++ b/android/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/android/.project b/android/.project new file mode 100644 index 0000000..7e8d136 --- /dev/null +++ b/android/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>Rockbox</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.ApkBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..a22c393 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.rockbox" + android:versionCode="1" + android:versionName="1.0"> + <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> + <activity android:name=".RockboxActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +<uses-sdk android:minSdkVersion="4" /> +<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> +</manifest>
\ No newline at end of file diff --git a/android/README b/android/README new file mode 100644 index 0000000..e41bfa6 --- /dev/null +++ b/android/README @@ -0,0 +1,34 @@ +This folder contains the java parts needed to build an Rockbox as an +application for android. + +* Build instructions + +Until there's a script which does all the work the procedure is documented here. + +First, make sure you have the ANDROID_NDK_PATH environment variable set up, +otherwise configure will fail to find the compiler. + +Use this as your build folder, using '../tools/configure' etc. + $ ../tools/configure + $ make + +After the build finished, you need to copy librockbox.so to libs/armeabi/. + $ cp librockbox.so libs/armeabi + +For the other files (codecs, themes), you execute 'make zip'. Then you copy the +zip to libs/armeabi, using the name libmisc.so. This is needed, since there's no +way to bundle stuff into apk's and have access to them from native code other +than pretending it was a library. + $ make zip + $ cp rockbox.zip lib/armeabi/libmisc.so + +rockbox.zip..err, libmisc.so will be unpacked at runtime. + +To finish, you can follow this guide [1], or use eclipse. Simply install eclipse +and the android plugins, then import this folder as a new Android project and run it. +See [2] for a guide on how to set up eclipse for android development. + + + +[1]: http://asantoso.wordpress.com/2009/09/15/how-to-build-android-application-package-apk-from-the-command-line-using-the-sdk-tools-continuously-integrated-using-cruisecontrol/ +[2]: http://developer.android.com/sdk/installing.html diff --git a/android/default.properties b/android/default.properties new file mode 100644 index 0000000..9d79b12 --- /dev/null +++ b/android/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-4 diff --git a/android/gen/org/rockbox/R.java b/android/gen/org/rockbox/R.java new file mode 100644 index 0000000..38c177e --- /dev/null +++ b/android/gen/org/rockbox/R.java @@ -0,0 +1,22 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.rockbox; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class layout { + public static final int main=0x7f030000; + } + public static final class string { + public static final int app_name=0x7f040000; + } +} diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..8074c4c --- /dev/null +++ b/android/res/drawable-hdpi/icon.png diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..1095584 --- /dev/null +++ b/android/res/drawable-ldpi/icon.png diff --git a/android/res/drawable-mdpi/icon.png b/android/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..a07c69f --- /dev/null +++ b/android/res/drawable-mdpi/icon.png diff --git a/android/res/layout/main.xml b/android/res/layout/main.xml new file mode 100644 index 0000000..4361cfe --- /dev/null +++ b/android/res/layout/main.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > +</LinearLayout> diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml new file mode 100644 index 0000000..6c3c846 --- /dev/null +++ b/android/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Rockbox</string> +</resources> diff --git a/android/src/org/rockbox/RockboxActivity.java b/android/src/org/rockbox/RockboxActivity.java new file mode 100644 index 0000000..791cad9 --- /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 0000000..f947806 --- /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 0000000..f098df6 --- /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 0000000..c7239b4 --- /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(); +} |