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: ", 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: ", 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);
578 if(gotInit && androidActivity.window)
580 int w = ANativeWindow_getWidth(androidActivity.window);
581 int h = ANativeWindow_getHeight(androidActivity.window);
582 if(desktopW != w || desktopH != h)
584 guiApp.SetDesktopPosition(0, 0, w, h, true);
587 guiApp.desktop.Update(null);
591 while(androidActivity.ident >= 0)
593 AndroidPollSource source = androidActivity.source;
595 androidActivity.source = null;
597 source.process(source.userData);
599 // If a sensor has data, process it now.
601 if(androidActivity.ident == user)
603 if(androidActivity.accelerometerSensor)
606 while (ASensorEventQueue_getEvents(androidActivity.sensorEventQueue, &event, 1) > 0)
607 LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z);
612 eventAvailable = true;
613 if(androidActivity.destroyRequested)
615 guiApp.desktop.Destroy(0);
616 eventAvailable = true;
617 androidActivity.ident = (LooperID)-1;
620 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
622 androidActivity.ident = (LooperID)-1;
624 return eventAvailable;
629 androidActivity.ident = (LooperID)ALooper_pollAll((int)(1000/18.2f), null, &androidActivity.events, (void**)&androidActivity.source);
630 // guiApp.WaitEvent();
633 void Lock(Window window)
638 void Unlock(Window window)
643 const char ** GraphicsDrivers(int * numDrivers)
645 static const char *graphicsDrivers[] = { "OpenGL" };
646 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
647 return (const char **)graphicsDrivers;
650 void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
655 void EnsureFullScreen(bool *fullScreen)
660 bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
667 // --- Window Creation ---
668 void * CreateRootWindow(Window window)
670 return androidActivity.window;
673 void DestroyRootWindow(Window window)
678 // -- Window manipulation ---
680 void SetRootWindowCaption(Window window, const char * name)
685 void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
690 void OrderRootWindow(Window window, bool topMost)
695 void SetRootWindowColor(Window window)
700 void OffsetWindow(Window window, int * x, int * y)
705 void UpdateRootWindow(Window window)
707 if(!window.parent || !window.parent.display)
711 Box box = window.box;
712 box.left -= window.clientStart.x;
713 box.top -= window.clientStart.y;
714 box.right -= window.clientStart.x;
715 box.bottom -= window.clientStart.y;
716 // Logf("Update root window %s\n", window.name);
718 box.left += window.clientStart.x;
719 box.top += window.clientStart.y;
720 box.right += window.clientStart.x;
721 box.bottom += window.clientStart.y;
722 window.UpdateDirty(box);
728 void SetRootWindowState(Window window, WindowState state, bool visible)
732 void FlashRootWindow(Window window)
737 void ActivateRootWindow(Window window)
742 // --- Mouse-based window movement ---
744 void StartMoving(Window window, int x, int y, bool fromKeyBoard)
749 void StopMoving(Window window)
754 // -- Mouse manipulation ---
756 void GetMousePosition(int *x, int *y)
762 void SetMousePosition(int x, int y)
768 void SetMouseRange(Window window, Box box)
772 void SetMouseCapture(Window window)
776 // -- Mouse cursor ---
778 void SetMouseCursor(Window window, int cursor)
788 void SetCaret(int x, int y, int size)
790 Window caretOwner = guiApp.caretOwner;
791 Window window = caretOwner ? caretOwner.rootWindow : null;
792 if(window && window.windowData)
797 void ClearClipboard()
801 delete clipBoardData;
805 bool AllocateClipboard(ClipBoard clipBoard, uint size)
808 if((clipBoard.text = new0 byte[size]))
813 bool SaveClipboard(ClipBoard clipBoard)
819 delete clipBoardData;
821 clipBoardData = clipBoard.text;
822 clipBoard.text = null;
828 bool LoadClipboard(ClipBoard clipBoard)
832 // The data is inside this client...
835 clipBoard.text = new char[strlen(clipBoardData)+1];
836 strcpy(clipBoard.text, clipBoardData);
839 // The data is with another client...
846 void UnloadClipboard(ClipBoard clipBoard)
848 delete clipBoard.text;
851 // --- State based input ---
853 bool AcquireInput(Window window, bool state)
858 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
866 bool GetJoystickState(int device, Joystick joystick)
872 bool GetKeyState(Key key)
874 bool keyState = false;
878 void SetTimerResolution(uint hertz)
880 // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
883 bool SetIcon(Window window, BitmapResource resource)
888 if(bitmap.Load(resource.fileName, null, null))
904 static AndroidActivity androidActivity;
906 default const char * AndroidInterface_GetLibLocation()
910 static char loc[MAX_LOCATION];
911 sprintf(loc, "/data/data/com.ecere.%s/lib/lib", androidActivity.moduleName);
919 default float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
920 int32_t axis, size_t pointer_index);
923 static define AMETA_META_ON = 0x00010000;
924 static define AMETA_META_LEFT_ON = 0x00020000;
925 static define AMETA_META_RIGHT_ON = 0x00040000;
927 static Key keyCodeTable[] =
929 0, //AKEYCODE_UNKNOWN = 0,
930 0, //AKEYCODE_SOFT_LEFT = 1,
931 0, //AKEYCODE_SOFT_RIGHT = 2,
932 0, //AKEYCODE_HOME = 3,
933 0, //AKEYCODE_BACK = 4,
934 0, //AKEYCODE_CALL = 5,
935 0, //AKEYCODE_ENDCALL = 6,
936 k0, //AKEYCODE_0 = 7,
937 k1, //AKEYCODE_1 = 8,
938 k2, //AKEYCODE_2 = 9,
939 k3, //AKEYCODE_3 = 10,
940 k4, //AKEYCODE_4 = 11,
941 k5, //AKEYCODE_5 = 12,
942 k6, //AKEYCODE_6 = 13,
943 k7, //AKEYCODE_7 = 14,
944 k8, //AKEYCODE_8 = 15,
945 k9, //AKEYCODE_9 = 16,
946 keyPadStar, //AKEYCODE_STAR = 17,
947 Key { k3, shift = true }, //AKEYCODE_POUND = 18,
948 up, //AKEYCODE_DPAD_UP = 19,
949 down, //AKEYCODE_DPAD_DOWN = 20,
950 left, //AKEYCODE_DPAD_LEFT = 21,
951 right, //AKEYCODE_DPAD_RIGHT = 22,
952 keyPad5, //AKEYCODE_DPAD_CENTER = 23,
953 0, //AKEYCODE_VOLUME_UP = 24,
954 0, //AKEYCODE_VOLUME_DOWN = 25,
955 0, //AKEYCODE_POWER = 26,
956 0, //AKEYCODE_CAMERA = 27,
957 0, //AKEYCODE_CLEAR = 28,
958 a, //AKEYCODE_A = 29,
959 b, //AKEYCODE_B = 30,
960 c, //AKEYCODE_C = 31,
961 d, //AKEYCODE_D = 32,
962 e, //AKEYCODE_E = 33,
963 f, //AKEYCODE_F = 34,
964 g, //AKEYCODE_G = 35,
965 h, //AKEYCODE_H = 36,
966 i, //AKEYCODE_I = 37,
967 j, //AKEYCODE_J = 38,
968 k, //AKEYCODE_K = 39,
969 l, //AKEYCODE_L = 40,
970 m, //AKEYCODE_M = 41,
971 n, //AKEYCODE_N = 42,
972 o, //AKEYCODE_O = 43,
973 p, //AKEYCODE_P = 44,
974 q, //AKEYCODE_Q = 45,
975 r, //AKEYCODE_R = 46,
976 s, //AKEYCODE_S = 47,
977 t, //AKEYCODE_T = 48,
978 u, //AKEYCODE_U = 49,
979 v, //AKEYCODE_V = 50,
980 w, //AKEYCODE_W = 51,
981 x, //AKEYCODE_X = 52,
982 y, //AKEYCODE_Y = 53,
983 z, //AKEYCODE_Z = 54,
984 comma, //AKEYCODE_COMMA = 55,
985 period, //AKEYCODE_PERIOD = 56,
986 leftAlt, //AKEYCODE_ALT_LEFT = 57,
987 rightAlt, //AKEYCODE_ALT_RIGHT = 58,
988 leftShift, //AKEYCODE_SHIFT_LEFT = 59,
989 rightShift, //AKEYCODE_SHIFT_RIGHT = 60,
990 tab, //AKEYCODE_TAB = 61,
991 space, //AKEYCODE_SPACE = 62,
992 0, //AKEYCODE_SYM = 63,
993 0, //AKEYCODE_EXPLORER = 64,
994 0, //AKEYCODE_ENVELOPE = 65,
995 enter, //AKEYCODE_ENTER = 66,
996 backSpace, //AKEYCODE_DEL = 67,
997 backQuote, //AKEYCODE_GRAVE = 68,
998 minus, //AKEYCODE_MINUS = 69,
999 plus, //AKEYCODE_EQUALS = 70,
1000 leftBracket, //AKEYCODE_LEFT_BRACKET = 71,
1001 rightBracket, //AKEYCODE_RIGHT_BRACKET = 72,
1002 backSlash, //AKEYCODE_BACKSLASH = 73,
1003 semicolon, //AKEYCODE_SEMICOLON = 74,
1004 quote, //AKEYCODE_APOSTROPHE = 75,
1005 slash, //AKEYCODE_SLASH = 76,
1006 Key { k2, shift = true }, //AKEYCODE_AT = 77,
1007 0, //AKEYCODE_NUM = 78, // Interpreted as an Alt
1008 0, //AKEYCODE_HEADSETHOOK = 79,
1009 0, //AKEYCODE_FOCUS = 80, // *Camera* focus
1010 keyPadPlus, //AKEYCODE_PLUS = 81,
1011 0, //AKEYCODE_MENU = 82,
1012 0, //AKEYCODE_NOTIFICATION = 83,
1013 0, //AKEYCODE_SEARCH = 84,
1014 0, //AKEYCODE_MEDIA_PLAY_PAUSE= 85,
1015 0, //AKEYCODE_MEDIA_STOP = 86,
1016 0, //AKEYCODE_MEDIA_NEXT = 87,
1017 0, //AKEYCODE_MEDIA_PREVIOUS = 88,
1018 0, //AKEYCODE_MEDIA_REWIND = 89,
1019 0, //AKEYCODE_MEDIA_FAST_FORWARD = 90,
1020 0, //AKEYCODE_MUTE = 91,
1021 0, //AKEYCODE_PAGE_UP = 92,
1022 0, //AKEYCODE_PAGE_DOWN = 93,
1023 0, //AKEYCODE_PICTSYMBOLS = 94,
1024 0, //AKEYCODE_SWITCH_CHARSET = 95,
1025 0, //AKEYCODE_BUTTON_A = 96,
1026 0, //AKEYCODE_BUTTON_B = 97,
1027 0, //AKEYCODE_BUTTON_C = 98,
1028 0, //AKEYCODE_BUTTON_X = 99,
1029 0, //AKEYCODE_BUTTON_Y = 100,
1030 0, //AKEYCODE_BUTTON_Z = 101,
1031 0, //AKEYCODE_BUTTON_L1 = 102,
1032 0, //AKEYCODE_BUTTON_R1 = 103,
1033 0, //AKEYCODE_BUTTON_L2 = 104,
1034 0, //AKEYCODE_BUTTON_R2 = 105,
1035 0, //AKEYCODE_BUTTON_THUMBL = 106,
1036 0, //AKEYCODE_BUTTON_THUMBR = 107,
1037 0, //AKEYCODE_BUTTON_START = 108,
1038 0, //AKEYCODE_BUTTON_SELECT = 109,
1039 0, //AKEYCODE_BUTTON_MODE = 110,
1040 escape, //AKEYCODE_BUTTON_ESCAPE = 111,
1041 del, //AKEYCODE_BUTTON_ESCAPE = 112,
1042 leftControl, // = 113
1043 rightControl, // = 114
1045 scrollLock, // = 116
1046 0, // = 117 KEYCODE_META_LEFT
1047 0, // = 118 KEYCODE_META_RIGHT
1048 0, // = 119 KEYCODE_FUNCTION
1049 printScreen, // = 120 KEYCODE_SYSRQ
1050 pauseBreak, // = 121
1056 // Why don't we have this in the NDK :(
1057 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
1059 class AndroidActivity : AndroidAppGlue
1061 AndroidPollSource source;
1065 ASensorManager* sensorManager;
1066 const ASensor* accelerometerSensor;
1067 ASensorEventQueue* sensorEventQueue;
1071 int onInputEvent(AInputEvent* event)
1073 Window window = guiApp.desktop;
1074 uint type = AInputEvent_getType(event);
1075 if(type == AINPUT_EVENT_TYPE_MOTION)
1077 uint actionAndIndex = AMotionEvent_getAction(event);
1078 //uint source = AInputEvent_getSource(event);
1079 uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
1080 //uint index = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
1081 //uint flags = AMotionEvent_getFlags(event);
1082 uint meta = AMotionEvent_getMetaState(event);
1083 //uint edge = AMotionEvent_getEdgeFlags(event);
1084 //int64 downTime = AMotionEvent_getDownTime(event); // nanotime
1085 //int64 eventTime = AMotionEvent_getDownTime(event);
1087 Modifiers keyFlags = 0;
1088 int x = (int)AMotionEvent_getX(event, 0);
1089 int y = (int)AMotionEvent_getY(event, 0);
1090 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1091 bool alt = (meta & AMETA_ALT_ON) ? true : false;
1092 //bool sym = (meta & AMETA_SYM_ON) ? true : false;
1094 keyFlags.shift = shift;
1097 //PrintLn("Got a motion input event: ", action);
1099 if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
1100 axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
1103 AInputQueue_finishEvent(inputQueue, event, 1);
1107 case 8: //AMOTION_EVENT_ACTION_SCROLL:
1108 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (axis < 0) ? wheelUp : wheelDown, 0);
1111 case AMOTION_EVENT_ACTION_DOWN:
1112 mouseX = x, mouseY = y;
1113 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
1115 case AMOTION_EVENT_ACTION_UP:
1116 mouseX = x, mouseY = y;
1117 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true);
1119 case AMOTION_EVENT_ACTION_MOVE:
1120 mouseX = x, mouseY = y;
1121 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true);
1123 case AMOTION_EVENT_ACTION_CANCEL: break;
1124 case AMOTION_EVENT_ACTION_OUTSIDE: break;
1125 case AMOTION_EVENT_ACTION_POINTER_DOWN: break;
1126 case AMOTION_EVENT_ACTION_POINTER_UP: break;
1130 else if(type == AINPUT_EVENT_TYPE_KEY)
1132 uint action = AKeyEvent_getAction(event);
1133 //uint flags = AKeyEvent_getFlags(event);
1134 uint keyCode = AKeyEvent_getKeyCode(event);
1135 uint meta = AKeyEvent_getMetaState(event);
1136 Key key = keyCodeTable[keyCode];
1137 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1138 bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
1139 //bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
1140 //bool sym = (meta & AMETA_SYM_ON) ? true : false;
1141 //unichar ch = AKeyEvent_getUnichar(event);
1147 AInputQueue_finishEvent(inputQueue, event, 1);
1149 // PrintLn("Got a key: action = ", action, ", flags = ", flags, ", keyCode = ", keyCode, ", meta = ", meta, ": key = ", (int)key);
1153 if(action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_MULTIPLE)
1155 /*if(key == wheelDown || key == wheelUp)
1156 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1159 char c = Interface::TranslateKey(key.code, shift);
1161 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, ch);
1164 else if(action == AKEY_EVENT_ACTION_UP)
1165 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, ch);
1170 AInputQueue_finishEvent(inputQueue, event, 0);
1174 void onAppCmd(AppCommand cmd)
1179 setSavedState(&state, sizeof(state));
1186 ANativeWindow_setBuffersGeometry(window, 0, 0, 0); //format);
1187 w = ANativeWindow_getWidth(window);
1188 h = ANativeWindow_getHeight(window);
1189 guiApp.Initialize(false);
1190 guiApp.desktop.windowHandle = window;
1191 guiApp.interfaceDriver = null;
1192 guiApp.SwitchMode(true, null, 0, 0, 0, null, false);
1194 if(desktopW != w || desktopH != h)
1196 guiApp.SetDesktopPosition(0, 0, w, h, true);
1200 guiApp.desktop.Update(null);
1204 guiApp.desktop.UnloadGraphics(false);
1207 guiApp.desktop.Update(null);
1208 guiApp.SetAppFocus(true);
1210 if(accelerometerSensor)
1212 ASensorEventQueue_enableSensor(sensorEventQueue, accelerometerSensor);
1213 ASensorEventQueue_setEventRate(sensorEventQueue, accelerometerSensor, (1000L/60)*1000);
1219 if(accelerometerSensor)
1220 ASensorEventQueue_disableSensor(sensorEventQueue, accelerometerSensor);
1222 guiApp.SetAppFocus(false);
1223 guiApp.desktop.Update(null);
1227 guiApp.desktop.UpdateDisplay();
1234 androidActivity = this;
1235 /* Let's have fun with sensors when we have an actual device to play with
1236 sensorManager = ASensorManager_getInstance();
1237 accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
1238 sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LooperID::user, null, null);
1242 state = *(SavedState*)savedState;
1247 // Evolve the Application class into a GuiApplication
1248 eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
1250 // Wait for the initWindow command:
1251 guiApp.interfaceDriver = class(AndroidInterface);
1254 // Can't call the GuiApplication here, because GuiApplication::Initialize() has not been called yet
1255 guiApp.interfaceDriver.Wait();
1256 guiApp.interfaceDriver.ProcessInput(true);
1259 // Invoke __ecereDll_Load() in lib[our package name].so
1260 app = eModule_Load(__androidCurrentModule, moduleName, publicAccess);
1264 // Find out if any GuiApplication class was defined in our module
1265 for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
1266 if(!c) c = class(GuiApplication);
1268 // Evolve the Application into it
1269 eInstance_Evolve((Instance *)&__androidCurrentModule, c);
1270 guiApp = (GuiApplication)__androidCurrentModule;
1273 const String skin = guiApp.skin;
1274 *&guiApp.currentSkin = null;
1275 guiApp.SelectSkin(skin);
1279 ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
1282 if(!destroyRequested)
1283 ANativeActivity_finish(activity);
1284 while(!destroyRequested)
1286 guiApp.interfaceDriver.Wait();
1287 guiApp.interfaceDriver.ProcessInput(true);