Request and handle external storage permissions on Marshmallow

- Also disentangles exposing APK assets internally and on external storage
This commit is contained in:
Aaron Culliney 2015-12-12 13:33:35 -08:00
parent ac78e00afa
commit 6cef33b501
2 changed files with 84 additions and 10 deletions

View File

@ -11,10 +11,12 @@
package org.deadc0de.apple2ix;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
@ -92,6 +94,8 @@ public class Apple2Activity extends Activity {
public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L;
public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL;
public final static int REQUEST_PERMISSION_RWSTORE = 42;
private native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
private native void nativeOnKeyDown(int keyCode, int metaState);
@ -166,6 +170,27 @@ public class Apple2Activity extends Activity {
showSplashScreen(!firstTime);
Apple2CrashHandler.getInstance().checkForCrashes(this);
boolean extperm = true;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// On Marshmallow+ specifically ask for permission to read/write storage
String readPermission = Manifest.permission.READ_EXTERNAL_STORAGE;
String writePermission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
int hasReadPermission = checkSelfPermission(readPermission);
int hasWritePermission = checkSelfPermission(writePermission);
ArrayList<String> permissions = new ArrayList<String>();
if (hasReadPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(readPermission);
}
if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(writePermission);
}
if (!permissions.isEmpty()) {
extperm = false;
String[] params = permissions.toArray(new String[permissions.size()]);
requestPermissions(params, REQUEST_PERMISSION_RWSTORE);
}
}
mGraphicsInitializedRunnable = new Runnable() {
@Override
public void run() {
@ -177,11 +202,15 @@ public class Apple2Activity extends Activity {
};
// first-time initializations
final boolean externalStoragePermission = extperm;
if (firstTime) {
new Thread(new Runnable() {
@Override
public void run() {
Apple2DisksMenu.firstTime(Apple2Activity.this);
Apple2DisksMenu.exposeAPKAssets(Apple2Activity.this);
if (externalStoragePermission) {
Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this);
}
mSplashScreen.setDismissable(true);
Log.d(TAG, "Finished first time copying...");
}
@ -204,6 +233,26 @@ public class Apple2Activity extends Activity {
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// We should already be gracefully handling the case where user denies access.
if (requestCode == REQUEST_PERMISSION_RWSTORE) {
boolean grantedPermissions = true;
for (int grant : grantResults) {
if (grant == PackageManager.PERMISSION_DENIED) {
grantedPermissions = false;
break;
}
}
if (grantedPermissions) {
// this will force copying APK files (now that we have permission
Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this);
} // else ... we keep nagging on app startup ...
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@Override
protected void onResume() {
super.onResume();

View File

@ -135,7 +135,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
return sDataDir;
}
public static void firstTime(Apple2Activity activity) {
public static void exposeAPKAssetsToExternal(Apple2Activity activity) {
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
activity.runOnUiThread(new Runnable() {
@Override
@ -144,7 +144,38 @@ public class Apple2DisksMenu implements Apple2MenuView {
bar.setVisibility(View.VISIBLE);
bar.setIndeterminate(true);
} catch (NullPointerException npe) {
Log.v(TAG, "Whoa, avoided NPE in first time #1");
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #1");
}
}
});
getExternalStorageDirectory(activity);
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath());
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
bar.setVisibility(View.INVISIBLE);
bar.setIndeterminate(false);
} catch (NullPointerException npe) {
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2");
}
}
});
}
public static void exposeAPKAssets(Apple2Activity activity) {
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
bar.setVisibility(View.VISIBLE);
bar.setIndeterminate(true);
} catch (NullPointerException npe) {
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
}
}
});
@ -154,16 +185,10 @@ public class Apple2DisksMenu implements Apple2MenuView {
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
getExternalStorageDirectory(activity);
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath());
// expose keyboards to modding
if (sExternalFilesDir != null) {
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath());
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
@ -171,7 +196,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
bar.setVisibility(View.INVISIBLE);
bar.setIndeterminate(false);
} catch (NullPointerException npe) {
Log.v(TAG, "Whoa, avoided NPE in first time #2");
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
}
}
});