ecere/drivers/Android: Tweaks to run with latest Android SDK/NDK on Nexus 9
[sdk] / ecere / src / gui / drivers / AndroidInterface.ec
index 1f7d07e..a79b8a3 100644 (file)
@@ -1,3 +1,5 @@
+#define _Noreturn
+
 namespace gui::drivers;
 
 import "Window"
@@ -10,6 +12,7 @@ import "Condition"
 #include <locale.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <sys/prctl.h>
 
 #include <android/configuration.h>
 #include <android/looper.h>
@@ -22,10 +25,12 @@ import "Condition"
 #undef set
 #undef uint
 
+#define printf(...) ((void)__android_log_print(ANDROID_LOG_INFO, "ecere-app", __VA_ARGS__))
+
 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "ecere-app", __VA_ARGS__))
 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "ecere-app", __VA_ARGS__))
 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "ecere-app", __VA_ARGS__))
-#ifdef _DEBUG
+#ifndef _DEBUG
 #define LOGV(...)  ((void)0)
 #else
 #define LOGV(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "ecere-app", __VA_ARGS__))
@@ -48,6 +53,8 @@ public:
    virtual void any_object::process();
 };
 
+static const char * packagePath;
+
 class AndroidAppGlue : Thread
 {
    void* userData;
@@ -128,11 +135,11 @@ private:
          AInputEvent* event = null;
          if(AInputQueue_getEvent(inputQueue, &event) >= 0)
          {
-            int handled = 0;
+            //int handled = 0;
             LOGV("New input event: type=%d\n", AInputEvent_getType(event));
             if(AInputQueue_preDispatchEvent(inputQueue, event))
                return;
-            handled = onInputEvent(event);
+            /*handled = */onInputEvent(event);
             //AInputQueue_finishEvent(inputQueue, event, handled);
          }
          else
@@ -199,7 +206,7 @@ private:
 
    void pre_exec_cmd(AppCommand cmd)
    {
-      PrintLn("pre_exec_cmd: ", (int)cmd);
+      //PrintLn("pre_exec_cmd: ", cmd);
       switch(cmd)
       {
          case inputChanged:
@@ -242,7 +249,7 @@ private:
 
    void post_exec_cmd(AppCommand cmd)
    {
-      PrintLn("post_exec_cmd: ", (int)cmd);
+      //PrintLn("post_exec_cmd: ", cmd);
       switch(cmd)
       {
          case termWindow:
@@ -327,7 +334,7 @@ private:
          savedStateSize = 0;
    }
 
-   void Create()
+   public void Create()
    {
       int msgpipe[2];
       if(pipe(msgpipe))
@@ -348,25 +355,25 @@ private:
 static void onDestroy(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("Destroy: %p\n", activity);
+   LOGI("Destroy: %p\n", activity);
    app.cleanup();
    app.Wait();
    delete androidActivity;
    delete __androidCurrentModule;
-   LOGV("THE END.");
+   LOGI("THE END.");
 }
 
 static void onStart(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("Start: %p\n", activity);
+   LOGI("Start: %p\n", activity);
    app.set_activity_state(start);
 }
 
 static void onResume(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("Resume: %p\n", activity);
+   LOGI("Resume: %p\n", activity);
    app.set_activity_state(resume);
 }
 
@@ -374,7 +381,7 @@ static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
    void* savedState = null;
-   LOGV("SaveInstanceState: %p\n", activity);
+   LOGI("SaveInstanceState: %p\n", activity);
    app.mutex.Wait();
    app.stateSaved = false;
    app.write_cmd(saveState);
@@ -394,63 +401,64 @@ static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
 static void onPause(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("Pause: %p\n", activity);
+   LOGI("Pause: %p\n", activity);
    app.set_activity_state(pause);
 }
 
 static void onStop(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("Stop: %p\n", activity);
+   LOGI("Stop: %p\n", activity);
    app.set_activity_state(stop);
 }
 
 static void onConfigurationChanged(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("ConfigurationChanged: %p\n", activity);
+   LOGI("ConfigurationChanged: %p\n", activity);
    app.write_cmd(configChanged);
 }
 
 static void onLowMemory(ANativeActivity* activity)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("LowMemory: %p\n", activity);
+   LOGI("LowMemory: %p\n", activity);
    app.write_cmd(lowMemory);
 }
 
 static void onWindowFocusChanged(ANativeActivity* activity, int focused)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
+   LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
    app.write_cmd(focused ? gainedFocus : lostFocus);
 }
 
 static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
+   LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
    app.set_window(window);
 }
 
 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
+   LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+   app.window = null;
    app.set_window(null);
 }
 
 static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
+   LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
    app.set_input(queue);
 }
 
 static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
 {
    AndroidAppGlue app = (AndroidAppGlue)activity->instance;
-   LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
+   LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
    app.inputQueue = null;
    app.set_input(null);
 }
