diff options
-rw-r--r-- | android/src/org/rockbox/RockboxActivity.java | 45 | ||||
-rw-r--r-- | android/src/org/rockbox/RockboxFramebuffer.java | 101 | ||||
-rw-r--r-- | android/src/org/rockbox/RockboxService.java | 45 | ||||
-rw-r--r-- | apps/keymaps/keymap-android.c | 3 | ||||
-rw-r--r-- | firmware/target/hosted/android/app/button-target.h | 2 | ||||
-rw-r--r-- | firmware/target/hosted/android/lcd-android.c | 140 |
6 files changed, 158 insertions, 178 deletions
diff --git a/android/src/org/rockbox/RockboxActivity.java b/android/src/org/rockbox/RockboxActivity.java index 76535687f9..f3f0d2151c 100644 --- a/android/src/org/rockbox/RockboxActivity.java +++ b/android/src/org/rockbox/RockboxActivity.java | |||
@@ -66,10 +66,9 @@ public class RockboxActivity extends Activity | |||
66 | protected void onReceiveResult(final int resultCode, final Bundle resultData) | 66 | protected void onReceiveResult(final int resultCode, final Bundle resultData) |
67 | { | 67 | { |
68 | switch (resultCode) { | 68 | switch (resultCode) { |
69 | case RockboxService.RESULT_LIB_LOADED: | 69 | case RockboxService.RESULT_INVOKING_MAIN: |
70 | rbservice = RockboxService.get_instance(); | ||
71 | if (loadingdialog != null) | 70 | if (loadingdialog != null) |
72 | loadingdialog.setIndeterminate(true); | 71 | loadingdialog.dismiss(); |
73 | break; | 72 | break; |
74 | case RockboxService.RESULT_LIB_LOAD_PROGRESS: | 73 | case RockboxService.RESULT_LIB_LOAD_PROGRESS: |
75 | if (loadingdialog == null) | 74 | if (loadingdialog == null) |
@@ -79,10 +78,10 @@ public class RockboxActivity extends Activity | |||
79 | loadingdialog.setMax(resultData.getInt("max", 100)); | 78 | loadingdialog.setMax(resultData.getInt("max", 100)); |
80 | loadingdialog.setProgress(resultData.getInt("value", 0)); | 79 | loadingdialog.setProgress(resultData.getInt("value", 0)); |
81 | break; | 80 | break; |
82 | case RockboxService.RESULT_FB_INITIALIZED: | 81 | case RockboxService.RESULT_SERVICE_RUNNING: |
82 | rbservice = RockboxService.get_instance(); | ||
83 | setServiceActivity(true); | ||
83 | attachFramebuffer(); | 84 | attachFramebuffer(); |
84 | if (loadingdialog != null) | ||
85 | loadingdialog.dismiss(); | ||
86 | break; | 85 | break; |
87 | case RockboxService.RESULT_ERROR_OCCURED: | 86 | case RockboxService.RESULT_ERROR_OCCURED: |
88 | Toast.makeText(RockboxActivity.this, resultData.getString("error"), Toast.LENGTH_LONG); | 87 | Toast.makeText(RockboxActivity.this, resultData.getString("error"), Toast.LENGTH_LONG); |
@@ -93,17 +92,17 @@ public class RockboxActivity extends Activity | |||
93 | startService(intent); | 92 | startService(intent); |
94 | } | 93 | } |
95 | 94 | ||
96 | private boolean isRockboxRunning() | 95 | private void setServiceActivity(boolean set) |
97 | { | 96 | { |
98 | if (rbservice == null) | 97 | if (rbservice != null) |
99 | rbservice = RockboxService.get_instance(); | 98 | rbservice.set_activity(this); |
100 | return (rbservice!= null && rbservice.isRockboxRunning() == true); | ||
101 | } | 99 | } |
102 | 100 | ||
103 | private void attachFramebuffer() | 101 | private void attachFramebuffer() |
104 | { | 102 | { |
105 | View rbFramebuffer = rbservice.get_fb(); | 103 | View rbFramebuffer = null; |
106 | try { | 104 | try { |
105 | rbFramebuffer = rbservice.get_fb(); | ||
107 | setContentView(rbFramebuffer); | 106 | setContentView(rbFramebuffer); |
108 | } catch (IllegalStateException e) { | 107 | } catch (IllegalStateException e) { |
109 | /* we are already using the View, | 108 | /* we are already using the View, |
@@ -111,17 +110,17 @@ public class RockboxActivity extends Activity | |||
111 | ViewGroup g = (ViewGroup) rbFramebuffer.getParent(); | 110 | ViewGroup g = (ViewGroup) rbFramebuffer.getParent(); |
112 | g.removeView(rbFramebuffer); | 111 | g.removeView(rbFramebuffer); |
113 | setContentView(rbFramebuffer); | 112 | setContentView(rbFramebuffer); |
114 | } finally { | 113 | } catch (NullPointerException e) { |
115 | rbFramebuffer.requestFocus(); | 114 | return; |
116 | rbservice.set_activity(this); | ||
117 | } | 115 | } |
116 | rbFramebuffer.requestFocus(); | ||
118 | } | 117 | } |
119 | 118 | ||
120 | public void onResume() | 119 | public void onResume() |
121 | { | 120 | { |
122 | super.onResume(); | 121 | super.onResume(); |
123 | if (isRockboxRunning()) | 122 | setVisible(true); |
124 | attachFramebuffer(); | 123 | attachFramebuffer(); |
125 | } | 124 | } |
126 | 125 | ||
127 | /* this is also called when the backlight goes off, | 126 | /* this is also called when the backlight goes off, |
@@ -131,27 +130,23 @@ public class RockboxActivity extends Activity | |||
131 | protected void onPause() | 130 | protected void onPause() |
132 | { | 131 | { |
133 | super.onPause(); | 132 | super.onPause(); |
134 | if (rbservice != null) | 133 | /* this will cause the framebuffer's Surface to be destroyed, enabling |
135 | { | 134 | * us to disable drawing */ |
136 | rbservice.set_activity(null); | 135 | setVisible(false); |
137 | rbservice.get_fb().dispatchWindowVisibilityChanged(View.INVISIBLE); | ||
138 | } | ||
139 | } | 136 | } |
140 | 137 | ||
141 | @Override | 138 | @Override |
142 | protected void onStop() | 139 | protected void onStop() |
143 | { | 140 | { |
144 | super.onStop(); | 141 | super.onStop(); |
145 | if (rbservice != null) | 142 | setServiceActivity(false); |
146 | rbservice.set_activity(null); | ||
147 | } | 143 | } |
148 | 144 | ||
149 | @Override | 145 | @Override |
150 | protected void onDestroy() | 146 | protected void onDestroy() |
151 | { | 147 | { |
152 | super.onDestroy(); | 148 | super.onDestroy(); |
153 | if (rbservice != null) | 149 | setServiceActivity(false); |
154 | rbservice.set_activity(null); | ||
155 | } | 150 | } |
156 | 151 | ||
157 | private void LOG(CharSequence text) | 152 | private void LOG(CharSequence text) |
diff --git a/android/src/org/rockbox/RockboxFramebuffer.java b/android/src/org/rockbox/RockboxFramebuffer.java index 05d2b11184..037fd2db85 100644 --- a/android/src/org/rockbox/RockboxFramebuffer.java +++ b/android/src/org/rockbox/RockboxFramebuffer.java | |||
@@ -23,8 +23,6 @@ package org.rockbox; | |||
23 | 23 | ||
24 | import java.nio.ByteBuffer; | 24 | import java.nio.ByteBuffer; |
25 | 25 | ||
26 | import org.rockbox.Helper.MediaButtonReceiver; | ||
27 | |||
28 | import android.content.Context; | 26 | import android.content.Context; |
29 | import android.graphics.Bitmap; | 27 | import android.graphics.Bitmap; |
30 | import android.graphics.Canvas; | 28 | import android.graphics.Canvas; |
@@ -33,45 +31,72 @@ import android.util.DisplayMetrics; | |||
33 | import android.util.Log; | 31 | import android.util.Log; |
34 | import android.view.KeyEvent; | 32 | import android.view.KeyEvent; |
35 | import android.view.MotionEvent; | 33 | import android.view.MotionEvent; |
36 | import android.view.View; | 34 | import android.view.SurfaceHolder; |
35 | import android.view.SurfaceView; | ||
37 | import android.view.ViewConfiguration; | 36 | import android.view.ViewConfiguration; |
38 | 37 | ||
39 | public class RockboxFramebuffer extends View | 38 | public class RockboxFramebuffer extends SurfaceView |
39 | implements SurfaceHolder.Callback | ||
40 | { | 40 | { |
41 | private Bitmap btm; | ||
42 | private Rect rect; | ||
43 | private ByteBuffer native_buf; | ||
44 | private MediaButtonReceiver media_monitor; | ||
45 | private final DisplayMetrics metrics; | 41 | private final DisplayMetrics metrics; |
46 | private final ViewConfiguration view_config; | 42 | private final ViewConfiguration view_config; |
43 | private ByteBuffer native_buf; | ||
44 | private Bitmap btm; | ||
47 | 45 | ||
48 | public RockboxFramebuffer(Context c, int lcd_width, | 46 | /* first stage init; needs to run from a thread that has a Looper |
49 | int lcd_height, ByteBuffer native_fb) | 47 | * setup stuff that needs a Context */ |
48 | public RockboxFramebuffer(Context c) | ||
50 | { | 49 | { |
51 | super(c); | 50 | super(c); |
51 | |||
52 | metrics = c.getResources().getDisplayMetrics(); | ||
53 | view_config = ViewConfiguration.get(c); | ||
54 | getHolder().addCallback(this); | ||
52 | /* Needed so we can catch KeyEvents */ | 55 | /* Needed so we can catch KeyEvents */ |
53 | setFocusable(true); | 56 | setFocusable(true); |
54 | setFocusableInTouchMode(true); | 57 | setFocusableInTouchMode(true); |
55 | setClickable(true); | 58 | setClickable(true); |
59 | /* don't draw until native is ready (2nd stage) */ | ||
60 | setEnabled(false); | ||
61 | } | ||
62 | |||
63 | /* second stage init; called from Rockbox with information about the | ||
64 | * display framebuffer */ | ||
65 | @SuppressWarnings("unused") | ||
66 | private void java_lcd_init(int lcd_width, int lcd_height, ByteBuffer native_fb) | ||
67 | { | ||
56 | btm = Bitmap.createBitmap(lcd_width, lcd_height, Bitmap.Config.RGB_565); | 68 | btm = Bitmap.createBitmap(lcd_width, lcd_height, Bitmap.Config.RGB_565); |
57 | rect = new Rect(); | ||
58 | native_buf = native_fb; | 69 | native_buf = native_fb; |
59 | media_monitor = new MediaButtonReceiver(c); | 70 | setEnabled(true); |
60 | media_monitor.register(); | ||
61 | /* the service needs to know the about us */ | ||
62 | ((RockboxService)c).set_fb(this); | ||
63 | |||
64 | metrics = c.getResources().getDisplayMetrics(); | ||
65 | view_config = ViewConfiguration.get(c); | ||
66 | } | 71 | } |
67 | 72 | ||
68 | public void onDraw(Canvas c) | 73 | @SuppressWarnings("unused") |
74 | private void java_lcd_update() | ||
75 | { | ||
76 | SurfaceHolder holder = getHolder(); | ||
77 | Canvas c = holder.lockCanvas(null); | ||
78 | btm.copyPixelsFromBuffer(native_buf); | ||
79 | synchronized (holder) | ||
80 | { /* draw */ | ||
81 | c.drawBitmap(btm, 0.0f, 0.0f, null); | ||
82 | } | ||
83 | holder.unlockCanvasAndPost(c); | ||
84 | } | ||
85 | |||
86 | @SuppressWarnings("unused") | ||
87 | private void java_lcd_update_rect(int x, int y, int width, int height) | ||
69 | { | 88 | { |
70 | /* can't copy a partial buffer :( */ | 89 | SurfaceHolder holder = getHolder(); |
90 | Rect dirty = new Rect(x, y, x+width, y+height); | ||
91 | Canvas c = holder.lockCanvas(dirty); | ||
92 | /* can't copy a partial buffer, | ||
93 | * but it doesn't make a noticeable difference anyway */ | ||
71 | btm.copyPixelsFromBuffer(native_buf); | 94 | btm.copyPixelsFromBuffer(native_buf); |
72 | c.getClipBounds(rect); | 95 | synchronized (holder) |
73 | c.drawBitmap(btm, rect, rect, null); | 96 | { /* draw */ |
74 | post_update_done(); | 97 | c.drawBitmap(btm, dirty, dirty, null); |
98 | } | ||
99 | holder.unlockCanvasAndPost(c); | ||
75 | } | 100 | } |
76 | 101 | ||
77 | @SuppressWarnings("unused") | 102 | @SuppressWarnings("unused") |
@@ -109,28 +134,6 @@ public class RockboxFramebuffer extends View | |||
109 | { | 134 | { |
110 | return buttonHandler(keyCode, false); | 135 | return buttonHandler(keyCode, false); |
111 | } | 136 | } |
112 | |||
113 | public void destroy() | ||
114 | { | ||
115 | set_lcd_active(0); | ||
116 | media_monitor.unregister(); | ||
117 | } | ||
118 | |||
119 | @Override | ||
120 | protected void onWindowVisibilityChanged(int visibility) | ||
121 | { | ||
122 | super.onWindowVisibilityChanged(visibility); | ||
123 | |||
124 | switch (visibility) { | ||
125 | case VISIBLE: | ||
126 | set_lcd_active(1); | ||
127 | break; | ||
128 | case GONE: | ||
129 | case INVISIBLE: | ||
130 | set_lcd_active(0); | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | 137 | ||
135 | @SuppressWarnings("unused") | 138 | @SuppressWarnings("unused") |
136 | private int getDpi() | 139 | private int getDpi() |
@@ -144,8 +147,12 @@ public class RockboxFramebuffer extends View | |||
144 | return view_config.getScaledTouchSlop(); | 147 | return view_config.getScaledTouchSlop(); |
145 | } | 148 | } |
146 | 149 | ||
147 | private native void post_update_done(); | ||
148 | private native void set_lcd_active(int active); | ||
149 | private native void touchHandler(boolean down, int x, int y); | 150 | private native void touchHandler(boolean down, int x, int y); |
150 | private native static boolean buttonHandler(int keycode, boolean state); | 151 | private native static boolean buttonHandler(int keycode, boolean state); |
152 | |||
153 | public native void surfaceCreated(SurfaceHolder holder); | ||
154 | public native void surfaceDestroyed(SurfaceHolder holder); | ||
155 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) | ||
156 | { | ||
157 | } | ||
151 | } | 158 | } |
diff --git a/android/src/org/rockbox/RockboxService.java b/android/src/org/rockbox/RockboxService.java index de90999783..4f5df62280 100644 --- a/android/src/org/rockbox/RockboxService.java +++ b/android/src/org/rockbox/RockboxService.java | |||
@@ -31,6 +31,7 @@ import java.util.TimerTask; | |||
31 | import java.util.zip.ZipEntry; | 31 | import java.util.zip.ZipEntry; |
32 | import java.util.zip.ZipFile; | 32 | import java.util.zip.ZipFile; |
33 | 33 | ||
34 | import org.rockbox.Helper.MediaButtonReceiver; | ||
34 | import org.rockbox.Helper.RunForegroundManager; | 35 | import org.rockbox.Helper.RunForegroundManager; |
35 | 36 | ||
36 | import android.app.Activity; | 37 | import android.app.Activity; |
@@ -59,20 +60,21 @@ public class RockboxService extends Service | |||
59 | 60 | ||
60 | /* locals needed for the c code and rockbox state */ | 61 | /* locals needed for the c code and rockbox state */ |
61 | private RockboxFramebuffer fb = null; | 62 | private RockboxFramebuffer fb = null; |
62 | private boolean mRockboxRunning = false; | 63 | private volatile boolean rockbox_running; |
63 | private volatile boolean rbLibLoaded; | ||
64 | private Activity current_activity = null; | 64 | private Activity current_activity = null; |
65 | private IntentFilter itf; | 65 | private IntentFilter itf; |
66 | private BroadcastReceiver batt_monitor; | 66 | private BroadcastReceiver batt_monitor; |
67 | private RunForegroundManager fg_runner; | 67 | private RunForegroundManager fg_runner; |
68 | private MediaButtonReceiver mMediaButtonReceiver; | ||
68 | @SuppressWarnings("unused") | 69 | @SuppressWarnings("unused") |
69 | private int battery_level; | 70 | private int battery_level; |
70 | private ResultReceiver resultReceiver; | 71 | private ResultReceiver resultReceiver; |
71 | 72 | ||
72 | public static final int RESULT_LIB_LOADED = 0; | 73 | public static final int RESULT_INVOKING_MAIN = 0; |
73 | public static final int RESULT_LIB_LOAD_PROGRESS = 1; | 74 | public static final int RESULT_LIB_LOAD_PROGRESS = 1; |
74 | public static final int RESULT_FB_INITIALIZED = 2; | 75 | public static final int RESULT_FB_INITIALIZED = 2; |
75 | public static final int RESULT_ERROR_OCCURED = 3; | 76 | public static final int RESULT_SERVICE_RUNNING = 3; |
77 | public static final int RESULT_ERROR_OCCURED = 4; | ||
76 | 78 | ||
77 | @Override | 79 | @Override |
78 | public void onCreate() | 80 | public void onCreate() |
@@ -89,14 +91,6 @@ public class RockboxService extends Service | |||
89 | { | 91 | { |
90 | return fb; | 92 | return fb; |
91 | } | 93 | } |
92 | /* framebuffer is initialised by the native code(!) so this is needed */ | ||
93 | public void set_fb(RockboxFramebuffer newfb) | ||
94 | { | ||
95 | fb = newfb; | ||
96 | mRockboxRunning = true; | ||
97 | if (resultReceiver != null) | ||
98 | resultReceiver.send(RESULT_FB_INITIALIZED, null); | ||
99 | } | ||
100 | 94 | ||
101 | public Activity get_activity() | 95 | public Activity get_activity() |
102 | { | 96 | { |
@@ -113,7 +107,7 @@ public class RockboxService extends Service | |||
113 | 107 | ||
114 | if (intent != null && intent.hasExtra("callback")) | 108 | if (intent != null && intent.hasExtra("callback")) |
115 | resultReceiver = (ResultReceiver) intent.getParcelableExtra("callback"); | 109 | resultReceiver = (ResultReceiver) intent.getParcelableExtra("callback"); |
116 | if (!rbLibLoaded) | 110 | if (!rockbox_running) |
117 | startservice(); | 111 | startservice(); |
118 | 112 | ||
119 | if (intent != null && intent.getAction() != null) | 113 | if (intent != null && intent.getAction() != null) |
@@ -151,6 +145,8 @@ public class RockboxService extends Service | |||
151 | e.printStackTrace(); | 145 | e.printStackTrace(); |
152 | } | 146 | } |
153 | } | 147 | } |
148 | if (resultReceiver != null) | ||
149 | resultReceiver.send(RESULT_SERVICE_RUNNING, null); | ||
154 | } | 150 | } |
155 | 151 | ||
156 | private void LOG(CharSequence text) | 152 | private void LOG(CharSequence text) |
@@ -176,6 +172,11 @@ public class RockboxService extends Service | |||
176 | private void startservice() | 172 | private void startservice() |
177 | { | 173 | { |
178 | final int BUFFER = 8*1024; | 174 | final int BUFFER = 8*1024; |
175 | fb = new RockboxFramebuffer(this); | ||
176 | if (resultReceiver != null) | ||
177 | resultReceiver.send(RESULT_FB_INITIALIZED, null); | ||
178 | mMediaButtonReceiver = new MediaButtonReceiver(this); | ||
179 | mMediaButtonReceiver.register(); | ||
179 | Thread rb = new Thread(new Runnable() | 180 | Thread rb = new Thread(new Runnable() |
180 | { | 181 | { |
181 | public void run() | 182 | public void run() |
@@ -247,10 +248,11 @@ public class RockboxService extends Service | |||
247 | } | 248 | } |
248 | } | 249 | } |
249 | 250 | ||
250 | System.loadLibrary("rockbox"); | 251 | System.loadLibrary("rockbox"); |
251 | rbLibLoaded = true; | 252 | |
253 | rockbox_running = true; | ||
252 | if (resultReceiver != null) | 254 | if (resultReceiver != null) |
253 | resultReceiver.send(RESULT_LIB_LOADED, null); | 255 | resultReceiver.send(RESULT_INVOKING_MAIN, null); |
254 | 256 | ||
255 | main(); | 257 | main(); |
256 | throw new IllegalStateException("native main() returned!"); | 258 | throw new IllegalStateException("native main() returned!"); |
@@ -259,15 +261,8 @@ public class RockboxService extends Service | |||
259 | rb.setDaemon(false); | 261 | rb.setDaemon(false); |
260 | rb.start(); | 262 | rb.start(); |
261 | } | 263 | } |
264 | |||
262 | private native void main(); | 265 | private native void main(); |
263 | |||
264 | /* returns true once rockbox is up and running. | ||
265 | * This is considered done once the framebuffer is initialised | ||
266 | */ | ||
267 | public boolean isRockboxRunning() | ||
268 | { | ||
269 | return mRockboxRunning; | ||
270 | } | ||
271 | 266 | ||
272 | @Override | 267 | @Override |
273 | public IBinder onBind(Intent intent) | 268 | public IBinder onBind(Intent intent) |
@@ -329,7 +324,7 @@ public class RockboxService extends Service | |||
329 | public void onDestroy() | 324 | public void onDestroy() |
330 | { | 325 | { |
331 | super.onDestroy(); | 326 | super.onDestroy(); |
332 | fb.destroy(); | 327 | mMediaButtonReceiver.unregister(); |
333 | /* Make sure our notification is gone. */ | 328 | /* Make sure our notification is gone. */ |
334 | stopForeground(); | 329 | stopForeground(); |
335 | } | 330 | } |
diff --git a/apps/keymaps/keymap-android.c b/apps/keymaps/keymap-android.c index df187e7ac8..c822a64fc2 100644 --- a/apps/keymaps/keymap-android.c +++ b/apps/keymaps/keymap-android.c | |||
@@ -50,6 +50,9 @@ static const struct button_mapping button_context_standard[] = { | |||
50 | { ACTION_STD_MENU, BUTTON_MENU|BUTTON_REL, BUTTON_MENU }, | 50 | { ACTION_STD_MENU, BUTTON_MENU|BUTTON_REL, BUTTON_MENU }, |
51 | { ACTION_STD_CONTEXT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU }, | 51 | { ACTION_STD_CONTEXT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU }, |
52 | 52 | ||
53 | /* special hack to get a redraw on activity resume, see lcd-android.c */ | ||
54 | { ACTION_REDRAW, BUTTON_FORCE_REDRAW, BUTTON_NONE }, | ||
55 | |||
53 | LAST_ITEM_IN_LIST | 56 | LAST_ITEM_IN_LIST |
54 | }; /* button_context_standard */ | 57 | }; /* button_context_standard */ |
55 | 58 | ||
diff --git a/firmware/target/hosted/android/app/button-target.h b/firmware/target/hosted/android/app/button-target.h index 6106b612f9..3b6028739c 100644 --- a/firmware/target/hosted/android/app/button-target.h +++ b/firmware/target/hosted/android/app/button-target.h | |||
@@ -58,6 +58,8 @@ void android_ignore_back_button(bool yes); | |||
58 | #define BUTTON_BOTTOMMIDDLE 0x00080000 | 58 | #define BUTTON_BOTTOMMIDDLE 0x00080000 |
59 | #define BUTTON_BOTTOMRIGHT 0x00100000 | 59 | #define BUTTON_BOTTOMRIGHT 0x00100000 |
60 | 60 | ||
61 | #define BUTTON_FORCE_REDRAW 0x00200000 | ||
62 | |||
61 | /* No remote */ | 63 | /* No remote */ |
62 | #define BUTTON_REMOTE 0 | 64 | #define BUTTON_REMOTE 0 |
63 | 65 | ||
diff --git a/firmware/target/hosted/android/lcd-android.c b/firmware/target/hosted/android/lcd-android.c index 92e8f5b96f..f719329819 100644 --- a/firmware/target/hosted/android/lcd-android.c +++ b/firmware/target/hosted/android/lcd-android.c | |||
@@ -21,10 +21,12 @@ | |||
21 | 21 | ||
22 | 22 | ||
23 | #include <jni.h> | 23 | #include <jni.h> |
24 | #include <string.h> | ||
24 | #include "config.h" | 25 | #include "config.h" |
25 | #include "system.h" | 26 | #include "system.h" |
26 | #include "kernel.h" | 27 | #include "kernel.h" |
27 | #include "lcd.h" | 28 | #include "lcd.h" |
29 | #include "button.h" | ||
28 | 30 | ||
29 | extern JNIEnv *env_ptr; | 31 | extern JNIEnv *env_ptr; |
30 | extern jclass RockboxService_class; | 32 | extern jclass RockboxService_class; |
@@ -32,57 +34,48 @@ extern jobject RockboxService_instance; | |||
32 | 34 | ||
33 | static jclass RockboxFramebuffer_class; | 35 | static jclass RockboxFramebuffer_class; |
34 | static jobject RockboxFramebuffer_instance; | 36 | static jobject RockboxFramebuffer_instance; |
35 | static jmethodID postInvalidate1; | 37 | static jmethodID java_lcd_update; |
36 | static jmethodID postInvalidate2; | 38 | static jmethodID java_lcd_update_rect; |
37 | 39 | ||
38 | static bool display_on; | ||
39 | static int dpi; | 40 | static int dpi; |
40 | static int scroll_threshold; | 41 | static int scroll_threshold; |
41 | static struct wakeup lcd_wakeup; | 42 | static bool display_on; |
42 | static struct mutex lcd_mtx; | ||
43 | 43 | ||
44 | void lcd_init_device(void) | 44 | void lcd_init_device(void) |
45 | { | 45 | { |
46 | JNIEnv e = *env_ptr; | 46 | JNIEnv e = *env_ptr; |
47 | wakeup_init(&lcd_wakeup); | 47 | /* get existing instance from the Service */ |
48 | mutex_init(&lcd_mtx); | 48 | jmethodID get_fb = e->GetMethodID(env_ptr, RockboxService_class, "get_fb", |
49 | RockboxFramebuffer_class = e->FindClass(env_ptr, | 49 | "()Lorg/rockbox/RockboxFramebuffer;"); |
50 | "org/rockbox/RockboxFramebuffer"); | 50 | RockboxFramebuffer_instance = e->CallObjectMethod(env_ptr, |
51 | /* instantiate a RockboxFramebuffer instance | 51 | RockboxService_instance, |
52 | * | 52 | get_fb); |
53 | * Pass lcd width and height and our framebuffer so the java layer | 53 | RockboxFramebuffer_class = (*env_ptr)->GetObjectClass(env_ptr, |
54 | * can create a Bitmap which directly maps to it | 54 | RockboxFramebuffer_instance); |
55 | **/ | 55 | |
56 | 56 | /* Get init function and set up what's left from the constructor */ | |
57 | /* map the framebuffer to a ByteBuffer, this way lcd updates will | 57 | jmethodID java_lcd_init = (*env_ptr)->GetMethodID(env_ptr, |
58 | * be directly feched from the framebuffer */ | 58 | RockboxFramebuffer_class, |
59 | "java_lcd_init", | ||
60 | "(IILjava/nio/ByteBuffer;)V"); | ||
61 | |||
59 | jobject buf = e->NewDirectByteBuffer(env_ptr, | 62 | jobject buf = e->NewDirectByteBuffer(env_ptr, |
60 | lcd_framebuffer, | 63 | lcd_framebuffer, |
61 | (jlong)sizeof(lcd_framebuffer)); | 64 | (jlong)sizeof(lcd_framebuffer)); |
62 | 65 | ||
63 | jmethodID constructor = e->GetMethodID(env_ptr, | 66 | e->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, java_lcd_init, |
64 | RockboxFramebuffer_class, | ||
65 | "<init>", | ||
66 | "(Landroid/content/Context;" /* Service */ | ||
67 | "II" /* lcd width/height */ | ||
68 | "Ljava/nio/ByteBuffer;)V"); /* ByteBuffer */ | ||
69 | |||
70 | RockboxFramebuffer_instance = e->NewObject(env_ptr, | ||
71 | RockboxFramebuffer_class, | ||
72 | constructor, | ||
73 | RockboxService_instance, | ||
74 | (jint)LCD_WIDTH, | 67 | (jint)LCD_WIDTH, |
75 | (jint)LCD_HEIGHT, | 68 | (jint)LCD_HEIGHT, |
76 | buf); | 69 | buf); |
77 | 70 | ||
78 | /* cache update functions */ | 71 | /* cache update functions */ |
79 | postInvalidate1 = (*env_ptr)->GetMethodID(env_ptr, | 72 | java_lcd_update = (*env_ptr)->GetMethodID(env_ptr, |
80 | RockboxFramebuffer_class, | 73 | RockboxFramebuffer_class, |
81 | "postInvalidate", | 74 | "java_lcd_update", |
82 | "()V"); | 75 | "()V"); |
83 | postInvalidate2 = (*env_ptr)->GetMethodID(env_ptr, | 76 | java_lcd_update_rect = (*env_ptr)->GetMethodID(env_ptr, |
84 | RockboxFramebuffer_class, | 77 | RockboxFramebuffer_class, |
85 | "postInvalidate", | 78 | "java_lcd_update_rect", |
86 | "(IIII)V"); | 79 | "(IIII)V"); |
87 | 80 | ||
88 | jmethodID get_dpi = e->GetMethodID(env_ptr, | 81 | jmethodID get_dpi = e->GetMethodID(env_ptr, |
@@ -98,49 +91,54 @@ void lcd_init_device(void) | |||
98 | get_dpi); | 91 | get_dpi); |
99 | scroll_threshold = e->CallIntMethod(env_ptr, RockboxFramebuffer_instance, | 92 | scroll_threshold = e->CallIntMethod(env_ptr, RockboxFramebuffer_instance, |
100 | get_scroll_threshold); | 93 | get_scroll_threshold); |
101 | display_on = true; | 94 | /* must not draw until surface is created */ |
95 | display_on = false; | ||
102 | } | 96 | } |
103 | 97 | ||
104 | /* the update mechanism is asynchronous since | ||
105 | * onDraw() must be called from the UI thread | ||
106 | * | ||
107 | * The Rockbox thread calling lcd_update() has to wait | ||
108 | * for the update to complete, so that it's synchronous, | ||
109 | * and we need to notify it (we could wait in the java layer, but | ||
110 | * that'd block the other Rockbox threads too) | ||
111 | * | ||
112 | * That should give more smoonth animations | ||
113 | */ | ||
114 | void lcd_update(void) | 98 | void lcd_update(void) |
115 | { | 99 | { |
116 | /* tell the system we're ready for drawing */ | ||
117 | if (display_on) | 100 | if (display_on) |
118 | { | 101 | (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, |
119 | mutex_lock(&lcd_mtx); | 102 | java_lcd_update); |
120 | (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate1); | ||
121 | wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK); | ||
122 | mutex_unlock(&lcd_mtx); | ||
123 | } | ||
124 | } | 103 | } |
125 | 104 | ||
126 | void lcd_update_rect(int x, int y, int width, int height) | 105 | void lcd_update_rect(int x, int y, int width, int height) |
127 | { | 106 | { |
128 | if (display_on) | 107 | if (display_on) |
129 | { | 108 | (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, |
130 | mutex_lock(&lcd_mtx); | 109 | java_lcd_update_rect, x, y, width, height); |
131 | (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate2, | 110 | } |
132 | (jint)x, (jint)y, (jint)x+width, (jint)y+height); | 111 | |
133 | wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK); | 112 | /* |
134 | mutex_unlock(&lcd_mtx); | 113 | * this is called when the surface is created, which called is everytime |
135 | } | 114 | * the activity is brought in front and the RockboxFramebuffer gains focus |
115 | * | ||
116 | * Note this is considered interrupt context | ||
117 | */ | ||
118 | JNIEXPORT void JNICALL | ||
119 | Java_org_rockbox_RockboxFramebuffer_surfaceCreated(JNIEnv *e, jobject this, | ||
120 | jobject surfaceholder) | ||
121 | { | ||
122 | (void)e; (void)this; (void)surfaceholder; | ||
123 | |||
124 | display_on = true; | ||
125 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
126 | /* Force an update, since the newly created surface is initially black | ||
127 | * waiting for the next normal update results in a longish black screen */ | ||
128 | queue_post(&button_queue, BUTTON_FORCE_REDRAW, 0); | ||
136 | } | 129 | } |
137 | 130 | ||
131 | /* | ||
132 | * the surface is destroyed everytime the RockboxFramebuffer loses focus and | ||
133 | * goes invisible | ||
134 | */ | ||
138 | JNIEXPORT void JNICALL | 135 | JNIEXPORT void JNICALL |
139 | Java_org_rockbox_RockboxFramebuffer_post_1update_1done(JNIEnv *e, jobject this) | 136 | Java_org_rockbox_RockboxFramebuffer_surfaceDestroyed(JNIEnv *e, jobject this, |
137 | jobject surfaceholder) | ||
140 | { | 138 | { |
141 | (void)e; | 139 | (void)e; (void)this; (void)surfaceholder; |
142 | (void)this; | 140 | |
143 | wakeup_signal(&lcd_wakeup); | 141 | display_on = false; |
144 | } | 142 | } |
145 | 143 | ||
146 | bool lcd_active(void) | 144 | bool lcd_active(void) |
@@ -158,26 +156,6 @@ int touchscreen_get_scroll_threshold(void) | |||
158 | return scroll_threshold; | 156 | return scroll_threshold; |
159 | } | 157 | } |
160 | 158 | ||
161 | /* | ||
162 | * (un)block lcd updates. | ||
163 | * | ||
164 | * Notice: This is called from the activity thread, so take it | ||
165 | * as interrupt context and take care what the event callback does | ||
166 | * (it shouldn't block in particular | ||
167 | * | ||
168 | * the 1s are needed due to strange naming conventions... | ||
169 | **/ | ||
170 | JNIEXPORT void JNICALL | ||
171 | Java_org_rockbox_RockboxFramebuffer_set_1lcd_1active(JNIEnv *e, | ||
172 | jobject this, | ||
173 | jint active) | ||
174 | { | ||
175 | (void)e; | ||
176 | (void)this; | ||
177 | display_on = active != 0; | ||
178 | if (active) | ||
179 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
180 | } | ||
181 | /* below is a plain copy from lcd-sdl.c */ | 159 | /* below is a plain copy from lcd-sdl.c */ |
182 | 160 | ||
183 | /** | 161 | /** |