# Impements the services of `mnit:app` using the API from the Android ndk
module android_app
-import android_opengles1
+import mnit
+import android
+import android_sensor
in "C header" `{
#include <jni.h>
#include <errno.h>
#include <android/log.h>
#include <android_native_app_glue.h>
+ #include <android/sensor.h>
+
+ #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
+ #ifdef DEBUG
+ #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
+ #else
+ #define LOGI(...) (void)0
+ #endif
`}
in "C" `{
#include <GLES/glext.h>
#include <errno.h>
- #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
- #ifdef DEBUG
- #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
- #else
- #define LOGI(...) (void)0
- #endif
-
extern EGLDisplay mnit_display;
extern EGLSurface mnit_surface;
extern EGLContext mnit_context;
LOGI("motion");
return App_extern_input_motion(nit_app, event);
}
-
+
return 0;
}
mnit_java_app = app;
AConfiguration_setOrientation(mnit_java_app->config, ACONFIGURATION_ORIENTATION_LAND);
LOGI("cmd %i", (int)pthread_self());
-
+
switch (cmd) {
case APP_CMD_SAVE_STATE:
LOGI ("save state");
mnit_java_app->savedState = malloc(1);
App_save(nit_app);
break;
-
+
case APP_CMD_INIT_WINDOW:
LOGI ("init window");
if (mnit_java_app->window != NULL) {
mnit_animating = 1;
}
break;
-
+
case APP_CMD_TERM_WINDOW:
LOGI ("term window");
mnit_term_display();
App_term_window(nit_app);
break;
-
+
case APP_CMD_GAINED_FOCUS:
LOGI ("gain foc");
mnit_animating = 1;
App_gained_focus(nit_app);
LOGI ("gain foc 1");
break;
-
+
case APP_CMD_LOST_FOCUS:
LOGI ("lost foc");
mnit_animating = 0;
App_lost_focus(nit_app);
mnit_frame();
break;
-
+
case APP_CMD_PAUSE:
LOGI ("app pause");
App_pause(nit_app);
break;
-
+
/*
case APP_CMD_STOP:
LOGI ("app stop");
App_stop(nit_app);
break;
-
+
case APP_CMD_DESTROY:
LOGI ("app destrop");
App_destroy(nit_app);
break;
-
+
case APP_CMD_START:
LOGI ("app start");
App_start(nit_app);
LOGI ("app resume");
App_resume(nit_app);
break;
-
+
case APP_CMD_LOW_MEMORY:
LOGI ("app low mem");
break;
-
+
case APP_CMD_CONFIG_CHANGED:
LOGI ("app cmd conf ch");
break;
-
+
case APP_CMD_INPUT_CHANGED:
LOGI ("app cmd in ch");
break;
-
+
case APP_CMD_WINDOW_RESIZED:
mnit_orientation_changed = 1;
LOGI ("app win res");
break;
-
+
case APP_CMD_WINDOW_REDRAW_NEEDED:
LOGI ("app win redraw needed");
break;
-
+
case APP_CMD_CONTENT_RECT_CHANGED:
LOGI ("app content rect ch");
break;
mnit_java_app = app;
app_dummy();
-
+
main(0, NULL);
}
extern InnerAndroidMotionEvent in "C" `{AInputEvent *`}
super Pointer
- private fun pointers_count: Int is extern `{
+ private fun pointers_count: Int is extern `{
return AMotionEvent_getPointerCount(recv);
`}
private fun just_went_down: Bool is extern `{
return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
else return -1;
`}
+
+ private fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
+end
+
+extern class AMotionEventAction `{ int32_t `}
+ protected fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
+ fun is_down: Bool do return action == 0
+ fun is_up: Bool do return action == 1
+ fun is_move: Bool do return action == 2
+ fun is_cancel: Bool do return action == 3
+ fun is_outside: Bool do return action == 4
+ fun is_pointer_down: Bool do return action == 5
+ fun is_pointer_up: Bool do return action == 6
end
interface AndroidInputEvent
- super InputEvent
+ super InputEvent
end
class AndroidMotionEvent
super AndroidInputEvent
super MotionEvent
-
+
private init(ie: InnerAndroidMotionEvent) do inner_event = ie
private var inner_event: InnerAndroidMotionEvent
-
+
private var pointers_cache: nullable Array[AndroidPointerEvent] = null
fun pointers: Array[AndroidPointerEvent]
do
protected var motion_event: AndroidMotionEvent
protected var pointer_id: Int
-
+
redef fun x: Float do return extern_x(motion_event.inner_event, pointer_id)
private fun extern_x(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
return ((int) AMotionEvent_getX(motion_event, pointer_id) * mnit_zoom);
`}
-
+
redef fun y: Float do return extern_y(motion_event.inner_event, pointer_id)
private fun extern_y(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
return ((int) AMotionEvent_getY(motion_event, pointer_id) * mnit_zoom) + 32;
`}
-
+
fun pressure: Float do return extern_pressure(motion_event.inner_event, pointer_id)
private fun extern_pressure(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
return AMotionEvent_getPressure(motion_event, pointer_id);
`}
- redef fun pressed do return true
- redef fun depressed do return false
+ redef fun pressed
+ do
+ var action = motion_event.inner_event.action
+ return action.is_down or action.is_move
+ end
+
+ redef fun depressed do return not pressed
end
extern AndroidKeyEvent in "C" `{AInputEvent *`}
fun key_code: Int is extern `{
return AKeyEvent_getKeyCode(recv);
`}
-
+
fun key_char: Char is extern `{
int code = AKeyEvent_getKeyCode(recv);
if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
redef class Object
# Uses Android logs for every print
redef fun print(text: Object) is extern import Object.to_s, String.to_cstring `{
- __android_log_print(ANDROID_LOG_INFO, "mnit print", "%s", String_to_cstring(Object_to_s(object)));
+ __android_log_print(ANDROID_LOG_INFO, "mnit print", "%s", String_to_cstring(Object_to_s(text)));
`}
end
redef type IE: AndroidInputEvent
redef type D: Opengles1Display
+ var accelerometer = new AndroidSensor
+ var magnetic_field = new AndroidSensor
+ var gyroscope = new AndroidSensor
+ var light = new AndroidSensor
+ var proximity = new AndroidSensor
+ var sensormanager: ASensorManager
+ var eventqueue: ASensorEventQueue
+ var sensors_support_enabled writable = false
+
redef fun log_warning(msg) is extern import String.to_cstring `{
LOGW("%s", String_to_cstring(msg));
`}
display = new Opengles1Display
end
-
- # these two are used as a callback from native to type incoming events
+
+ # these are used as a callback from native to type incoming events
private fun extern_input_key(event: AndroidKeyEvent): Bool
do
return input(event)
return handled
end
-
- redef fun main_loop is extern import full_frame, save, pause, resume, gained_focus, lost_focus, init_window, term_window, extern_input_key, extern_input_motion `{
+
+ private fun extern_input_sensor_accelerometer(event: ASensorAccelerometer) do input(event)
+ private fun extern_input_sensor_magnetic_field(event: ASensorMagneticField) do input(event)
+ private fun extern_input_sensor_gyroscope(event: ASensorGyroscope) do input(event)
+ private fun extern_input_sensor_light(event: ASensorLight) do input(event)
+ private fun extern_input_sensor_proximity(event: ASensorProximity) do input(event)
+
+ # Sensors support
+ # The user decides which sensors he wants to use by setting them enabled
+ private fun enable_sensors
+ do
+ if sensors_support_enabled then enable_sensors_management else return
+ if accelerometer.enabled then enable_accelerometer
+ if magnetic_field.enabled then enable_magnetic_field
+ if gyroscope.enabled then enable_gyroscope
+ if light.enabled then enable_light
+ if proximity.enabled then enable_proximity
+ end
+
+ private fun enable_sensors_management
+ do
+ sensormanager = new ASensorManager.get_instance
+ #eventqueue = sensormanager.create_event_queue(new NdkAndroidApp)
+ eventqueue = initialize_event_queue(sensormanager)
+ end
+
+ # HACK: need a nit method to get mnit_java_app, then we can use the appropriate sensormanager.create_event_queue method to initialize the event queue
+ private fun initialize_event_queue(sensormanager: ASensorManager): ASensorEventQueue `{
+ return ASensorManager_createEventQueue(sensormanager, mnit_java_app->looper, LOOPER_ID_USER, NULL, NULL);
+ `}
+
+ private fun enable_accelerometer
+ do
+ accelerometer.asensor = sensormanager.get_default_sensor(new ASensorType.accelerometer)
+ if accelerometer.asensor.address_is_null then
+ print "Accelerometer sensor unavailable"
+ else
+ if eventqueue.enable_sensor(accelerometer.asensor) < 0 then print "Accelerometer enabling failed"
+ eventqueue.set_event_rate(accelerometer.asensor, accelerometer.event_rate)
+ end
+ end
+
+ private fun enable_magnetic_field
+ do
+ magnetic_field.asensor = sensormanager.get_default_sensor(new ASensorType.magnetic_field)
+ if magnetic_field.asensor.address_is_null then
+ print "Magnetic Field unavailable"
+ else
+ if eventqueue.enable_sensor(magnetic_field.asensor) < 0 then print "Magnetic Field enabling failed"
+ eventqueue.set_event_rate(magnetic_field.asensor, magnetic_field.event_rate)
+ end
+ end
+
+ private fun enable_gyroscope
+ do
+ gyroscope.asensor = sensormanager.get_default_sensor(new ASensorType.gyroscope)
+ if gyroscope.asensor.address_is_null then
+ print "Gyroscope sensor unavailable"
+ else
+ if eventqueue.enable_sensor(gyroscope.asensor) < 0 then print "Gyroscope enabling failed"
+ eventqueue.set_event_rate(gyroscope.asensor, gyroscope.event_rate)
+ end
+ end
+
+ private fun enable_light
+ do
+ light.asensor = sensormanager.get_default_sensor(new ASensorType.light)
+ if light.asensor.address_is_null then
+ print "Light sensor unavailable"
+ else
+ if eventqueue.enable_sensor(light.asensor) < 0 then print "Light enabling failed"
+ eventqueue.set_event_rate(light.asensor, light.event_rate)
+ end
+ end
+
+ private fun enable_proximity
+ do
+ proximity.asensor = sensormanager.get_default_sensor(new ASensorType.proximity)
+ if proximity.asensor.address_is_null then
+ print "Proximity sensor unavailable"
+ else
+ if eventqueue.enable_sensor(proximity.asensor) < 0 then print "Proximity enabling failed"
+ eventqueue.set_event_rate(light.asensor, light.event_rate)
+ end
+ end
+
+ redef fun main_loop is extern import full_frame, generate_input, enable_sensors `{
LOGI("nitni loop");
-
+
nit_app = recv;
mnit_java_app->userData = &nit_app;
mnit_java_app->onAppCmd = mnit_handle_cmd;
mnit_java_app->onInputEvent = mnit_handle_input;
-
+
+ //Enbales sensors if needed
+ App_enable_sensors(nit_app);
+
while (1) {
- int ident;
- int events;
- static int block = 0;
- struct android_poll_source* source;
-
- while ((ident=ALooper_pollAll(0, NULL, &events,
- (void**)&source)) >= 0) { /* first 0 is for non-blocking */
-
- // Process this event.
- if (source != NULL)
- source->process(mnit_java_app, source);
-
- // Check if we are exiting.
- if (mnit_java_app->destroyRequested != 0) {
- mnit_term_display();
- return;
- }
- }
-
+ App_generate_input(recv);
+
+ if (mnit_java_app->destroyRequested != 0) return;
+
if (mnit_animating == 1) {
mnit_frame();
LOGI("frame at loop end 1");
}
}
-
- /* App_exit(); // this is unreachable anyway*/
+ /* App_exit(); // this is unreachable anyway*/
`}
-end
+ redef fun generate_input import save, pause, resume, gained_focus, lost_focus, init_window, term_window, extern_input_key, extern_input_motion, extern_input_sensor_accelerometer, extern_input_sensor_magnetic_field, extern_input_sensor_gyroscope, extern_input_sensor_light, extern_input_sensor_proximity, eventqueue `{
+ int ident;
+ int events;
+ static int block = 0;
+ struct android_poll_source* source;
+
+ while ((ident=ALooper_pollAll(0, NULL, &events,
+ (void**)&source)) >= 0) { /* first 0 is for non-blocking */
+
+ // Process this event.
+ if (source != NULL)
+ source->process(mnit_java_app, source);
+
+ //If a sensor has data, process it
+ if(ident == LOOPER_ID_USER) {
+ //maybe add a boolean to the app to know if we want to use Sensor API or ASensorEvent directly ...
+ ASensorEvent* events = malloc(sizeof(ASensorEvent)*10);
+ int nbevents;
+ ASensorEventQueue* queue = App_eventqueue(nit_app);
+ while((nbevents = ASensorEventQueue_getEvents(queue, events, 10)) > 0) {
+ int i;
+ for(i = 0; i < nbevents; i++){
+ ASensorEvent event = events[i];
+ switch (event.type) {
+ case ASENSOR_TYPE_ACCELEROMETER:
+ App_extern_input_sensor_accelerometer(nit_app, &event);
+ break;
+ case ASENSOR_TYPE_MAGNETIC_FIELD:
+ App_extern_input_sensor_magnetic_field(nit_app, &event);
+ break;
+ case ASENSOR_TYPE_GYROSCOPE:
+ App_extern_input_sensor_gyroscope(nit_app, &event);
+ break;
+ case ASENSOR_TYPE_LIGHT:
+ App_extern_input_sensor_light(nit_app, &event);
+ break;
+ case ASENSOR_TYPE_PROXIMITY:
+ App_extern_input_sensor_proximity(nit_app, &event);
+ break;
+ }
+ }
+ }
+ }
+
+ // Check if we are exiting.
+ if (mnit_java_app->destroyRequested != 0) {
+ mnit_term_display();
+ return;
+ }
+ }
+ `}
+end