@@ -477,35 +485,46 @@ default dllexport void ANativeActivity_onCreate(ANativeActivity* activity, void*
    __thisModule = null;
    __androidCurrentModule = null;
 
-   LOGV("Creating: %p\n", activity);
+   prctl(PR_SET_DUMPABLE, 1);
+
+   LOGI("Creating: %p\n", activity);
 
    //(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);
    clazz = (*env)->GetObjectClass(env, activity->clazz);
    methodID = (*env)->GetMethodID(env, clazz, "getPackageName", "()Ljava/lang/String;");
    result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
    str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
-   // (*activity->vm)->DetachCurrentThread(activity->vm);
+
    moduleName = strstr(str, "com.ecere.");
    if(moduleName) moduleName += 10;
    androidArgv[0] = moduleName;
 
+   methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
+   result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
+   str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
+   packagePath = str;
+   // (*activity->vm)->DetachCurrentThread(activity->vm);
+   LOGI("packagePath: %s\n", packagePath);
+
    // Create a base Application class
    __androidCurrentModule = __ecere_COM_Initialize(true, 1, androidArgv);
    // Load up Ecere
    eModule_Load(__androidCurrentModule, "ecere", publicAccess);
 
-
+   /*
    if(activity->internalDataPath) PrintLn("internalDataPath is ", activity->internalDataPath);
    if(activity->externalDataPath) PrintLn("externalDataPath is ", activity->externalDataPath);
    {
       char tmp[256];
       PrintLn("cwd is ", GetWorkingDir(tmp, sizeof(tmp)));
    }
+   */
 
    ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON, 0 );
    app = AndroidActivity { activity = activity, moduleName = moduleName };
+
    incref app;
-   app.setSavedState(savedState, savedStateSize);
+   app.setSavedState(savedState, (uint)savedStateSize);
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onStart = onStart;
    activity->callbacks->onResume = onResume;
@@ -574,6 +593,20 @@ class AndroidInterface : Interface
 
       if(androidActivity.ident < 0)
          androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
+
+      if(gotInit && androidActivity.window)
+      {
+         int w = ANativeWindow_getWidth(androidActivity.window);
+         int h = ANativeWindow_getHeight(androidActivity.window);
+         if(desktopW != w || desktopH != h)
+         {
+            guiApp.SetDesktopPosition(0, 0, w, h, true);
+            desktopW = w;
+            desktopH = h;
+            guiApp.desktop.Update(null);
+         }
+      }
+
       while(androidActivity.ident >= 0)
       {
          AndroidPollSource source = androidActivity.source;
@@ -594,18 +627,6 @@ class AndroidInterface : Interface
             }
          }
          */
-         if(gotInit)
-         {
-            int w = ANativeWindow_getWidth(androidActivity.window);
-            int h = ANativeWindow_getHeight(androidActivity.window);
-            if(desktopW != w || desktopH != h)
-            {
-               guiApp.SetDesktopPosition(0, 0, w, h, true);
-               desktopW = w;
-               desktopH = h;
-               guiApp.desktop.Update(null);
-            }
-         }
 
          eventAvailable = true;
          if(androidActivity.destroyRequested)
