Gimp: updated to Jessie, new warning dialog about removing old installation, fixed infinite restart in SDL

This commit is contained in:
Sergii Pylypenko
2015-04-02 21:06:22 +03:00
parent 4fc05b347f
commit b416a6ea17
7 changed files with 146 additions and 94 deletions

View File

@@ -129,6 +129,7 @@ public class RestartMainActivity extends Activity
} catch (InterruptedException e) {}
Intent intent = new Intent(RestartMainActivity.this, MainActivity.class);
intent.putExtra(ACTIVITY_AUTODETECT_SCREEN_ORIENTATION, getIntent().getBooleanExtra(ACTIVITY_AUTODETECT_SCREEN_ORIENTATION, false));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
RestartMainActivity.this.startActivity(intent);
try{
Thread.sleep(1000);

View File

@@ -918,17 +918,21 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer
public void openExternalApp(String pkgName, String activity, String url)
{
Intent i = new Intent();
if (url != null)
{
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
try {
Intent i = new Intent();
if (url != null && url.length() > 0)
{
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
}
if (pkgName != null && activity != null && pkgName.length() > 0 && activity.length() > 0)
{
i.setClassName(pkgName, activity);
}
context.startActivity(i);
} catch (Exception e) {
Log.i("SDL", "libSDL: cannot start external app: " + e.toString());
}
if (pkgName != null && activity != null)
{
i.setClassName(pkgName, activity);
}
context.startActivity(i);
}
private int PowerOf2(int i)

View File

@@ -18,13 +18,13 @@ AppVersionName="2.8.14.20"
# If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir -
# these files are put inside .apk package by build system
# You can specify Google Play expansion files in the form 'obb:main.12345' or 'obb:patch.12345' where 12345 is the app version, first associated with the file
AppDataDownloadUrl="!!Data files|:data.tar.xz:obb:main.281420|:data.tar.xz:http://sourceforge.net/projects/libsdl-android/files/ubuntu/jessie/dist-gimp-jessie.tar.xz/download^!!XSDL data files|:data-1.tar.gz:data-1.tgz^!!XSDL fonts|:DroidSansMono.ttf:DroidSansMono.ttf^!!Postinstall script|:postinstall.sh:postinstall.sh"
AppDataDownloadUrl="!!Data files|:data.tar.xz:obb:main.281420|:data.tar.xz:http://sourceforge.net/projects/libsdl-android/files/ubuntu/jessie/dist-gimp-jessie.tar.xz/download^!!XSDL data files|:data-1.tar.gz:data-1.tgz^!!XSDL fonts|:DroidSansMono.ttf:DroidSansMono.ttf^!!Postinstall script|:postinstall.sh:postinstall.sh^!!Loading image|:loading.gif:loading.gif^!!Update 1|:update1.tar.gz:update1.tgz"
# Reset SDL config when updating application to the new version (y) / (n)
ResetSdlConfigForThisVersion=y
# Delete application data files when upgrading (specify file/dir paths separated by spaces)
DeleteFilesOnUpgrade="%"
DeleteFilesOnUpgrade="postinstall.sh libsdl-DownloadFinished-0.flag libsdl-DownloadFinished-1.flag libsdl-DownloadFinished-2.flag libsdl-DownloadFinished-3.flag libsdl-DownloadFinished-4.flag libsdl-DownloadFinished-5.flag libsdl-DownloadFinished-6.flag libsdl-DownloadFinished-7.flag libsdl-DownloadFinished-8.flag libsdl-DownloadFinished-9.flag"
# Here you may type readme text, which will be shown during startup. Format is:
# Text in English, use \\\\n to separate lines (that's four backslashes)^de:Text in Deutsch^ru:Text in Russian^button:Button that will open some URL:http://url-to-open/
@@ -249,7 +249,7 @@ AppSubdirsBuild=''
AppBuildExclude=''
# Application command line parameters, including app name as 0-th param
AppCmdline='XSDL -nohelp -screenbuttons -exec $SECURE_STORAGE_DIR/usr/bin/xli -onroot -border black -center $SECURE_STORAGE_DIR/loading.gif ; $SECURE_STORAGE_DIR/img/proot.sh ./startx.sh'
AppCmdline='XSDL -nohelp -screenbuttons -warndiskspacemb 1750 -exec $SECURE_STORAGE_DIR/usr/bin/xli -onroot -border black -center $UNSECURE_STORAGE_DIR/loading.gif ; $SECURE_STORAGE_DIR/img/proot.sh ./startx.sh'
# Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens
# Minimum screen size that application supports: (s)mall / (m)edium / (l)arge

View File

@@ -10,6 +10,7 @@
#include <net/if.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/vfs.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_screenkeyboard.h>
@@ -22,8 +23,10 @@ static TTF_Font* sFont;
static int unpackFinished = 0;
enum { UPGRADE_WARNING_NONE, UPGRADE_WARNING_ASK, UPGRADE_WARNING_PROCEED, UPGRADE_WARNING_CANCEL };
// Mutex here would be nice, but I'm lazy and don't care
static int upgradeWarning = UPGRADE_WARNING_NONE;
static char unpackLog[4][256];
static int freeSpaceRequiredMb = 0;
static void renderString(const char *c, int x, int y);
static void renderStringColor(const char *c, int x, int y, int r, int g, int b, SDL_Surface * surf);
@@ -32,7 +35,7 @@ static void renderStringScaled(const char *c, int size, int x, int y, int r, int
static void * unpackFilesThread(void * unused);
static void showErrorMessage(const char *msg);
static int unpackFiles(const char *archive, const char *script, const char *deleteOldDataMarkerFile)
static int unpackFiles(const char *archive, const char *script, const char *deleteOldDataMarkerFile, const char *pathsToDelete)
{
int unpackProgressMb;
int unpackProgressMbTotal = 1;
@@ -73,15 +76,11 @@ static int unpackFiles(const char *archive, const char *script, const char *dele
unpackProgressMb = 0;
strcpy( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/" );
strcat( fname, script );
strcpy( fname2, getenv("SECURE_STORAGE_DIR") );
strcat( fname2, "/" );
strcat( fname2, deleteOldDataMarkerFile );
if( strlen(deleteOldDataMarkerFile) > 0 && stat( fname, &st ) == 0 && stat( fname2, &st ) == 0 )
if( strlen(deleteOldDataMarkerFile) > 0 && stat( fname2, &st ) == 0 )
{
__android_log_print(ANDROID_LOG_INFO, "XSDL", "Upgrade detected, showing warning dialog");
upgradeWarning = UPGRADE_WARNING_ASK;
@@ -94,43 +93,35 @@ static int unpackFiles(const char *archive, const char *script, const char *dele
strcpy( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/busybox" );
strcat( fname, " mkdir -p " );
strcat( fname, " sh -c 'cd " );
strcat( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/../cache" );
strcat( fname, " ; rm -rf " );
strcat( fname, pathsToDelete );
strcat( fname, "'" );
__android_log_print(ANDROID_LOG_INFO, "XSDL", "%s", fname);
system( fname );
}
strcpy( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/busybox" );
strcat( fname, " cp -a " );
strcat( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/busybox " );
strcat( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/../cache/busybox" );
__android_log_print(ANDROID_LOG_INFO, "XSDL", "%s", fname);
system( fname );
strcpy( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/../cache/busybox" );
strcat( fname, " rm -rf " );
strcat( fname, getenv("SECURE_STORAGE_DIR") );
strcat( fname, "/*" );
__android_log_print(ANDROID_LOG_INFO, "XSDL", "%s", fname);
system( fname );
sprintf(unpackLog[0], "Restarting the app...");
__android_log_print(ANDROID_LOG_INFO, "XSDL", "Restarting the app: %s", fname);
SDL_ANDROID_OpenExternalApp(getenv("ANDROID_PACKAGE_NAME"), ".RestartMainActivity", NULL);
sleep(1);
exit(0);
for (;;)
{
struct statfs freeSpace;
memset(&freeSpace, 0, sizeof(freeSpace));
if( statfs(getenv("SECURE_STORAGE_DIR"), &freeSpace) == 0 )
{
if( (uint64_t)freeSpace.f_bsize * (uint64_t)freeSpace.f_bavail < (uint64_t)freeSpaceRequiredMb * 1024 * 1024 )
{
sprintf(unpackLog[0], "Error: not enough free space on internal storage");
sprintf(unpackLog[1], "Available %llu Mb, required %d Mb", (uint64_t)freeSpace.f_bsize * freeSpace.f_bavail / 1024 / 1024, freeSpaceRequiredMb);
sprintf(unpackLog[2], "Please uninstall large apps to free more space on internal storage");
sleep(1);
continue;
}
}
sprintf(unpackLog[1], " ");
sprintf(unpackLog[2], " ");
break;
}
sprintf(unpackLog[0], "Unpacking data: %s", archive);
@@ -243,9 +234,10 @@ static int unpackFiles(const char *archive, const char *script, const char *dele
if( strchr(buf, '\n') != NULL )
strchr(buf, '\n')[0] = 0;
__android_log_print(ANDROID_LOG_INFO, "XSDL", "> %s", buf);
strncpy(unpackLog[3], unpackLog[2], sizeof(unpackLog[1]) - 4);
strncpy(unpackLog[2], unpackLog[1], sizeof(unpackLog[1]) - 4);
strncpy(unpackLog[1], buf, sizeof(unpackLog[1]) - 4);
strncpy(unpackLog[3], unpackLog[2], sizeof(unpackLog[0]) - 4);
strncpy(unpackLog[2], unpackLog[1], sizeof(unpackLog[0]) - 4);
strncpy(unpackLog[1], unpackLog[0], sizeof(unpackLog[0]) - 4);
strncpy(unpackLog[0], buf, sizeof(unpackLog[0]) - 4);
}
__android_log_print(ANDROID_LOG_INFO, "XSDL", "Postinstall script exited with status %d", pclose(fo));
@@ -256,26 +248,26 @@ static int unpackFiles(const char *archive, const char *script, const char *dele
static void * unpackFilesThread(void * unused)
{
const char *unpack[][3] =
const char *unpack[][4] =
{
{ "data.tar.gz", "postinstall.sh", "usr/lib/xorg/protocol.txt" },
{ "xfonts.tar.gz", "", "" },
{ "update1.tar.gz", "update1.sh", "" },
{ "update2.tar.gz", "update2.sh", "" },
{ "update3.tar.gz", "update3.sh", "" },
{ "update4.tar.gz", "update4.sh", "" },
{ "update5.tar.gz", "update5.sh", "" },
{ "update6.tar.gz", "update6.sh", "" },
{ "update7.tar.gz", "update7.sh", "" },
{ "update8.tar.gz", "update8.sh", "" },
{ "update9.tar.gz", "update9.sh", "" },
{NULL, NULL, NULL}
{ "data.tar.gz", "postinstall.sh", "usr/lib/xorg/protocol.txt", "img img-* postinstall.sh update*.sh" },
{ "xfonts.tar.gz", "", "", "" },
{ "update1.tar.gz", "update1.sh", "", "" },
{ "update2.tar.gz", "update2.sh", "", "" },
{ "update3.tar.gz", "update3.sh", "", "" },
{ "update4.tar.gz", "update4.sh", "", "" },
{ "update5.tar.gz", "update5.sh", "", "" },
{ "update6.tar.gz", "update6.sh", "", "" },
{ "update7.tar.gz", "update7.sh", "", "" },
{ "update8.tar.gz", "update8.sh", "", "" },
{ "update9.tar.gz", "update9.sh", "", "" },
{NULL, NULL, NULL, NULL}
};
int i;
for( i = 0; unpack[i][0] != NULL; i++ )
{
int status = unpackFiles(unpack[i][0], unpack[i][1], unpack[i][2]);
int status = unpackFiles(unpack[i][0], unpack[i][1], unpack[i][2], unpack[i][3]);
if( status == 0 && i == 0 ) // Only the first archive is mandatory
{
unpackFinished = 1;
@@ -287,19 +279,55 @@ static void * unpackFilesThread(void * unused)
return (void *)1;
}
void XSDL_unpackFiles()
void XSDL_unpackFiles(int _freeSpaceRequiredMb)
{
pthread_t thread_id;
void * status;
memset(unpackLog, 0, sizeof(unpackLog));
freeSpaceRequiredMb = _freeSpaceRequiredMb;
pthread_create(&thread_id, NULL, &unpackFilesThread, NULL);
int progress = 0;
enum {PROGRESS_WHEEL_NUM = 8};
const char *progressWheel[PROGRESS_WHEEL_NUM] = { ";,,,,,,,", ",;,,,,,,", ",,;,,,,,", ",,,;,,,,", ",,,,;,,,", ",,,,,;,,", ",,,,,,;,", ",,,,,,,;" };
enum {PROGRESS_WHEEL_NUM = 14};
const char *progressWheel[PROGRESS_WHEEL_NUM] =
{
"[<=>=======]",
"[=<=>======]",
"[==<=>=====]",
"[===<=>====]",
"[====<=>===]",
"[=====<=>==]",
"[======<=>=]",
"[=======<=>]",
"[======<=>=]",
"[=====<=>==]",
"[====<=>===]",
"[===<=>====]",
"[==<=>=====]",
"[=<=>======]",
};
/*
const char *progressWheel[PROGRESS_WHEEL_NUM] =
{
"°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´",
"´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚",
"˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´",
"´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°",
"°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤",
"¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø",
"ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,",
",ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸",
"¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳",
"˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸",
"¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,",
",¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø",
"ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤",
"¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°¤ø,¸˳¸,ø¤°´˚´°",
};
*/
SDL_Joystick * j0 = SDL_JoystickOpen(0);
while (!unpackFinished)
{
SDL_Delay(400);
SDL_Delay(300);
SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);
renderString(unpackLog[0], VID_X/2, VID_Y*2/8);
renderString(unpackLog[1], VID_X/2, VID_Y*3/8);
@@ -309,18 +337,31 @@ void XSDL_unpackFiles()
renderString(progressWheel[progress % PROGRESS_WHEEL_NUM], VID_X/2, VID_Y*6/8);
renderString("You may put this app to background while it's unpacking", VID_X/2, VID_Y*7/8);
SDL_Flip(SDL_GetVideoSurface());
int x, y;
int x = 0, y = 0;
while( upgradeWarning == UPGRADE_WARNING_ASK )
{
SDL_Delay(100);
SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);
char s[PATH_MAX];
sprintf(s, "New update available for %s", getenv("ANDROID_APP_NAME"));
renderString(s, VID_X/2, VID_Y*2/8);
sprintf(s, "Please move all your %s files to SD card", getenv("ANDROID_APP_NAME"));
renderString(s, VID_X/2, VID_Y*3/8);
renderString("or they will be deleted during upgrade", VID_X/2, VID_Y*4/8);
renderString("Install now", VID_X/4, VID_Y*6/8);
renderString("Install later", VID_X*3/4, VID_Y*6/8);
SDL_Flip(SDL_GetVideoSurface());
renderString("――――――――――――――――――――", VID_X/4, VID_Y*11/16);
renderString("| |", VID_X/4, VID_Y*45/64);
renderString("| |", VID_X/4, VID_Y*48/64);
renderString("| |", VID_X/4, VID_Y*101/128);
renderString("――――――――――――――――――――", VID_X/4, VID_Y*13/16);
renderString("Install now", VID_X/4, VID_Y*6/8);
renderString("――――――――――――――――――――", VID_X*3/4, VID_Y*11/16);
renderString("| |", VID_X*3/4, VID_Y*45/64);
renderString("| |", VID_X*3/4, VID_Y*48/64);
renderString("| |", VID_X*3/4, VID_Y*101/128);
renderString("――――――――――――――――――――", VID_X*3/4, VID_Y*13/16);
renderString("Install later", VID_X*3/4, VID_Y*6/8);
SDL_Event event;
while (SDL_PollEvent(&event))
{
@@ -340,7 +381,7 @@ void XSDL_unpackFiles()
break;
}
}
SDL_Delay(200);
SDL_Flip(SDL_GetVideoSurface());
}
}
@@ -350,6 +391,7 @@ void XSDL_unpackFiles()
showErrorMessage("Cannot unpack data files, please reinstall the app");
exit(1);
}
SDL_JoystickClose(j0);
}
void XSDL_showConfigMenu(int * resolutionW, int * displayW, int * resolutionH, int * displayH)

View File

@@ -5,7 +5,7 @@ enum { VID_X = 480, VID_Y = 320 };
void XSDL_initSDL();
void XSDL_deinitSDL();
void XSDL_unpackFiles();
void XSDL_unpackFiles(int freeSpaceRequiredMb);
void XSDL_showConfigMenu(int * resolutionW, int * displayW, int * resolutionH, int * displayH);
void XSDL_generateBackground(const char * port, int showHelp, int resolutionW, int resolutionH);
void XSDL_showServerLaunchErrorMessage();

View File

@@ -42,6 +42,7 @@ int main( int argc, char* argv[] )
int printHelp = 1;
int screenResOverride = 0;
int screenButtons = 0;
int warnDiskSpaceMb = 0;
int resolutionW = atoi(getenv("DISPLAY_RESOLUTION_WIDTH"));
int resolutionH = atoi(getenv("DISPLAY_RESOLUTION_HEIGHT"));
@@ -55,10 +56,6 @@ int main( int argc, char* argv[] )
XSDL_initSDL();
XSDL_unpackFiles();
XSDL_showConfigMenu(&resolutionW, &displayW, &resolutionH, &displayH);
for(i = 0; i < 1024; i++)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
@@ -126,6 +123,12 @@ int main( int argc, char* argv[] )
{
screenButtons = 1;
}
else if( strcmp(argv[1], "-warndiskspacemb") == 0 && argc > 2 )
{
warnDiskSpaceMb = atoi(argv[2]);
argc--;
argv++;
}
else
{
args[argnum] = argv[1];
@@ -146,13 +149,18 @@ int main( int argc, char* argv[] )
getenv("SECURE_STORAGE_DIR"),
getenv("SECURE_STORAGE_DIR") );
XSDL_unpackFiles(warnDiskSpaceMb);
if( !screenResOverride )
{
XSDL_showConfigMenu(&resolutionW, &displayW, &resolutionH, &displayH);
sprintf( screenres, "%d/%dx%d/%dx%d", resolutionW, displayW, resolutionH, displayH, SDL_GetVideoInfo()->vfmt->BitsPerPixel );
}
XSDL_generateBackground( port, printHelp, resolutionW, resolutionH );
XSDL_deinitSDL();
if( !screenResOverride )
sprintf( screenres, "%d/%dx%d/%dx%d", resolutionW, displayW, resolutionH, displayH, SDL_GetVideoInfo()->vfmt->BitsPerPixel );
if( printHelp )
{
sprintf( clientcmd, "%s/usr/bin/xhost + ; %s/usr/bin/xli -onroot -center %s/background.bmp",

View File

@@ -574,16 +574,13 @@ int SDLCALL SDL_ANDROID_CloudLoad(const char *filename, const char *saveId, cons
void SDLCALL SDL_ANDROID_OpenExternalApp(const char *package, const char *activity, const char *data)
{
(*JavaEnv)->PushLocalFrame(JavaEnv, 3);
jstring s1 = package ? (*JavaEnv)->NewStringUTF(JavaEnv, package) : NULL;
jstring s2 = activity ? (*JavaEnv)->NewStringUTF(JavaEnv, activity) : NULL;
jstring s3 = data ? (*JavaEnv)->NewStringUTF(JavaEnv, data) : NULL;
jstring s1 = package ? (*JavaEnv)->NewStringUTF(JavaEnv, package) : (*JavaEnv)->NewStringUTF(JavaEnv, "");
jstring s2 = activity ? (*JavaEnv)->NewStringUTF(JavaEnv, activity) : (*JavaEnv)->NewStringUTF(JavaEnv, "");
jstring s3 = data ? (*JavaEnv)->NewStringUTF(JavaEnv, data) : (*JavaEnv)->NewStringUTF(JavaEnv, "");
(*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaRequestOpenExternalApp, s1, s2, s3 );
if (s3)
(*JavaEnv)->DeleteLocalRef(JavaEnv, s3);
if (s2)
(*JavaEnv)->DeleteLocalRef(JavaEnv, s2);
if (s1)
(*JavaEnv)->DeleteLocalRef(JavaEnv, s1);
(*JavaEnv)->DeleteLocalRef(JavaEnv, s3);
(*JavaEnv)->DeleteLocalRef(JavaEnv, s2);
(*JavaEnv)->DeleteLocalRef(JavaEnv, s1);
(*JavaEnv)->PopLocalFrame(JavaEnv, NULL);
}