*/}}
YimingWu 6 ヶ月 前
コミット
388e0f06e7
8 ファイル変更431 行追加43 行削除
  1. 8 4
      la_data.c
  2. 6 2
      la_interface.h
  3. 382 18
      la_kernel.c
  4. 4 3
      la_tns_kernel.c
  5. 1 1
      la_util.c
  6. 0 2
      la_util.h
  7. 17 1
      resources/la_operators.c
  8. 13 12
      resources/la_widgets.c

+ 8 - 4
la_data.c

@@ -3790,7 +3790,7 @@ laUDF *laOpenUDF(char *FileName, int ReadToMemory, laUDFRegistry* ReadRegistryRe
 
     strSafeSet(&udf->FileName, FileName);
 
-    udf->DiskFile = fopen(udf->FileName->Ptr, "rb");
+    udf->DiskFile = fopen(SSTR(udf->FileName), "rb");
     if (!udf->DiskFile) return 0;
 
     if(ReadToMemory){ la_ReadUDFToMemory(udf); fclose(udf->DiskFile); udf->DiskFile = 0; }
@@ -3912,7 +3912,7 @@ void laRefreshUDFResourcesIn(char* rootpath){
     char Final[2048];
     int NumFiles=-1;
     int len = strlen(rootpath);
-    if (rootpath[len - 1] != LA_PATH_SEP) strcat(rootpath, LA_PATH_SEPSTR);
+    if (len && rootpath[len - 1] != LA_PATH_SEP) strcat(rootpath, LA_PATH_SEPSTR);
 #ifdef __linux__
     struct dirent **NameList=0;
     NumFiles=scandir(rootpath,&NameList,0,alphasort);
@@ -3923,6 +3923,7 @@ void laRefreshUDFResourcesIn(char* rootpath){
         for(laExtensionType* et=MAIN.ExtraExtensions.pFirst;et;et=et->Item.pNext){ if(et->FileType==LA_FILETYPE_UDF && strSame(et->Extension,format)){file_okay=1;break;} }
         if(!file_okay) continue;
 
+
         struct stat s;
         sprintf(Final, "%s%s",rootpath,d->d_name);
         stat(Final, &s);
@@ -3975,8 +3976,11 @@ void laRefreshUDFRegistries(){
     laClearUDFRegistries();
     char LookupM[PATH_MAX];
     for(laResourceFolder* rf = MAIN.ResourceFolders.pFirst;rf;rf=rf->Item.pNext){
-        if(!rf->Path) continue;
-        realpath(rf->Path->Ptr, LookupM);
+#ifdef LAGUI_ANDROID
+        sprintf(LookupM,"%s/%s",MAIN.InternalDataPath,SSTR(rf->Path));
+#else
+        realpath(SSTR(rf->Path), LookupM);
+#endif
         laRefreshUDFResourcesIn(LookupM);
     }
 }

+ 6 - 2
la_interface.h

@@ -447,7 +447,8 @@ STRUCTURE(LA){
     int AppReady,AppEnabled;
     int ContextRebindRequired;
     AAssetManager *AssetManager;
-    char *InternalDataPath; 
+    char *InternalDataPath;
+    char *ExternalDataPath;
 #endif
     int InkOrWinTab;
     int WacomDeviceStylus; real StylusPressure, StylusOrientation, StylusDeviation, StylusMaxPressure;
@@ -707,7 +708,7 @@ STRUCTURE(laWindow){
 
     SYSWINDOW* win;
     SYSGLCONTEXT glc;
-#ifdef LA_USE_GLES
+#if defined(LA_USE_GLES) && !defined(LAGUI_ANDROID)
     EGLSurface egl_surf;
 #endif
     int GLDebugNeedsUpdate;
@@ -2620,6 +2621,9 @@ void laGetConfirmString(laOperator *a, char *buf);
 void *laGetConfirmUserData(laOperator *a);
 //int laInvokeSub(laProp* From, char * ID, laEvent* e, void* inst);
 
+void la_DisplayKeyboard(bool pShow);
+void la_HideNavBar();
+
 void laFinalizeOperators();
 
 int laWaitFor(laOperator *Who, int State);

+ 382 - 18
la_kernel.c

@@ -52,12 +52,11 @@
 #endif
 #ifdef LAGUI_ANDROID
 #include <GLES3/gl32.h>
+#include <jni.h>
 #include <android/log.h>
 #include <android/native_activity.h>
-#include <jni.h>
 #include <android/native_window.h>
 #include <android/native_window_jni.h>
-#include <jni.h>
 #include <android_native_app_glue.h>
 #include <android/window.h>
 #include <android/asset_manager.h>
@@ -1306,11 +1305,15 @@ int laGetReadyWith(laInitArguments* ia){
     MAIN.WireThickness = 5;
     MAIN.WireSaggyness = 0.5;
 
+#ifdef LAGUI_ANDROID
+    laAddResourceFolder("");
+#else
     laAddResourceFolder(".");
+#endif
 
     laSetMenuBarTemplates(laui_DefaultMenuButtons, laui_DefaultMenuExtras, "🧩LaGUI 2022");
 
-    laAddExtraExtension(LA_FILETYPE_UDF,"udf",0);
+    laAddExtraExtension(LA_FILETYPE_UDF,"udf",0ll);
 
     la_InitProgressWindow();
     la_MakeTranslations();
@@ -1442,12 +1445,22 @@ void laShutoff(int SavePrefereces){
 }
 
 int laRestoreFactorySettings(){
-    char path[1024]; sprintf(path, "%s%s", SSTR(MAIN.WorkingDirectory), "preferences.udf");
+    char path[1024];
+#ifdef LAGUI_ANDROID
+    sprintf(path,"%s","preferences.udf");
+#else
+    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");
+#endif
     if(remove(path)){ return 0; }
     return 1;
 }
 void laSaveUserPreferences(){
-    char path[1024]; sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");
+    char path[1024];
+#ifdef LAGUI_ANDROID
+    sprintf(path,"%s","preferences.udf");
+#else
+    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");
+#endif
     laUDF* udf=laPrepareUDF(path);
     laWriteProp(udf,"la.windows");
     laWriteProp(udf,"la.user_preferences");
@@ -1459,10 +1472,15 @@ void laSaveUserPreferences(){
     laPackUDF(udf,0,0);
 }
 void laEnsureUserPreferences(){
-    char path[1024]; sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");
+    char path[1024];
+#ifdef LAGUI_ANDROID
+    sprintf(path,"%s/%s",MAIN.InternalDataPath,"preferences.udf");
+#else
+    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");
+#endif
     laUDFRegistry* r=laFindUDFRegistry(path);
     if(!r){ laSaveUserPreferences(); return; }
-    laUDF* udf=laOpenUDF(r->Path->Ptr,1,0,0); if(!udf){ logPrint("Can't read preferences. Using default settings."); return; }
+    laUDF* udf=laOpenUDF(SSTR(r->Path),1,0,0); if(!udf){ logPrint("Can't read preferences on %s. Using default settings.",SSTR(r->Path)); return; }
     laClearUDFRegistries();
     while(MAIN.ResourceFolders.pFirst){ laRemoveResourceFolder(MAIN.ResourceFolders.pFirst); }
     while(MAIN.InputMapping->InputMappings.pFirst){ laRemoveInputMapping(MAIN.InputMapping->InputMappings.pFirst); }
@@ -1482,6 +1500,7 @@ void laAddExtraExtension(int FileType, ...){
         laExtensionType* et=memAcquireSimple(sizeof(laExtensionType));
         et->FileType=FileType; et->Extension=ext;
         lstAppendItem(&MAIN.ExtraExtensions, et);
+        logPrintNew("add ext %s",ext);
     }
     va_end(list);
 }
@@ -3075,6 +3094,9 @@ void la_AssignWindowPP(laWindow* w){
     w->PP.LastPs->Type = U'.';
 }
 laWindow *laDesignWindow(int X, int Y, int W, int H){
+#ifdef LAGUI_ANDROID
+    if(MAIN.Windows.pFirst){ return MAIN.Windows.pFirst; }
+#endif
     laWindow *n = memAcquire(sizeof(laWindow));
 
     strSafeSet(&n->Title, "Empty SYSWINDOW");
@@ -8041,6 +8063,11 @@ void laMainLoop(){
 
     laSetWindowCursor(LA_ARROW);
     MAIN.DelayTriggered=1;
+
+#ifdef LAGUI_ANDROID
+    while(!MAIN.AppReady){ usleep(1000); }
+    la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
+#endif
     
     while (1){
         laRecordTime(&FrameStartTime);
@@ -8110,6 +8137,8 @@ int la_AndroidInitGraphics(void){
     MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);
     MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);
 
+    logPrintNew("Android init graphics %d x %d", MAIN.AppWidth, MAIN.AppHeight);
+
     la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
 
     EGLint samples = 0;
@@ -8132,7 +8161,7 @@ int la_AndroidInitGraphics(void){
 
     EGLint numConfigs = 0;
 
-    MAIN.egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    MAIN.egl_dpy=eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (MAIN.egl_dpy == EGL_NO_DISPLAY){ logPrint("Android no display"); return -1; }
     if (eglInitialize(MAIN.egl_dpy, NULL, NULL) == EGL_FALSE){ logPrint("Android can't init display");  return -1; }
     eglChooseConfig(MAIN.egl_dpy, framebufferAttribs, &MAIN.BestFBC, 1, &numConfigs);
@@ -8146,16 +8175,13 @@ int la_AndroidInitGraphics(void){
 
     ANativeWindow_setBuffersGeometry(MAIN.app->window, MAIN.AppWidth, MAIN.AppHeight, displayFormat);
 
-    MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_surf, MAIN.BestFBC, MAIN.app->window, NULL);
+    MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, MAIN.app->window, NULL);
 
     // There must be at least one frame displayed before the buffers are swapped
-    //eglSwapInterval(MAIN.egl_dpy, 1);
+    eglSwapInterval(MAIN.egl_dpy, 1);
 
     if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return -1; }
-    
-    glViewport(0,0,MAIN.AppWidth, MAIN.AppHeight);
-    glClearColor(0,1,1,1);
-    glClear(GL_COLOR_BUFFER_BIT);
+
     eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
 
     MAIN.AppReady = 1;
@@ -8192,7 +8218,7 @@ static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){
                 //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight);
                 //glClearColor(1,0.2,1,1);
                 //glClear(GL_COLOR_BUFFER_BIT);
-                eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
+                //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);
                 la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
 
                 MAIN.ContextRebindRequired = false;
@@ -8223,6 +8249,7 @@ static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){
     case APP_CMD_CONFIG_CHANGED:
         MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);
         MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);
+        
         la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);
         //AConfiguration_fromAssetManager(MAIN.app->config, MAIN.app->activity->assetManager);
         //print_cur_config(MAIN.app);
@@ -8233,6 +8260,172 @@ static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){
     }
 }
 
+#define KEYCODE_MAP_SIZE 162
+static const int KeycodeMap[KEYCODE_MAP_SIZE] = {
+    0,           // AKEYCODE_UNKNOWN
+    0,                  // AKEYCODE_SOFT_LEFT
+    0,                  // AKEYCODE_SOFT_RIGHT
+    0,                  // AKEYCODE_HOME
+    0,           // AKEYCODE_BACK
+    0,                  // AKEYCODE_CALL
+    0,                  // AKEYCODE_ENDCALL
+    '0',           // AKEYCODE_0
+    '1',            // AKEYCODE_1
+    '2',            // AKEYCODE_2
+    '3',          // AKEYCODE_3
+    '4',           // AKEYCODE_4
+    '5',           // AKEYCODE_5
+    '6',            // AKEYCODE_6
+    '7',          // AKEYCODE_7
+    '8',          // AKEYCODE_8
+    '9',           // AKEYCODE_9
+    0,                  // AKEYCODE_STAR
+    0,                  // AKEYCODE_POUND
+    LA_KEY_ARRUP,             // AKEYCODE_DPAD_UP
+    LA_KEY_ARRDOWN,           // AKEYCODE_DPAD_DOWN
+    LA_KEY_ARRLEFT,           // AKEYCODE_DPAD_LEFT
+    LA_KEY_ARRRIGHT,          // AKEYCODE_DPAD_RIGHT
+    0,                  // AKEYCODE_DPAD_CENTER
+    0,      // AKEYCODE_VOLUME_UP
+    0,    // AKEYCODE_VOLUME_DOWN
+    0,                  // AKEYCODE_POWER
+    0,                  // AKEYCODE_CAMERA
+    0,                  // AKEYCODE_CLEAR
+    'a',              // AKEYCODE_A
+    'b',              // AKEYCODE_B
+    'c',              // AKEYCODE_C
+    'd',              // AKEYCODE_D
+    'e',              // AKEYCODE_E
+    'f',              // AKEYCODE_F
+    'g',              // AKEYCODE_G
+    'h',              // AKEYCODE_H
+    'i',              // AKEYCODE_I
+    'j',              // AKEYCODE_J
+    'k',              // AKEYCODE_K
+    'l',              // AKEYCODE_L
+    'm',              // AKEYCODE_M
+    'n',              // AKEYCODE_N
+    'o',              // AKEYCODE_O
+    'p',              // AKEYCODE_P
+    'q',              // AKEYCODE_Q
+    'r',              // AKEYCODE_R
+    's',              // AKEYCODE_S
+    't',              // AKEYCODE_T
+    'u',              // AKEYCODE_U
+    'v',              // AKEYCODE_V
+    'w',              // AKEYCODE_W
+    'x',              // AKEYCODE_X
+    'y',              // AKEYCODE_Y
+    'z',              // AKEYCODE_Z
+    ',',          // AKEYCODE_COMMA
+    '.',         // AKEYCODE_PERIOD
+    LA_KEY_ALT,       // AKEYCODE_ALT_LEFT
+    LA_KEY_ALT,      // AKEYCODE_ALT_RIGHT
+    LA_KEY_SHIFT,     // AKEYCODE_SHIFT_LEFT
+    LA_KEY_SHIFT,    // AKEYCODE_SHIFT_RIGHT
+    LA_KEY_TAB,            // AKEYCODE_TAB
+    ' ',          // AKEYCODE_SPACE
+    0,                  // AKEYCODE_SYM
+    0,                  // AKEYCODE_EXPLORER
+    0,                  // AKEYCODE_ENVELOPE
+    LA_KEY_ENTER,          // AKEYCODE_ENTER
+    LA_KEY_BACKSPACE,      // AKEYCODE_DEL
+    '`',          // AKEYCODE_GRAVE
+    '-',          // AKEYCODE_MINUS
+    '=',          // AKEYCODE_EQUALS
+    '(',   // AKEYCODE_LEFT_BRACKET
+    ')',  // AKEYCODE_RIGHT_BRACKET
+    '\\',      // AKEYCODE_BACKSLASH
+    ';',      // AKEYCODE_SEMICOLON
+    '\'',     // AKEYCODE_APOSTROPHE
+    '/',          // AKEYCODE_SLASH
+    0,                  // AKEYCODE_AT
+    0,                  // AKEYCODE_NUM
+    0,                  // AKEYCODE_HEADSETHOOK
+    0,                  // AKEYCODE_FOCUS
+    0,                  // AKEYCODE_PLUS
+    0,           // AKEYCODE_MENU
+    0,                  // AKEYCODE_NOTIFICATION
+    0,                  // AKEYCODE_SEARCH
+    0,                  // AKEYCODE_MEDIA_PLAY_PAUSE
+    0,                  // AKEYCODE_MEDIA_STOP
+    0,                  // AKEYCODE_MEDIA_NEXT
+    0,                  // AKEYCODE_MEDIA_PREVIOUS
+    0,                  // AKEYCODE_MEDIA_REWIND
+    0,                  // AKEYCODE_MEDIA_FAST_FORWARD
+    0,                  // AKEYCODE_MUTE
+    0,        // AKEYCODE_PAGE_UP
+    0,      // AKEYCODE_PAGE_DOWN
+    0,                  // AKEYCODE_PICTSYMBOLS
+    0,                  // AKEYCODE_SWITCH_CHARSET
+    0,                  // AKEYCODE_BUTTON_A
+    0,                  // AKEYCODE_BUTTON_B
+    0,                  // AKEYCODE_BUTTON_C
+    0,                  // AKEYCODE_BUTTON_X
+    0,                  // AKEYCODE_BUTTON_Y
+    0,                  // AKEYCODE_BUTTON_Z
+    0,                  // AKEYCODE_BUTTON_L1
+    0,                  // AKEYCODE_BUTTON_R1
+    0,                  // AKEYCODE_BUTTON_L2
+    0,                  // AKEYCODE_BUTTON_R2
+    0,                  // AKEYCODE_BUTTON_THUMBL
+    0,                  // AKEYCODE_BUTTON_THUMBR
+    0,                  // AKEYCODE_BUTTON_START
+    0,                  // AKEYCODE_BUTTON_SELECT
+    0,                  // AKEYCODE_BUTTON_MODE
+    LA_KEY_ESCAPE,         // AKEYCODE_ESCAPE
+    LA_KEY_DELETE,         // AKEYCODE_FORWARD_DELL
+    LA_KEY_CTRL,   // AKEYCODE_CTRL_LEFT
+    LA_KEY_CTRL,  // AKEYCODE_CTRL_RIGHT
+    0,      // AKEYCODE_CAPS_LOCK
+    0,    // AKEYCODE_SCROLL_LOCK
+    LA_KEY_ARRLEFT,     // AKEYCODE_META_LEFT
+    LA_KEY_ARRRIGHT,    // AKEYCODE_META_RIGHT
+    0,                  // AKEYCODE_FUNCTION
+    0,   // AKEYCODE_SYSRQ
+    0,          // AKEYCODE_BREAK
+    0,           // AKEYCODE_MOVE_HOME
+    0,            // AKEYCODE_MOVE_END
+    0,         // AKEYCODE_INSERT
+    0,                  // AKEYCODE_FORWARD
+    0,                  // AKEYCODE_MEDIA_PLAY
+    0,                  // AKEYCODE_MEDIA_PAUSE
+    0,                  // AKEYCODE_MEDIA_CLOSE
+    0,                  // AKEYCODE_MEDIA_EJECT
+    0,                  // AKEYCODE_MEDIA_RECORD
+    LA_KEY_F1,             // AKEYCODE_F1
+    LA_KEY_F2,             // AKEYCODE_F2
+    LA_KEY_F3,             // AKEYCODE_F3
+    LA_KEY_F4,             // AKEYCODE_F4
+    LA_KEY_F5,             // AKEYCODE_F5
+    LA_KEY_F6,             // AKEYCODE_F6
+    LA_KEY_F7,             // AKEYCODE_F7
+    LA_KEY_F8,             // AKEYCODE_F8
+    LA_KEY_F9,             // AKEYCODE_F9
+    LA_KEY_F10,            // AKEYCODE_F10
+    LA_KEY_F11,            // AKEYCODE_F11
+    LA_KEY_F12,            // AKEYCODE_F12
+    0,       // AKEYCODE_NUM_LOCK
+    LA_KEY_NUM0,           // AKEYCODE_NUMPAD_0
+    LA_KEY_NUM1,           // AKEYCODE_NUMPAD_1
+    LA_KEY_NUM2,           // AKEYCODE_NUMPAD_2
+    LA_KEY_NUM3,           // AKEYCODE_NUMPAD_3
+    LA_KEY_NUM4,           // AKEYCODE_NUMPAD_4
+    LA_KEY_NUM5,           // AKEYCODE_NUMPAD_5
+    LA_KEY_NUM6,           // AKEYCODE_NUMPAD_6
+    LA_KEY_NUM7,           // AKEYCODE_NUMPAD_7
+    LA_KEY_NUM8,           // AKEYCODE_NUMPAD_8
+    LA_KEY_NUM9,           // AKEYCODE_NUMPAD_9
+    LA_KEY_NUMDIVIDE,      // AKEYCODE_NUMPAD_DIVIDE
+    LA_KEY_NUMMULT,    // AKEYCODE_NUMPAD_MULTIPLY
+    LA_KEY_NUMMINUS,    // AKEYCODE_NUMPAD_SUBTRACT
+    LA_KEY_NUMPLUS,         // AKEYCODE_NUMPAD_ADD
+    LA_KEY_NUMDOT,     // AKEYCODE_NUMPAD_DOT
+    0,                  // AKEYCODE_NUMPAD_COMMA
+    LA_KEY_NUMENTER,       // AKEYCODE_NUMPAD_ENTER
+    '='        // AKEYCODE_NUMPAD_EQUALS
+};
+
 static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event)
 {
     __android_log_print(ANDROID_LOG_DEBUG, "huh 5678", "123 input");
@@ -8241,7 +8434,46 @@ static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *eve
 
     int type = AInputEvent_getType(event);
     if(type == AINPUT_EVENT_TYPE_KEY){
+        int32_t keycode = AKeyEvent_getKeyCode(event);
+        //int32_t AKeyEvent_getMetaState(event);
+        int key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE) ? KeycodeMap[keycode] : 0;
+        if (key != 0){
+            // Save current key and its state
+            // NOTE: Android key action is 0 for down and 1 for up
+            if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN){
+                la_SendKeyboardEvent(0,LA_KEY_DOWN,key);
+                if(key!=LA_KEY_BACKSPACE)
+                    la_SendInputEvent(0,key);
+            }
+            else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE){
+                la_SendKeyboardEvent(0,LA_KEY_DOWN,key);
+                la_SendInputEvent(0,key);
+            }
+            else la_SendKeyboardEvent(0,LA_KEY_UP,key);  // Key up
+        }
+
+        if (keycode == AKEYCODE_POWER)
+        {
+            // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS
+            // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS
+            // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.
+            // NOTE: AndroidManifest.xml must have <activity android:configChanges="orientation|keyboardHidden|screenSize" >
+            // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour
+            return 0;
+        }
+        else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU))
+        {
+            // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!
+            return 1;
+        }
+        else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))
+        {
+            // Set default OS behaviour
+            return 0;
+        }
+
         return 0;
