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 eventAvailable = true;
598 if(androidActivity.destroyRequested)
600 guiApp.desktop.Destroy(0);
601 eventAvailable = true;
602 androidActivity.ident = (LooperID)-1;
605 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
607 androidActivity.ident = (LooperID)-1;
609 return eventAvailable;
614 androidActivity.ident = (LooperID)ALooper_pollAll((int)(1000/18.2f), null, &androidActivity.events, (void**)&androidActivity.source);
615 // guiApp.WaitEvent();
618 void Lock(Window window)
623 void Unlock(Window window)
628 char ** GraphicsDrivers(int * numDrivers)
630 static char *graphicsDrivers[] = { "OpenGL" };
631 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
632 return (char **)graphicsDrivers;
635 void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
640 void EnsureFullScreen(bool *fullScreen)
645 bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
652 // --- Window Creation ---
653 void * CreateRootWindow(Window window)
655 return androidActivity.window;
658 void DestroyRootWindow(Window window)
663 // -- Window manipulation ---
665 void SetRootWindowCaption(Window window, char * name)
670 void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
675 void OrderRootWindow(Window window, bool topMost)
680 void SetRootWindowColor(Window window)
685 void OffsetWindow(Window window, int * x, int * y)
690 void UpdateRootWindow(Window window)
692 if(!window.parent || !window.parent.display)
696 Box box = window.box;
697 box.left -= window.clientStart.x;
698 box.top -= window.clientStart.y;
699 box.right -= window.clientStart.x;
700 box.bottom -= window.clientStart.y;
701 // Logf("Update root window %s\n", window.name);
703 box.left += window.clientStart.x;
704 box.top += window.clientStart.y;
705 box.right += window.clientStart.x;
706 box.bottom += window.clientStart.y;
707 window.UpdateDirty(box);
713 void SetRootWindowState(Window window, WindowState state, bool visible)
717 void FlashRootWindow(Window window)
722 void ActivateRootWindow(Window window)
727 // --- Mouse-based window movement ---
729 void StartMoving(Window window, int x, int y, bool fromKeyBoard)
734 void StopMoving(Window window)
739 // -- Mouse manipulation ---
741 void GetMousePosition(int *x, int *y)
743 int rootWindow, childWindow;
751 void SetMousePosition(int x, int y)
757 void SetMouseRange(Window window, Box box)
761 void SetMouseCapture(Window window)
765 // -- Mouse cursor ---
767 void SetMouseCursor(int cursor)
777 void SetCaret(int x, int y, int size)
779 Window caretOwner = guiApp.caretOwner;
780 Window window = caretOwner ? caretOwner.rootWindow : null;
781 if(window && window.windowData)
786 void ClearClipboard()
790 delete clipBoardData;
794 bool AllocateClipboard(ClipBoard clipBoard, uint size)
797 if((clipBoard.text = new0 byte[size]))
802 bool SaveClipboard(ClipBoard clipBoard)
808 delete clipBoardData;
810 clipBoardData = clipBoard.text;
811 clipBoard.text = null;
817 bool LoadClipboard(ClipBoard clipBoard)
821 // The data is inside this client...
824 clipBoard.text = new char[strlen(clipBoardData)+1];
825 strcpy(clipBoard.text, clipBoardData);
828 // The data is with another client...
835 void UnloadClipboard(ClipBoard clipBoard)
837 delete clipBoard.text;
840 // --- State based input ---
842 bool AcquireInput(Window window, bool state)
847 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
855 bool GetJoystickState(int device, Joystick joystick)
861 bool GetKeyState(Key key)
867 void SetTimerResolution(uint hertz)
869 // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
872 bool SetIcon(Window window, BitmapResource resource)
877 if(bitmap.Load(resource.fileName, null, null))
893 static AndroidActivity androidActivity;
895 default const char * AndroidInterface_GetLibLocation()
899 static char loc[MAX_LOCATION];
900 sprintf(loc, "/data/data/com.ecere.%s/lib/lib", androidActivity.moduleName);
908 default float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
909 int32_t axis, size_t pointer_index);
912 static define AMETA_META_ON = 0x00010000;
913 static define AMETA_META_LEFT_ON = 0x00020000;
914 static define AMETA_META_RIGHT_ON = 0x00040000;
916 static Key keyCodeTable[] =
918 0, //AKEYCODE_UNKNOWN = 0,
919 0, //AKEYCODE_SOFT_LEFT = 1,
920 0, //AKEYCODE_SOFT_RIGHT = 2,
921 0, //AKEYCODE_HOME = 3,
922 0, //AKEYCODE_BACK = 4,
923 0, //AKEYCODE_CALL = 5,
924 0, //AKEYCODE_ENDCALL = 6,
925 k0, //AKEYCODE_0 = 7,
926 k1, //AKEYCODE_1 = 8,
927 k2, //AKEYCODE_2 = 9,
928 k3, //AKEYCODE_3 = 10,
929 k4, //AKEYCODE_4 = 11,
930 k5, //AKEYCODE_5 = 12,
931 k6, //AKEYCODE_6 = 13,
932 k7, //AKEYCODE_7 = 14,
933 k8, //AKEYCODE_8 = 15,
934 k9, //AKEYCODE_9 = 16,
935 keyPadStar, //AKEYCODE_STAR = 17,
936 Key { k3, shift = true }, //AKEYCODE_POUND = 18,
937 up, //AKEYCODE_DPAD_UP = 19,
938 down, //AKEYCODE_DPAD_DOWN = 20,
939 left, //AKEYCODE_DPAD_LEFT = 21,
940 right, //AKEYCODE_DPAD_RIGHT = 22,
941 keyPad5, //AKEYCODE_DPAD_CENTER = 23,
942 0, //AKEYCODE_VOLUME_UP = 24,
943 0, //AKEYCODE_VOLUME_DOWN = 25,
944 0, //AKEYCODE_POWER = 26,
945 0, //AKEYCODE_CAMERA = 27,
946 0, //AKEYCODE_CLEAR = 28,
947 a, //AKEYCODE_A = 29,
948 b, //AKEYCODE_B = 30,
949 c, //AKEYCODE_C = 31,
950 d, //AKEYCODE_D = 32,
951 e, //AKEYCODE_E = 33,
952 f, //AKEYCODE_F = 34,
953 g, //AKEYCODE_G = 35,
954 h, //AKEYCODE_H = 36,
955 i, //AKEYCODE_I = 37,
956 j, //AKEYCODE_J = 38,
957 k, //AKEYCODE_K = 39,
958 l, //AKEYCODE_L = 40,
959 m, //AKEYCODE_M = 41,
960 n, //AKEYCODE_N = 42,
961 o, //AKEYCODE_O = 43,
962 p, //AKEYCODE_P = 44,
963 q, //AKEYCODE_Q = 45,
964 r, //AKEYCODE_R = 46,
965 s, //AKEYCODE_S = 47,
966 t, //AKEYCODE_T = 48,
967 u, //AKEYCODE_U = 49,
968 v, //AKEYCODE_V = 50,
969 w, //AKEYCODE_W = 51,
970 x, //AKEYCODE_X = 52,
971 y, //AKEYCODE_Y = 53,
972 z, //AKEYCODE_Z = 54,
973 comma, //AKEYCODE_COMMA = 55,
974 period, //AKEYCODE_PERIOD = 56,
975 leftAlt, //AKEYCODE_ALT_LEFT = 57,
976 rightAlt, //AKEYCODE_ALT_RIGHT = 58,
977 leftShift, //AKEYCODE_SHIFT_LEFT = 59,
978 rightShift, //AKEYCODE_SHIFT_RIGHT = 60,
979 tab, //AKEYCODE_TAB = 61,
980 space, //AKEYCODE_SPACE = 62,
981 0, //AKEYCODE_SYM = 63,
982 0, //AKEYCODE_EXPLORER = 64,
983 0, //AKEYCODE_ENVELOPE = 65,
984 enter, //AKEYCODE_ENTER = 66,
985 backSpace, //AKEYCODE_DEL = 67,
986 backQuote, //AKEYCODE_GRAVE = 68,
987 minus, //AKEYCODE_MINUS = 69,
988 plus, //AKEYCODE_EQUALS = 70,
989 leftBracket, //AKEYCODE_LEFT_BRACKET = 71,
990 rightBracket, //AKEYCODE_RIGHT_BRACKET = 72,
991 backSlash, //AKEYCODE_BACKSLASH = 73,
992 semicolon, //AKEYCODE_SEMICOLON = 74,
993 quote, //AKEYCODE_APOSTROPHE = 75,
994 slash, //AKEYCODE_SLASH = 76,
995 Key { k2, shift = true }, //AKEYCODE_AT = 77,
996 0, //AKEYCODE_NUM = 78, // Interpreted as an Alt
997 0, //AKEYCODE_HEADSETHOOK = 79,
998 0, //AKEYCODE_FOCUS = 80, // *Camera* focus
999 keyPadPlus, //AKEYCODE_PLUS = 81,
1000 0, //AKEYCODE_MENU = 82,
1001 0, //AKEYCODE_NOTIFICATION = 83,
1002 0, //AKEYCODE_SEARCH = 84,
1003 0, //AKEYCODE_MEDIA_PLAY_PAUSE= 85,
1004 0, //AKEYCODE_MEDIA_STOP = 86,
1005 0, //AKEYCODE_MEDIA_NEXT = 87,
1006 0, //AKEYCODE_MEDIA_PREVIOUS = 88,
1007 0, //AKEYCODE_MEDIA_REWIND = 89,
1008 0, //AKEYCODE_MEDIA_FAST_FORWARD = 90,
1009 0, //AKEYCODE_MUTE = 91,
1010 0, //AKEYCODE_PAGE_UP = 92,
1011 0, //AKEYCODE_PAGE_DOWN = 93,
1012 0, //AKEYCODE_PICTSYMBOLS = 94,
1013 0, //AKEYCODE_SWITCH_CHARSET = 95,
1014 0, //AKEYCODE_BUTTON_A = 96,
1015 0, //AKEYCODE_BUTTON_B = 97,
1016 0, //AKEYCODE_BUTTON_C = 98,
1017 0, //AKEYCODE_BUTTON_X = 99,
1018 0, //AKEYCODE_BUTTON_Y = 100,
1019 0, //AKEYCODE_BUTTON_Z = 101,
1020 0, //AKEYCODE_BUTTON_L1 = 102,
1021 0, //AKEYCODE_BUTTON_R1 = 103,
1022 0, //AKEYCODE_BUTTON_L2 = 104,
1023 0, //AKEYCODE_BUTTON_R2 = 105,
1024 0, //AKEYCODE_BUTTON_THUMBL = 106,
1025 0, //AKEYCODE_BUTTON_THUMBR = 107,
1026 0, //AKEYCODE_BUTTON_START = 108,
1027 0, //AKEYCODE_BUTTON_SELECT = 109,
1028 0, //AKEYCODE_BUTTON_MODE = 110,
1029 escape, //AKEYCODE_BUTTON_ESCAPE = 111,
1030 del //AKEYCODE_BUTTON_ESCAPE = 112,
1031 leftControl, // = 113
1032 rightControl, // = 114
1034 scrollLock, // = 116
1035 0, // = 117 KEYCODE_META_LEFT
1036 0, // = 118 KEYCODE_META_RIGHT
1037 0, // = 119 KEYCODE_FUNCTION
1038 printScreen, // = 120 KEYCODE_SYSRQ
1039 pauseBreak, // = 121
1045 // Why don't we have this in the NDK :(
1046 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
1048 class AndroidActivity : AndroidAppGlue
1050 AndroidPollSource source;
1054 ASensorManager* sensorManager;
1055 const ASensor* accelerometerSensor;
1056 ASensorEventQueue* sensorEventQueue;
1060 int onInputEvent(AInputEvent* event)
1062 Window window = guiApp.desktop;
1063 uint type = AInputEvent_getType(event);
1064 if(type == AINPUT_EVENT_TYPE_MOTION)
1066 uint actionAndIndex = AMotionEvent_getAction(event);
1067 uint source = AInputEvent_getSource(event);
1068 uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
1069 uint index = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
1070 uint flags = AMotionEvent_getFlags(event);
1071 uint meta = AMotionEvent_getMetaState(event);
1072 uint edge = AMotionEvent_getEdgeFlags(event);
1073 int64 downTime = AMotionEvent_getDownTime(event); // nanotime
1074 int64 eventTime = AMotionEvent_getDownTime(event);
1076 Modifiers keyFlags = 0;
1077 int x = (int)AMotionEvent_getX(event, 0);
1078 int y = (int)AMotionEvent_getY(event, 0);
1079 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1080 bool alt = (meta & AMETA_ALT_ON) ? true : false;
1081 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1083 keyFlags.shift = shift;
1086 //PrintLn("Got a motion input event: ", action);
1088 if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
1089 axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
1092 AInputQueue_finishEvent(inputQueue, event, 1);
1096 case 8: //AMOTION_EVENT_ACTION_SCROLL:
1097 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (axis < 0) ? wheelUp : wheelDown, 0);
1100 case AMOTION_EVENT_ACTION_DOWN:
1101 mouseX = x, mouseY = y;
1102 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
1104 case AMOTION_EVENT_ACTION_UP:
1105 mouseX = x, mouseY = y;
1106 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true);
1108 case AMOTION_EVENT_ACTION_MOVE:
1109 mouseX = x, mouseY = y;
1110 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true);
1112 case AMOTION_EVENT_ACTION_CANCEL: break;
1113 case AMOTION_EVENT_ACTION_OUTSIDE: break;
1114 case AMOTION_EVENT_ACTION_POINTER_DOWN: break;
1115 case AMOTION_EVENT_ACTION_POINTER_UP: break;
1119 else if(type == AINPUT_EVENT_TYPE_KEY)
1121 uint action = AKeyEvent_getAction(event);
1122 uint flags = AKeyEvent_getFlags(event);
1123 uint keyCode = AKeyEvent_getKeyCode(event);
1124 uint meta = AKeyEvent_getMetaState(event);
1125 Key key = keyCodeTable[keyCode];
1126 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1127 bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
1128 bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
1129 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1130 //unichar ch = AKeyEvent_getUnichar(event);
1136 AInputQueue_finishEvent(inputQueue, event, 1);
1138 // PrintLn("Got a key: action = ", action, ", flags = ", flags, ", keyCode = ", keyCode, ", meta = ", meta, ": key = ", (int)key);
1142 if(action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_MULTIPLE)
1144 /*if(key == wheelDown || key == wheelUp)
1145 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1148 char c = Interface::TranslateKey(key.code, shift);
1150 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, ch);
1153 else if(action == AKEY_EVENT_ACTION_UP)
1154 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, ch);
1159 AInputQueue_finishEvent(inputQueue, event, 0);
1163 void onAppCmd(AppCommand cmd)
1168 setSavedState(&state, sizeof(state));
1175 ANativeWindow_setBuffersGeometry(window, 0, 0, 0); //format);
1176 w = ANativeWindow_getWidth(window);
1177 h = ANativeWindow_getHeight(window);
1178 guiApp.Initialize(false);
1179 guiApp.desktop.windowHandle = window;
1180 guiApp.interfaceDriver = null;
1181 guiApp.SwitchMode(true, null, 0, 0, 0, null, false);
1183 if(desktopW != w || desktopH != h)
1185 guiApp.SetDesktopPosition(0, 0, w, h, true);
1189 guiApp.desktop.Update(null);
1193 guiApp.desktop.UnloadGraphics(false);
1196 guiApp.desktop.Update(null);
1197 guiApp.SetAppFocus(true);
1199 if(accelerometerSensor)
1201 ASensorEventQueue_enableSensor(sensorEventQueue, accelerometerSensor);
1202 ASensorEventQueue_setEventRate(sensorEventQueue, accelerometerSensor, (1000L/60)*1000);
1208 if(accelerometerSensor)
1209 ASensorEventQueue_disableSensor(sensorEventQueue, accelerometerSensor);
1211 guiApp.SetAppFocus(false);
1212 guiApp.desktop.Update(null);
1217 int w = ANativeWindow_getWidth(window);
1218 int h = ANativeWindow_getHeight(window);
1219 if(desktopW != w || desktopH != h)
1221 guiApp.SetDesktopPosition(0, 0, w, h, true);
1225 guiApp.desktop.Update(null);
1233 androidActivity = this;
1234 /* Let's have fun with sensors when we have an actual device to play with
1235 sensorManager = ASensorManager_getInstance();
1236 accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
1237 sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LooperID::user, null, null);
1241 state = *(SavedState*)savedState;
1246 // Evolve the Application class into a GuiApplication
1247 eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
1249 // Wait for the initWindow command:
1250 guiApp.interfaceDriver = class(AndroidInterface);
1253 // Can't call the GuiApplication here, because GuiApplication::Initialize() has not been called yet
1254 guiApp.interfaceDriver.Wait();
1255 guiApp.interfaceDriver.ProcessInput(true);
1258 // Invoke __ecereDll_Load() in lib[our package name].so
1259 app = eModule_Load(__androidCurrentModule, moduleName, publicAccess);
1263 // Find out if any GuiApplication class was defined in our module
1264 for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
1265 if(!c) c = class(GuiApplication);
1267 // Evolve the Application into it
1268 eInstance_Evolve((Instance *)&__androidCurrentModule, c);
1269 guiApp = (GuiApplication)__androidCurrentModule;
1272 String skin = guiApp.skin;
1273 *&guiApp.currentSkin = null;
1274 guiApp.SelectSkin(skin);
1278 ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
1281 if(!destroyRequested)
1282 ANativeActivity_finish(activity);
1283 while(!destroyRequested)
1285 guiApp.interfaceDriver.Wait();
1286 guiApp.interfaceDriver.ProcessInput(true);