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 : byte { 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;
551 class AndroidInterface : Interface
553 class_property(name) = "Android";
555 // --- User Interface System ---
558 setlocale(LC_ALL, "en_US.UTF-8");
567 #define DBLCLICK_DELAY 300 // 0.3 second
568 #define DBLCLICK_DELTA 1
570 bool ProcessInput(bool processAll)
572 bool eventAvailable = false;
573 if(androidActivity.ident >= 0)
575 AndroidPollSource source = androidActivity.source;
576 //PrintLn("androidActivity.ident >= 0");
577 // Process this event.
578 androidActivity.ident = 0;
579 androidActivity.source = null;
581 source.process(source.userData);
583 // If a sensor has data, process it now.
585 if(androidActivity.ident == user)
587 if(androidActivity.accelerometerSensor)
590 while (ASensorEventQueue_getEvents(androidActivity.sensorEventQueue, &event, 1) > 0)
591 LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z);
595 // eventAvailable = true;
596 if(androidActivity.destroyRequested)
598 guiApp.desktop.Destroy(0);
599 eventAvailable = true;
603 if(androidActivity.animating)
604 guiApp.desktop.Update(null);
613 androidActivity.ident = (LooperID)ALooper_pollAll(androidActivity.animating ? 0 : -1, null, &androidActivity.events, (void**)&androidActivity.source);
614 // guiApp.WaitEvent();
617 void Lock(Window window)
622 void Unlock(Window window)
627 char ** GraphicsDrivers(int * numDrivers)
629 static char *graphicsDrivers[] = { "OpenGL" };
630 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
631 return (char **)graphicsDrivers;
634 void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
639 void EnsureFullScreen(bool *fullScreen)
644 bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
651 // --- Window Creation ---
652 void * CreateRootWindow(Window window)
654 return androidActivity.window;
657 void DestroyRootWindow(Window window)
662 // -- Window manipulation ---
664 void SetRootWindowCaption(Window window, char * name)
669 void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
674 void OrderRootWindow(Window window, bool topMost)
679 void SetRootWindowColor(Window window)
684 void OffsetWindow(Window window, int * x, int * y)
689 void UpdateRootWindow(Window window)
691 if(!window.parent || !window.parent.display)
695 Box box = window.box;
696 box.left -= window.clientStart.x;
697 box.top -= window.clientStart.y;
698 box.right -= window.clientStart.x;
699 box.bottom -= window.clientStart.y;
700 // Logf("Update root window %s\n", window.name);
702 box.left += window.clientStart.x;
703 box.top += window.clientStart.y;
704 box.right += window.clientStart.x;
705 box.bottom += window.clientStart.y;
706 window.UpdateDirty(box);
712 void SetRootWindowState(Window window, WindowState state, bool visible)
716 void FlashRootWindow(Window window)
721 void ActivateRootWindow(Window window)
726 // --- Mouse-based window movement ---
728 void StartMoving(Window window, int x, int y, bool fromKeyBoard)
733 void StopMoving(Window window)
738 // -- Mouse manipulation ---
740 void GetMousePosition(int *x, int *y)
742 int rootWindow, childWindow;
747 void SetMousePosition(int x, int y)
752 void SetMouseRange(Window window, Box box)
756 void SetMouseCapture(Window window)
760 // -- Mouse cursor ---
762 void SetMouseCursor(int cursor)
772 void SetCaret(int x, int y, int size)
774 Window caretOwner = guiApp.caretOwner;
775 Window window = caretOwner ? caretOwner.rootWindow : null;
776 if(window && window.windowData)
781 void ClearClipboard()
785 delete clipBoardData;
789 bool AllocateClipboard(ClipBoard clipBoard, uint size)
792 if((clipBoard.text = new0 byte[size]))
797 bool SaveClipboard(ClipBoard clipBoard)
803 delete clipBoardData;
805 clipBoardData = clipBoard.text;
806 clipBoard.text = null;
812 bool LoadClipboard(ClipBoard clipBoard)
816 // The data is inside this client...
819 clipBoard.text = new char[strlen(clipBoardData)+1];
820 strcpy(clipBoard.text, clipBoardData);
823 // The data is with another client...
830 void UnloadClipboard(ClipBoard clipBoard)
832 delete clipBoard.text;
835 // --- State based input ---
837 bool AcquireInput(Window window, bool state)
842 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
850 bool GetJoystickState(int device, Joystick joystick)
856 bool GetKeyState(Key key)
862 void SetTimerResolution(uint hertz)
864 // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
867 bool SetIcon(Window window, BitmapResource resource)
872 if(bitmap.Load(resource.fileName, null, null))
888 /*static */AndroidActivity androidActivity;
892 default float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
893 int32_t axis, size_t pointer_index);
896 static define AMETA_META_ON = 0x00010000;
897 static define AMETA_META_LEFT_ON = 0x00020000;
898 static define AMETA_META_RIGHT_ON = 0x00040000;
900 static Key keyCodeTable[] =
902 0, //AKEYCODE_UNKNOWN = 0,
903 0, //AKEYCODE_SOFT_LEFT = 1,
904 0, //AKEYCODE_SOFT_RIGHT = 2,
905 0, //AKEYCODE_HOME = 3,
906 0, //AKEYCODE_BACK = 4,
907 0, //AKEYCODE_CALL = 5,
908 0, //AKEYCODE_ENDCALL = 6,
909 k0, //AKEYCODE_0 = 7,
910 k1, //AKEYCODE_1 = 8,
911 k2, //AKEYCODE_2 = 9,
912 k3, //AKEYCODE_3 = 10,
913 k4, //AKEYCODE_4 = 11,
914 k5, //AKEYCODE_5 = 12,
915 k6, //AKEYCODE_6 = 13,
916 k7, //AKEYCODE_7 = 14,
917 k8, //AKEYCODE_8 = 15,
918 k9, //AKEYCODE_9 = 16,
919 keyPadStar, //AKEYCODE_STAR = 17,
920 Key { k3, shift = true }, //AKEYCODE_POUND = 18,
921 up, //AKEYCODE_DPAD_UP = 19,
922 down, //AKEYCODE_DPAD_DOWN = 20,
923 left, //AKEYCODE_DPAD_LEFT = 21,
924 right, //AKEYCODE_DPAD_RIGHT = 22,
925 keyPad5, //AKEYCODE_DPAD_CENTER = 23,
926 0, //AKEYCODE_VOLUME_UP = 24,
927 0, //AKEYCODE_VOLUME_DOWN = 25,
928 0, //AKEYCODE_POWER = 26,
929 0, //AKEYCODE_CAMERA = 27,
930 0, //AKEYCODE_CLEAR = 28,
931 a, //AKEYCODE_A = 29,
932 b, //AKEYCODE_B = 30,
933 c, //AKEYCODE_C = 31,
934 d, //AKEYCODE_D = 32,
935 e, //AKEYCODE_E = 33,
936 f, //AKEYCODE_F = 34,
937 g, //AKEYCODE_G = 35,
938 h, //AKEYCODE_H = 36,
939 i, //AKEYCODE_I = 37,
940 j, //AKEYCODE_J = 38,
941 k, //AKEYCODE_K = 39,
942 l, //AKEYCODE_L = 40,
943 m, //AKEYCODE_M = 41,
944 n, //AKEYCODE_N = 42,
945 o, //AKEYCODE_O = 43,
946 p, //AKEYCODE_P = 44,
947 q, //AKEYCODE_Q = 45,
948 r, //AKEYCODE_R = 46,
949 s, //AKEYCODE_S = 47,
950 t, //AKEYCODE_T = 48,
951 u, //AKEYCODE_U = 49,
952 v, //AKEYCODE_V = 50,
953 w, //AKEYCODE_W = 51,
954 x, //AKEYCODE_X = 52,
955 y, //AKEYCODE_Y = 53,
956 z, //AKEYCODE_Z = 54,
957 comma, //AKEYCODE_COMMA = 55,
958 period, //AKEYCODE_PERIOD = 56,
959 leftAlt, //AKEYCODE_ALT_LEFT = 57,
960 rightAlt, //AKEYCODE_ALT_RIGHT = 58,
961 leftShift, //AKEYCODE_SHIFT_LEFT = 59,
962 rightShift, //AKEYCODE_SHIFT_RIGHT = 60,
963 tab, //AKEYCODE_TAB = 61,
964 space, //AKEYCODE_SPACE = 62,
965 0, //AKEYCODE_SYM = 63,
966 0, //AKEYCODE_EXPLORER = 64,
967 0, //AKEYCODE_ENVELOPE = 65,
968 enter, //AKEYCODE_ENTER = 66,
969 backSpace, //AKEYCODE_DEL = 67,
970 backQuote, //AKEYCODE_GRAVE = 68,
971 minus, //AKEYCODE_MINUS = 69,
972 plus, //AKEYCODE_EQUALS = 70,
973 leftBracket, //AKEYCODE_LEFT_BRACKET = 71,
974 rightBracket, //AKEYCODE_RIGHT_BRACKET = 72,
975 backSlash, //AKEYCODE_BACKSLASH = 73,
976 semicolon, //AKEYCODE_SEMICOLON = 74,
977 quote, //AKEYCODE_APOSTROPHE = 75,
978 slash, //AKEYCODE_SLASH = 76,
979 Key { k2, shift = true }, //AKEYCODE_AT = 77,
980 0, //AKEYCODE_NUM = 78, // Interpreted as an Alt
981 0, //AKEYCODE_HEADSETHOOK = 79,
982 0, //AKEYCODE_FOCUS = 80, // *Camera* focus
983 keyPadPlus, //AKEYCODE_PLUS = 81,
984 0, //AKEYCODE_MENU = 82,
985 0, //AKEYCODE_NOTIFICATION = 83,
986 0, //AKEYCODE_SEARCH = 84,
987 0, //AKEYCODE_MEDIA_PLAY_PAUSE= 85,
988 0, //AKEYCODE_MEDIA_STOP = 86,
989 0, //AKEYCODE_MEDIA_NEXT = 87,
990 0, //AKEYCODE_MEDIA_PREVIOUS = 88,
991 0, //AKEYCODE_MEDIA_REWIND = 89,
992 0, //AKEYCODE_MEDIA_FAST_FORWARD = 90,
993 0, //AKEYCODE_MUTE = 91,
994 0, //AKEYCODE_PAGE_UP = 92,
995 0, //AKEYCODE_PAGE_DOWN = 93,
996 0, //AKEYCODE_PICTSYMBOLS = 94,
997 0, //AKEYCODE_SWITCH_CHARSET = 95,
998 0, //AKEYCODE_BUTTON_A = 96,
999 0, //AKEYCODE_BUTTON_B = 97,
1000 0, //AKEYCODE_BUTTON_C = 98,
1001 0, //AKEYCODE_BUTTON_X = 99,
1002 0, //AKEYCODE_BUTTON_Y = 100,
1003 0, //AKEYCODE_BUTTON_Z = 101,
1004 0, //AKEYCODE_BUTTON_L1 = 102,
1005 0, //AKEYCODE_BUTTON_R1 = 103,
1006 0, //AKEYCODE_BUTTON_L2 = 104,
1007 0, //AKEYCODE_BUTTON_R2 = 105,
1008 0, //AKEYCODE_BUTTON_THUMBL = 106,
1009 0, //AKEYCODE_BUTTON_THUMBR = 107,
1010 0, //AKEYCODE_BUTTON_START = 108,
1011 0, //AKEYCODE_BUTTON_SELECT = 109,
1012 0, //AKEYCODE_BUTTON_MODE = 110,
1013 escape, //AKEYCODE_BUTTON_ESCAPE = 111,
1014 del //AKEYCODE_BUTTON_ESCAPE = 112,
1015 leftControl, // = 113
1016 rightControl, // = 114
1018 scrollLock, // = 116
1019 0, // = 117 KEYCODE_META_LEFT
1020 0, // = 118 KEYCODE_META_RIGHT
1021 0, // = 119 KEYCODE_FUNCTION
1022 printScreen, // = 120 KEYCODE_SYSRQ
1023 pauseBreak, // = 121
1029 // Why don't we have this in the NDK :(
1030 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
1032 class AndroidActivity : AndroidAppGlue
1034 AndroidPollSource source;
1038 ASensorManager* sensorManager;
1039 const ASensor* accelerometerSensor;
1040 ASensorEventQueue* sensorEventQueue;
1045 int onInputEvent(AInputEvent* event)
1047 Window window = guiApp.desktop;
1048 uint type = AInputEvent_getType(event);
1049 if(type == AINPUT_EVENT_TYPE_MOTION)
1051 uint actionAndIndex = AMotionEvent_getAction(event);
1052 uint source = AInputEvent_getSource(event);
1053 uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
1054 uint index = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
1055 uint flags = AMotionEvent_getFlags(event);
1056 uint meta = AMotionEvent_getMetaState(event);
1057 uint edge = AMotionEvent_getEdgeFlags(event);
1058 int64 downTime = AMotionEvent_getDownTime(event); // nanotime
1059 int64 eventTime = AMotionEvent_getDownTime(event);
1061 Modifiers keyFlags = 0;
1062 int x = (int)AMotionEvent_getX(event, 0);
1063 int y = (int)AMotionEvent_getY(event, 0);
1064 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1065 bool alt = (meta & AMETA_ALT_ON) ? true : false;
1066 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1068 keyFlags.shift = shift;
1071 //PrintLn("Got a motion input event: ", action);
1073 if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
1074 axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
1077 AInputQueue_finishEvent(inputQueue, event, 1);
1081 case 8: //AMOTION_EVENT_ACTION_SCROLL:
1082 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (axis < 0) ? wheelUp : wheelDown, 0);
1085 case AMOTION_EVENT_ACTION_DOWN:
1086 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
1088 case AMOTION_EVENT_ACTION_UP:
1089 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true);
1091 case AMOTION_EVENT_ACTION_MOVE:
1092 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true);
1094 case AMOTION_EVENT_ACTION_CANCEL: break;
1095 case AMOTION_EVENT_ACTION_OUTSIDE: break;
1096 case AMOTION_EVENT_ACTION_POINTER_DOWN: break;
1097 case AMOTION_EVENT_ACTION_POINTER_UP: break;
1103 else if(type == AINPUT_EVENT_TYPE_KEY)
1105 uint action = AKeyEvent_getAction(event);
1106 uint flags = AKeyEvent_getFlags(event);
1107 uint keyCode = AKeyEvent_getKeyCode(event);
1108 uint meta = AKeyEvent_getMetaState(event);
1109 Key key = keyCodeTable[keyCode];
1110 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1111 bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
1112 bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
1113 bool sym = (meta & AMETA_SYM_ON) ? true : false;
1114 //unichar ch = AKeyEvent_getUnichar(event);
1120 AInputQueue_finishEvent(inputQueue, event, 1);
1122 // PrintLn("Got a key: action = ", action, ", flags = ", flags, ", keyCode = ", keyCode, ", meta = ", meta, ": key = ", (int)key);
1126 if(action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_MULTIPLE)
1128 /*if(key == wheelDown || key == wheelUp)
1129 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1132 char c = Interface::TranslateKey(key.code, shift);
1134 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, ch);
1137 else if(action == AKEY_EVENT_ACTION_UP)
1138 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, ch);
1143 AInputQueue_finishEvent(inputQueue, event, 0);
1147 void onAppCmd(AppCommand cmd)
1152 setSavedState(&state, sizeof(state));
1159 ANativeWindow_setBuffersGeometry(window, 0, 0, 0); //format);
1160 w = ANativeWindow_getWidth(window);
1161 h = ANativeWindow_getHeight(window);
1162 guiApp.Initialize(false);
1163 guiApp.desktop.windowHandle = window;
1164 guiApp.interfaceDriver = null;
1165 guiApp.SwitchMode(true, null, 0, 0, 0, null, false);
1167 if(desktopW != w || desktopH != h)
1169 guiApp.SetDesktopPosition(0, 0, w, h, true);
1173 guiApp.desktop.Update(null);
1178 guiApp.desktop.UnloadGraphics(false);
1181 androidActivity.animating = true;
1182 guiApp.SetAppFocus(true);
1184 if(accelerometerSensor)
1186 ASensorEventQueue_enableSensor(sensorEventQueue, accelerometerSensor);
1187 ASensorEventQueue_setEventRate(sensorEventQueue, accelerometerSensor, (1000L/60)*1000);
1193 if(accelerometerSensor)
1194 ASensorEventQueue_disableSensor(sensorEventQueue, accelerometerSensor);
1197 guiApp.SetAppFocus(false);
1198 guiApp.desktop.Update(null);
1205 androidActivity = this;
1206 /* Let's have fun with sensors when we have an actual device to play with
1207 sensorManager = ASensorManager_getInstance();
1208 accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
1209 sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LooperID::user, null, null);
1213 state = *(SavedState*)savedState;
1218 // Evolve the Application class into a GuiApplication
1219 eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
1221 // Wait for the initWindow command:
1222 guiApp.interfaceDriver = class(AndroidInterface);
1225 // Can't call the GuiApplication here, because GuiApplication::Initialize() has not been called yet
1226 guiApp.interfaceDriver.Wait();
1227 guiApp.interfaceDriver.ProcessInput(true);
1230 // Invoke __ecereDll_Load() in lib[our package name].so
1231 app = eModule_Load(__androidCurrentModule, moduleName, publicAccess);
1235 // Find out if any GuiApplication class was defined in our module
1236 for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
1237 if(!c) c = class(GuiApplication);
1239 // Evolve the Application into it
1240 eInstance_Evolve((Instance *)&__androidCurrentModule, c);
1241 guiApp = (GuiApplication)__androidCurrentModule;
1244 String skin = guiApp.skin;
1245 *&guiApp.currentSkin = null;
1246 guiApp.SelectSkin(skin);
1250 ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
1253 if(!destroyRequested)
1254 ANativeActivity_finish(activity);
1255 while(!destroyRequested)
1257 guiApp.interfaceDriver.Wait();
1258 guiApp.interfaceDriver.ProcessInput(true);