+
     }
     elif(type == AINPUT_EVENT_TYPE_MOTION){
         int pcount = AMotionEvent_getPointerCount(event); int x,y;
@@ -8277,9 +8509,10 @@ static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *eve
     return 0;
 }
 
-void la_InitAssetManager(AAssetManager *manager, const char *dataPath){
+void la_InitAssetManager(AAssetManager *manager, const char *dataPath, const char *externalDataPath){
     MAIN.AssetManager = manager;
     MAIN.InternalDataPath = dataPath;
+    MAIN.ExternalDataPath = externalDataPath;
 }
 
 static int android_read(void *cookie, char *data, int dataSize){
@@ -8311,7 +8544,10 @@ FILE *android_fopen(const char *fileName, const char *mode)
         // write data when required using the standard stdio FILE access functions
         // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
         #undef fopen
+        FILE* result=fopen(fileName, mode); if(result){ return result; }
         sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName);
+        result=fopen(buf, mode); if(result) return result;
+        sprintf(buf,"%s/%s", MAIN.ExternalDataPath, fileName);
         return fopen(buf, mode);
         #define fopen(name, mode) android_fopen(name, mode)
     }
@@ -8328,23 +8564,57 @@ FILE *android_fopen(const char *fileName, const char *mode)
         else
         {
             #undef fopen
+            FILE* result=fopen(fileName, mode); if(result){ return result; }
             // Just do a regular open if file is not found in the assets
             sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName);
