main_android.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #if CROWN_PLATFORM_ANDROID
  7. #include "core/error/error.inl"
  8. #include "core/guid.h"
  9. #include "core/memory/globals.h"
  10. #include "core/memory/memory.inl"
  11. #include "core/thread/spsc_queue.inl"
  12. #include "core/thread/thread.h"
  13. #include "device/device.h"
  14. #include "device/device_event_queue.inl"
  15. #include <android/sensor.h>
  16. #include <android/window.h>
  17. #include <jni.h>
  18. #include <stdlib.h>
  19. #define STB_SPRINTF_IMPLEMENTATION
  20. #define STB_SPRINTF_NOUNALIGNED
  21. #include <stb_sprintf.h>
  22. extern "C"
  23. {
  24. #include <android_native_app_glue.c>
  25. }
  26. namespace crown
  27. {
  28. static bool push_event(const OsEvent &ev);
  29. struct AndroidDevice
  30. {
  31. SPSCQueue<OsEvent, CROWN_MAX_OS_EVENTS> _events;
  32. DeviceEventQueue _queue;
  33. Thread _main_thread;
  34. DeviceOptions *_opts;
  35. ANativeWindow *_window;
  36. explicit AndroidDevice(Allocator &a)
  37. : _events(a)
  38. , _queue(push_event)
  39. , _opts(NULL)
  40. {
  41. }
  42. void run(struct android_app *app, DeviceOptions &opts)
  43. {
  44. _opts = &opts;
  45. app->userData = this;
  46. app->onAppCmd = crown::AndroidDevice::on_app_cmd;
  47. app->onInputEvent = crown::AndroidDevice::on_input_event;
  48. ANativeActivity_setWindowFlags(app->activity
  49. , AWINDOW_FLAG_FULLSCREEN | AWINDOW_FLAG_KEEP_SCREEN_ON
  50. , 0
  51. );
  52. while (app->destroyRequested == 0) {
  53. s32 num;
  54. android_poll_source *source;
  55. ALooper_pollOnce(-1, NULL, &num, (void **)&source);
  56. if (source != NULL)
  57. source->process(app, source);
  58. }
  59. _main_thread.stop();
  60. }
  61. void process_command(struct android_app *app, s32 cmd)
  62. {
  63. switch (cmd) {
  64. case APP_CMD_SAVE_STATE:
  65. break;
  66. case APP_CMD_INIT_WINDOW: {
  67. CE_ASSERT(app->window != NULL, "Android window is NULL");
  68. _window = app->window;
  69. // Push metrics here since Android does not trigger APP_CMD_WINDOW_RESIZED
  70. const s32 width = ANativeWindow_getWidth(app->window);
  71. const s32 height = ANativeWindow_getHeight(app->window);
  72. _queue.push_resolution_event(width, height);
  73. if (!_main_thread.is_running()) {
  74. _main_thread.start([](void *user_data) {
  75. return crown::main_runtime(*((DeviceOptions *)user_data));
  76. }
  77. , _opts
  78. );
  79. }
  80. break;
  81. }
  82. case APP_CMD_TERM_WINDOW:
  83. // The window is being hidden or closed, clean it up.
  84. break;
  85. case APP_CMD_WINDOW_RESIZED:
  86. // Not triggered by Android
  87. break;
  88. case APP_CMD_GAINED_FOCUS:
  89. break;
  90. case APP_CMD_LOST_FOCUS:
  91. break;
  92. case APP_CMD_DESTROY:
  93. _queue.push_exit_event();
  94. break;
  95. }
  96. }
  97. s32 process_input(struct android_app *app, AInputEvent *event)
  98. {
  99. if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
  100. const s32 action_raw = AMotionEvent_getAction(event);
  101. const s32 pointer_index = (action_raw & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
  102. const s32 pointer_count = AMotionEvent_getPointerCount(event);
  103. const s32 pointer_id = AMotionEvent_getPointerId(event, pointer_index);
  104. const f32 x = AMotionEvent_getX(event, pointer_index);
  105. const f32 y = AMotionEvent_getY(event, pointer_index);
  106. const s32 action = (action_raw & AMOTION_EVENT_ACTION_MASK);
  107. switch (action) {
  108. case AMOTION_EVENT_ACTION_DOWN:
  109. case AMOTION_EVENT_ACTION_POINTER_DOWN:
  110. if (pointer_id < TouchButton::COUNT)
  111. _queue.push_button_event(InputDeviceType::TOUCHSCREEN, 0, pointer_id, true);
  112. if (pointer_id < TouchAxis::COUNT)
  113. _queue.push_axis_event(InputDeviceType::TOUCHSCREEN, 0, pointer_id, x, y, 0);
  114. break;
  115. case AMOTION_EVENT_ACTION_UP:
  116. case AMOTION_EVENT_ACTION_POINTER_UP:
  117. if (pointer_id < TouchAxis::COUNT)
  118. _queue.push_axis_event(InputDeviceType::TOUCHSCREEN, 0, pointer_id, x, y, 0);
  119. if (pointer_id < TouchButton::COUNT)
  120. _queue.push_button_event(InputDeviceType::TOUCHSCREEN, 0, pointer_id, false);
  121. break;
  122. case AMOTION_EVENT_ACTION_OUTSIDE:
  123. case AMOTION_EVENT_ACTION_CANCEL:
  124. if (pointer_id < TouchButton::COUNT)
  125. _queue.push_button_event(InputDeviceType::TOUCHSCREEN, 0, pointer_id, false);
  126. break;
  127. case AMOTION_EVENT_ACTION_MOVE:
  128. for (int index = 0; index < pointer_count; index++) {
  129. const s32 id = AMotionEvent_getPointerId(event, index);
  130. if (id < TouchAxis::COUNT) {
  131. const f32 xx = AMotionEvent_getX(event, index);
  132. const f32 yy = AMotionEvent_getY(event, index);
  133. _queue.push_axis_event(InputDeviceType::TOUCHSCREEN, 0, id, xx, yy, 0);
  134. }
  135. }
  136. break;
  137. }
  138. return 1;
  139. } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
  140. const s32 keycode = AKeyEvent_getKeyCode(event);
  141. const s32 keyaction = AKeyEvent_getAction(event);
  142. if (keycode == AKEYCODE_BACK) {
  143. _queue.push_button_event(InputDeviceType::KEYBOARD
  144. , 0
  145. , KeyboardButton::ESCAPE
  146. , keyaction == AKEY_EVENT_ACTION_DOWN ? true : false
  147. );
  148. }
  149. return 1;
  150. }
  151. return 0;
  152. }
  153. static s32 on_input_event(struct android_app *app, AInputEvent *event)
  154. {
  155. return static_cast<AndroidDevice *>(app->userData)->process_input(app, event);
  156. }
  157. static void on_app_cmd(struct android_app *app, s32 cmd)
  158. {
  159. static_cast<AndroidDevice *>(app->userData)->process_command(app, cmd);
  160. }
  161. };
  162. static AndroidDevice *s_android_device;
  163. struct WindowAndroid : public Window
  164. {
  165. WindowAndroid()
  166. {
  167. }
  168. void open(u16 x, u16 y, u16 width, u16 height, u32 parent) override
  169. {
  170. CE_UNUSED_5(x, y, width, height, parent);
  171. }
  172. void close() override
  173. {
  174. }
  175. void show() override
  176. {
  177. }
  178. void hide() override
  179. {
  180. }
  181. void resize(u16 width, u16 height) override
  182. {
  183. CE_UNUSED_2(width, height);
  184. }
  185. void move(u16 x, u16 y) override
  186. {
  187. CE_UNUSED_2(x, y);
  188. }
  189. void minimize() override
  190. {
  191. }
  192. void maximize() override
  193. {
  194. }
  195. void restore() override
  196. {
  197. }
  198. const char *title() override
  199. {
  200. return NULL;
  201. }
  202. void set_title(const char *title) override
  203. {
  204. CE_UNUSED(title);
  205. }
  206. void show_cursor(bool show) override
  207. {
  208. CE_UNUSED(show);
  209. }
  210. void set_fullscreen(bool fullscreen) override
  211. {
  212. CE_UNUSED(fullscreen);
  213. }
  214. void set_cursor(MouseCursor::Enum cursor) override
  215. {
  216. CE_UNUSED(cursor);
  217. }
  218. void set_cursor_mode(CursorMode::Enum mode) override
  219. {
  220. CE_UNUSED(mode);
  221. }
  222. void *native_handle() override
  223. {
  224. return s_android_device->_window;
  225. }
  226. void *native_display() override
  227. {
  228. return NULL;
  229. }
  230. };
  231. namespace window
  232. {
  233. Window *create(Allocator &a)
  234. {
  235. return CE_NEW(a, WindowAndroid)();
  236. }
  237. void destroy(Allocator &a, Window &w)
  238. {
  239. CE_DELETE(a, &w);
  240. }
  241. } // namespace window
  242. struct DisplayAndroid : public Display
  243. {
  244. void modes(Array<DisplayMode> &modes) override
  245. {
  246. CE_UNUSED(modes);
  247. }
  248. void set_mode(u32 id) override
  249. {
  250. CE_UNUSED(id);
  251. }
  252. };
  253. namespace display
  254. {
  255. Display *create(Allocator &a)
  256. {
  257. return CE_NEW(a, DisplayAndroid)();
  258. }
  259. void destroy(Allocator &a, Display &d)
  260. {
  261. CE_DELETE(a, &d);
  262. }
  263. } // namespace display
  264. static bool push_event(const OsEvent &ev)
  265. {
  266. return s_android_device->_events.push(ev);
  267. }
  268. bool next_event(OsEvent &ev)
  269. {
  270. return s_android_device->_events.pop(ev);
  271. }
  272. } // namespace crown
  273. void android_main(struct android_app *app)
  274. {
  275. using namespace crown;
  276. memory_globals::init();
  277. guid_globals::init();
  278. DeviceOptions opts(default_allocator(), 0, NULL);
  279. opts._asset_manager = app->activity->assetManager;
  280. s_android_device = CE_NEW(default_allocator(), AndroidDevice)(default_allocator());
  281. s_android_device->run(app, opts);
  282. CE_DELETE(default_allocator(), s_android_device);
  283. guid_globals::shutdown();
  284. memory_globals::shutdown();
  285. }
  286. #endif // if CROWN_PLATFORM_ANDROID