X-Git-Url: http://nitlanguage.org diff --git a/lib/mnit_android/android_app.nit b/lib/mnit_android/android_app.nit index 19b0c97..9d0d6c4 100644 --- a/lib/mnit_android/android_app.nit +++ b/lib/mnit_android/android_app.nit @@ -15,33 +15,18 @@ # limitations under the License. # Impements the services of `mnit:app` using the API from the Android ndk -module android_app +module android_app is android_manifest_activity """ + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:configChanges="orientation|keyboardHidden" +""" import mnit import android -import android_sensor - -in "C header" `{ - #include - #include - #include - #include - #include - - #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 -`} +import mnit::opengles1 +intrude import ::android::input_events in "C" `{ #include - #include - #define GL_GLEXT_PROTOTYPES 1 - #include - #include extern EGLDisplay mnit_display; extern EGLSurface mnit_surface; @@ -49,370 +34,28 @@ in "C" `{ extern EGLConfig mnit_config; extern int32_t mnit_width; extern int32_t mnit_height; - extern float mnit_zoom; - - int mnit_orientation_changed; - float mnit_zoom; - int mnit_animating = 0; - - /* This is confusing; the type come from android_native_app_glue.h - and so identifies the java part of the app */ - struct android_app *mnit_java_app; - - /* This is the pure Nit App */ - App nit_app; - - /* The main of the Nit application, compiled somewhere else */ - extern int main(int, char**); - - /* Wraps App_full_frame() and check for orientation. */ - void mnit_frame(); - - void mnit_term_display() - { - // At this point we have nothing to do - } - - /* Handle inputs from the Android platform and sort them before - sending them in the Nit App */ - static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) { - LOGI("handle input %i", (int)pthread_self()); - if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { - LOGI("key"); - return App_extern_input_key(nit_app, event); - } - else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { - LOGI("motion"); - return App_extern_input_motion(nit_app, event); - } - - return 0; - } - - static void mnit_handle_cmd(struct android_app* app, int32_t cmd) { - - 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->savedStateSize = 1; - 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) { - LOGI("init window in"); - App_init_window(nit_app); - mnit_frame(); - 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); - break; - */ - - case APP_CMD_RESUME: - 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; - } - } - - void android_main(struct android_app* app) - { - mnit_java_app = app; - - app_dummy(); - - main(0, NULL); - } - - void mnit_frame() - { - if (mnit_display == EGL_NO_DISPLAY) { - LOGI("no frame"); - return; - } - - if (mnit_orientation_changed) - { - mnit_orientation_changed = 0; - - if (mnit_surface != EGL_NO_SURFACE) { - eglDestroySurface(mnit_display, mnit_surface); - } - EGLSurface surface = eglCreateWindowSurface(mnit_display, mnit_config, mnit_java_app->window, NULL); - - if (eglMakeCurrent(mnit_display, surface, surface, mnit_context) == EGL_FALSE) { - LOGW("Unable to eglMakeCurrent"); - } - - eglQuerySurface(mnit_display, surface, EGL_WIDTH, &mnit_width); - eglQuerySurface(mnit_display, surface, EGL_HEIGHT, &mnit_height); - - mnit_surface = surface; - - glViewport(0, 0, mnit_width, mnit_height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0.0f, mnit_width, mnit_height, 0.0f, 0.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - } - - LOGI("frame"); - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); // | GL_DEPTH_BUFFER_BIT); - - App_full_frame(nit_app); - - LOGI("frame b"); - } `} - -extern InnerAndroidMotionEvent in "C" `{AInputEvent *`} - super Pointer - private fun pointers_count: Int is extern `{ - return AMotionEvent_getPointerCount(recv); - `} - private fun just_went_down: Bool is extern `{ - return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN; - `} - private fun edge: Int is extern `{ - return AMotionEvent_getEdgeFlags(recv); - `} - private fun index_down_pointer: Int is extern `{ - int a = AMotionEvent_getAction(recv); - if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) - 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 -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 - if pointers_cache != null then - return pointers_cache.as(not null) - else - var pointers = new Array[AndroidPointerEvent] - var pointers_count = inner_event.pointers_count - for i in [0 .. pointers_count [do - var pointer_event = new AndroidPointerEvent(self, i) - pointers.add(pointer_event) - end - pointers_cache = pointers - return pointers - end - end - - redef fun just_went_down: Bool do return inner_event.just_went_down - fun edge: Int do return inner_event.edge - - redef fun down_pointer: nullable AndroidPointerEvent - do - var i = inner_event.index_down_pointer - if i > 0 then - return pointers[i] - else - return null - end - end -end - -class AndroidPointerEvent - super PointerEvent - super AndroidInputEvent - - 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 - 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 *`} - super KeyEvent - super AndroidInputEvent - - fun action: Int is extern `{ - return AKeyEvent_getAction(recv); - `} - redef fun is_down: Bool do return action == 0 - redef fun is_up: Bool do return action == 1 - - 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) - return '0'+code-AKEYCODE_0; - if (code >= AKEYCODE_A && code <= AKEYCODE_Z) - return 'a'+code-AKEYCODE_A; - return 0; - `} - - fun is_back_key: Bool do return key_code == 2 - fun is_menu_key: Bool do return key_code == 82 - fun is_search_key: Bool do return key_code == 84 -end - -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(text))); - `} -end - redef class App - 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)); - `} - redef fun log_info(msg) is extern import String.to_cstring `{ - LOGI("%s", String_to_cstring(msg)); - `} - redef fun init_window do - super - display = new Opengles1Display + + super end - # these are used as a callback from native to type incoming events - private fun extern_input_key(event: AndroidKeyEvent): Bool + redef fun full_frame do if not paused then super + + redef fun generate_input do poll_looper 0 + + redef fun native_input_key(event) do return input(event) end - private fun extern_input_motion(event: InnerAndroidMotionEvent): Bool + + redef fun native_input_motion(event) do var ie = new AndroidMotionEvent(event) var handled = input(ie) @@ -425,181 +68,4 @@ redef class App return handled end - - 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) { - 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*/ - `} - - 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 - -redef class Sys - # Get the running JVM - redef fun create_default_jvm - do - var jvm = ndk_jvm - var jni_env = jvm.attach_current_thread - if jni_env.address_is_null then jni_env = jvm.env - - self.jvm = jvm - self.jni_env = jni_env - end - - protected fun ndk_jvm: JavaVM `{ return mnit_java_app->activity->vm; `} end