+            result=fopen(buf, mode); if(result){ return result; }
+            sprintf(buf,"%s/%s", MAIN.ExternalDataPath, fileName);
             return fopen(buf, mode);
             #define fopen(name, mode) android_fopen(name, mode)
         }
     }
 }
 
+void la_HideNavBar(){
+    JavaVM* lJavaVM = MAIN.app->activity->vm;
+    JNIEnv* lJNIEnv = MAIN.app->activity->env;
+    (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);
+
+	jclass activityClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/app/NativeActivity");
+	jmethodID getWindow = (*lJNIEnv)->GetMethodID(lJNIEnv,activityClass, "getWindow", "()Landroid/view/Window;");
+
+	jclass windowClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/Window");
+	jmethodID getDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv,windowClass, "getDecorView", "()Landroid/view/View;");
+
+	jclass viewClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/View");
+	jmethodID setSystemUiVisibility = (*lJNIEnv)->GetMethodID(lJNIEnv,viewClass, "setSystemUiVisibility", "(I)V");
+
+	jobject window = (*lJNIEnv)->CallObjectMethod(lJNIEnv,MAIN.app->activity->clazz, getWindow);
+
+	jobject decorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,window, getDecorView);
+
+	jfieldID flagFullscreenID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
+	jfieldID flagHideNavigationID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I");
+
+	int flagFullscreen = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagFullscreenID);
+	int flagHideNavigation = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagHideNavigationID);
+
+	int flag = flagFullscreen | flagHideNavigation;
+
+	(*lJNIEnv)->CallVoidMethod(lJNIEnv,decorView, setSystemUiVisibility, flag);
+    (*lJavaVM)->DetachCurrentThread(lJavaVM);
+}
+
 void la_InitAndroidPlatform(struct android_app *app){
     MAIN.app=app;
 
-    ANativeActivity_setWindowFlags(MAIN.app->activity, AWINDOW_FLAG_FULLSCREEN, 1);  //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
+    ANativeActivity_setWindowFlags(MAIN.app->activity, AWINDOW_FLAG_FULLSCREEN, 0);  //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
+    //la_HideNavBar();
 
     MAIN.app->onAppCmd = la_AndroidCommandCallback;
     MAIN.app->onInputEvent = la_AndroidInputCallback;
 
-    la_InitAssetManager(MAIN.app->activity->assetManager, MAIN.app->activity->internalDataPath);
+    la_InitAssetManager(MAIN.app->activity->assetManager, MAIN.app->activity->internalDataPath, MAIN.app->activity->externalDataPath);
 
     int pollResult = 0;
     int pollEvents = 0;
@@ -8380,5 +8650,99 @@ void android_main(struct android_app *app){
     }
 }
 
