Merge: doc: fixed some typos and other misc. corrections
[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 # * `NativeNativeActivity` 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
40 ldflags("-landroid", "-lnative_app_glue")
41 android_activity "android.app.NativeActivity"
42 end
43
44 import platform
45 import log
46 import dalvik
47
48 in "C header" `{
49 #include <android_native_app_glue.h>
50 `}
51
52 in "C body" `{
53 struct android_app* native_app_glue_data;
54
55 // Was `android_main` called?
56 int android_main_launched = 0;
57
58 // Entry point called by the native_app_glue_framework framework
59 // We relay the call to the Nit application.
60 void android_main(struct android_app* app) {
61 native_app_glue_data = app;
62
63 if (android_main_launched) {
64 // Second call to `android_main`, may happen if `exit 0` was not
65 // called previously to force unloading the Nit app state.
66 // This happens sometimes when the `destroy` lifecycle command
67 // was not correctly received.
68 // We `exit 0` here hoping the system restarts the app nicely
69 // without an error popup.
70 exit(0);
71 } else {
72 android_main_launched = 1;
73 int main(int argc, char ** argv);
74 main(0, NULL);
75 }
76 }
77
78 // Main callback on the native_app_glue framework
79 //
80 // We relay everything to our App.
81 static void app_cmd_handler(struct android_app* app, int32_t cmd) {
82 App nit_app = app->userData;
83 switch (cmd) {
84 case APP_CMD_SAVE_STATE:
85 App_save_state(nit_app);
86 break;
87 case APP_CMD_INIT_WINDOW:
88 App_init_window(nit_app);
89 break;
90 case APP_CMD_TERM_WINDOW:
91 App_term_window(nit_app);
92 break;
93 case APP_CMD_GAINED_FOCUS:
94 App_gained_focus(nit_app);
95 break;
96 case APP_CMD_LOST_FOCUS:
97 App_lost_focus(nit_app);
98 break;
99 case APP_CMD_PAUSE:
100 App_pause(nit_app);
101 break;
102 case APP_CMD_STOP:
103 App_stop(nit_app);
104 break;
105 case APP_CMD_DESTROY:
106 App_destroy(nit_app);
107 break;
108 case APP_CMD_START:
109 App_start(nit_app);
110 break;
111 case APP_CMD_RESUME:
112 App_resume(nit_app);
113 break;
114 case APP_CMD_LOW_MEMORY:
115 App_low_memory(nit_app);
116 break;
117 case APP_CMD_CONFIG_CHANGED:
118 App_config_changed(nit_app);
119 break;
120 case APP_CMD_INPUT_CHANGED:
121 App_input_changed(nit_app);
122 break;
123 case APP_CMD_WINDOW_RESIZED:
124 App_window_resized(nit_app);
125 break;
126 case APP_CMD_WINDOW_REDRAW_NEEDED:
127 App_window_redraw_needed(nit_app);
128 break;
129 case APP_CMD_CONTENT_RECT_CHANGED:
130 App_content_rect_changed(nit_app);
131 break;
132 }
133 }
134 `}
135
136 # Android SDK's `android.app.NativeActivity`.
137 #
138 # Can be used to get anything related to the `Context` of the activity in Java
139 # and as anchor to execute Java UI code.
140 extern class NativeNativeActivity in "Java" `{ android.app.NativeActivity `}
141 super NativeActivity
142 end
143
144 redef class Sys
145 redef fun jvm do return app.native_app_glue.ndk_native_activity.vm
146 end
147
148 redef class App
149 redef fun setup
150 do
151 var native_app_glue = native_app_glue
152 native_app_glue.user_data = self
153
154 set_as_cmd_handler(native_app_glue)
155 end
156
157 # The underlying implementation using the Android native_app_glue framework
158 fun native_app_glue: NativeAppGlue `{ return native_app_glue_data; `}
159
160 redef fun native_activity do return native_app_glue.ndk_native_activity.java_native_activity
161
162 # Set `native_app_glue` command handler to our C implementation which
163 # will callback self.
164 private fun set_as_cmd_handler(native_app_glue: NativeAppGlue) import save_state,
165 init_window, term_window, gained_focus, lost_focus, pause, stop, destroy,
166 start, resume, low_memory, config_changed, input_changed, window_resized,
167 window_redraw_needed, content_rect_changed `{
168 native_app_glue->onAppCmd = &app_cmd_handler;
169 `}
170
171 # Notification from the Android framework to generate a new saved state
172 #
173 # You can use the `shared_preferences` module or `NativeAppGlue::saved_state`.
174 fun save_state do end
175
176 # Notification from the native_app glue framework, a new ANativeWindow is ready
177 #
178 # When called, `NativeAppGlue::window` returns a poiter to the new window surface.
179 fun init_window do end
180
181 # Notification from the native_app glue framework, the existing window needs to be terminated
182 #
183 # Upon receiving this command, `native_app_glue.window` still contains the existing window.
184 fun term_window do end
185
186 # Notification from the Android framework, `native_activity` has gained focus
187 fun gained_focus do end
188
189 # Notification from the Android framework, `native_activity` has lost focus
190 fun lost_focus do end
191
192 # Notification from the Android framework, your app has been paused
193 fun pause do end
194
195 # Notification from the Android framework, your app has been stopped
196 fun stop do end
197
198 # Notification from the Android framework, `native_activity` is being destroyed
199 #
200 # Clean up and exit.
201 fun destroy do end
202
203 # Notification from the Android framework, `native_activity` has been started
204 fun start do end
205
206 # Notification from the Android framework, `native_activity` has been resumed
207 fun resume do end
208
209 # Notification from the Android framework, the system is running low on memory
210 #
211 # Try to reduce your memory use.
212 fun low_memory do force_garbage_collection
213
214 # Notification from the Android framework, the current device configuration has changed
215 fun config_changed do end
216
217 # Notification from the Android framework, `native_app_glue.input_queue` has changed
218 fun input_changed do end
219
220 # Notification from the Android framework, the window has been resized.
221 #
222 # Please redraw with its new size.
223 fun window_resized do end
224
225 # Notification from the Android framework, the current ANativeWindow must be redrawn
226 fun window_redraw_needed do end
227
228 # Notification from the Android framework, the content area of the window has changed
229 #
230 # Raised when the soft input window being shown or hidden, and similar events.
231 fun content_rect_changed do end
232
233 # Call the `ALooper_pollAll` to retrieve events and callback the application
234 fun poll_looper(timeout_ms: Int) import handle_looper_event `{
235 int ident;
236 int event;
237 void* source;
238 while ((ident=ALooper_pollAll(timeout_ms, NULL, &event, &source)) >= 0) {
239 App_handle_looper_event(self, ident, event, source);
240 }
241 `}
242
243 # Call the `ALooper_pollOnce` to retrieve at most one event and callback the application
244 fun poll_looper_pause(timeout_ms: Int) import handle_looper_event `{
245 int event;
246 void* source;
247 int ident = ALooper_pollOnce(timeout_ms, NULL, &event, &source);
248 if (ident >= 0) {
249 App_handle_looper_event(self, ident, event, source);
250 }
251 `}
252
253 # Handle an event retrieved by the `ALooper` and `poll_looper` without a callback
254 protected fun handle_looper_event(ident, event: Int, data: Pointer) import native_app_glue,
255 save_state, init_window, term_window, gained_focus, lost_focus, pause, stop,
256 destroy, start, resume, low_memory, config_changed, input_changed,
257 window_resized, window_redraw_needed, content_rect_changed `{
258
259 struct android_app *app_glue = App_native_app_glue(self);
260 struct android_poll_source* source = (struct android_poll_source*)data;
261
262 // Process this event.
263 if (source != NULL) source->process(app_glue, source);
264 `}
265 end
266
267 # An Android activity implemented in C. This is the C part of `NativeActivity`
268 # which is the Java part.
269 #
270 # The callbacks at this level are synchronous on the UI thread. Thus app.nit
271 # do not use them, and instead rely on `NativeAppGlue`.
272 extern class NdkNativeActivity `{ ANativeActivity * `}
273
274 # Callbacks on the main thread
275 # FIXME This would not yet be usable, to implement when Nit has threads
276 #fun set_callbacks_handler(handler: App) or callbacks= ...
277
278 # Java VM associated to `self`
279 fun vm: JavaVM `{ return self->vm; `}
280
281 # JNI environmnet associated to `self`
282 fun env: JniEnv `{ return self->env; `}
283
284 # The `NativeActivity`, as in the Java object, associated to `self`
285 fun java_native_activity: NativeActivity `{ return self->clazz; `}
286
287 # Path to this application's internal data directory.
288 fun internal_data_path: CString `{ return (char*)self->internalDataPath; `}
289
290 # Path to this application's external (removable/mountable) data directory.
291 fun external_data_path: CString `{ return (char*)self->externalDataPath; `}
292
293 # The platform's SDK version code.
294 fun sdk_version: Int `{ return self->sdkVersion; `}
295
296 # This is the native instance of the application. It is not used by
297 # the framework, but can be set by the application to its own instance
298 # state.
299 fun instance: Pointer `{ return self->instance; `}
300
301 # Pointer to the Asset Manager instance for the application. The application
302 # uses this to access binary assets bundled inside its own .apk file.
303 #
304 # TODO activate in a future `asset_manager` module if it cannot be done in Java
305 #fun asset_manager: AssetManager `{ return self->assetManager; `}
306
307 # Available starting with Honeycomb: path to the directory containing
308 # the application's OBB files (if any). If the app doesn't have any
309 # OBB files, this directory may not exist.
310 # api?
311 #
312 # TODO activate in a future module at API 11
313 #fun obb_path: CString `{ return (char*)self->obbPath; `}
314 end
315
316 # This is the interface for the standard glue code of a threaded
317 # application. In this model, the application's code is running
318 # in its own thread separate from the main thread of the process.
319 # It is not required that this thread be associated with the Java
320 # VM, although it will need to be in order to make JNI calls any
321 # Java objects.
322 extern class NativeAppGlue `{ struct android_app* `}
323 # We use the `userData` field of the C structure to store an handle to
324 # the associated App
325 private fun user_data: App `{ return self->userData; `}
326 private fun user_data=(val: App) `{
327 App_incr_ref(val);
328 self->userData = val;
329 `}
330
331 # Fill this in with the function to process input events. At this point
332 # the event has already been pre-dispatched, and it will be finished upon
333 # return. Return 1 if you have handled the event, 0 for any default
334 # dispatching.
335 #int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
336 #fun set_input_event_handler(handler: App) `{ `}
337
338 # The ANativeActivity object instance that this app is running in.
339 fun ndk_native_activity: NdkNativeActivity `{ return self->activity; `}
340
341 # The current configuration the app is running in.
342 fun config: AConfiguration `{ return self->config; `}
343
344 # This is the last instance's saved state, as provided at creation time.
345 # It is NULL if there was no state. You can use this as you need; the
346 # memory will remain around until you call android_app_exec_cmd() for
347 # APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
348 # These variables should only be changed when processing a APP_CMD_SAVE_STATE,
349 # at which point they will be initialized to NULL and you can malloc your
350 # state and place the information here. In that case the memory will be
351 # freed for you later.
352 fun saved_state: Pointer `{ return self->savedState; `}
353 fun saved_state_size: Int `{ return self->savedStateSize; `}
354
355 # The ALooper associated with the app's thread.
356 fun looper: ALooper `{ return self->looper; `}
357
358 # When non-NULL, this is the input queue from which the app will
359 # receive user input events.
360 fun input_queue: AInputQueue `{ return self->inputQueue; `}
361
362 # When non-NULL, this is the window surface that the app can draw in.
363 fun window: ANativeWindow `{ return self->window; `}
364
365 # Current content rectangle of the window; this is the area where the
366 # window's content should be placed to be seen by the user.
367 #
368 # TODO activate when we know what to return (returns a struct not a pointer)
369 #fun content_self: ARect `{ return self->contentRect; `}
370
371 # Current state of the app's activity. May be either APP_CMD_START,
372 # APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
373 fun activity_state: Int `{ return self->activityState; `}
374
375 # This is non-zero when the application's NativeActivity is being
376 # destroyed and waiting for the app thread to complete.
377 fun destroy_requested: Bool `{ return self->destroyRequested; `}
378 end
379
380 # Android NDK's struture holding configurations of the native app
381 extern class AConfiguration `{ AConfiguration* `}
382 end
383
384 # Android NDK's structure to handle events synchronously
385 extern class ALooper `{ ALooper* `}
386 # Returns the looper associated with the calling thread, or NULL if there is not one
387 new for_thread `{ return ALooper_forThread(); `}
388 end
389
390 # Android NDK's struture to handle input events synchronously
391 extern class AInputQueue `{ AInputQueue* `}
392 end
393
394 # Android NDK's structure to control the native window for drawing
395 extern class ANativeWindow `{ ANativeWindow* `}
396 # Change the format and size of the window buffers
397 #
398 # All arguments can be set to 0 to use the default devices values.
399 # `width` and `height` must both be set to 0 or have significant values.
400 #
401 # `format` is a value specified by EGL.
402 fun set_buffers_geometry(width, height, format: Int): Bool `{
403 return ANativeWindow_setBuffersGeometry(self, (int32_t)width, (int32_t)height, (int32_t)format);
404 `}
405 end