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 2115ad348..14ad663c3 100644 Binary files a/project/jni/application/fheroes2/AndroidData/data8.zip and b/project/jni/application/fheroes2/AndroidData/data9.zip differ 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 ====================================================================