diff options
author | Thomas Martitz <kugel@rockbox.org> | 2011-02-23 01:10:54 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2011-02-23 01:10:54 +0000 |
commit | 95e24dd7a54256e8df56e347c0f43133087a1df2 (patch) | |
tree | 677d66d4e72fedfe134bca103ed98b5792da1440 /android/src/org/rockbox/RockboxService.java | |
parent | da3417706d927c7da0b59351fa8cc010d63d7928 (diff) | |
download | rockbox-95e24dd7a54256e8df56e347c0f43133087a1df2.tar.gz rockbox-95e24dd7a54256e8df56e347c0f43133087a1df2.zip |
Android:
* Re-create RockboxFramebuffer instance with every time there's a new Activity.
* Also, allow Rockbox to be started via multimedia buttons, immediately starting playback if wanted.
We don't need to keep the fb instance around when it backround, and it makes us less depending on it and the activity (less race conditions). And this is how you usually do it in Android apps.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29384 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'android/src/org/rockbox/RockboxService.java')
-rw-r--r-- | android/src/org/rockbox/RockboxService.java | 113 |
1 files changed, 52 insertions, 61 deletions
diff --git a/android/src/org/rockbox/RockboxService.java b/android/src/org/rockbox/RockboxService.java index 43d122a8cc..4f0caa7704 100644 --- a/android/src/org/rockbox/RockboxService.java +++ b/android/src/org/rockbox/RockboxService.java | |||
@@ -59,8 +59,7 @@ public class RockboxService extends Service | |||
59 | private static RockboxService instance = null; | 59 | private static RockboxService instance = null; |
60 | 60 | ||
61 | /* locals needed for the c code and rockbox state */ | 61 | /* locals needed for the c code and rockbox state */ |
62 | private RockboxFramebuffer fb = null; | 62 | private static volatile boolean rockbox_running; |
63 | private volatile boolean rockbox_running; | ||
64 | private Activity current_activity = null; | 63 | private Activity current_activity = null; |
65 | private IntentFilter itf; | 64 | private IntentFilter itf; |
66 | private BroadcastReceiver batt_monitor; | 65 | private BroadcastReceiver batt_monitor; |
@@ -69,11 +68,9 @@ public class RockboxService extends Service | |||
69 | @SuppressWarnings("unused") | 68 | @SuppressWarnings("unused") |
70 | private int battery_level; | 69 | private int battery_level; |
71 | private ResultReceiver resultReceiver; | 70 | private ResultReceiver resultReceiver; |
72 | final private Object lock = new Object(); | ||
73 | 71 | ||
74 | public static final int RESULT_INVOKING_MAIN = 0; | 72 | public static final int RESULT_INVOKING_MAIN = 0; |
75 | public static final int RESULT_LIB_LOAD_PROGRESS = 1; | 73 | public static final int RESULT_LIB_LOAD_PROGRESS = 1; |
76 | public static final int RESULT_FB_INITIALIZED = 2; | ||
77 | public static final int RESULT_SERVICE_RUNNING = 3; | 74 | public static final int RESULT_SERVICE_RUNNING = 3; |
78 | public static final int RESULT_ERROR_OCCURED = 4; | 75 | public static final int RESULT_ERROR_OCCURED = 4; |
79 | public static final int RESULT_LIB_LOADED = 5; | 76 | public static final int RESULT_LIB_LOADED = 5; |
@@ -88,14 +85,15 @@ public class RockboxService extends Service | |||
88 | 85 | ||
89 | public static RockboxService get_instance() | 86 | public static RockboxService get_instance() |
90 | { | 87 | { |
88 | /* don't call the construtor here, the instances are managed by | ||
89 | * android, so we can't just create a new one */ | ||
91 | return instance; | 90 | return instance; |
92 | } | 91 | } |
93 | 92 | ||
94 | public RockboxFramebuffer get_fb() | 93 | public boolean isRockboxRunning() |
95 | { | 94 | { |
96 | return fb; | 95 | return rockbox_running; |
97 | } | 96 | } |
98 | |||
99 | public Activity get_activity() | 97 | public Activity get_activity() |
100 | { | 98 | { |
101 | return current_activity; | 99 | return current_activity; |
@@ -108,71 +106,48 @@ public class RockboxService extends Service | |||
108 | private void do_start(Intent intent) | 106 | private void do_start(Intent intent) |
109 | { | 107 | { |
110 | LOG("Start Service"); | 108 | LOG("Start Service"); |
111 | |||
112 | if (intent != null && intent.hasExtra("callback")) | 109 | if (intent != null && intent.hasExtra("callback")) |
113 | resultReceiver = (ResultReceiver) intent.getParcelableExtra("callback"); | 110 | resultReceiver = (ResultReceiver) intent.getParcelableExtra("callback"); |
114 | 111 | ||
115 | /* Display a notification about us starting. | ||
116 | * We put an icon in the status bar. */ | ||
117 | if (fg_runner == null) | ||
118 | { /* needs to be initialized before main() runs */ | ||
119 | try { | ||
120 | } catch (Exception e) { | ||
121 | e.printStackTrace(); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (!rockbox_running) | 112 | if (!rockbox_running) |
126 | { | 113 | startservice(); |
127 | synchronized(lock) | ||
128 | { | ||
129 | startservice(); | ||
130 | while(true) { | ||
131 | try { | ||
132 | lock.wait(); | ||
133 | } catch (InterruptedException e) { | ||
134 | continue; | ||
135 | } | ||
136 | break; | ||
137 | } | ||
138 | fb = new RockboxFramebuffer(this); | ||
139 | if (resultReceiver != null) | ||
140 | resultReceiver.send(RESULT_FB_INITIALIZED, null); | ||
141 | } | ||
142 | } | ||
143 | if (resultReceiver != null) | 114 | if (resultReceiver != null) |
144 | resultReceiver.send(RESULT_LIB_LOADED, null); | 115 | resultReceiver.send(RESULT_LIB_LOADED, null); |
145 | 116 | ||
117 | |||
146 | if (intent != null && intent.getAction() != null) | 118 | if (intent != null && intent.getAction() != null) |
147 | { | 119 | { |
148 | Log.d("RockboxService", intent.getAction()); | 120 | if (!rockbox_running) |
149 | if (intent.getAction().equals("org.rockbox.PlayPause")) | 121 | { /* give it a bit of time so we can register button presses |
150 | { | 122 | * sleeping longer doesn't work here, apparently Android |
151 | if (fb != null) | 123 | * surpresses long sleeps during intent handling */ |
152 | fb.onKeyUp(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, null); | 124 | try { |
125 | Thread.sleep(50); | ||
126 | } | ||
127 | catch (InterruptedException e) { } | ||
153 | } | 128 | } |
154 | else if (intent.getAction().equals("org.rockbox.Prev")) | 129 | |
130 | if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) | ||
155 | { | 131 | { |
156 | if (fb != null) | 132 | KeyEvent kev = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); |
157 | fb.onKeyUp(KeyEvent.KEYCODE_MEDIA_PREVIOUS, null); | 133 | RockboxFramebuffer.buttonHandler(kev.getKeyCode(), kev.getAction() == KeyEvent.ACTION_DOWN); |
158 | } | 134 | } |
135 | else if (intent.getAction().equals("org.rockbox.PlayPause")) | ||
136 | RockboxFramebuffer.buttonHandler(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, false); | ||
137 | else if (intent.getAction().equals("org.rockbox.Prev")) | ||
138 | RockboxFramebuffer.buttonHandler(KeyEvent.KEYCODE_MEDIA_PREVIOUS, false); | ||
159 | else if (intent.getAction().equals("org.rockbox.Next")) | 139 | else if (intent.getAction().equals("org.rockbox.Next")) |
160 | { | 140 | RockboxFramebuffer.buttonHandler(KeyEvent.KEYCODE_MEDIA_NEXT, false); |
161 | if (fb != null) | ||
162 | fb.onKeyUp(KeyEvent.KEYCODE_MEDIA_NEXT, null); | ||
163 | } | ||
164 | else if (intent.getAction().equals("org.rockbox.Stop")) | 141 | else if (intent.getAction().equals("org.rockbox.Stop")) |
165 | { | 142 | RockboxFramebuffer.buttonHandler(KeyEvent.KEYCODE_MEDIA_STOP, false); |
166 | if (fb != null) | ||
167 | fb.onKeyUp(KeyEvent.KEYCODE_MEDIA_STOP, null); | ||
168 | } | ||
169 | } | 143 | } |
170 | 144 | ||
171 | /* (Re-)attach the media button receiver, in case it has been lost */ | 145 | /* (Re-)attach the media button receiver, in case it has been lost */ |
172 | mMediaButtonReceiver.register(); | 146 | mMediaButtonReceiver.register(); |
173 | |||
174 | if (resultReceiver != null) | 147 | if (resultReceiver != null) |
175 | resultReceiver.send(RESULT_SERVICE_RUNNING, null); | 148 | resultReceiver.send(RESULT_SERVICE_RUNNING, null); |
149 | |||
150 | rockbox_running = true; | ||
176 | } | 151 | } |
177 | 152 | ||
178 | private void LOG(CharSequence text) | 153 | private void LOG(CharSequence text) |
@@ -195,16 +170,23 @@ public class RockboxService extends Service | |||
195 | return 1; /* old API compatibility: 1 == START_STICKY */ | 170 | return 1; /* old API compatibility: 1 == START_STICKY */ |
196 | } | 171 | } |
197 | 172 | ||
198 | private void startservice() | 173 | private void startservice() |
199 | { | 174 | { |
200 | final int BUFFER = 8*1024; | 175 | final Object lock = new Object(); |
201 | Thread rb = new Thread(new Runnable() | 176 | Thread rb = new Thread(new Runnable() |
202 | { | 177 | { |
203 | public void run() | 178 | public void run() |
204 | { | 179 | { |
180 | final int BUFFER = 8*1024; | ||
205 | String rockboxDirPath = "/data/data/org.rockbox/app_rockbox/rockbox"; | 181 | String rockboxDirPath = "/data/data/org.rockbox/app_rockbox/rockbox"; |
206 | File rockboxDir = new File(rockboxDirPath); | 182 | File rockboxDir = new File(rockboxDirPath); |
207 | 183 | ||
184 | /* load library before unzipping which may take a while */ | ||
185 | synchronized (lock) { | ||
186 | System.loadLibrary("rockbox"); | ||
187 | lock.notify(); | ||
188 | } | ||
189 | |||
208 | /* the following block unzips libmisc.so, which contains the files | 190 | /* the following block unzips libmisc.so, which contains the files |
209 | * we ship, such as themes. It's needed to put it into a .so file | 191 | * we ship, such as themes. It's needed to put it into a .so file |
210 | * because there's no other way to ship files and have access | 192 | * because there's no other way to ship files and have access |
@@ -268,13 +250,7 @@ public class RockboxService extends Service | |||
268 | } | 250 | } |
269 | } | 251 | } |
270 | } | 252 | } |
271 | |||
272 | synchronized (lock) { | ||
273 | System.loadLibrary("rockbox"); | ||
274 | lock.notify(); | ||
275 | } | ||
276 | 253 | ||
277 | rockbox_running = true; | ||
278 | if (resultReceiver != null) | 254 | if (resultReceiver != null) |
279 | resultReceiver.send(RESULT_INVOKING_MAIN, null); | 255 | resultReceiver.send(RESULT_INVOKING_MAIN, null); |
280 | 256 | ||
@@ -283,7 +259,20 @@ public class RockboxService extends Service | |||
283 | } | 259 | } |
284 | }, "Rockbox thread"); | 260 | }, "Rockbox thread"); |
285 | rb.setDaemon(false); | 261 | rb.setDaemon(false); |
286 | rb.start(); | 262 | /* wait at least until the library is loaded */ |
263 | synchronized (lock) | ||
264 | { | ||
265 | rb.start(); | ||
266 | while(true) | ||
267 | { | ||
268 | try { | ||
269 | lock.wait(); | ||
270 | } catch (InterruptedException e) { | ||
271 | continue; | ||
272 | } | ||
273 | break; | ||
274 | } | ||
275 | } | ||
287 | } | 276 | } |
288 | 277 | ||
289 | private native void main(); | 278 | private native void main(); |
@@ -352,5 +341,7 @@ public class RockboxService extends Service | |||
352 | mMediaButtonReceiver = null; | 341 | mMediaButtonReceiver = null; |
353 | /* Make sure our notification is gone. */ | 342 | /* Make sure our notification is gone. */ |
354 | stopForeground(); | 343 | stopForeground(); |
344 | instance = null; | ||
345 | rockbox_running = false; | ||
355 | } | 346 | } |
356 | } | 347 | } |