4ae4753a790147f25a63a2616b65f3829d80cf1e
[nit.git] / lib / android / native_app_glue.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Some documentation of this module has been adapted from the documentation
18 # of the Android NDK projet.
19
20 # Wrapper of the Android native_app_glue framework to implement app.nit
21 #
22 # The framework provides 3 different structures for a single C application
23 # under Android. We use all 3 structures in this API to implement app.nit
24 # on Android. Each structure is wrapped in a Nit extern class:
25 #
26 # * `NativeAppGlue` is the lowest level class, it is implemented by the C
27 # structure `android_app`. It offers features on the main Android thread
28 # (not on the same thread as Nit). For this reason, prefer to use
29 # `NdkNativeActivity`.
30 #
31 # * `NdkNativeActivity` is implemented by the C structure `ANativeActivity`. It
32 # is on the same thread as Nit and manages the synchronization with the
33 # main Android thread.
34 #
35 # * `NativeActivity` is implemented in Java by `android.app.NativeActivity`,
36 # which is a subclass of `Activity` and `Context` (in Java). It represent
37 # main activity of the running application. Use it to get anything related
38 # to the `Context` and as anchor to execute Java UI code.
39 module native_app_glue is ldflags "-landroid"
40
41 import platform
42 import log
43
44 in "C header" `{
45 #include <android_native_app_glue.h>
46 `}
47
48 in "C body" `{
49 struct android_app* native_app_glue_data;
50
51 // Entry point called by the native_app_glue_framework framework
52 // We relay the call to the Nit application.
53 void android_main(struct android_app* app) {
54 native_app_glue_data = app;
55 app_dummy();
56 main(0, NULL);
57 }
58
59 // Main callback on the native_app_glue framework
60 //
61 // We relay everything to our App.
62 static void app_cmd_handler(struct android_app* app, int32_t cmd) {
63 App nit_app = app->userData;
64 switch (cmd) {
65 case APP_CMD_SAVE_STATE:
66 App_save_state(nit_app);
67 break;
68 case APP_CMD_INIT_WINDOW:
69 App_init_window(nit_app);
70 break;
71 case APP_CMD_TERM_WINDOW:
72 App_term_window(nit_app);
73 break;
74 case APP_CMD_GAINED_FOCUS:
75 App_gained_focus(nit_app);
76 break;
77 case APP_CMD_LOST_FOCUS:
78 App_lost_focus(nit_app);
79 break;
80 case APP_CMD_PAUSE:
81 App_pause(nit_app);
82 break;
83 case APP_CMD_STOP:
84 App_stop(nit_app);
85 break;
86 case APP_CMD_DESTROY:
87 App_destroy(nit_app);
88 break;
89 case APP_CMD_START:
90 App_start(nit_app);
91 break;
92 case APP_CMD_RESUME:
93 App_resume(nit_app);
94 break;
95 case APP_CMD_LOW_MEMORY:
96 App_low_memory(nit_app);
97 break;
98 case APP_CMD_CONFIG_CHANGED:
99 App_config_changed(nit_app);
100 break;
101 case APP_CMD_INPUT_CHANGED:
102 App_input_changed(nit_app);
103 break;
104 case APP_CMD_WINDOW_RESIZED:
105 App_window_resized(nit_app);
106 break;
107 case APP_CMD_WINDOW_REDRAW_NEEDED:
108 App_window_redraw_needed(nit_app);
109 break;
110 case APP_CMD_CONTENT_RECT_CHANGED:
111 App_content_rect_changed(nit_app);
112 break;
113 }
114 }
115 `}
116
117 # An Android activity context
118 extern class NativeContext in "Java" `{ android.content.Context `}
119 super JavaObject
120 end
121
122 # A wrapper of context
123 extern class NativeContextWrapper in "Java" `{ android.content.ContextWrapper `}
124 super NativeContext
125 end
126
127 # Android SDK's `android.app.NativeActivity`.
128 #
129 # Can be used to get anything related to the `Context` of the activity in Java
130 # and as anchor to execute Java UI code.
131 extern class NativeActivity in "Java" `{ android.app.NativeActivity `}
132 super NativeContextWrapper
133 end
134
135 redef class App
136 redef fun setup
137 do
138 var native_app_glue = native_app_glue
139 native_app_glue.user_data = self
140
141 set_as_cmd_handler(native_app_glue)
142 end
143
144 # The underlying implementation using the Android native_app_glue framework
145 fun native_app_glue: NativeAppGlue `{ return native_app_glue_data; `}
146
147 # The main Java Activity of this application
148 fun native_activity: NativeActivity do return native_app_glue.ndk_native_activity.java_native_activity
149
150 # Set `native_app_glue` command handler to our C implementation which
151 # will callback self.
152 private fun set_as_cmd_handler(native_app_glue: NativeAppGlue) import save_state,
153 init_window, term_window, gained_focus, lost_focus, pause, stop, destroy,
154 start, resume, low_memory, config_changed, input_changed, window_resized,
155 window_redraw_needed, content_rect_changed `{
156 native_app_glue->onAppCmd = &app_cmd_handler;
157 `}
158
159 # Notification from the Android framework to generate a new saved state
160 #
161 # You can use the `shared_preferences` module or `NativeAppGlue::saved_state`.
162 fun save_state do end
163
164 # Notification from the native_app glue framework, a new ANativeWindow is ready
165 #
166 # When called, `NativeAppGlue::window` returns a poiter to the new window surface.
167 fun init_window do end
168
169 # Notification from the native_app glue framework, the existing window needs to be terminated
170 #
171 # Upon receiving this command, `native_app_glue.window` still contains the existing window.
172 fun term_window do end
173
174 # Notification from the Android framework, `native_activity` has gained focus
175 fun gained_focus do end
176
177 # Notification from the Android framework, `native_activity` has lost focus
178 fun lost_focus do end
179
180 # Notification from the Android framework, your app has been paused
181 fun pause do end
182
183 # Notification from the Android framework, your app has been stopped
184 fun stop do end
185
186 # Notification from the Android framework, `native_activity` is being destroyed
187 #
188 # Clean up and exit.
189 fun destroy do end
190
191 # Notification from the Android framework, `native_activity` has been started
192 fun start do end
193
194 # Notification from the Android framework, `native_activity` has been resumed
195 fun resume do end
196
197 # Notification from the Android framework, the system is running low on memory
198 #
199 # Try to reduce your memory use.
200 fun low_memory do end
201
202 # Notification from the Android framework, the current device configuration has changed
203 fun config_changed do end
204
205 # Notification from the Android framework, `native_app_glue.input_queue` has changed
206 fun input_changed do end
207
208 # Notification from the Android framework, the window has been resized.
209 #
210 # Please redraw with its new size.
211 fun window_resized do end
212
213 # Notification from the Android framework, the current ANativeWindow must be redrawn
214 fun window_redraw_needed do end
215
216 # Notification from the Android framework, the content area of the window has changed
217 #
218 # Raised when the soft input window being shown or hidden, and similar events.
219 fun content_rect_changed do end
220
221 # Call the `ALooper` to retrieve events and callback the application
222 fun poll_looper(timeout_ms: Int) import handle_looper_event `{
223 int ident;
224 int event;
225 void* source;
226 while ((ident=ALooper_pollAll(timeout_ms, NULL, &event, &source)) >= 0) {
227 App_handle_looper_event(recv, ident, event, source);
228 }
229 `}
230
231 # Handle an event retrieved by the `ALooper` and `poll_looper` without a callback
232 protected fun handle_looper_event(ident, event: Int, data: Pointer) import native_app_glue,
233 save_state, init_window, term_window, gained_focus, lost_focus, pause, stop,
234 destroy, start, resume, low_memory, config_changed, input_changed,
235 window_resized, window_redraw_needed, content_rect_changed `{
236
237 struct android_app *app_glue = App_native_app_glue(recv);
238 struct android_poll_source* source = (struct android_poll_source*)data;
239
240 // Process this event.
241 if (source != NULL) source->process(app_glue, source);
242 `}
243 end
244
245 # An Android activity implemented in C. This is the C part of `NativeActivity`
246 # which is the Java part.
247 #
248 # The callbacks at this level are synchronous on the UI thread. Thus app.nit
249 # do not use them, and instead rely on `NativeAppGlue`.
250 extern class NdkNativeActivity `{ ANativeActivity * `}
251
252 # Callbacks on the main thread
253 # FIXME This would not yet be usable, to implement when Nit has threads
254 #fun set_callbacks_handler(handler: App) or callbacks= ...
255
256 # Java VM associated to `self`
257 fun vm: JavaVM `{ return recv->vm; `}
258
259 # JNI environmnet associated to `self`
260 fun env: JniEnv `{ return recv->env; `}
261
262 # The `NativeActivity`, as in the Java object, associated to `self`
263 fun java_native_activity: NativeActivity `{ return recv->clazz; `}
264
265 # Path to this application's internal data directory.
266 fun internal_data_path: NativeString `{ return (char*)recv->internalDataPath; `}
267
268 # Path to this application's external (removable/mountable) data directory.
269 fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
270
271 # The platform's SDK version code.
272 fun sdk_version: Int `{ return recv->sdkVersion; `}
273
274 # This is the native instance of the application. It is not used by
275 # the framework, but can be set by the application to its own instance
276 # state.
277 fun instance: Pointer `{ return recv->instance; `}
278
279 # Pointer to the Asset Manager instance for the application. The application
280 # uses this to access binary assets bundled inside its own .apk file.
281 #
282 # TODO activate in a future `asset_manager` module if it cannot be done in Java
283 #fun asset_manager: AssetManager `{ return recv->assetManager; `}
284
285 # Available starting with Honeycomb: path to the directory containing
286 # the application's OBB files (if any). If the app doesn't have any
287 # OBB files, this directory may not exist.
288 # api?
289 #
290 # TODO activate in a future module at API 11
291 #fun obb_path: NativeString `{ return (char*)recv->obbPath; `}
292 end
293
294 # This is the interface for the standard glue code of a threaded
295 # application. In this model, the application's code is running
296 # in its own thread separate from the main thread of the process.
297 # It is not required that this thread be associated with the Java
298 # VM, although it will need to be in order to make JNI calls any
299 # Java objects.
300 extern class NativeAppGlue `{ struct android_app* `}
301 # We use the `userData` field of the C structure to store an handle to
302 # the associated App
303 private fun user_data: App `{ return recv->userData; `}
304 private fun user_data=(val: App) `{
305 App_incr_ref(val);
306 recv->userData = val;
307 `}
308
309 # Fill this in with the function to process input events. At this point
310 # the event has already been pre-dispatched, and it will be finished upon
311 # return. Return 1 if you have handled the event, 0 for any default
312 # dispatching.
313 #int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
314 #fun set_input_event_handler(handler: App) `{ `}
315
316 # The ANativeActivity object instance that this app is running in.
317 fun ndk_native_activity: NdkNativeActivity `{ return recv->activity; `}
318
319 # The current configuration the app is running in.
320 fun config: AConfiguration `{ return recv->config; `}
321
322 # This is the last instance's saved state, as provided at creation time.
323 # It is NULL if there was no state. You can use this as you need; the
324 # memory will remain around until you call android_app_exec_cmd() for
325 # APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
326 # These variables should only be changed when processing a APP_CMD_SAVE_STATE,
327 # at which point they will be initialized to NULL and you can malloc your
328 # state and place the information here. In that case the memory will be
329 # freed for you later.
330 fun saved_state: Pointer `{ return recv->savedState; `}
331 fun saved_state_size: Int `{ return recv->savedStateSize; `}
332
333 # The ALooper associated with the app's thread.
334 fun looper: ALooper `{ return recv->looper; `}
335
336 # When non-NULL, this is the input queue from which the app will
337 # receive user input events.
338 fun input_queue: AInputQueue `{ return recv->inputQueue; `}
339
340 # When non-NULL, this is the window surface that the app can draw in.
341 fun window: ANativeWindow `{ return recv->window; `}
342
343 # Current content rectangle of the window; this is the area where the
344 # window's content should be placed to be seen by the user.
345 #
346 # TODO activate when we know what to return (returns a struct not a pointer)
347 #fun content_recv: ARect `{ return recv->contentRect; `}
348
349 # Current state of the app's activity. May be either APP_CMD_START,
350 # APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
351 fun activity_state: Int `{ return recv->activityState; `}
352
353 # This is non-zero when the application's NativeActivity is being
354 # destroyed and waiting for the app thread to complete.
355 fun detroy_request: Bool `{ return recv->destroyRequested; `}
356 end
357
358 # Android NDK's struture holding configurations of the native app
359 extern class AConfiguration `{ AConfiguration* `}
360 end
361
362 # Android NDK's structure to handle events synchronously
363 extern class ALooper `{ ALooper* `}
364 # Returns the looper associated with the calling thread, or NULL if there is not one
365 new for_thread `{ return ALooper_forThread(); `}
366 end
367
368 # Android NDK's struture to handle input events synchronously
369 extern class AInputQueue `{ AInputQueue* `}
370 end
371
372 # Android NDK's structure to control the native window for drawing
373 extern class ANativeWindow `{ ANativeWindow* `}
374 end