+void la_DisplayKeyboard(bool pShow) {
+    // Attaches the current thread to the JVM.
+    jint lResult;
+    jint lFlags = 0;
+
+    JavaVM* lJavaVM = MAIN.app->activity->vm;
+    JNIEnv* lJNIEnv = MAIN.app->activity->env;
+
+    JavaVMAttachArgs lJavaVMAttachArgs;
+    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+    lJavaVMAttachArgs.name = "NativeThread";
+    lJavaVMAttachArgs.group = NULL;
+
+    lResult=(*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);
+    if (lResult == JNI_ERR) {
+        return;
+    }
+    // Retrieves NativeActivity.
+    jobject lNativeActivity = MAIN.app->activity->clazz;
+    jclass ClassNativeActivity = (*lJNIEnv)->GetObjectClass(lJNIEnv,lNativeActivity);
+    logPrintNew("jvm3");
+
+    // Retrieves Context.INPUT_METHOD_SERVICE.
+    jclass ClassContext = (*lJNIEnv)->FindClass(lJNIEnv,"android/content/Context");
+    jfieldID FieldINPUT_METHOD_SERVICE =
+        (*lJNIEnv)->GetStaticFieldID(lJNIEnv,ClassContext,
+            "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
+    jobject INPUT_METHOD_SERVICE =
+        (*lJNIEnv)->GetStaticObjectField(lJNIEnv,ClassContext,
+            FieldINPUT_METHOD_SERVICE);
+    //jniCheck(INPUT_METHOD_SERVICE);
+    logPrintNew("jvm4");
+
+    // Runs getSystemService(Context.INPUT_METHOD_SERVICE).
+    jclass ClassInputMethodManager = (*lJNIEnv)->FindClass(lJNIEnv,
+        "android/view/inputmethod/InputMethodManager");
+    jmethodID MethodGetSystemService = (*lJNIEnv)->GetMethodID(lJNIEnv,
+        ClassNativeActivity, "getSystemService",
+        "(Ljava/lang/String;)Ljava/lang/Object;");
+    jobject lInputMethodManager = (*lJNIEnv)->CallObjectMethod(lJNIEnv,
+        lNativeActivity, MethodGetSystemService,
+        INPUT_METHOD_SERVICE);
+
+    // Runs getWindow().getDecorView().
+    jmethodID MethodGetWindow = (*lJNIEnv)->GetMethodID(lJNIEnv,
+        ClassNativeActivity, "getWindow",
+        "()Landroid/view/Window;");
+    jobject lWindow = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lNativeActivity,
+        MethodGetWindow);
+    jclass ClassWindow = (*lJNIEnv)->FindClass(lJNIEnv,
+        "android/view/Window");
+    jmethodID MethodGetDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv,
+        ClassWindow, "getDecorView", "()Landroid/view/View;");
+    jobject lDecorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lWindow,
+        MethodGetDecorView);
+
+    if (pShow) {
+        // Runs lInputMethodManager.showSoftInput(...).
+        jmethodID MethodShowSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv,
+            ClassInputMethodManager, "showSoftInput",
+            "(Landroid/view/View;I)Z");
+        jboolean lResult = (*lJNIEnv)->CallBooleanMethod(lJNIEnv,
+            lInputMethodManager, MethodShowSoftInput,
+            lDecorView, lFlags);
+    } else {
+        // Runs lWindow.getViewToken()
+        jclass ClassView = (*lJNIEnv)->FindClass(lJNIEnv,
+            "android/view/View");
+        jmethodID MethodGetWindowToken = (*lJNIEnv)->GetMethodID(lJNIEnv,
+            ClassView, "getWindowToken", "()Landroid/os/IBinder;");
+        jobject lBinder = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lDecorView,
+            MethodGetWindowToken);
+
+        // lInputMethodManager.hideSoftInput(...).
+        jmethodID MethodHideSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv,
+            ClassInputMethodManager, "hideSoftInputFromWindow",
+            "(Landroid/os/IBinder;I)Z");
+        jboolean lRes = (*lJNIEnv)->CallBooleanMethod(lJNIEnv,
+            lInputMethodManager, MethodHideSoftInput,
+            lBinder, lFlags);
+    }
+
+    // Finished with the JVM.
+    (*lJavaVM)->DetachCurrentThread(lJavaVM);
+}
+
 #endif //android
 