@@ -638,11 +659,11 @@ class AndroidInterface : Interface
 
    }
 
-   char ** GraphicsDrivers(int * numDrivers)
+   const char ** GraphicsDrivers(int * numDrivers)
    {
-      static char *graphicsDrivers[] = { "OpenGL" };
+      static const char *graphicsDrivers[] = { "OpenGL" };
       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
-      return (char **)graphicsDrivers;
+      return (const char **)graphicsDrivers;
    }
 
    void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
@@ -675,7 +696,7 @@ class AndroidInterface : Interface
 
    // -- Window manipulation ---
 
-   void SetRootWindowCaption(Window window, char * name)
+   void SetRootWindowCaption(Window window, const char * name)
    {
 
    }
@@ -753,10 +774,6 @@ class AndroidInterface : Interface
 
    void GetMousePosition(int *x, int *y)
    {
-      int rootWindow, childWindow;
-      int mx, my;
-      unsigned int state;
-
       *x = mouseX;
       *y = mouseY;
    }
@@ -777,7 +794,7 @@ class AndroidInterface : Interface
 
    // -- Mouse cursor ---
 
-   void SetMouseCursor(int cursor)
+   void SetMouseCursor(Window window, int cursor)
    {
       if(cursor == -1)
       {
@@ -794,7 +811,7 @@ class AndroidInterface : Interface
       if(window && window.windowData)
       {
       }
-   }  
+   }
 
    void ClearClipboard()
    {
@@ -808,7 +825,7 @@ class AndroidInterface : Interface
    {
       bool result = false;
       if((clipBoard.text = new0 byte[size]))
-         result = true;   
+         result = true;
       return result;
    }
 
@@ -873,14 +890,14 @@ class AndroidInterface : Interface
 
    bool GetKeyState(Key key)
    {
-      int keyState = 0;
+      bool keyState = false;
       return keyState;
    }
 
    void SetTimerResolution(uint hertz)
    {
       // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
-   }  
+   }
 
    bool SetIcon(Window window, BitmapResource resource)
    {
@@ -905,15 +922,50 @@ struct SavedState
 
 static AndroidActivity androidActivity;
 
-default const char * AndroidInterface_GetLibLocation()
+default const char * AndroidInterface_GetLibLocation(Application a)
 {
-   if(androidActivity)
+   static char loc[MAX_LOCATION] = "", mod[MAX_LOCATION];
+   bool found = false;
+#if defined(__LP64__)
+   static const char * arch = "arm64";
+#else
+   static const char * arch = "armeabi";
+#endif
+   int i;
+   bool useArch = true;
+
+   while(!found)
    {
-      static char loc[MAX_LOCATION];
-      sprintf(loc, "/data/data/com.ecere.%s/lib/lib", androidActivity.moduleName);
-      return loc;
+      StripLastDirectory(packagePath, loc);
+      strcatf(loc, "/lib/%s/lib", useArch ? arch : "");
+      sprintf(mod, "%s%s.so", loc, a.argv[0]);
+      found = FileExists(mod).isFile;
+      if(!found)
+      {
+         bool useApp = true;
+         while(!found)
+         {
+            for(i = 0; !found && i < 10; i++)
+            {
+               if(i)
+                  sprintf(loc, "/data/%s/com.ecere.%s-%d/lib/%s/lib", useApp ? "app" : "data", a.argv[0], i, useArch ? arch : "");
+               else
+                  sprintf(loc, "/data/%s/com.ecere.%s/lib/%s/lib",    useApp ? "app" : "data", a.argv[0], useArch ? arch : "");
+               sprintf(mod, "%s%s.so", loc, a.argv[0]);
+               found = FileExists(mod).isFile;
+            }
+            if(useApp)
+               useApp = false;
+            else
+               break;
+         }
+      }
+      if(useArch)
+         useArch = false;
+      else
+         break;
    }
-   return null;
+   return loc;
 }
 
 static bool gotInit;
@@ -1039,8 +1091,8 @@ static Key keyCodeTable[] =
     0, //AKEYCODE_BUTTON_START    = 108,
     0, //AKEYCODE_BUTTON_SELECT   = 109,
     0, //AKEYCODE_BUTTON_MODE     = 110,
-    escape, //AKEYCODE_BUTTON_ESCAPE     = 111,
-    del //AKEYCODE_BUTTON_ESCAPE     = 112,
+    escape, //AKEYCODE_BUTTON_ESCAPE = 111,
+    del, //AKEYCODE_BUTTON_ESCAPE    = 112,
     leftControl, // = 113
     rightControl, // = 114
     capsLock, // = 115
@@ -1058,6 +1110,21 @@ static Key keyCodeTable[] =
 // Why don't we have this in the NDK :(
 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
 
+static Array<TouchPointerInfo> buildPointerInfo(AInputEvent * event)
+{
+   uint count = (uint)AMotionEvent_getPointerCount(event);
+   Array<TouchPointerInfo> infos { size = count };
+   int i;
+   for(i = 0; i < count; i++)
+   {
+      infos[i].point = { (int)AMotionEvent_getX(event, i), (int)AMotionEvent_getY(event, i) };
+      infos[i].id = (int)AMotionEvent_getPointerId(event, i);
+      infos[i].pressure = AMotionEvent_getPressure(event, i);
+      infos[i].size = AMotionEvent_getSize(event, i);
+   }
+   return infos;
+}
+
 class AndroidActivity : AndroidAppGlue
 {
    AndroidPollSource source;
@@ -1072,26 +1139,27 @@ class AndroidActivity : AndroidAppGlue
 
    int onInputEvent(AInputEvent* event)
    {
+      static Time lastTime = 0;
       Window window = guiApp.desktop;
       uint type = AInputEvent_getType(event);
       if(type == AINPUT_EVENT_TYPE_MOTION)
       {
          uint actionAndIndex = AMotionEvent_getAction(event);
-         uint source = AInputEvent_getSource(event);
+         //uint source = AInputEvent_getSource(event);
          uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
-         uint index  = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-         uint flags = AMotionEvent_getFlags(event);
+         //uint index  = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+         //uint flags = AMotionEvent_getFlags(event);
          uint meta = AMotionEvent_getMetaState(event);
-         uint edge = AMotionEvent_getEdgeFlags(event);
-         int64 downTime = AMotionEvent_getDownTime(event);     // nanotime
-         int64 eventTime = AMotionEvent_getDownTime(event);
+         //uint edge = AMotionEvent_getEdgeFlags(event);
+         //int64 downTime = AMotionEvent_getDownTime(event);     // nanotime
+         //int64 eventTime = AMotionEvent_getDownTime(event);
          //float axis;
          Modifiers keyFlags = 0;
          int x = (int)AMotionEvent_getX(event, 0);
          int y = (int)AMotionEvent_getY(event, 0);
          bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
          bool alt = (meta & AMETA_ALT_ON) ? true : false;
-         bool sym = (meta & AMETA_SYM_ON) ? true : false;
+         //bool sym = (meta & AMETA_SYM_ON) ? true : false;
 
          keyFlags.shift = shift;
          keyFlags.alt = alt;
@@ -1099,7 +1167,7 @@ class AndroidActivity : AndroidAppGlue
          //PrintLn("Got a motion input event: ", action);
          /*
          if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
-            axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL); 
+            axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
          */
 
          AInputQueue_finishEvent(inputQueue, event, 1);
@@ -1111,35 +1179,73 @@ class AndroidActivity : AndroidAppGlue
                break;
                */
             case AMOTION_EVENT_ACTION_DOWN:
+            {
+               Time time = GetTime();
+               bool result = true;
+               if(Abs(x - mouseX) < 40 && Abs(y - mouseY) < 40 && time - lastTime < 0.3)
+                  if(!window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick, x, y, &keyFlags, false, true))
+                     result = false;
+               lastTime = time;
                mouseX = x, mouseY = y;
-               window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
+               if(result)
+                  // TOCHECK: Should we do result = here?
+                  window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
+               if(result)
+               {
+                  Array<TouchPointerInfo> infos = buildPointerInfo(event);
+                  window.MultiTouchMessage(down, infos, &keyFlags, false, true);
+                  delete infos;
+               }
                break;
+            }
             case AMOTION_EVENT_ACTION_UP:
                mouseX = x, mouseY = y;
-               window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true);
+               if(window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true))
+               {
+                  Array<TouchPointerInfo> infos = buildPointerInfo(event);
+                  window.MultiTouchMessage(up, infos, &keyFlags, false, true);
+                  delete infos;
+               }
                break;
             case AMOTION_EVENT_ACTION_MOVE:
                mouseX = x, mouseY = y;
-               window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true);
+               if(window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true))
+               {
+                  Array<TouchPointerInfo> infos = buildPointerInfo(event);
+                  window.MultiTouchMessage(move, infos, &keyFlags, false, true);
+                  delete infos;
+               }
                break;
             case AMOTION_EVENT_ACTION_CANCEL: break;
             case AMOTION_EVENT_ACTION_OUTSIDE: break;
