From 4f3665edef694e743d369d2e02e7048dd68ee3bb Mon Sep 17 00:00:00 2001 From: pelya Date: Fri, 18 Feb 2011 16:09:20 +0000 Subject: [PATCH] app2sd support for shared libraries --- ChangeAppSettings.sh | 6 +- app2sd.sh | 35 +++++ project/java/Globals.java | 6 +- project/java/MainActivity.java | 134 +++++++++++++++--- project/java/Video.java | 24 +++- .../fheroes2/AndroidAppSettings.cfg | 9 +- .../AndroidData/{data8.zip => data9.zip} | Bin 850252 -> 869389 bytes project/jni/application/src | 2 +- project/jni/sdl_main/sdl_main.c | 1 + readme.txt | 10 ++ 10 files changed, 197 insertions(+), 30 deletions(-) create mode 100755 app2sd.sh rename project/jni/application/fheroes2/AndroidData/{data8.zip => data9.zip} (97%) diff --git a/ChangeAppSettings.sh b/ChangeAppSettings.sh index 037bf215a..23815d8e9 100755 --- a/ChangeAppSettings.sh +++ b/ChangeAppSettings.sh @@ -488,7 +488,7 @@ if [ "$MultiABI" = "y" ] ; then else MultiABI="armeabi" fi -LibrariesToLoad="System.loadLibrary(\\\"sdl-$LibSdlVersion\\\");" +LibrariesToLoad="\\\"sdl-$LibSdlVersion\\\"" StaticLibraries=`grep 'APP_AVAILABLE_STATIC_LIBS' project/jni/SettingsTemplate.mk | sed 's/.*=\(.*\)/\1/'` for lib in $CompiledLibraries; do process=true @@ -496,7 +496,7 @@ for lib in $CompiledLibraries; do if [ "$lib" = "$lib1" ]; then process=false; fi done if $process; then - LibrariesToLoad="$LibrariesToLoad System.loadLibrary(\\\"$lib\\\");" + LibrariesToLoad="$LibrariesToLoad, \\\"$lib\\\"" fi done @@ -545,7 +545,7 @@ cat project/src/Globals.java | \ sed "s/public static int AppTouchscreenKeyboardKeysAmountAutoFire = .*;/public static int AppTouchscreenKeyboardKeysAmountAutoFire = $AppTouchscreenKeyboardKeysAmountAutoFire;/" | \ sed "s%public static String ReadmeText = .*%public static String ReadmeText = \"$ReadmeText\".replace(\"^\",\"\\\n\");%" | \ sed "s%public static String CommandLine = .*%public static String CommandLine = \"$AppCmdline\";%" | \ - sed "s/public LoadLibrary() .*/public LoadLibrary() { $LibrariesToLoad };/" > \ + sed "s/public static String AppLibraries.*/public static String AppLibraries[] = { $LibrariesToLoad };/" > \ project/src/Globals.java.1 mv -f project/src/Globals.java.1 project/src/Globals.java diff --git a/app2sd.sh b/app2sd.sh new file mode 100755 index 000000000..a2d1496e1 --- /dev/null +++ b/app2sd.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +APK=$1 +if [ -z "$APK" ] ; then + APK=project/bin/DemoActivity-debug.apk +fi + +echo Moving shared libraries on $APK to SD card +APK=`pwd`/$APK + +[ -e $APK ] || { echo File $APK does not exist; exit 1; } + +TMPDIR=app2sd-$$ + +mkdir -p $TMPDIR +cd $TMPDIR + +unzip $APK "lib/armeabi/*" || { echo "This apk file has already been app2sd-ed, or improperly compiled"; exit 1; } + +zip -j bindata.zip lib/armeabi/* +mkdir assets +split -b 1048576 -d -a 1 bindata.zip assets/bindata +rm bindata.zip + +zip -d $APK "lib/armeabi/*" "META-INF/*" + +zip -0 $APK assets/bindata* + +jarsigner -verbose -keystore ~/.android/debug.keystore -storepass "android" $APK androiddebugkey + +zipalign 4 $APK $APK-tmp +mv -f $APK-tmp $APK + +cd .. +rm -rf $TMPDIR diff --git a/project/java/Globals.java b/project/java/Globals.java index e9930a1a7..c5a1879dc 100644 --- a/project/java/Globals.java +++ b/project/java/Globals.java @@ -9,6 +9,8 @@ import android.view.KeyEvent; class Globals { public static String ApplicationName = "CommanderGenius"; + public static String AppLibraries[] = { "sdl-1.2", }; + public static final boolean Using_SDL_1_3 = false; // Should be zip file @@ -105,7 +107,3 @@ class Globals { public static boolean SmoothVideo = false; public static boolean MultiThreadedVideo = SwVideoMode; } - -class LoadLibrary { - public LoadLibrary() { System.loadLibrary("sdl-1.2"); }; -} diff --git a/project/java/MainActivity.java b/project/java/MainActivity.java index 48487ca04..ad26441bc 100644 --- a/project/java/MainActivity.java +++ b/project/java/MainActivity.java @@ -24,6 +24,16 @@ import android.app.PendingIntent; import android.content.Intent; import android.view.View.OnKeyListener; import java.util.LinkedList; +import java.io.SequenceInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.File; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + public class MainActivity extends Activity { @@ -81,7 +91,7 @@ public class MainActivity extends Activity { if(mAudioThread == null) // Starting from background (should not happen) { System.out.println("libSDL: Loading libraries"); - mLoadLibraryStub = new LoadLibrary(); + LoadLibraries(); mAudioThread = new AudioThread(this); System.out.println("libSDL: Loading settings"); Settings.Load(this); @@ -223,19 +233,13 @@ public class MainActivity extends Activity { { if(_screenKeyboard == null) return; - String text = _screenKeyboard.getText().toString(); - if( mGLView != null ) + + synchronized(textInput) { - synchronized(textInput) { - for(int i = 0; i < text.length(); i++) - { - DemoRenderer.nativeTextInput( (int)text.charAt(i), (int)text.codePointAt(i) ); - //textInput.addLast((int)text.charAt(i)); - //textInput.addLast((int)text.codePointAt(i)); - } - DemoRenderer.nativeTextInput( 13, 13 ); // send return - //textInput.addLast(13); - //textInput.addLast(13); + String text = _screenKeyboard.getText().toString(); + for(int i = 0; i < text.length(); i++) + { + DemoRenderer.nativeTextInput( (int)text.charAt(i), (int)text.codePointAt(i) ); } } _videoLayout.removeView(_screenKeyboard); @@ -255,12 +259,19 @@ public class MainActivity extends Activity { myKeyListener(MainActivity parent) { _parent = parent; }; public boolean onKey(View v, int keyCode, KeyEvent event) { - if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) + if ((event.getAction() == KeyEvent.ACTION_UP) && ((keyCode == KeyEvent.KEYCODE_ENTER) || (keyCode == KeyEvent.KEYCODE_BACK))) { _parent.hideScreenKeyboard(); + if(keyCode == KeyEvent.KEYCODE_ENTER) + { + synchronized(textInput) + { + DemoRenderer.nativeTextInput( 13, 13 ); // send return + } + } return true; } - if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_CLEAR)) + if ((event.getAction() == KeyEvent.ACTION_UP) && (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_CLEAR)) { synchronized(textInput) { DemoRenderer.nativeTextInput( 8, 8 ); @@ -376,13 +387,104 @@ public class MainActivity extends Activity { NotificationManager NotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager.cancel(NOTIFY_ID); } + + public void LoadLibraries() + { + try + { + for(String l : Globals.AppLibraries) + { + System.loadLibrary(l); + } + } + catch ( UnsatisfiedLinkError e ) + { + try { + System.out.println("libSDL: Extracting APP2SD-ed libs"); + + InputStream in = null; + try + { + for( int i = 0; ; i++ ) + { + InputStream in2 = getAssets().open("bindata" + String.valueOf(i)); + if( in == null ) + in = in2; + else + in = new SequenceInputStream( in, in2 ); + } + } + catch( IOException ee ) { } + + if( in == null ) + throw new RuntimeException("libSDL: Extracting APP2SD-ed libs failed, the .apk file packaged incorrectly"); + + ZipInputStream zip = new ZipInputStream(in); + + File cacheDir = getCacheDir(); + try { + cacheDir.mkdirs(); + } catch( SecurityException ee ) { }; + + byte[] buf = new byte[16384]; + while(true) + { + ZipEntry entry = null; + entry = zip.getNextEntry(); + /* + if( entry != null ) + System.out.println("Extracting lib " + entry.getName()); + */ + if( entry == null ) + { + System.out.println("Extracting libs finished"); + break; + } + if( entry.isDirectory() ) + { + System.out.println("Warning '" + entry.getName() + "' is a directory"); + continue; + } + + OutputStream out = null; + String path = cacheDir.getAbsolutePath() + "/" + entry.getName(); + + System.out.println("Saving to file '" + path + "'"); + + out = new FileOutputStream( path ); + int len = zip.read(buf); + while (len >= 0) + { + if(len > 0) + out.write(buf, 0, len); + len = zip.read(buf); + } + + out.flush(); + out.close(); + } + + for(String l : Globals.AppLibraries) + { + String libname = System.mapLibraryName(l); + File libpath = new File(cacheDir, libname); + System.out.println("libSDL: loading lib " + libpath.getPath()); + System.load(libpath.getPath()); + libpath.delete(); + } + } + catch ( Exception ee ) + { + System.out.println("libSDL: Error: " + e.toString()); + } + } + }; public FrameLayout getVideoLayout() { return _videoLayout; } static int NOTIFY_ID = 12367098; // Random ID private static DemoGLSurfaceView mGLView = null; - private static LoadLibrary mLoadLibraryStub = null; private static AudioThread mAudioThread = null; private static DataDownloader downloader = null; diff --git a/project/java/Video.java b/project/java/Video.java index 8f873437e..72604b272 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -18,6 +18,7 @@ import android.view.KeyEvent; import android.view.Window; import android.view.WindowManager; import android.os.Environment; +import java.io.File; import android.widget.TextView; import java.lang.Thread; @@ -205,8 +206,27 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer { // Thread.currentThread().setPriority((Thread.currentThread().getPriority() + Thread.MIN_PRIORITY)/2); mGlContextLost = false; - System.loadLibrary("application"); - System.loadLibrary("sdl_main"); + + String libs[] = { "application", "sdl_main" }; + try + { + for(String l : libs) + { + System.loadLibrary(l); + } + } + catch ( UnsatisfiedLinkError e ) + { + for(String l : libs) + { + String libname = System.mapLibraryName(l); + File libpath = new File(context.getCacheDir(), libname); + System.out.println("libSDL: loading lib " + libpath.getPath()); + System.load(libpath.getPath()); + libpath.delete(); + } + } + Settings.Apply(context); accelerometer = new AccelerometerReader(context); // Tweak video thread priority, if user selected big audio buffer diff --git a/project/jni/application/fheroes2/AndroidAppSettings.cfg b/project/jni/application/fheroes2/AndroidAppSettings.cfg index cc78f4b23..aef695512 100644 --- a/project/jni/application/fheroes2/AndroidAppSettings.cfg +++ b/project/jni/application/fheroes2/AndroidAppSettings.cfg @@ -1,14 +1,15 @@ # The application settings for Android libSDL port -AppSettingVersion=16 +AppSettingVersion=17 LibSdlVersion=1.2 AppName="Free Heroes 2" AppFullName=net.sourceforge.fheroes2 ScreenOrientation=h InhibitSuspend=n -AppDataDownloadUrl="Game data|data8.zip^Heroes 2 DEMO data files (45 Mb)|http://downloads.pcworld.com/pub/new/fun_and_games/adventure_strategy/h2demo.zip|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/h2demo.zip/download^MIDI music support (18 Mb)|http://sourceforge.net/projects/libsdl-android/files/timidity.zip/download^Essential map pack (9 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/EssentialMapPack.zip/download^Additional map pack (95 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/AdditionalMapPack.zip/download^Mega map pack (280 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/MegaMapPack.zip/download^Russian translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-ru.cfg/download^Czech translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-cs.cfg/download^Spanish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-es.cfg/download^French translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-fr.cfg/download^Hungarian translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-hu.cfg/download^Polish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-pl.cfg/download^Portugese translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-pt.cfg/download^Swedish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-sv.cfg/download" +AppDataDownloadUrl="Game data|data9.zip^Heroes 2 DEMO data files (45 Mb)|http://downloads.pcworld.com/pub/new/fun_and_games/adventure_strategy/h2demo.zip|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/h2demo.zip/download^MIDI music support (18 Mb)|http://sourceforge.net/projects/libsdl-android/files/timidity.zip/download^Essential map pack (9 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/EssentialMapPack.zip/download^Additional map pack (95 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/AdditionalMapPack.zip/download^Mega map pack (280 Mb)|http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/MegaMapPack.zip/download^Russian translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-ru.cfg/download^Czech translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-cs.cfg/download^Spanish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-es.cfg/download^French translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-fr.cfg/download^Hungarian translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-hu.cfg/download^Polish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-pl.cfg/download^Portugese translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-pt.cfg/download^Swedish translation|:fheroes2.cfg:http://sourceforge.net/projects/libsdl-android/files/FreeHeroes2/lang/fheroes2-sv.cfg/download" SdlVideoResize=y SdlVideoResizeKeepAspect=n NeedDepthBuffer=n +SwVideoMode=y AppUsesMouse=y AppNeedsTwoButtonMouse=y AppNeedsArrowKeys=n @@ -22,8 +23,8 @@ AppTouchscreenKeyboardKeysAmount=0 AppTouchscreenKeyboardKeysAmountAutoFire=0 RedefinedKeysScreenKb="LCTRL M T H E C SPACE C S L" MultiABI=n -AppVersionCode=225912 -AppVersionName="2259.12" +AppVersionCode=226512 +AppVersionName="2265.12" CompiledLibraries="sdl_net sdl_mixer sdl_image sdl_ttf png intl" CustomBuildScript=n AppCflags='-finline-functions -O2 -DWITH_ZLIB -DWITH_MIXER -DWITH_XML -DWITH_IMAGE -DWITH_TTF -DWITH_AI=simple' diff --git a/project/jni/application/fheroes2/AndroidData/data8.zip b/project/jni/application/fheroes2/AndroidData/data9.zip similarity index 97% rename from project/jni/application/fheroes2/AndroidData/data8.zip rename to project/jni/application/fheroes2/AndroidData/data9.zip index 2115ad3486ea43ad56bcf8a59ce2cbeb6a7f836b..14ad663c3d6739d4cbbb50fa229f56a0f4fb8a76 100644 GIT binary patch delta 19340 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 delta 60 zcmeC}Fg^3hxS@ryg{g(Pg{6hHg{_6Xg`DoOU}${I!@$4*0BffaKL7v# diff --git a/project/jni/application/src b/project/jni/application/src index 104f796a6..59d41f41e 120000 --- a/project/jni/application/src +++ b/project/jni/application/src @@ -1 +1 @@ -ballfield \ No newline at end of file +fheroes2 \ No newline at end of file diff --git a/project/jni/sdl_main/sdl_main.c b/project/jni/sdl_main/sdl_main.c index d4d5486c0..03ab8dd9e 100644 --- a/project/jni/sdl_main/sdl_main.c +++ b/project/jni/sdl_main/sdl_main.c @@ -33,6 +33,7 @@ static char ** argv = NULL; static int threadedMain(void * unused) { SDL_main( argc, argv ); + __android_log_print(ANDROID_LOG_INFO, "libSDL", "Application closed, calling exit(0)"); exit(0); } diff --git a/readme.txt b/readme.txt index f036e9df9..a49fe8d9c 100644 --- a/readme.txt +++ b/readme.txt @@ -167,6 +167,16 @@ memcpy( &i, p, sizeof(int) ); // The correct way to dereference a non-aligned po This compiler flags will catch most obvious errors, you may add them to AppCflags var in settings: -Werror=strict-aliasing -Werror=cast-align -Werror=pointer-arith -Werror=address +The application will automatically get moved to SD-card on Android 2.2 or newer, +(or you can install app2sd for older, but rooted phones), +however the shared libraries have to be stored on the device internal storage, +and that may be not desired for older phones with very little storage. +The script app2sd.sh will re-package your .apk file in such a way that +the shared libraries will not be extracted by Android OS but by application itself, +and it will remove them from internal storage right after starting up, +so you still need that space free, but only temporarily. + + How to compile your own application using automake/configure scripts ====================================================================