+#ifndef LAGUI_ANDROID
+void la_DisplayKeyboard(bool pShow) {
+    return;
+}
+void la_HideNavBar(){
+    return;
+}
+#endif

+ 4 - 3
la_tns_kernel.c

@@ -143,11 +143,12 @@ void tnsContextMakeFBOCurrent(tnsOffscreen* off){
 }
 void tnsContextMakeWindowCurrent(laWindow* w){
 #ifdef LAGUI_ANDROID
-    T->CurrentContext=MAIN.glc;
+    T->CurrentContext=MAIN.glc; T->CurrentSurface=MAIN.egl_surf;
     if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return; }
-   return;
-#endif
+    return;
+#else
     tnsContextMakeCurrent(w->glc,w->win,w->egl_surf);
+#endif
 }
 #else
 void tnsContextMakeFBOCurrent(tnsOffscreen* off){

+ 1 - 1
la_util.c

@@ -2392,7 +2392,7 @@ void transSetLanguage(const char *LanguageID){
         return;
     }
     for (tn = MAIN.Translation.Languages.pFirst; tn; tn = tn->Item.pNext){
-        if (!strcmp(tn->LanguageName->Ptr, LanguageID)){
+        if (!strcmp(SSTR(tn->LanguageName), LanguageID)){
             MAIN.Translation.CurrentLanguage = tn; return;
         }
     }

+ 0 - 2
la_util.h

@@ -35,8 +35,6 @@
 #include <stdio.h>
 #define fopen(name, mode) android_fopen(name, mode)
 FILE *android_fopen(const char *fileName, const char *mode);
-#else
-#include <GL/gl.h>
 #endif
 
 #include "ft2build.h"

+ 17 - 1
resources/la_operators.c

@@ -242,7 +242,12 @@ void la_FileBrowserRebuildList(laFileBrowser *fb){
     u64bit TotalSpace = 0;
     real Ratio = 0;
 
-#ifdef LA_LINUX
+#ifdef __linux__
+
+#ifdef LAGUI_ANDROID
+#define versionsort alphasort
+#endif
+
     if (fb->Path[len - 1] != U'/') strcat(fb->Path, "/");
     struct dirent **NameList=0;
     int NumFiles=scandir(fb->Path,&NameList,0,versionsort);
@@ -369,7 +374,15 @@ laFileBrowser *la_FileBrowserInit(laOperator *a){
     laFileBrowser *fb = memAcquire(sizeof(laFileBrowser));
     char* arg=0;
 
+#ifdef LAGUI_ANDROID
+    strcpy(fb->Path, MAIN.ExternalDataPath);
+    laBookmarkedFolder* bf=memAcquireSimple(sizeof(laBookmarkedFolder));
+    strcpy(bf->Path,fb->Path); strcpy(bf->Name,strGetLastSegment(fb->Path,"External")); lstAppendItem(&fb->Bookmarks,bf);
+    bf=memAcquireSimple(sizeof(laBookmarkedFolder));
+    strcpy(bf->Path,MAIN.InternalDataPath); strcpy(bf->Name,"Internal"); lstAppendItem(&fb->Bookmarks,bf);
+#else
     strcpy(fb->Path, SSTR(MAIN.WorkingDirectory));
+#endif
 
     if (strArgumentMatch(a->ExtraInstructionsP, "select", "folder")){ fb->SelectFolder = LA_FILE_SELECT_FOLDER; }
     if (strArgumentMatch(a->ExtraInstructionsP, "warn_file_exists", "true")){ fb->WarnFileExists = 1; }
@@ -511,11 +524,13 @@ void* laget_FileBrowserAcceptedExtensionsFrist(laFileBrowser* fb, laPropIterator
     for(laExtensionType*et=MAIN.ExtraExtensions.pFirst;et;et=et->Item.pNext){
         if(et->FileType==fb->UseType){ return et; }
     }
+    return 0;
 }
 void* laget_FileBrowserAcceptedExtensionsNext(laExtensionType* et, laPropIterator* pi){
     for(laExtensionType*iet=et->Item.pNext;iet;iet=iet->Item.pNext){
         if(et->FileType==iet->FileType){ return iet; }
     }
+    return 0;
 }
 void* laset_FileBrowserExtension(laFileBrowser* fb, laExtensionType* et){
     if(fb->UseType && fb->FileName[0] && et){ char* ext=strGetLastSegment(fb->FileName,'.');
@@ -523,6 +538,7 @@ void* laset_FileBrowserExtension(laFileBrowser* fb, laExtensionType* et){
         elif(strcmp(et->Extension,ext)){ sprintf(ext,"%s",et->Extension); }
         la_FileBrowserRebuildList(fb); laRecalcCurrentPanel();
     }
+    return 0;
 }
 void laset_FileBrowserShowBackups(laFileBrowser* fb, int show){
     fb->ShowBackups = show; la_FileBrowserRebuildList(fb); laRecalcCurrentPanel();

+ 13 - 12
resources/la_widgets.c

@@ -2228,7 +2228,7 @@ int la_ProcessTextEdit(laEvent *e, laStringEdit *se, laUiItem* ui){
     switch (e->type){
     case LA_INPUT:
         switch (e->Input){
-        case 0x08: if(strHasSelection(se)) strClearSelection(se); else strBackspace(se); return 1;
+        //case 0x08: if(strHasSelection(se)) strClearSelection(se); else strBackspace(se); return 1;
         case 0x7f: if(strHasSelection(se)) strClearSelection(se); else { strMoveCursor(se,0,0); strBackspace(se); } return 1;
         case 0x09: strInsertChar(se, ' ');strInsertChar(se, ' ');strInsertChar(se, ' ');strInsertChar(se, ' '); return 1;
         case 0x1B: case 0x0D: return 0;
@@ -2242,6 +2242,7 @@ int la_ProcessTextEdit(laEvent *e, laStringEdit *se, laUiItem* ui){
         case LA_KEY_ARRRIGHT: strMoveCursor(se, 0, Select); return 1;
         case LA_KEY_ARRUP: strMoveCursorLine(se, 1, Select); return 1;
         case LA_KEY_ARRDOWN: strMoveCursorLine(se, 0, Select); return 1;
+        case LA_KEY_BACKSPACE: if(strHasSelection(se)) strClearSelection(se); else strBackspace(se); return 1;
         }
         break;
     case LA_L_MOUSE_DOWN:
@@ -2324,11 +2325,11 @@ int OPMOD_IntArrayHorizon(laOperator *a, laEvent *e){
             if (!laIsInUiItem(ui, e->x, e->y)){
                 strEndEdit(&uit->Edit, 1);
                 uit->On = 0;
-                laRedrawCurrentPanel();
+                laRedrawCurrentPanel(); la_DisplayKeyboard(0);
                 return LA_FINISHED;
             }
             if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);
-            else strSelectLineAll(uit->Edit);
+            else strSelectLineAll(uit->Edit); la_DisplayKeyboard(1);
             return LA_RUNNING;
         }
         uit->LastX = e->x;
@@ -2375,7 +2376,7 @@ int OPMOD_IntArrayHorizon(laOperator *a, laEvent *e){
                 uit->TargetIndexVali = TmpArr[ui->Extra->On - 1];
                 strPrintIntAfter(buf, 32, uit->TargetIndexVali);
                 strBeginEdit(&uit->Edit,buf);
-                strSelectLineAll(uit->Edit);
+                strSelectLineAll(uit->Edit); la_DisplayKeyboard(1);
             }
         }
         uit->Dragging = 0;
@@ -2446,11 +2447,11 @@ int OPMOD_FloatArrayHorizon(laOperator *a, laEvent *e){
             if (!laIsInUiItem(ui, e->x, e->y)){
                 strEndEdit(&uit->Edit, 1);
                 uit->On = 0;
-                laRedrawCurrentPanel();
+                laRedrawCurrentPanel(); la_DisplayKeyboard(0);
                 return LA_FINISHED;
             }
             if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);
-            else strSelectLineAll(uit->Edit);
+            else strSelectLineAll(uit->Edit); la_DisplayKeyboard(1);
             return LA_RUNNING;
         }
         if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
@@ -2499,7 +2500,7 @@ int OPMOD_FloatArrayHorizon(laOperator *a, laEvent *e){
                 uit->TargetIndexValf = TmpArr[ui->Extra->On - 1];
                 strPrintFloatAfter(buf, 32, 5, IsRad?deg(uit->TargetIndexValf):uit->TargetIndexValf);
                 strBeginEdit(&uit->Edit,buf);
-                strSelectLineAll(uit->Edit);
+                strSelectLineAll(uit->Edit); la_DisplayKeyboard(1);
             }
         }
         uit->Dragging = 0;
@@ -2922,7 +2923,7 @@ int OPMOD_SingleLineString(laOperator *a, laEvent *e){
                 buf=strEndEdit(&uit->Edit, 0);
                 laSetString(&ui->PP, buf); free(buf);
                 laRecordAndPushProp(&ui->PP,0); laMarkPropChanged(&ui->PP);
-                ui->State = LA_UI_NORMAL;
+                ui->State = LA_UI_NORMAL; la_DisplayKeyboard(0);
                 laRedrawCurrentPanel();
                 return LA_FINISHED_PASS;
             }
@@ -2945,16 +2946,16 @@ int OPMOD_SingleLineString(laOperator *a, laEvent *e){
             laRedrawCurrentPanel();
             if(!IsTerminal){
                 laRecordAndPushProp(&ui->PP,0); laMarkPropChanged(&ui->PP);
-                ui->State = LA_UI_NORMAL;
+                ui->State = LA_UI_NORMAL; la_DisplayKeyboard(0);
                 return LA_FINISHED_PASS;
             }else{
                 laGetString(&ui->PP, _buf, &buf);
-                strBeginEdit(&uit->Edit,buf);
+                strBeginEdit(&uit->Edit,buf); la_DisplayKeyboard(1);
                 MAIN.IsTerminalEnter=0;
                 return LA_RUNNING;
             }
         }else if (e->key == LA_KEY_ESCAPE && ui->State != LA_UI_NORMAL){
-            ui->State = LA_UI_NORMAL;
+            ui->State = LA_UI_NORMAL; la_DisplayKeyboard(0);
             laRedrawCurrentPanel();
             return LA_FINISHED;
         }
@@ -2967,7 +2968,7 @@ int OPMOD_SingleLineString(laOperator *a, laEvent *e){
             if(laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING;
             ui->State = LA_UI_EDITING;
             laGetString(&ui->PP, _buf, &buf);
-            strBeginEdit(&uit->Edit,buf);
+            strBeginEdit(&uit->Edit,buf); la_DisplayKeyboard(1);
             strSelectLineAll(uit->Edit);
         }elif (ui->State == LA_UI_EDITING){
             if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);