Android: don't compile powermgmt-sim.c
[maemo-rb.git] / android / src / org / rockbox / RockboxService.java
blob6dc69b3404cbd80f69c0dbf01d91461abf3f3669
1 package org.rockbox;
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
5 import java.io.File;
6 import java.io.FileNotFoundException;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.lang.reflect.InvocationTargetException;
10 import java.lang.reflect.Method;
11 import java.util.Enumeration;
12 import java.util.Timer;
13 import java.util.TimerTask;
14 import java.util.zip.ZipEntry;
15 import java.util.zip.ZipFile;
17 import android.app.Notification;
18 import android.app.NotificationManager;
19 import android.app.PendingIntent;
20 import android.app.Service;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.os.IBinder;
26 import android.util.Log;
28 public class RockboxService extends Service
30 /* this Service is really a singleton class */
31 public static RockboxFramebuffer fb = null;
32 private static RockboxService instance;
33 private Notification notification;
34 private static final Class<?>[] mStartForegroundSignature = new Class[] {
35 int.class, Notification.class};
36 private static final Class<?>[] mStopForegroundSignature = new Class[] {
37 boolean.class};
39 private NotificationManager mNM;
40 private Method mStartForeground;
41 private Method mStopForeground;
42 private Object[] mStartForegroundArgs = new Object[2];
43 private Object[] mStopForegroundArgs = new Object[1];
44 private IntentFilter itf;
45 private BroadcastReceiver batt_monitor;
46 private int battery_level;
47 @Override
48 public void onCreate()
50 mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
51 try {
52 mStartForeground = getClass().getMethod("startForeground",
53 mStartForegroundSignature);
54 mStopForeground = getClass().getMethod("stopForeground",
55 mStopForegroundSignature);
56 } catch (NoSuchMethodException e) {
57 /* Running on an older platform: fall back to old API */
58 mStartForeground = mStopForeground = null;
60 startservice();
61 instance = this;
64 private void do_start(Intent intent)
66 LOG("Start Service");
67 /* Display a notification about us starting. We put an icon in the status bar. */
68 create_notification();
71 private void LOG(CharSequence text)
73 Log.d("Rockbox", (String) text);
76 private void LOG(CharSequence text, Throwable tr)
78 Log.d("Rockbox", (String) text, tr);
81 public void onStart(Intent intent, int startId) {
82 do_start(intent);
85 public int onStartCommand(Intent intent, int flags, int startId)
87 do_start(intent);
88 return 1; /* old API compatibility: 1 == START_STICKY */
91 private void startservice()
93 fb = new RockboxFramebuffer(this);
94 final int BUFFER = 2048;
95 /* the following block unzips libmisc.so, which contains the files
96 * we ship, such as themes. It's needed to put it into a .so file
97 * because there's no other way to ship files and have access
98 * to them from native code
102 BufferedOutputStream dest = null;
103 BufferedInputStream is = null;
104 ZipEntry entry;
105 File file = new File("/data/data/org.rockbox/lib/libmisc.so");
106 /* use arbitary file to determine whether extracting is needed */
107 File file2 = new File("/data/data/org.rockbox/app_rockbox/rockbox/codecs/mpa.codec");
108 if (!file2.exists() || (file.lastModified() > file2.lastModified()))
110 ZipFile zipfile = new ZipFile(file);
111 Enumeration<? extends ZipEntry> e = zipfile.entries();
112 File folder;
113 while(e.hasMoreElements()) {
114 entry = (ZipEntry) e.nextElement();
115 LOG("Extracting: " +entry);
116 if (entry.isDirectory())
118 folder = new File(entry.getName());
119 LOG("mkdir "+ entry);
120 try {
121 folder.mkdirs();
122 } catch (SecurityException ex){
123 LOG(ex.getMessage());
125 continue;
127 is = new BufferedInputStream(zipfile.getInputStream(entry));
128 int count;
129 byte data[] = new byte[BUFFER];
130 folder = new File(new File(entry.getName()).getParent());
131 LOG("" + folder.getAbsolutePath());
132 if (!folder.exists())
133 folder.mkdirs();
134 FileOutputStream fos = new FileOutputStream(entry.getName());
135 dest = new BufferedOutputStream(fos, BUFFER);
136 while ((count = is.read(data, 0, BUFFER)) != -1) {
137 dest.write(data, 0, count);
139 dest.flush();
140 dest.close();
141 is.close();
144 } catch(FileNotFoundException e) {
145 LOG("FileNotFoundException when unzipping", e);
146 e.printStackTrace();
147 } catch(IOException e) {
148 LOG("IOException when unzipping", e);
149 e.printStackTrace();
152 System.loadLibrary("rockbox");
154 Thread rb = new Thread(new Runnable()
156 public void run()
158 main();
160 },"Rockbox thread");
161 rb.setDaemon(false);
162 rb.start();
165 private native void main();
166 @Override
167 public IBinder onBind(Intent intent) {
168 // TODO Auto-generated method stub
169 return null;
173 @SuppressWarnings("unused")
175 * Sets up the battery monitor which receives the battery level
176 * about each 30 seconds
178 private void initBatteryMonitor()
180 itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
181 batt_monitor = new BroadcastReceiver()
183 @Override
184 public void onReceive(Context context, Intent intent)
186 /* we get literally spammed with battery statuses
187 * if we don't delay the re-attaching
189 TimerTask tk = new TimerTask() {
190 public void run() {
191 registerReceiver(batt_monitor, itf);
194 Timer t = new Timer();
195 context.unregisterReceiver(this);
196 int rawlevel = intent.getIntExtra("level", -1);
197 int scale = intent.getIntExtra("scale", -1);
198 if (rawlevel >= 0 && scale > 0)
199 battery_level = (rawlevel * 100) / scale;
200 else
201 battery_level = -1;
202 /* query every 30s should be sufficient */
203 t.schedule(tk, 30000);
206 registerReceiver(batt_monitor, itf);
209 /* all below is heavily based on the examples found on
210 * http://developer.android.com/reference/android/app/Service.html
213 private void create_notification()
215 /* For now we'll use the same text for the ticker and the expanded notification */
216 CharSequence text = getText(R.string.notification);
217 /* Set the icon, scrolling text and timestamp */
218 notification = new Notification(R.drawable.icon, text,
219 System.currentTimeMillis());
221 /* The PendingIntent to launch our activity if the user selects this notification */
222 Intent intent = new Intent(this, RockboxActivity.class);
223 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
225 /* Set the info for the views that show in the notification panel. */
226 notification.setLatestEventInfo(this, getText(R.string.notification), text, contentIntent);
229 public static void startForeground()
231 if (instance != null)
234 * Send the notification.
235 * We use a layout id because it is a unique number. We use it later to cancel.
237 instance.mNM.notify(R.string.notification, instance.notification);
239 * this call makes the service run as foreground, which
240 * provides enough cpu time to do music decoding in the
241 * background
243 instance.startForegroundCompat(R.string.notification, instance.notification);
247 public static void stopForeground()
249 if (instance.notification != null)
251 instance.stopForegroundCompat(R.string.notification);
252 instance.mNM.cancel(R.string.notification);
257 * This is a wrapper around the new startForeground method, using the older
258 * APIs if it is not available.
260 void startForegroundCompat(int id, Notification notification)
262 if (mStartForeground != null) {
263 mStartForegroundArgs[0] = Integer.valueOf(id);
264 mStartForegroundArgs[1] = notification;
265 try {
266 mStartForeground.invoke(this, mStartForegroundArgs);
267 } catch (InvocationTargetException e) {
268 /* Should not happen. */
269 LOG("Unable to invoke startForeground", e);
270 } catch (IllegalAccessException e) {
271 /* Should not happen. */
272 LOG("Unable to invoke startForeground", e);
274 return;
277 /* Fall back on the old API.*/
278 setForeground(true);
279 mNM.notify(id, notification);
283 * This is a wrapper around the new stopForeground method, using the older
284 * APIs if it is not available.
286 void stopForegroundCompat(int id)
288 if (mStopForeground != null) {
289 mStopForegroundArgs[0] = Boolean.TRUE;
290 try {
291 mStopForeground.invoke(this, mStopForegroundArgs);
292 } catch (InvocationTargetException e) {
293 /* Should not happen. */
294 LOG("Unable to invoke stopForeground", e);
295 } catch (IllegalAccessException e) {
296 /* Should not happen. */
297 LOG("Unable to invoke stopForeground", e);
299 return;
302 /* Fall back on the old API. Note to cancel BEFORE changing the
303 * foreground state, since we could be killed at that point. */
304 mNM.cancel(id);
305 setForeground(false);
308 @Override
309 public void onDestroy() {
310 super.onDestroy();
311 /* Make sure our notification is gone. */
312 stopForegroundCompat(R.string.notification);