-            case AMOTION_EVENT_ACTION_POINTER_DOWN: break;
-            case AMOTION_EVENT_ACTION_POINTER_UP: break;
+            case AMOTION_EVENT_ACTION_POINTER_DOWN:
+            {
+               Array<TouchPointerInfo> infos = buildPointerInfo(event);
+               window.MultiTouchMessage(pointerDown, infos, &keyFlags, false, true);
+               delete infos;
+               break;
+            }
+            case AMOTION_EVENT_ACTION_POINTER_UP:
+            {
+               Array<TouchPointerInfo> infos = buildPointerInfo(event);
+               window.MultiTouchMessage(pointerUp, infos, &keyFlags, false, true);
+               delete infos;
+               break;
+            }
          }
          return 1;
       }
       else if(type == AINPUT_EVENT_TYPE_KEY)
       {
          uint action = AKeyEvent_getAction(event);
-         uint flags = AKeyEvent_getFlags(event);
+         //uint flags = AKeyEvent_getFlags(event);
          uint keyCode = AKeyEvent_getKeyCode(event);
          uint meta = AKeyEvent_getMetaState(event);
          Key key = keyCodeTable[keyCode];
          bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
          bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
-         bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
-         bool sym = (meta & AMETA_SYM_ON) ? true : false;
+         //bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
+         //bool sym = (meta & AMETA_SYM_ON) ? true : false;
          //unichar ch = AKeyEvent_getUnichar(event);
          unichar ch = 0;
 
@@ -1245,7 +1351,7 @@ class AndroidActivity : AndroidAppGlue
 
       {
          Module app;
-          
+
          // Evolve the Application class into a GuiApplication
          eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
 
@@ -1267,16 +1373,20 @@ class AndroidActivity : AndroidAppGlue
             for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
             if(!c) c = class(GuiApplication);
 
+            guiApp.lockMutex.Release();   // TOCHECK: Seems the evolve is losing our mutex lock here ?
+
             // Evolve the Application into it
             eInstance_Evolve((Instance *)&__androidCurrentModule, c);
             guiApp = (GuiApplication)__androidCurrentModule;
 
             {
-               String skin = guiApp.skin;
+               const String skin = guiApp.skin;
                *&guiApp.currentSkin = null;
                guiApp.SelectSkin(skin);
             }
 
+            guiApp.lockMutex.Wait();
+
             // Call Main()
             ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
          }