Background saving/restoring fully works (And pauses audio)
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.googlecode.opentyrian"
|
||||
android:versionCode="2113"
|
||||
android:versionName="2.1.13 - more options for auto-fire and touchscreen controls in Keyboard menu"
|
||||
android:versionCode="2114"
|
||||
android:versionName="2.1.14 - game can be put to background with Home button and successfully restored back"
|
||||
android:installLocation="preferExternal"
|
||||
>
|
||||
<application android:label="@string/app_name"
|
||||
|
||||
@@ -15,8 +15,8 @@ RedefinedKeys="SPACE RETURN LCTRL LALT SPACE"
|
||||
AppTouchscreenKeyboardKeysAmount=4
|
||||
AppTouchscreenKeyboardKeysAmountAutoFire=1
|
||||
MultiABI=n
|
||||
AppVersionCode=2113
|
||||
AppVersionName="2.1.13 - more options for auto-fire and touchscreen controls in Keyboard menu"
|
||||
AppVersionCode=2114
|
||||
AppVersionName="2.1.14 - game can be put to background with Home button and successfully restored back"
|
||||
CompiledLibraries="sdl_net"
|
||||
CustomBuildScript=n
|
||||
AppCflags='-finline-functions -O2'
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
#define SDL_VIDEO_DRIVER_ANDROID 1
|
||||
#define SDL_VIDEO_OPENGL_ES 1
|
||||
#define SDL_VIDEO_RENDER_OGL_ES 1
|
||||
@@ -159,4 +160,29 @@
|
||||
#undef SDL_ALTIVEC_BLITTERS
|
||||
#define SDL_ASSEMBLY_ROUTINES 1 // There is no assembly code for Arm CPU yet
|
||||
|
||||
/* Prototypes for Android-specific functions */
|
||||
|
||||
#include "begin_code.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Sets callbacks to be called when OS decides to put application to background, and restored to foreground.
|
||||
*/
|
||||
typedef void ( * SDL_ANDROID_ApplicationPutToBackgroundCallback_t ) (void);
|
||||
|
||||
extern DECLSPEC int SDLCALL SDL_ANDROID_SetApplicationPutToBackgroundCallback(
|
||||
SDL_ANDROID_ApplicationPutToBackgroundCallback_t appPutToBackground,
|
||||
SDL_ANDROID_ApplicationPutToBackgroundCallback_t appRestored );
|
||||
|
||||
/* Use these functions instead of setting volume to 0, that will save CPU and battery on device */
|
||||
extern DECLSPEC int SDLCALL SDL_ANDROID_PauseAudioPlayback(void);
|
||||
extern DECLSPEC int SDLCALL SDL_ANDROID_ResumeAudioPlayback(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include "close_code.h"
|
||||
|
||||
#endif /* _SDL_config_minimal_h */
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "SDL_video.h"
|
||||
#include "SDL_keysym.h"
|
||||
|
||||
/* Android-specific functions, mainly on-screen keyboard exposed to the application */
|
||||
/* On-screen keyboard exposed to the application, it's yet available on Android platform only */
|
||||
|
||||
#include "begin_code.h"
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
@@ -74,4 +74,4 @@ extern DECLSPEC int SDLCALL SDL_ANDROID_GetScreenKeyboardSize();
|
||||
#endif
|
||||
#include "close_code.h"
|
||||
|
||||
#endif /* _SDL_config_minimal_h */
|
||||
#endif
|
||||
|
||||
@@ -137,6 +137,8 @@ static JavaVM *jniVM = NULL;
|
||||
static jobject JavaAudioThread = NULL;
|
||||
static jmethodID JavaInitAudio = NULL;
|
||||
static jmethodID JavaDeinitAudio = NULL;
|
||||
static jmethodID JavaPauseAudioPlayback = NULL;
|
||||
static jmethodID JavaResumeAudioPlayback = NULL;
|
||||
|
||||
|
||||
static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS)
|
||||
@@ -301,6 +303,20 @@ static void ANDROIDAUD_PlayAudio(_THIS)
|
||||
__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio() JNI returns a copy of byte array - that's slow");
|
||||
}
|
||||
|
||||
int SDL_ANDROID_PauseAudioPlayback(void)
|
||||
{
|
||||
JNIEnv * jniEnv = NULL;
|
||||
(*jniVM)->AttachCurrentThread(jniVM, &jniEnv, NULL);
|
||||
return (*jniEnv)->CallIntMethod( jniEnv, JavaAudioThread, JavaPauseAudioPlayback );
|
||||
};
|
||||
int SDL_ANDROID_ResumeAudioPlayback(void)
|
||||
{
|
||||
JNIEnv * jniEnv = NULL;
|
||||
(*jniVM)->AttachCurrentThread(jniVM, &jniEnv, NULL);
|
||||
return (*jniEnv)->CallIntMethod( jniEnv, JavaAudioThread, JavaResumeAudioPlayback );
|
||||
};
|
||||
|
||||
|
||||
#ifndef SDL_JAVA_PACKAGE_PATH
|
||||
#error You have to define SDL_JAVA_PACKAGE_PATH to your package path with dots replaced with underscores, for example "com_example_SanAngeles"
|
||||
#endif
|
||||
@@ -315,10 +331,8 @@ JNIEXPORT jint JNICALL JAVA_EXPORT_NAME(AudioThread_nativeAudioInitJavaCallbacks
|
||||
JavaAudioThreadClass = (*jniEnv)->GetObjectClass(jniEnv, JavaAudioThread);
|
||||
JavaInitAudio = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "initAudio", "(IIII)I");
|
||||
JavaDeinitAudio = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "deinitAudio", "()I");
|
||||
/*
|
||||
__android_log_print(ANDROID_LOG_INFO, "libSDL", "nativeAudioInitJavaCallbacks(): JavaAudioThread %p JavaFillBuffer %p JavaInitAudio %p JavaDeinitAudio %p",
|
||||
JavaAudioThread, JavaFillBuffer, JavaInitAudio, JavaDeinitAudio);
|
||||
*/
|
||||
JavaPauseAudioPlayback = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "pauseAudioPlayback", "()I");
|
||||
JavaResumeAudioPlayback = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "resumeAudioPlayback", "()I");
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
|
||||
@@ -57,6 +57,18 @@ static jobject JavaRenderer = NULL;
|
||||
static jmethodID JavaSwapBuffers = NULL;
|
||||
static int glContextLost = 0;
|
||||
|
||||
static void appPutToBackgroundCallbackDefault(void)
|
||||
{
|
||||
SDL_ANDROID_PauseAudioPlayback();
|
||||
}
|
||||
static void appRestoredCallbackDefault(void)
|
||||
{
|
||||
SDL_ANDROID_ResumeAudioPlayback();
|
||||
}
|
||||
|
||||
static SDL_ANDROID_ApplicationPutToBackgroundCallback_t appPutToBackgroundCallback = appPutToBackgroundCallbackDefault;
|
||||
static SDL_ANDROID_ApplicationPutToBackgroundCallback_t appRestoredCallback = appRestoredCallbackDefault;
|
||||
|
||||
int SDL_ANDROID_CallJavaSwapBuffers()
|
||||
{
|
||||
glContextLost = 0;
|
||||
@@ -68,6 +80,7 @@ int SDL_ANDROID_CallJavaSwapBuffers()
|
||||
glContextLost = 0;
|
||||
__android_log_print(ANDROID_LOG_INFO, "libSDL", "OpenGL context recreated, refreshing textures");
|
||||
SDL_ANDROID_VideoContextRecreated();
|
||||
appRestoredCallbackDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +110,7 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeGlContextLost) ( JNIEnv* env, jobject thiz
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, "libSDL", "OpenGL context lost, waiting for new OpenGL context");
|
||||
glContextLost = 1;
|
||||
appPutToBackgroundCallbackDefault();
|
||||
SDL_ANDROID_VideoContextLost();
|
||||
}
|
||||
|
||||
@@ -112,3 +126,17 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeInitJavaCallbacks) ( JNIEnv* env, jobject t
|
||||
ANDROID_InitOSKeymap();
|
||||
|
||||
}
|
||||
|
||||
int SDL_ANDROID_SetApplicationPutToBackgroundCallback(
|
||||
SDL_ANDROID_ApplicationPutToBackgroundCallback_t appPutToBackground,
|
||||
SDL_ANDROID_ApplicationPutToBackgroundCallback_t appRestored )
|
||||
{
|
||||
appPutToBackgroundCallback = appPutToBackgroundCallbackDefault;
|
||||
appRestoredCallback = appRestoredCallbackDefault;
|
||||
|
||||
if( appPutToBackground )
|
||||
appPutToBackgroundCallback = appPutToBackground;
|
||||
|
||||
if( appRestoredCallback )
|
||||
appRestoredCallback = appRestored;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,26 @@ class AudioThread {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int pauseAudioPlayback()
|
||||
{
|
||||
if( mAudio != null )
|
||||
{
|
||||
mAudio.pause();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int resumeAudioPlayback()
|
||||
{
|
||||
if( mAudio != null )
|
||||
{
|
||||
mAudio.play();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private native int nativeAudioInitJavaCallbacks();
|
||||
}
|
||||
|
||||
|
||||
59
readme.txt
59
readme.txt
@@ -156,15 +156,55 @@ gdb libsdl.so -ex "list *0x0002ca00"
|
||||
|
||||
It will output the exact line in your source where the application crashed.
|
||||
|
||||
Android Application lifectcle support
|
||||
=====================================
|
||||
|
||||
Application may be put to background at any time, for example if user gets phone call onto the device.
|
||||
The application will lose OpenGL context then, and has to re-create it when put to foreground.
|
||||
|
||||
The SDL provides function
|
||||
SDL_ANDROID_SetApplicationPutToBackgroundCallback( callback_t appPutToBackground, callback_t appRestored );
|
||||
where callback_t is function pointer of type "void (*) void".
|
||||
The default callbacks will call another Android-specific functions:
|
||||
SDL_ANDROID_PauseAudioPlayback() and SDL_ANDROID_ResumeAudioPlayback()
|
||||
which will pause and resume audio from HW layer, so appplication does not need to destroy and re-init audio.
|
||||
|
||||
If you're using pure SDL 1.2 API (with or without HW acceleration) you don't need to worry about anything -
|
||||
the SDL itself will re-create GL textures and fill them with pixel data from existing SDL HW surfaces,
|
||||
so you may leave the callbacks to defaults.
|
||||
|
||||
If you're using SDL 1.3 API and using SDL_Texture, then the textures pixeldata is lost - you will need
|
||||
to call SDL_UpdateTexture() to refill texture pixeldata from appRestored() callback for all your textures.
|
||||
If you're using compatibility API with SDL_Surfaces you don't have to worry about that.
|
||||
|
||||
If you're using SDL with OpenGL with either SDL 1.2 or SDL 1.3, the situation is even more grim -
|
||||
not only all your GL textures are lost, but all GL matrices, blend modes, etc. has to be re-created.
|
||||
|
||||
OS may decide there's too little free RAM left on device, and kill background applications
|
||||
without notice, so it vill be good to create temporary savegame etc. from appPutToBackground() callback.
|
||||
|
||||
Also it's a good practice to pause any application audio, especially if the user gets phone call,
|
||||
and if you won't set your own callbacks the default callbacks will do exactly that.
|
||||
There are circumstances when you want to avoid that, for example if the application is audio player,
|
||||
or if application gets some notification over network (for example you're running a game server,
|
||||
and want a beep when someone connects to you) - you may unpause audio for some short time then.
|
||||
|
||||
The application is not allowed to do any GFX output without OpenGL context (or it will crash),
|
||||
that's why SDL_Flip() call will block until we're re-acquired context, and the callbacks will be called
|
||||
from inside SDL_Flip(). so you won't receive SDL_WINDOWEVENT_HIDDEN / SDL_WINDOWEVENT_SHOWN,
|
||||
because if SDL sends them the application will get them only after SDL_Flip() successfully
|
||||
re-acquired GL context, and it's too late to pause audio and save application state,
|
||||
so please use callbacks instead of SDL window events on Android OS.
|
||||
|
||||
The whole idea behind callbacks is that the existing application should not be modified to
|
||||
operate correctly - the whole time in background will just look to app as one very long SDL_Flip(),
|
||||
so it's good idea to implement some maximum time cap on game frame, so it won't process
|
||||
the game to the end level 'till the app is in background, or calculate the difference in time
|
||||
between appPutToBackground() and appRestored() and update game time variables.
|
||||
|
||||
Known bugs
|
||||
==========
|
||||
|
||||
0. Application will crash when you're pressing "Home" button or open/close keyboard
|
||||
- the correct behavior for Android apps is to stay in memory and go to foreground
|
||||
when you're launching app again, that's not working yet because
|
||||
app will lose OpenGL context (there are rumors that it won't lose GL context in 2.1 SDK).
|
||||
Anyway, SDL should sleep inside SDL_Flip() and re-create all HW textures when it gains back video.
|
||||
|
||||
1. Merge all config screens into single big config screen, make option to rerun config.
|
||||
|
||||
2. Fix on-screen keyboard, add more keys and more options, make possible for application to control it.
|
||||
@@ -192,6 +232,13 @@ so the data on your TV will lag halfsecond behind the data on the device screen.
|
||||
|
||||
7. Make app data to come inside .apk file in assets instead of downloading it from net.
|
||||
|
||||
8. OpenTyrian:
|
||||
1. Navigating game menus downwards with trackball skips events, that does not happen
|
||||
when navigting upwards.
|
||||
2. The detail level can be set to WILD by pressing "w" key in gameplay escape menu, expose that through interface.
|
||||
|
||||
9. Ur-Quan Masters: add Russian, Deutsch and Slovak translations: http://wiki.uqm.stack.nl/Translations
|
||||
|
||||
Games to port
|
||||
=============
|
||||
|
||||
|
||||
Reference in New Issue
Block a user