diff --git a/project/java/DataDownloader.java b/project/java/DataDownloader.java index e0484228d..5fa4a6a74 100644 --- a/project/java/DataDownloader.java +++ b/project/java/DataDownloader.java @@ -53,6 +53,9 @@ import android.text.SpannedString; import android.app.AlertDialog; import android.content.DialogInterface; +import android.Manifest; +import android.content.pm.PackageManager; + class CountingInputStream extends BufferedInputStream { @@ -328,6 +331,19 @@ class DataDownloader extends Thread Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.connecting_to, url) ); if( url.indexOf("obb:") == 0 ) // APK expansion file provided by Google Play { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) + { + int permissionCheck = Parent.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permissionCheck != PackageManager.PERMISSION_GRANTED && !Parent.writeExternalStoragePermissionDialogAnswered) + { + Parent.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + while( !Parent.writeExternalStoragePermissionDialogAnswered ) + { + try{ Thread.sleep(300); } catch (InterruptedException e) {} + } + } + } + url = getObbFilePath(url); InputStream stream1 = null; try { diff --git a/project/java/MainActivity.java b/project/java/MainActivity.java index b3c0a880c..007cd8d2d 100644 --- a/project/java/MainActivity.java +++ b/project/java/MainActivity.java @@ -1580,6 +1580,11 @@ public class MainActivity extends Activity { Log.i("SDL", "libSDL: Record audio permission: " + (grantResults[0] == PackageManager.PERMISSION_GRANTED ? "GRANTED" : "DENIED")); } + if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0])) + { + Log.i("SDL", "libSDL: Write external storage permission: " + (grantResults[0] == PackageManager.PERMISSION_GRANTED ? "GRANTED" : "DENIED")); + writeExternalStoragePermissionDialogAnswered = true; + } } public FrameLayout getVideoLayout() { return _videoLayout; } @@ -1620,6 +1625,7 @@ public class MainActivity extends Activity public LinkedList textInput = new LinkedList (); public static MainActivity instance = null; + public boolean writeExternalStoragePermissionDialogAnswered = false; } // *** HONEYCOMB / ICS FIX FOR FULLSCREEN MODE, by lmak *** diff --git a/project/java/Video.java b/project/java/Video.java index 55b8bea00..9b54c4386 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -63,6 +63,8 @@ import android.content.Intent; import android.view.View; import android.view.Display; import android.net.Uri; +import android.Manifest; +import android.content.pm.PackageManager; class Mouse @@ -947,6 +949,18 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer Settings.setConfigOptionFromSDL(option, value); } + public void requestExternalStorageRuntimePermissionFromSDL() + { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) + { + int permissionCheck = context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permissionCheck != PackageManager.PERMISSION_GRANTED && !context.writeExternalStoragePermissionDialogAnswered) + { + context.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + } + } + } + private int PowerOf2(int i) { int value = 1; diff --git a/project/jni/application/ballfield/AndroidAppSettings.cfg b/project/jni/application/ballfield/AndroidAppSettings.cfg index 3241236f0..5f7c557fe 100644 --- a/project/jni/application/ballfield/AndroidAppSettings.cfg +++ b/project/jni/application/ballfield/AndroidAppSettings.cfg @@ -170,7 +170,7 @@ AppUsesMultitouch=y AppRecordsAudio=n # Application needs to access SD card. If your data files are bigger than 5 Mb, enable it. (y) / (n) -AccessSdCard= +AccessSdCard=y # Application needs Internet access. If you disable it, you'll have to bundle all your data files inside .apk (y) / (n) AccessInternet= diff --git a/project/jni/application/ballfield/ballfield.cpp b/project/jni/application/ballfield/ballfield.cpp index c50770387..d74dc789b 100644 --- a/project/jni/application/ballfield/ballfield.cpp +++ b/project/jni/application/ballfield/ballfield.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #define fprintf(X, ...) __android_log_print(ANDROID_LOG_INFO, "Ballfield", __VA_ARGS__) #define printf(...) __android_log_print(ANDROID_LOG_INFO, "Ballfield", __VA_ARGS__) @@ -686,7 +687,10 @@ int main(int argc, char* argv[]) if(evt.key.keysym.sym == SDLK_0) SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_2, 1); if(evt.key.keysym.sym == SDLK_1) + { SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_2, 0); + SDL_ANDROID_RequestExternalStorageRuntimePermission(); + } if(evt.key.keysym.sym == SDLK_2) { SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD, 1); diff --git a/project/jni/application/openarena/AndroidAppSettings.cfg b/project/jni/application/openarena/AndroidAppSettings.cfg index 407336b0a..f37113a19 100644 --- a/project/jni/application/openarena/AndroidAppSettings.cfg +++ b/project/jni/application/openarena/AndroidAppSettings.cfg @@ -64,7 +64,7 @@ SdlVideoResize=y SdlVideoResizeKeepAspect=n # Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer -InhibitSuspend=n +InhibitSuspend=y # Create Android service, so the app is less likely to be killed while in background CreateService= diff --git a/project/jni/sdl-1.2/include/SDL_android.h b/project/jni/sdl-1.2/include/SDL_android.h index f7e268a46..5c1f284a8 100644 --- a/project/jni/sdl-1.2/include/SDL_android.h +++ b/project/jni/sdl-1.2/include/SDL_android.h @@ -134,6 +134,9 @@ enum { /* Set SDL Android-specifc option, such as video depth or mouse emulation mode. Most options require restarting the app. */ extern DECLSPEC void SDLCALL SDL_ANDROID_SetConfigOption(int option, int value); +/* Show runtime permission dialog for accessing SD card on Android 6.0 and above */ +extern DECLSPEC void SDLCALL SDL_ANDROID_RequestExternalStorageRuntimePermission(); + #ifdef __cplusplus } #endif diff --git a/project/jni/sdl-1.2/src/video/android/SDL_androidvideo.c b/project/jni/sdl-1.2/src/video/android/SDL_androidvideo.c index d72741986..876c3a220 100644 --- a/project/jni/sdl-1.2/src/video/android/SDL_androidvideo.c +++ b/project/jni/sdl-1.2/src/video/android/SDL_androidvideo.c @@ -88,6 +88,7 @@ static jmethodID JavaRequestCloudLoad = NULL; static jmethodID JavaRequestOpenExternalApp = NULL; static jmethodID JavaRequestRestartMyself = NULL; static jmethodID JavaRequestSetConfigOption = NULL; +static jmethodID JavaRequestExternalStorageRuntimePermission = NULL; static int glContextLost = 0; static int showScreenKeyboardDeferred = 0; static const char * showScreenKeyboardOldText = ""; @@ -361,6 +362,7 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeInitJavaCallbacks) ( JNIEnv* env, jobject t JavaRequestOpenExternalApp = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "openExternalApp", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); JavaRequestRestartMyself = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "restartMyself", "(Ljava/lang/String;)V"); JavaRequestSetConfigOption = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "setConfigOptionFromSDL", "(II)V"); + JavaRequestExternalStorageRuntimePermission = (*JavaEnv)->GetMethodID(JavaEnv, JavaRendererClass, "requestExternalStorageRuntimePermissionFromSDL", "()V"); ANDROID_InitOSKeymap(); } @@ -607,6 +609,11 @@ void SDLCALL SDL_ANDROID_OpenExternalWebBrowser(const char *url) SDL_ANDROID_OpenExternalApp(NULL, NULL, url); } +void SDLCALL SDL_ANDROID_RequestExternalStorageRuntimePermission() +{ + (*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaRequestExternalStorageRuntimePermission ); +} + // Dummy callback for SDL2 to satisfy linker extern void SDL_Android_Init(JNIEnv* env, jclass cls); void SDL_Android_Init(JNIEnv* env, jclass cls)