1 #include "main.h"
2
3 #include "gl.h"
4 #include "freetype.h"
5
6 #include "../debug.h"
7 #include "../filesys.h"
8 #include "../flist.h"
9 #include "../main.h"
10 #include "../settings.h"
11 #include "../stb.h"
12 #include "../theme.h"
13 #include "../tox.h"
14 #include "../ui.h"
15 #include "../utox.h"
16
17 #include "../ui/svg.h"
18 #include "../ui/edit.h"
19
20 #include "../layout/background.h"
21
22 #include "../native/keyboard.h"
23 #include "../native/notify.h"
24
25 #include <pthread.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <stdlib.h>
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 #include <android/native_activity.h>
36
37 static volatile bool destroy;
38 bool have_focus = false;
39
40 static bool shift;
41
42 static ANativeActivity * activity;
43 static ANativeWindow * window;
44 static volatile ANativeWindow *windowN;
45 static AInputQueue * inputQueue;
46 static volatile AInputQueue * inputQueueNew;
47
48 static volatile ARect rect;
49 static volatile bool _redraw;
50
51 const char *internalPath[UTOX_FILE_NAME_LENGTH];
52
53 static int pipefd[2];
54 typedef struct {
55 uint32_t msg;
56 uint16_t param1, param2;
57 void * data;
58 } PIPING;
59
postmessage_utox(UTOX_MSG msg,uint16_t param1,uint16_t param2,void * data)60 void postmessage_utox(UTOX_MSG msg, uint16_t param1, uint16_t param2, void *data) {
61 PIPING piping = {.msg = msg, .param1 = param1, .param2 = param2, .data = data };
62
63 write(pipefd[1], &piping, sizeof(PIPING));
64 }
65
init_ptt(void)66 void init_ptt(void) {
67 settings.push_to_talk = 0; /* android is unsupported */
68 }
check_ptt_key(void)69 bool check_ptt_key(void) {
70 return 1; /* android is unsupported */
71 }
exit_ptt(void)72 void exit_ptt(void) {
73 settings.push_to_talk = 0; /* android is unsupported */
74 }
75
image_set_filter(NATIVE_IMAGE * image,uint8_t filter)76 void image_set_filter(NATIVE_IMAGE *image, uint8_t filter) { /* Unsupported on android */
77 }
image_set_scale(NATIVE_IMAGE * image,double scale)78 void image_set_scale(NATIVE_IMAGE *image, double scale) { /* Unsupported on android */
79 }
80
draw_image(const NATIVE_IMAGE * data,int x,int y,uint32_t width,uint32_t height,uint32_t imgx,uint32_t imgy)81 void draw_image(const NATIVE_IMAGE *data, int x, int y, uint32_t width, uint32_t height, uint32_t imgx, uint32_t imgy) {
82 GL_draw_image(data, x, y, width, height, imgx, imgy);
83 }
84
draw_inline_image(uint8_t * img_data,size_t size,uint16_t w,uint16_t h,int x,int y)85 void draw_inline_image(uint8_t *img_data, size_t size, uint16_t w, uint16_t h, int x, int y) {
86 draw_image(img_data, x, y, w, h, 0, 0);
87 }
88
thread(void func (void *),void * args)89 void thread(void func(void *), void *args) {
90 pthread_t thread_temp;
91 pthread_create(&thread_temp, NULL, (void *(*)(void *))func, args);
92 }
93
yieldcpu(uint32_t ms)94 void yieldcpu(uint32_t ms) {
95 usleep(1000 * ms);
96 }
97
get_time(void)98 uint64_t get_time(void) {
99 struct timespec ts;
100 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
101
102 return ((uint64_t)ts.tv_sec * (1000 * 1000 * 1000)) + (uint64_t)ts.tv_nsec;
103 }
104
105
106 /* These functions aren't support on Andorid HELP?
107 * TODO: fix these! */
copy(int value)108 void copy(int value) { /* Unsupported on android */
109 }
paste(void)110 void paste(void) { /* Unsupported on android */
111 }
openurl(char * str)112 void openurl(char *str) { /* Unsupported on android */
113 }
openfilesend(void)114 void openfilesend(void) { /* Unsupported on android */
115 }
openfileavatar(void)116 void openfileavatar(void) { /* Unsupported on android */
117 }
118
119 typedef struct msg_header MSG_HEADER;
file_save_inline_image_png(MSG_HEADER * msg)120 void file_save_inline_image_png(MSG_HEADER *msg) { /* Unsupported on android */
121 }
setselection(char * data,uint16_t length)122 void setselection(char *data, uint16_t length) { /* Unsupported on android */
123 }
edit_will_deactivate(void)124 void edit_will_deactivate(void) { /* Unsupported on android */
125 }
126
utox_image_to_native(const UTOX_IMAGE data,size_t size,uint16_t * w,uint16_t * h,bool keep_alpha)127 NATIVE_IMAGE *utox_image_to_native(const UTOX_IMAGE data, size_t size, uint16_t *w, uint16_t *h, bool keep_alpha) {
128 return GL_utox_image_to_native(data, size, w, h, keep_alpha);
129 }
130
image_free(NATIVE_IMAGE * image)131 void image_free(NATIVE_IMAGE *image) {
132 if (!image) {
133 return;
134 }
135 GLuint texture = image;
136 glDeleteTextures(1, &texture);
137 }
138
139 // TODO: DRY. This function exists in both posix/filesys.c and in android/main.c
140 // Make a posix native_get_file that you pass a complete path to instead of letting it construct
141 // one would fix this.
opts_to_sysmode(UTOX_FILE_OPTS opts,char * mode)142 static void opts_to_sysmode(UTOX_FILE_OPTS opts, char *mode) {
143 if (opts & UTOX_FILE_OPTS_READ) {
144 mode[0] = 'r';
145 }
146
147 if (opts & UTOX_FILE_OPTS_APPEND) {
148 mode[0] = 'a';
149 } else if (opts & UTOX_FILE_OPTS_WRITE) {
150 mode[0] = 'w';
151 }
152
153 mode[1] = 'b';
154
155 if ((opts & (UTOX_FILE_OPTS_WRITE | UTOX_FILE_OPTS_APPEND)) && (opts & UTOX_FILE_OPTS_READ)) {
156 mode[2] = '+';
157 }
158
159 mode[3] = 0;
160
161 return;
162 }
163
native_get_file_simple(const char * path,UTOX_FILE_OPTS opts)164 FILE *native_get_file_simple(const char *path, UTOX_FILE_OPTS opts) {
165 char mode[4] = { 0 };
166 opts_to_sysmode(opts, mode);
167
168 FILE *fp = fopen(path, mode);
169
170 if (!fp && opts & UTOX_FILE_OPTS_READ && opts & UTOX_FILE_OPTS_WRITE) {
171 LOG_WARN("Android Native", "Unable to simple open, falling back to fd" );
172 // read won't create a file if it doesn't already exist. If we're allowed to write, let's try
173 // to create the file, then reopen it.
174 int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
175 fp = fdopen(fd, mode);
176 }
177
178 return fp;
179 }
180
native_get_file(const uint8_t * name,size_t * size,UTOX_FILE_OPTS opts,bool portable_mode)181 FILE *native_get_file(const uint8_t *name, size_t *size, UTOX_FILE_OPTS opts, bool portable_mode) {
182 uint8_t path[UTOX_FILE_NAME_LENGTH] = { 0 };
183
184 snprintf(path, UTOX_FILE_NAME_LENGTH, ANDROID_INTERNAL_SAVE);
185
186 // native_get_file should never be called with DELETE in combination with other FILE_OPTS.
187 assert(opts <= UTOX_FILE_OPTS_DELETE);
188 // WRITE and APPEND are mutually exclusive. WRITE will serve you a blank file. APPEND will append (duh).
189 assert((opts & UTOX_FILE_OPTS_WRITE && opts & UTOX_FILE_OPTS_APPEND) == false);
190
191 if (opts & UTOX_FILE_OPTS_READ || opts & UTOX_FILE_OPTS_MKDIR) {
192 if (!native_create_dir(path)) {
193 return NULL;
194 }
195 }
196
197 if (strlen((char *)path) + strlen((char *)name) >= UTOX_FILE_NAME_LENGTH) {
198 LOG_TRACE("Android Native", "Load directory name too long" );
199 return NULL;
200 } else {
201 snprintf((char *)path + strlen((char *)path), UTOX_FILE_NAME_LENGTH - strlen((char *)path), "%s", name);
202 }
203
204 if (opts == UTOX_FILE_OPTS_DELETE) {
205 remove((char *)path);
206 return NULL;
207 }
208
209 FILE *fp = native_get_file_simple((char *)path, opts);
210
211 if (fp == NULL) {
212 LOG_NOTE("Android Native", "Could not open %s" , path);
213 return NULL;
214 }
215
216 if (size != NULL) {
217 fseek(fp, 0, SEEK_END);
218 *size = ftell(fp);
219 fseek(fp, 0, SEEK_SET);
220 }
221
222 return fp;
223 }
224
native_move_file(const uint8_t * current_name,const uint8_t * new_name)225 bool native_move_file(const uint8_t *current_name, const uint8_t *new_name) {
226 if(!current_name || !new_name) {
227 return false;
228 }
229
230 return rename((char *)current_name, (char *)new_name);
231 }
232
native_select_dir_ft(uint32_t fid,void * file)233 void native_select_dir_ft(uint32_t fid, void *file) {
234 return; /* TODO unsupported on android
235 //fall back to working dir
236 char *path = malloc(file->name_length + 1);
237 memcpy(path, file->name, file->name_length);
238 path[file->name_length] = 0;
239
240 postmessage_toxcore(TOX_FILE_ACCEPT, fid, file->filenumber, path); */
241 }
242
native_autoselect_dir_ft(uint32_t fid,void * file)243 void native_autoselect_dir_ft(uint32_t fid, void *file) {
244 return; /* TODO unsupported on android
245 /* TODO: maybe do something different here?
246 char *path = malloc(file->name_length + 1);
247 memcpy(path, file->name, file->name_length);
248 path[file->name_length] = 0;
249 postmessage_toxcore(TOX_FILE_ACCEPT, fid, file->file_number, path); */
250 }
251
native_create_dir(const uint8_t * filepath)252 bool native_create_dir(const uint8_t *filepath) {
253 const int status = mkdir((char *)filepath, S_IRWXU);
254 if (status == 0 || errno == EEXIST) {
255 return true;
256 }
257 return false;
258 }
259
native_remove_file(const uint8_t * name,size_t length,bool portable_mode)260 bool native_remove_file(const uint8_t *name, size_t length, bool portable_mode) {
261 uint8_t path[UTOX_FILE_NAME_LENGTH] = { 0 };
262
263 snprintf((char *)path, UTOX_FILE_NAME_LENGTH, ANDROID_INTERNAL_SAVE);
264
265 if (strlen((const char *)path) + length >= UTOX_FILE_NAME_LENGTH) {
266 LOG_TRACE("Android Native", "File/directory name too long, unable to remove" );
267 return 0;
268 } else {
269 snprintf((char *)path + strlen((const char *)path), UTOX_FILE_NAME_LENGTH - strlen((const char *)path), "%.*s",
270 (int)length, (char *)name);
271 }
272
273 if (remove((const char *)path)) {
274 LOG_ERR("Android Native", "Unable to delete file!\n\t\t%s" , path);
275 return 0;
276 } else {
277 LOG_INFO("Android Native", "File deleted!" );
278 LOG_TRACE("Android Native", "\t%s" , path);
279 }
280 return 1;
281 }
282
native_export_chatlog_init(uint32_t friend_number)283 void native_export_chatlog_init(uint32_t friend_number)
284 { /* Unsupported on Android */ }
285
native_save_image_png(const char * name,const uint8_t * image,const int image_size)286 bool native_save_image_png(const char *name, const uint8_t *image, const int image_size) {
287 /* Unsupported on Android */
288 }
289
flush_file(FILE * file)290 void flush_file(FILE *file) {
291 fflush(file);
292 int fd = fileno(file);
293 fsync(fd);
294 }
295
ch_mod(uint8_t * file)296 int ch_mod(uint8_t *file) {
297 /* You're probably looking for ./xlib as android isn't working when this was written. */
298 return -1;
299 }
300
file_lock(FILE * file,uint64_t start,size_t length)301 int file_lock(FILE *file, uint64_t start, size_t length) {
302 // Unsupported on android
303 return 0;
304 }
305
native_video_init(void * handle)306 bool native_video_init(void *handle) {
307 return 0; /* Unsupported on android */
308 }
native_video_close(void * handle)309 void native_video_close(void *handle) { /* Unsupported on android */
310 }
native_video_startread(void)311 bool native_video_startread(void) {
312 return 1; /* Unsupported on android */
313 }
native_video_endread(void)314 bool native_video_endread(void) {
315 return 1; /* Unsupported on android */
316 }
native_video_getframe(uint8_t * y,uint8_t * u,uint8_t * v,uint16_t width,uint16_t height)317 int native_video_getframe(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t width, uint16_t height) {
318 return 0; /* Unsupported on android */
319 }
file_unlock(FILE * file,uint64_t start,size_t length)320 int file_unlock(FILE *file, uint64_t start, size_t length) {
321 return 0; /* Unsupported on android */
322 }
323
setscale_fonts(void)324 void setscale_fonts(void) {
325 freefonts();
326 loadfonts();
327 }
328
329
setscale(void)330 void setscale(void) {
331 if (window) {
332 svg_draw(0);
333 }
334 setscale_fonts();
335 }
336
notify(char * title,uint16_t title_length,const char * msg,uint16_t msg_length,void * object,bool is_group)337 void notify(char *title, uint16_t title_length, const char *msg, uint16_t msg_length, void *object,
338 bool is_group)
339 { /* Unsupported on android */ }
340
desktopgrab(bool video)341 void desktopgrab(bool video)
342 { /* Unsupported on android */ }
343
video_frame(uint16_t id,uint8_t * img_data,uint16_t width,uint16_t height,bool resize)344 void video_frame(uint16_t id, uint8_t *img_data, uint16_t width, uint16_t height,
345 bool resize)
346 { /* Unsupported on android */ }
347
video_begin(uint16_t id,char * name,uint16_t name_length,uint16_t width,uint16_t height)348 void video_begin(uint16_t id, char *name, uint16_t name_length, uint16_t width,
349 uint16_t height)
350 { /* Unsupported on android */ }
351
video_end(uint16_t id)352 void video_end(uint16_t id)
353 { /* Unsupported on android */ }
354
native_video_detect(void)355 uint16_t native_video_detect(void)
356 { return 0; /* Unsupported on android */ }
357
video_init(void * handle)358 bool video_init(void *handle)
359 { return 0; /* Unsupported on android */ }
360
video_close(void * handle)361 void video_close(void *handle)
362 { /* Unsupported on android */ }
363
video_startread(void)364 bool video_startread(void)
365 { return 1; /* Unsupported on android */ }
366
video_endread(void)367 bool video_endread(void)
368 { return 1; /* Unsupported on android */ }
369
video_getframe(uint8_t * y,uint8_t * u,uint8_t * v,uint16_t width,uint16_t height)370 int video_getframe(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t width, uint16_t height)
371 { return 0; /* Unsupported on android */ }
372
373
374
375 #define MAP(x, y) case AKEYCODE_##x : return y
376
377 #define MAPS(x, y, z) case AKEYCODE_##x : return ((shift) ? z : y)
378
379 #define MAPC(x) case AKEYCODE_##x : return (#x[0] + ((shift) ? 0 : ('a' - 'A')))
380
381 #define MAPN(x, y) case AKEYCODE_##x : return ((shift) ? y : #x[0])
382
getkeychar(int32_t key)383 static uint32_t getkeychar(int32_t key) /* get a character from an android keycode */ {
384
385 switch (key) {
386 MAP(ENTER, KEY_RETURN);
387 MAP(DEL, KEY_BACK);
388 MAP(DPAD_LEFT, KEY_LEFT);
389 MAP(DPAD_RIGHT, KEY_RIGHT);
390 MAP(DPAD_UP, KEY_UP);
391 MAP(DPAD_DOWN, KEY_DOWN);
392
393 MAP(SPACE, ' ');
394
395 MAPS(MINUS, '-', '_');
396 MAPS(EQUALS, '=', '+');
397 MAPS(LEFT_BRACKET, '[', '{');
398 MAPS(RIGHT_BRACKET, ']', '}');
399 MAPS(BACKSLASH, '\\', '|');
400 MAPS(SEMICOLON, ';', ':');
401 MAPS(APOSTROPHE, '\'', '\"');
402 MAPS(COMMA, ',', '<');
403 MAPS(PERIOD, '.', '>');
404 MAPS(SLASH, '/', '?');
405 MAPS(GRAVE, '`', '~');
406
407 MAP(AT, '@');
408 MAP(STAR, '*');
409 MAP(PLUS, '+');
410
411 MAPC(A);
412 MAPC(B);
413 MAPC(C);
414 MAPC(D);
415 MAPC(E);
416 MAPC(F);
417 MAPC(G);
418 MAPC(H);
419 MAPC(I);
420 MAPC(J);
421 MAPC(K);
422 MAPC(L);
423 MAPC(M);
424 MAPC(N);
425 MAPC(O);
426 MAPC(P);
427 MAPC(Q);
428 MAPC(R);
429 MAPC(S);
430 MAPC(T);
431 MAPC(U);
432 MAPC(V);
433 MAPC(W);
434 MAPC(X);
435 MAPC(Y);
436 MAPC(Z);
437 MAPN(0, ')');
438 MAPN(1, '!');
439 MAPN(2, '@');
440 MAPN(3, '#');
441 MAPN(4, '$');
442 MAPN(5, '%');
443 MAPN(6, '^');
444 MAPN(7, '&');
445 MAPN(8, '*');
446 MAPN(9, '(');
447
448 default: {
449 LOG_TRACE("Android", "un-mapped %u", key);
450 break;
451 }
452 }
453 return 0;
454
455 #undef MAP
456 #undef MAPC
457 }
458
redraw(void)459 void redraw(void) {
460 _redraw = 1;
461 }
462
force_redraw(void)463 void force_redraw(void) {
464 redraw();
465 }
466
update_tray(void)467 void update_tray(void) { /* Unsupported on android */
468 }
469
config_osdefaults(UTOX_SAVE * r)470 void config_osdefaults(UTOX_SAVE *r) { /* Unsupported on android */
471 }
472
utox_android_redraw_window(void)473 void utox_android_redraw_window(void) {
474 if (!_redraw) {
475 return;
476 }
477 _redraw = GL_utox_android_redraw_window();
478 panel_draw(&panel_root, 0, 0, settings.window_width, settings.window_height);
479 }
480
481 int lx = 0, ly = 0;
482 uint64_t p_last_down;
483 bool p_down, already_up;
utox_andoid_input(AInputQueue * in_queue,AInputEvent * event)484 static void utox_andoid_input(AInputQueue *in_queue, AInputEvent *event) {
485 if (AInputQueue_preDispatchEvent(inputQueue, event) == 0) {
486 int32_t handled = 1;
487
488 int32_t type = AInputEvent_getType(event);
489 if (type == AINPUT_EVENT_TYPE_MOTION) {
490 int32_t action = AMotionEvent_getAction(event);
491 int32_t pointer_index =
492 ((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
493 int32_t action_bits = (action & AMOTION_EVENT_ACTION_MASK);
494
495 float x = AMotionEvent_getX(event, pointer_index);
496 float y = AMotionEvent_getY(event, pointer_index);
497
498 switch (action_bits) {
499 case AMOTION_EVENT_ACTION_DOWN:
500 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
501 lx = x;
502 ly = y;
503 panel_mmove(&panel_root, 0, 0, settings.window_width, settings.window_height, x, y, 0, 0);
504 panel_mdown(&panel_root);
505 // pointer[pointer_index].down = true;
506 // pointer[pointer_index].x = x;
507 // pointer[pointer_index].y = y;
508
509 // pointerinput2(pointer_index);
510
511 already_up = 0;
512 LOG_TRACE("Android", "down %f %f, %u" , x, y, pointer_index);
513 p_down = 1;
514 p_last_down = get_time();
515 break;
516 }
517
518 case AMOTION_EVENT_ACTION_UP:
519 case AMOTION_EVENT_ACTION_POINTER_UP: {
520 // panel_mmove(&panel_root, 0, 0, width, height, x, y, 0);
521 if (!already_up) {
522 panel_mup(&panel_root);
523 panel_mleave(&panel_root);
524 }
525 // pointer[pointer_index].down = false;
526 // pointer[pointer_index].x = x;
527 // pointer[pointer_index].y = y;
528
529 // pointerinput(pointer_index);
530
531 LOG_TRACE("Android", "up %f %f, %u" , x, y, pointer_index);
532 p_down = 0;
533 break;
534 }
535
536 case AMOTION_EVENT_ACTION_MOVE: {
537 panel_mmove(&panel_root, 0, 0, settings.window_width, settings.window_height, x, y, x - lx, y - ly);
538 if (lx != (int)x || ly != (int)y) {
539 p_down = 0;
540 lx = x;
541 ly = y;
542 LOG_TRACE("Android", "move %f %f, %u" , x, y, pointer_index);
543 }
544 // pointer[pointer_index].x = x;
545 // pointer[pointer_index].y = y;
546
547 break;
548 }
549 }
550 } else if (type == AINPUT_EVENT_TYPE_KEY) {
551 int32_t action = AMotionEvent_getAction(event);
552 int32_t key = AKeyEvent_getKeyCode(event);
553
554 if (action == AKEY_EVENT_ACTION_DOWN) {
555 switch (key) {
556 case AKEYCODE_VOLUME_UP:
557 case AKEYCODE_VOLUME_DOWN: {
558 handled = 0;
559 break;
560 }
561
562 case AKEYCODE_MENU: {
563 // open menu
564 break;
565 }
566
567 case AKEYCODE_SHIFT_LEFT:
568 case AKEYCODE_SHIFT_RIGHT: {
569 shift = 1;
570 break;
571 }
572
573 case AKEYCODE_BACK: {
574 // ANativeActivity_finish(activity);
575 break;
576 }
577
578
579 default: {
580 uint32_t c = getkeychar(key);
581 if (c != 0) {
582 if (edit_active()) {
583 // LOG_TRACE("Android", "%u" , c);
584 edit_char(c, 0, 0);
585 }
586 // inputchar(c);
587 }
588 break;
589 }
590 }
591 } else if (action == AKEY_EVENT_ACTION_UP) {
592 if (key == AKEYCODE_SHIFT_LEFT || key == AKEYCODE_SHIFT_RIGHT) {
593 shift = 0;
594 }
595 }
596 }
597 AInputQueue_finishEvent(inputQueue, event, handled);
598 }
599 }
600
android_main(struct android_app * state)601 static void android_main(struct android_app *state) {
602 utox_init();
603
604 theme_load(THEME_DEFAULT);
605
606 settings.verbose = ~0;
607
608 // Make sure glue isn't stripped
609 // ANativeActivity* nativeActivity = state->activity;
610 // internalPath = nativeActivity->internalDataPath;
611
612 pipe(pipefd);
613 fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
614
615 // Override to max spam for android
616 settings.verbose = LOG_LVL_TRACE;
617
618 thread(toxcore_thread, NULL);
619
620 initfonts();
621
622 ui_rescale(12);
623
624 /* wait for tox thread to start */
625 while (!tox_thread_init) {
626 yieldcpu(1);
627 }
628
629 /* Code has been changed, this probably should be moved! */
630 flist_start();
631 ui_rescale(15);
632
633 while (!destroy) {
634 if (p_down && (p_last_down + 500 * 1000 * 1000) < get_time()) {
635 panel_mup(&panel_root);
636 panel_mright(&panel_root);
637 p_down = 0;
638 already_up = 1;
639 }
640
641 inputQueue = (AInputQueue *)inputQueueNew;
642 if (inputQueue != NULL) {
643 AInputEvent *event = NULL;
644 while (AInputQueue_hasEvents(inputQueue) && AInputQueue_getEvent(inputQueue, &event) >= 0) {
645 utox_andoid_input(inputQueue, event);
646 }
647 }
648
649 int rlen, len;
650 PIPING piping;
651 while ((len = read(pipefd[0], (void *)&piping, sizeof(PIPING))) > 0) {
652 LOG_TRACE("Android", "Piping %u %u" , len, sizeof(PIPING));
653 while (len != sizeof(PIPING)) {
654 if ((rlen = read(pipefd[0], (void *)&piping + len, sizeof(PIPING) - len)) > 0) {
655 len += rlen;
656 }
657 }
658
659 utox_message_dispatch(piping.msg, piping.param1, piping.param2, piping.data);
660 }
661
662 ANativeWindow *win = (ANativeWindow *)windowN;
663 if (win != window) { // new window
664 if (window != NULL) {
665 LOG_INFO("AndroidNative", "Replace old Window");
666 freefonts();
667 GL_raze_surface();
668 }
669 window = win;
670
671 if (window != NULL) {
672 if (init_display(window) == false) {
673 LOG_INFO("AndroidNative", "init_err");
674 ANativeActivity_finish(activity);
675 break;
676 }
677 }
678 }
679
680 if (window != NULL && have_focus) {
681 utox_android_redraw_window();
682 }
683
684 usleep(1000);
685 }
686
687 LOG_TRACE("Android", "ANDROID DESTROYED" );
688 }
689
showkeyboard(bool show)690 void showkeyboard(bool show) {
691 JavaVM *vm = activity->vm;
692 JNIEnv *env = activity->env;
693
694 JavaVMAttachArgs lJavaVMAttachArgs;
695 lJavaVMAttachArgs.version = JNI_VERSION_1_6;
696 lJavaVMAttachArgs.name = "NativeThread";
697 lJavaVMAttachArgs.group = NULL;
698
699 (*vm)->AttachCurrentThread(vm, &env, &lJavaVMAttachArgs); // error check
700
701 jobject lNativeActivity = activity->clazz;
702 jclass ClassNativeActivity = (*env)->GetObjectClass(env, lNativeActivity);
703
704 jclass ClassInputMethodManager = (*env)->FindClass(env, "android/view/inputmethod/InputMethodManager");
705 jfieldID fid =
706 (*env)->GetFieldID(env, ClassNativeActivity, "mIMM", "Landroid/view/inputmethod/InputMethodManager;");
707 jobject lInputMethodManager = (*env)->GetObjectField(env, lNativeActivity, fid);
708
709 jmethodID MethodGetWindow = (*env)->GetMethodID(env, ClassNativeActivity, "getWindow", "()Landroid/view/Window;");
710 jobject lWindow = (*env)->CallObjectMethod(env, lNativeActivity, MethodGetWindow);
711 jclass ClassWindow = (*env)->FindClass(env, "android/view/Window");
712 jmethodID MethodGetDecorView = (*env)->GetMethodID(env, ClassWindow, "getDecorView", "()Landroid/view/View;");
713 jobject lDecorView = (*env)->CallObjectMethod(env, lWindow, MethodGetDecorView);
714
715
716 if (show) {
717 jmethodID MethodShowSoftInput =
718 (*env)->GetMethodID(env, ClassInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z");
719 jboolean lResult = (*env)->CallBooleanMethod(env, lInputMethodManager, MethodShowSoftInput, lDecorView, 0);
720 utox_android_redraw_window();
721 } else {
722 jclass ClassView = (*env)->FindClass(env, "android/view/View");
723 jmethodID MethodGetWindowToken =
724 (*env)->GetMethodID(env, ClassView, "getWindowToken", "()Landroid/os/IBinder;");
725 jobject lBinder = (*env)->CallObjectMethod(env, lDecorView, MethodGetWindowToken);
726
727 jmethodID MethodHideSoftInput =
728 (*env)->GetMethodID(env, ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
729 jboolean lRes = (*env)->CallBooleanMethod(env, lInputMethodManager, MethodHideSoftInput, lBinder, 0);
730 }
731
732 /*jmethodID MethodToggle = (*env)->GetMethodID(env, ClassInputMethodManager, "toggleSoftInput", "(II)V");
733 (*env)->CallVoidMethod(env, lInputMethodManager, MethodToggle, 0, 0);*/
734
735 (*vm)->DetachCurrentThread(vm);
736 }
737
onDestroy(ANativeActivity * act)738 static void onDestroy(ANativeActivity *act) {
739 destroy = 1;
740 }
741
onNativeWindowCreated(ANativeActivity * act,ANativeWindow * win)742 static void onNativeWindowCreated(ANativeActivity *act, ANativeWindow *win) {
743 LOG_NOTE("AndroidNative", "Native Window Made");
744 windowN = win;
745 }
746
onNativeWindowDestroyed(ANativeActivity * act,ANativeWindow * win)747 static void onNativeWindowDestroyed(ANativeActivity *act, ANativeWindow *win) {
748 LOG_NOTE("AndroidNative", "Native Window Killed");
749 windowN = NULL;
750 }
751
onWindowFocusChanged(ANativeActivity * act,int focus)752 static void onWindowFocusChanged(ANativeActivity *act, int focus) {
753 have_focus = (focus != 0);
754 }
755
onInputQueueCreated(ANativeActivity * act,AInputQueue * queue)756 static void onInputQueueCreated(ANativeActivity *act, AInputQueue *queue) {
757 inputQueueNew = queue;
758 }
759
onInputQueueDestroyed(ANativeActivity * act,AInputQueue * queue)760 static void onInputQueueDestroyed(ANativeActivity *act, AInputQueue *queue) {
761 inputQueueNew = NULL;
762 }
763
onContentRectChanged(ANativeActivity * activity,const ARect * r)764 static void onContentRectChanged(ANativeActivity *activity, const ARect *r) {
765 rect = *r;
766 LOG_TRACE("AndroidNative", "window changed rect: %u %u %u %u" , rect.left, rect.right, rect.top, rect.bottom);
767
768 settings.window_baseline = rect.bottom;
769 _redraw = 1;
770 }
771
ANativeActivity_onCreate(ANativeActivity * act,void * savedState,size_t savedStateSize)772 __attribute__((externally_visible)) void ANativeActivity_onCreate(ANativeActivity *act, void *savedState,
773 size_t savedStateSize) {
774 if (!act) {
775 return;
776 }
777 activity = act;
778
779 // Add callbacks here (find them in android/native_activity.h)
780 act->callbacks->onDestroy = onDestroy;
781 act->callbacks->onNativeWindowCreated = onNativeWindowCreated;
782 act->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
783 act->callbacks->onWindowFocusChanged = onWindowFocusChanged;
784 act->callbacks->onInputQueueCreated = onInputQueueCreated;
785 act->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
786 act->callbacks->onContentRectChanged = onContentRectChanged;
787
788 // start main thread (android_main)
789 pthread_t thread;
790 pthread_attr_t myattr;
791 pthread_attr_init(&myattr);
792 pthread_attr_setdetachstate(&myattr, PTHREAD_CREATE_DETACHED);
793 pthread_create(&thread, &myattr, (void *(*)(void *))android_main, NULL);
794 }
795
launch_at_startup(bool should)796 void launch_at_startup(bool should) {}
797