1 namespace gui::drivers;
14 #include <android/configuration.h>
15 #include <android/looper.h>
16 #include <android/native_activity.h>
17 #include <android/sensor.h>
18 #include <android/log.h>
19 #include <android/window.h>
25 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "ecere-app", __VA_ARGS__))
26 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "ecere-app", __VA_ARGS__))
27 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "ecere-app", __VA_ARGS__))
29 #define LOGV(...) ((void)0)
31 #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "ecere-app", __VA_ARGS__))
34 // *** NATIVE APP GLUE ********
35 enum LooperID { main = 1, input = 2, user = 3 };
36 enum AppCommand : byte
38 error = 0, inputChanged, initWindow, termWindow, windowResized, windowRedrawNeeded,
39 contentRectChanged, gainedFocus, lostFocus,
40 configChanged, lowMemory, start, resume, saveState, pause, stop, destroy
43 class AndroidPollSource
48 virtual void any_object::process();
51 class AndroidAppGlue : Thread
54 virtual void onAppCmd(AppCommand cmd);
55 virtual int onInputEvent(AInputEvent* event);
58 ANativeActivity* activity;
59 AConfiguration* config;
64 AInputQueue* inputQueue;
65 ANativeWindow* window;
67 AppCommand activityState;
68 bool destroyRequested;
75 int msgread, msgwrite;
79 config = AConfiguration_new();
80 AConfiguration_fromAssetManager(config, activity->assetManager);
84 looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
85 ALooper_addFd(looper, msgread, LooperID::main, ALOOPER_EVENT_INPUT, null, cmdPollSource);
103 AInputQueue_detachLooper(inputQueue);
104 AConfiguration_delete(config);
110 AndroidPollSource cmdPollSource
116 AppCommand cmd = read_cmd();
122 AndroidPollSource inputPollSource
128 AInputEvent* event = null;
129 if(AInputQueue_getEvent(inputQueue, &event) >= 0)
132 LOGV("New input event: type=%d\n", AInputEvent_getType(event));
133 if(AInputQueue_preDispatchEvent(inputQueue, event))
135 handled = onInputEvent(event);
136 //AInputQueue_finishEvent(inputQueue, event, handled);
139 LOGE("Failure reading next input event: %s\n", strerror(errno));
146 AInputQueue* pendingInputQueue;
147 ANativeWindow* pendingWindow;
148 ARect pendingContentRect;
150 void free_saved_state()
160 AppCommand read_cmd()
163 if(read(msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
170 LOGE("No data on command pipe!");
174 void print_cur_config()
176 char lang[2], country[2];
177 AConfiguration_getLanguage(config, lang);
178 AConfiguration_getCountry(config, country);
180 LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
181 "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
182 "modetype=%d modenight=%d",
183 AConfiguration_getMcc(config),
184 AConfiguration_getMnc(config),
185 lang[0], lang[1], country[0], country[1],
186 AConfiguration_getOrientation(config),
187 AConfiguration_getTouchscreen(config),
188 AConfiguration_getDensity(config),
189 AConfiguration_getKeyboard(config),
190 AConfiguration_getNavigation(config),
191 AConfiguration_getKeysHidden(config),
192 AConfiguration_getNavHidden(config),
193 AConfiguration_getSdkVersion(config),
194 AConfiguration_getScreenSize(config),
195 AConfiguration_getScreenLong(config),
196 AConfiguration_getUiModeType(config),
197 AConfiguration_getUiModeNight(config));
200 void pre_exec_cmd(AppCommand cmd)
202 PrintLn("pre_exec_cmd: ", (int)cmd);
208 AInputQueue_detachLooper(inputQueue);
209 inputQueue = pendingInputQueue;
211 AInputQueue_attachLooper(inputQueue, looper, LooperID::input, null, inputPollSource);
217 window = pendingWindow;
234 AConfiguration_fromAssetManager(config, activity->assetManager);
238 destroyRequested = true;
243 void post_exec_cmd(AppCommand cmd)
245 PrintLn("post_exec_cmd: ", (int)cmd);
266 void write_cmd(AppCommand cmd)
268 if(write(msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd))
269 LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
272 void set_input(AInputQueue* inputQueue)
275 pendingInputQueue = inputQueue;
276 write_cmd(inputChanged);
277 while(inputQueue != pendingInputQueue)
282 void set_window(ANativeWindow* window)
286 write_cmd(termWindow);
287 pendingWindow = window;
289 write_cmd(initWindow);
290 while(window != pendingWindow)
295 void set_activity_state(AppCommand cmd)
299 while(activityState != cmd)
315 void setSavedState(void * state, uint size)
322 savedState = malloc(size);
323 savedStateSize = size;
324 memcpy(savedState, state, size);
334 LOGE("could not create pipe: %s", strerror(errno));
335 msgread = msgpipe[0];
336 msgwrite = msgpipe[1];
340 // Wait for thread to start.
342 while(!running) cond.Wait(mutex);
348 static void onDestroy(ANativeActivity* activity)
350 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
351 LOGV("Destroy: %p\n", activity);
354 delete androidActivity;
355 delete __androidCurrentModule;
359 static void onStart(ANativeActivity* activity)
361 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
362 LOGV("Start: %p\n", activity);
363 app.set_activity_state(start);
366 static void onResume(ANativeActivity* activity)
368 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
369 LOGV("Resume: %p\n", activity);
370 app.set_activity_state(resume);
373 static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
375 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
376 void* savedState = null;
377 LOGV("SaveInstanceState: %p\n", activity);
379 app.stateSaved = false;
380 app.write_cmd(saveState);
381 while(!app.stateSaved)
382 app.cond.Wait(app.mutex);
385 savedState = app.savedState;
386 *outLen = app.savedStateSize;
387 app.savedState = null;
388 app.savedStateSize = 0;
394 static void onPause(ANativeActivity* activity)
396 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
397 LOGV("Pause: %p\n", activity);
398 app.set_activity_state(pause);
401 static void onStop(ANativeActivity* activity)
403 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
404 LOGV("Stop: %p\n", activity);
405 app.set_activity_state(stop);
408 static void onConfigurationChanged(ANativeActivity* activity)
410 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
411 LOGV("ConfigurationChanged: %p\n", activity);
412 app.write_cmd(configChanged);
415 static void onLowMemory(ANativeActivity* activity)
417 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
418 LOGV("LowMemory: %p\n", activity);
419 app.write_cmd(lowMemory);
422 static void onWindowFocusChanged(ANativeActivity* activity, int focused)
424 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
425 LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
426 app.write_cmd(focused ? gainedFocus : lostFocus);
429 static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
431 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
432 LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
433 app.set_window(window);
436 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
438 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
439 LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
440 app.set_window(null);
443 static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
445 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
446 LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
447 app.set_input(queue);
450 static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
452 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
453 LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
454 app.inputQueue = null;
458 default dllexport void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
463 // Determine our package name
464 JNIEnv* env=activity->env;
471 // *** Reinitialize static global variables ***
473 guiApplicationInitialized = false;
475 desktopW = 0; desktopH = 0;
476 clipBoardData = null;
478 __androidCurrentModule = null;
480 LOGV("Creating: %p\n", activity);
482 //(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);
483 clazz = (*env)->GetObjectClass(env, activity->clazz);
484 methodID = (*env)->GetMethodID(env, clazz, "getPackageName", "()Ljava/lang/String;");
485 result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
486 str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
487 // (*activity->vm)->DetachCurrentThread(activity->vm);
488 moduleName = strstr(str, "com.ecere.");
489 if(moduleName) moduleName += 10;
490 androidArgv[0] = moduleName;
492 // Create a base Application class
493 __androidCurrentModule = __ecere_COM_Initialize(true, 1, androidArgv);
495 eModule_Load(__androidCurrentModule, "ecere", publicAccess);
498 if(activity->internalDataPath) PrintLn("internalDataPath is ", activity->internalDataPath);
499 if(activity->externalDataPath) PrintLn("externalDataPath is ", activity->externalDataPath);
502 PrintLn("cwd is ", GetWorkingDir(tmp, sizeof(tmp)));
505 ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON, 0 );
506 app = AndroidActivity { activity = activity, moduleName = moduleName };
508 app.setSavedState(savedState, savedStateSize);
509 activity->callbacks->onDestroy = onDestroy;
510 activity->callbacks->onStart = onStart;
511 activity->callbacks->onResume = onResume;
512 activity->callbacks->onSaveInstanceState = onSaveInstanceState;
513 activity->callbacks->onPause = onPause;
514 activity->callbacks->onStop = onStop;
515 activity->callbacks->onConfigurationChanged = onConfigurationChanged;
516 activity->callbacks->onLowMemory = onLowMemory;
517 activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
518 activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
519 activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
520 activity->callbacks->onInputQueueCreated = onInputQueueCreated;
521 activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
522 activity->instance = app;
526 // *** END OF NATIVE APP GLUE ******
529 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
530 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
531 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
532 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
533 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
534 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
535 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
536 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
537 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
538 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
539 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
540 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
541 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
542 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
545 static Module __androidCurrentModule;
546 static char * androidArgv[1];
548 static int desktopW, desktopH;
549 static char * clipBoardData;
550 static int mouseX, mouseY;
552 class AndroidInterface : Interface
554 class_property(name) = "Android";
556 // --- User Interface System ---
559 setlocale(LC_ALL, "en_US.UTF-8");
568 #define DBLCLICK_DELAY 300 // 0.3 second
569 #define DBLCLICK_DELTA 1
571 bool ProcessInput(bool processAll)
573 bool eventAvailable = false;
575 if(androidActivity.ident < 0)
576 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
577 while(androidActivity.ident >= 0)
579 AndroidPollSource source = androidActivity.source;
581 androidActivity.source = null;
583 source.process(source.userData);
585 // If a sensor has data, process it now.
587 if(androidActivity.ident == user)
589 if(androidActivity.accelerometerSensor)
592 while (ASensorEventQueue_getEvents(androidActivity.sensorEventQueue, &event, 1) > 0)
593 LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z);
597 if(gotInit && androidActivity.window)
599 int w = ANativeWindow_getWidth(androidActivity.window);
600 int h = ANativeWindow_getHeight(androidActivity.window);
601 if(desktopW != w || desktopH != h)
603 guiApp.SetDesktopPosition(0, 0, w, h, true);
606 guiApp.desktop.Update(null);
610 eventAvailable = true;
611 if(androidActivity.destroyRequested)
613 guiApp.desktop.Destroy(0);
614 eventAvailable = true;
615 androidActivity.ident = (LooperID)-1;
618 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
620 androidActivity.ident = (LooperID)-1;
622 return eventAvailable;
627 androidActivity.ident = (LooperID)ALooper_pollAll((int)(1000/18.2f), null, &androidActivity.events, (void**)&androidActivity.source);
628 // guiApp.WaitEvent();
631 void Lock(Window window)
636 void Unlock(Window window)
641 char ** GraphicsDrivers(int * numDrivers)
643 static char *graphicsDrivers[] = { "OpenGL" };
644 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
645 return (char **)graphicsDrivers;
648 void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
653 void EnsureFullScreen(bool *fullScreen)
658 bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
665 // --- Window Creation ---
666 void * CreateRootWindow(Window window)
668 return androidActivity.window;
671 void DestroyRootWindow(Window window)
676 // -- Window manipulation ---
678 void SetRootWindowCaption(Window window, char * name)
683 void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
688 void OrderRootWindow(Window window, bool topMost)
693 void SetRootWindowColor(Window window)
698 void OffsetWindow(Window window, int * x, int * y)
703 void UpdateRootWindow(Window window)
705 if(!window.parent || !window.parent.display)
709 Box box = window.box;
710 box.left -= window.clientStart.x;
711 box.top -= window.clientStart.y;
712 box.right -= window.clientStart.x;
713 box.bottom -= window.clientStart.y;
714 // Logf("Update root window %s\n", window.name);
716 box.left += window.clientStart.x;
717 box.top += window.clientStart.y;
718 box.right += window.clientStart.x;
719 box.bottom += window.clientStart.y;
720 window.UpdateDirty(box);
726 void SetRootWindowState(Window window, WindowState state, bool visible)
730 void FlashRootWindow(Window window)
735 void ActivateRootWindow(Window window)
740 // --- Mouse-based window movement ---
742 void StartMoving(Window window, int x, int y, bool fromKeyBoard)
747 void StopMoving(Window window)
752 // -- Mouse manipulation ---
754 void GetMousePosition(int *x, int *y)
756 int rootWindow, childWindow;
764 void SetMousePosition(int x, int y)
770 void SetMouseRange(Window window, Box box)
774 void SetMouseCapture(Window window)
778 // -- Mouse cursor ---
780 void SetMouseCursor(int cursor)
790 void SetCaret(int x, int y, int size)
792 Window caretOwner = guiApp.caretOwner;
793 Window window = caretOwner ? caretOwner.rootWindow : null;
794 if(window && window.windowData)
799 void ClearClipboard()
803 delete clipBoardData;
807 bool AllocateClipboard(ClipBoard clipBoard, uint size)
810 if((clipBoard.text = new0 byte[size]))
815 bool SaveClipboard(ClipBoard clipBoard)
821 delete clipBoardData;
823 clipBoardData = clipBoard.text;
824 clipBoard.text = null;
830 bool LoadClipboard(ClipBoard clipBoard)
834 // The data is inside this client...
837 clipBoard.text = new char[strlen(clipBoardData)+1];
838 strcpy(clipBoard.text, clipBoardData);
841 // The data is with another client...
848 void UnloadClipboard(ClipBoard clipBoard)
850 delete clipBoard.text;
853 // --- State based input ---
855 bool AcquireInput(Window window, bool state)
860 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
868 bool GetJoystickState(int device, Joystick joystick)
874 bool GetKeyState(Key key)
880 void SetTimerResolution(uint hertz)
882 // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
885 bool SetIcon(Window window, BitmapResource resource)
890 if(bitmap.Load(resource.fileName, null, null))
906 static AndroidActivity androidActivity;
908 default const char * AndroidInterface_GetLibLocation()
912 static char loc[MAX_LOCATION];
913 sprintf(loc, "/data/data/com.ecere.%s/lib/lib", androidActivity.moduleName);
921 default float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
922 int32_t axis, size_t pointer_index);
925 static define AMETA_META_ON = 0x00010000;
926 static define AMETA_META_LEFT_ON = 0x00020000;
927 static define AMETA_META_RIGHT_ON = 0x00040000;
929 static Key keyCodeTable[] =
931 0, //AKEYCODE_UNKNOWN = 0,
932 0, //AKEYCODE_SOFT_LEFT = 1,
933 0, //AKEYCODE_SOFT_RIGHT = 2,
934 0, //AKEYCODE_HOME = 3,
935 0, //AKEYCODE_BACK = 4,
936 0, //AKEYCODE_CALL = 5,
937 0, //AKEYCODE_ENDCALL = 6,
938 k0, //AKEYCODE_0 = 7,
939 k1, //AKEYCODE_1 = 8,
940 k2, //AKEYCODE_2 = 9,
941 k3, //AKEYCODE_3 = 10,
942 k4, //AKEYCODE_4 = 11,
943 k5, //AKEYCODE_5 = 12,
944 k6, //AKEYCODE_6 = 13,
945 k7, //AKEYCODE_7 = 14,
946 k8, //AKEYCODE_8 = 15,
947 k9, //AKEYCODE_9 = 16,
948 keyPadStar, //AKEYCODE_STAR = 17,
949 Key { k3, shift = true }, //AKEYCODE_POUND = 18,
950 up, //AKEYCODE_DPAD_UP = 19,
951 down, //AKEYCODE_DPAD_DOWN = 20,
952 left, //AKEYCODE_DPAD_LEFT = 21,
953 right, //AKEYCODE_DPAD_RIGHT = 22,
954 keyPad5, //AKEYCODE_DPAD_CENTER = 23,
955 0, //AKEYCODE_VOLUME_UP = 24,
956 0, //AKEYCODE_VOLUME_DOWN = 25,
957 0, //AKEYCODE_POWER = 26,
958 0, //AKEYCODE_CAMERA = 27,
959 0, //AKEYCODE_CLEAR = 28,
960 a, //AKEYCODE_A = 29,
961 b, //AKEYCODE_B = 30,
962 c, //AKEYCODE_C = 31,
963 d, //AKEYCODE_D = 32,
964 e, //AKEYCODE_E = 33,
965 f, //AKEYCODE_F = 34,
966 g, //AKEYCODE_G = 35,
967 h, //AKEYCODE_H = 36,
968 i, //AKEYCODE_I = 37,
969 j, //AKEYCODE_J = 38,
970 k, //AKEYCODE_K = 39,
971 l, //AKEYCODE_L = 40,
972 m, //AKEYCODE_M = 41,
973 n, //AKEYCODE_N = 42,
974 o, //AKEYCODE_O = 43,
975 p, //AKEYCODE_P = 44,
976 q, //AKEYCODE_Q = 45,
977 r, //AKEYCODE_R = 46,
978 s, //AKEYCODE_S = 47,
979 t, //AKEYCODE_T = 48,
980 u, //AKEYCODE_U = 49,
981 v, //AKEYCODE_V = 50,
982 w, //AKEYCODE_W = 51,
983 x, //AKEYCODE_X = 52,
984 y, //AKEYCODE_Y = 53,
985 z, //AKEYCODE_Z = 54,
986 comma, //AKEYCODE_COMMA = 55,
987 period, //AKEYCODE_PERIOD = 56,
988 leftAlt, //AKEYCODE_ALT_LEFT = 57,
989 rightAlt, //AKEYCODE_ALT_RIGHT = 58,
990 leftShift, //AKEYCODE_SHIFT_LEFT = 59,
991 rightShift, //AKEYCODE_SHIFT_RIGHT = 60,
992 tab, //AKEYCODE_TAB = 61,
993 space, //AKEYCODE_SPACE = 62,
994 0, //AKEYCODE_SYM = 63,
995 0, //AKEYCODE_EXPLORER = 64,
996 0, //AKEYCODE_ENVELOPE = 65,
997 enter, //AKEYCODE_ENTER = 66,
998 backSpace, //AKEYCODE_DEL = 67,
999 backQuote, //AKEYCODE_GRAVE = 68,
1000 minus, //AKEYCODE_MINUS = 69,
1001 plus, //AKEYCODE_EQUALS = 70,
1002 leftBracket, //AKEYCODE_LEFT_BRACKET = 71,
1003 rightBracket, //AKEYCODE_RIGHT_BRACKET = 72,
1004 backSlash, //AKEYCODE_BACKSLASH = 73,
1005 semicolon, //AKEYCODE_SEMICOLON = 74,
1006 quote, //AKEYCODE_APOSTROPHE = 75,
1007 slash, //AKEYCODE_SLASH = 76,
1008 Key { k2, shift = true }, //AKEYCODE_AT = 77,
1009 0, //AKEYCODE_NUM = 78, // Interpreted as an Alt
1010 0, //AKEYCODE_HEADSETHOOK = 79,
1011 0, //AKEYCODE_FOCUS = 80, // *Camera* focus
1012 keyPadPlus, //AKEYCODE_PLUS = 81,
1013 0, //AKEYCODE_MENU = 82,
1014 0, //AKEYCODE_NOTIFICATION = 83,
1015 0, //AKEYCODE_SEARCH = 84,
1016 0, //AKEYCODE_MEDIA_PLAY_PAUSE= 85,
1017 0, //AKEYCODE_MEDIA_STOP = 86,
1018 0, //AKEYCODE_MEDIA_NEXT = 87,
1019 0, //AKEYCODE_MEDIA_PREVIOUS = 88,
1020 0, //AKEYCODE_MEDIA_REWIND = 89,
1021 0, //AKEYCODE_MEDIA_FAST_FORWARD = 90,
1022 0, //AKEYCODE_MUTE = 91,
1023 0, //AKEYCODE_PAGE_UP = 92,
1024 0, //AKEYCODE_PAGE_DOWN = 93,
1025 0, //AKEYCODE_PICTSYMBOLS = 94,
1026 0, //AKEYCODE_SWITCH_CHARSET = 95,
1027 0, //AKEYCODE_BUTTON_A = 96,
1028 0, //AKEYCODE_BUTTON_B = 97,
1029 0, //AKEYCODE_BUTTON_C = 98,
1030 0, //AKEYCODE_BUTTON_X = 99,
1031 0, //AKEYCODE_BUTTON_Y = 100,
1032 0, //AKEYCODE_BUTTON_Z = 101,
1033 0, //AKEYCODE_BUTTON_L1 = 102,
1034 0, //AKEYCODE_BUTTON_R1 = 103,
1035 0, //AKEYCODE_BUTTON_L2 = 104,
1036 0, //AKEYCODE_BUTTON_R2 = 105,
1037 0, //AKEYCODE_BUTTON_THUMBL = 106,
1038 0, //AKEYCODE_BUTTON_THUMBR = 107,
1039 0, //AKEYCODE_BUTTON_START = 108,
1040 0, //AKEYCODE_BUTTON_SELECT = 109,
1041 0, //AKEYCODE_BUTTON_MODE = 110,
1042 escape, //AKEYCODE_BUTTON_ESCAPE = 111,
1043 del //AKEYCODE_BUTTON_ESCAPE = 112,
1044 leftControl, // = 113
1045 rightControl, // = 114
1047 scrollLock, // = 116
1048 0, // = 117 KEYCODE_META_LEFT
1049 0, // = 118 KEYCODE_META_RIGHT
1050 0, // = 119 KEYCODE_FUNCTION
1051 printScreen, // = 120 KEYCODE_SYSRQ
1052 pauseBreak, // = 121
1058 // Why don't we have this in the NDK :(
1059 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
1061 class AndroidActivity : AndroidAppGlue
1063 AndroidPollSource source;
1067 ASensorManager* sensorManager;
1068 const ASensor* accelerometerSensor;
1069 ASensorEventQueue* sensorEventQueue;
1073 int onInputEvent(AInputEvent* event)
1075 Window window = guiApp.desktop;
1076 uint type = AInputEvent_getType(event);
1077 if(type == AINPUT_EVENT_TYPE_MOTION)
1079 uint actionAndIndex = AMotionEvent_getAction(event);
1080 uint source = AInputEvent_getSource(event);
1081 uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
1082 uint index = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
1083 uint flags = AMotionEvent_getFlags(event);
1084 uint meta = AMotionEvent_getMetaState(event);
1085 uint edge = AMotionEvent_getEdgeFlags(event);
1086 int64 downTime = AMotionEvent_getDownTime(event); // nanotime
1087 int64 eventTime = AMotionEvent_getDownTime(event);
1089 Modifiers keyFlags = 0;
1090 int x = (int)AMotionEvent_getX(event, 0);
1091 int y = (int)AMotionEvent_getY(event, 0);
1092 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1093 bool alt = (meta & AMETA_ALT_ON) ? true : false;
1094 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1096 keyFlags.shift = shift;
1099 //PrintLn("Got a motion input event: ", action);
1101 if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
1102 axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
1105 AInputQueue_finishEvent(inputQueue, event, 1);
1109 case 8: //AMOTION_EVENT_ACTION_SCROLL:
1110 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (axis < 0) ? wheelUp : wheelDown, 0);
1113 case AMOTION_EVENT_ACTION_DOWN:
1114 mouseX = x, mouseY = y;
1115 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
1117 case AMOTION_EVENT_ACTION_UP:
1118 mouseX = x, mouseY = y;
1119 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true);
1121 case AMOTION_EVENT_ACTION_MOVE:
1122 mouseX = x, mouseY = y;
1123 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true);
1125 case AMOTION_EVENT_ACTION_CANCEL: break;
1126 case AMOTION_EVENT_ACTION_OUTSIDE: break;
1127 case AMOTION_EVENT_ACTION_POINTER_DOWN: break;
1128 case AMOTION_EVENT_ACTION_POINTER_UP: break;
1132 else if(type == AINPUT_EVENT_TYPE_KEY)
1134 uint action = AKeyEvent_getAction(event);
1135 uint flags = AKeyEvent_getFlags(event);
1136 uint keyCode = AKeyEvent_getKeyCode(event);
1137 uint meta = AKeyEvent_getMetaState(event);
1138 Key key = keyCodeTable[keyCode];
1139 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1140 bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
1141 bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
1142 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1143 //unichar ch = AKeyEvent_getUnichar(event);
1149 AInputQueue_finishEvent(inputQueue, event, 1);
1151 // PrintLn("Got a key: action = ", action, ", flags = ", flags, ", keyCode = ", keyCode, ", meta = ", meta, ": key = ", (int)key);
1155 if(action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_MULTIPLE)
1157 /*if(key == wheelDown || key == wheelUp)
1158 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1161 char c = Interface::TranslateKey(key.code, shift);
1163 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, ch);
1166 else if(action == AKEY_EVENT_ACTION_UP)
1167 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, ch);
1172 AInputQueue_finishEvent(inputQueue, event, 0);
1176 void onAppCmd(AppCommand cmd)
1181 setSavedState(&state, sizeof(state));
1188 ANativeWindow_setBuffersGeometry(window, 0, 0, 0); //format);
1189 w = ANativeWindow_getWidth(window);
1190 h = ANativeWindow_getHeight(window);
1191 guiApp.Initialize(false);
1192 guiApp.desktop.windowHandle = window;
1193 guiApp.interfaceDriver = null;
1194 guiApp.SwitchMode(true, null, 0, 0, 0, null, false);
1196 if(desktopW != w || desktopH != h)
1198 guiApp.SetDesktopPosition(0, 0, w, h, true);
1202 guiApp.desktop.Update(null);
1206 guiApp.desktop.UnloadGraphics(false);
1209 guiApp.desktop.Update(null);
1210 guiApp.SetAppFocus(true);
1212 if(accelerometerSensor)
1214 ASensorEventQueue_enableSensor(sensorEventQueue, accelerometerSensor);
1215 ASensorEventQueue_setEventRate(sensorEventQueue, accelerometerSensor, (1000L/60)*1000);
1221 if(accelerometerSensor)
1222 ASensorEventQueue_disableSensor(sensorEventQueue, accelerometerSensor);
1224 guiApp.SetAppFocus(false);
1225 guiApp.desktop.Update(null);
1229 guiApp.desktop.UpdateDisplay();
1236 androidActivity = this;
1237 /* Let's have fun with sensors when we have an actual device to play with
1238 sensorManager = ASensorManager_getInstance();
1239 accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
1240 sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LooperID::user, null, null);
1244 state = *(SavedState*)savedState;
1249 // Evolve the Application class into a GuiApplication
1250 eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
1252 // Wait for the initWindow command:
1253 guiApp.interfaceDriver = class(AndroidInterface);
1256 // Can't call the GuiApplication here, because GuiApplication::Initialize() has not been called yet
1257 guiApp.interfaceDriver.Wait();
1258 guiApp.interfaceDriver.ProcessInput(true);
1261 // Invoke __ecereDll_Load() in lib[our package name].so
1262 app = eModule_Load(__androidCurrentModule, moduleName, publicAccess);
1266 // Find out if any GuiApplication class was defined in our module
1267 for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
1268 if(!c) c = class(GuiApplication);
1270 // Evolve the Application into it
1271 eInstance_Evolve((Instance *)&__androidCurrentModule, c);
1272 guiApp = (GuiApplication)__androidCurrentModule;
1275 String skin = guiApp.skin;
1276 *&guiApp.currentSkin = null;
1277 guiApp.SelectSkin(skin);
1281 ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
1284 if(!destroyRequested)
1285 ANativeActivity_finish(activity);
1286 while(!destroyRequested)
1288 guiApp.interfaceDriver.Wait();
1289 guiApp.interfaceDriver.ProcessInput(true);