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