diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml
index dafdc7e2e6..16c235a30b 100644
--- a/pkg/android/phoenix/AndroidManifest.xml
+++ b/pkg/android/phoenix/AndroidManifest.xml
@@ -10,6 +10,8 @@
+
+
@@ -23,6 +25,7 @@
android:isGame="true"
android:banner="@drawable/banner"
android:extractNativeLibs="true"
+ android:requestLegacyExternalStorage="true"
tools:ignore="UnusedAttribute">
diff --git a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java
index bc555a74f9..7a7117c901 100644
--- a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java
+++ b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java
@@ -26,7 +26,92 @@ import android.util.Log;
*/
public final class MainMenuActivity extends PreferenceActivity
{
+ final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
public static String PACKAGE_NAME;
+ boolean checkPermissions = false;
+
+ public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener)
+ {
+ new AlertDialog.Builder(this).setMessage(message)
+ .setPositiveButton("OK", onClickListener).setCancelable(false)
+ .setNegativeButton("Cancel", null).create().show();
+ }
+
+ private boolean addPermission(List permissionsList, String permission)
+ {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
+ {
+ if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
+ {
+ permissionsList.add(permission);
+
+ // Check for Rationale Option
+ if (!shouldShowRequestPermissionRationale(permission))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void checkRuntimePermissions()
+ {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
+ {
+ // Android 6.0+ needs runtime permission checks
+ List permissionsNeeded = new ArrayList();
+ final List permissionsList = new ArrayList();
+
+ if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE))
+ permissionsNeeded.add("Read External Storage");
+ if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE))
+ permissionsNeeded.add("Write External Storage");
+
+ if (permissionsList.size() > 0)
+ {
+ checkPermissions = true;
+
+ if (permissionsNeeded.size() > 0)
+ {
+ // Need Rationale
+ Log.i("MainMenuActivity", "Need to request external storage permissions.");
+
+ String message = "You need to grant access to " + permissionsNeeded.get(0);
+
+ for (int i = 1; i < permissionsNeeded.size(); i++)
+ message = message + ", " + permissionsNeeded.get(i);
+
+ showMessageOKCancel(message,
+ new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ if (which == AlertDialog.BUTTON_POSITIVE)
+ {
+ requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
+ REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
+
+ Log.i("MainMenuActivity", "User accepted request for external storage permissions.");
+ }
+ }
+ });
+ }
+ else
+ {
+ requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
+ REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
+
+ Log.i("MainMenuActivity", "Requested external storage permissions.");
+ }
+ }
+ }
+
+ if (!checkPermissions)
+ {
+ finalStartup();
+ }
+ }
public void finalStartup()
{
@@ -47,6 +132,33 @@ public final class MainMenuActivity extends PreferenceActivity
finish();
}
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+ {
+ switch (requestCode)
+ {
+ case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
+ for (int i = 0; i < permissions.length; i++)
+ {
+ if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
+ {
+ Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted.");
+ }
+ else
+ {
+ Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted.");
+ }
+ }
+
+ break;
+ default:
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ break;
+ }
+
+ finalStartup();
+ }
+
public static void startRetroActivity(Intent retro, String contentPath, String corePath,
String configFilePath, String imePath, String dataDirPath, String dataSourcePath)
{
@@ -58,8 +170,8 @@ public final class MainMenuActivity extends PreferenceActivity
retro.putExtra("IME", imePath);
retro.putExtra("DATADIR", dataDirPath);
retro.putExtra("APK", dataSourcePath);
+ retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath());
String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + PACKAGE_NAME + "/files";
- retro.putExtra("SDCARD", external);
retro.putExtra("EXTERNAL", external);
}
@@ -75,6 +187,6 @@ public final class MainMenuActivity extends PreferenceActivity
UserPreferences.updateConfigFile(this);
- finalStartup();
+ checkRuntimePermissions();
}
}
diff --git a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java
index 52bd33a058..4d2f927835 100644
--- a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java
+++ b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java
@@ -10,7 +10,6 @@ import android.database.MatrixCursor;
import android.graphics.Point;
import android.os.Build;
import android.os.CancellationSignal;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -70,31 +69,19 @@ public class RetroDocumentsProvider extends DocumentsProvider {
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+ final File BASE_DIR = new File(getContext().getFilesDir().getParent());
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
@SuppressWarnings("ConstantConditions") final String applicationName = getContext().getString(R.string.app_name);
- final File CORE_DIR = new File(getContext().getFilesDir().getParent());
- final MatrixCursor.RowBuilder core = result.newRow();
- core.add(Root.COLUMN_ROOT_ID, getDocIdForFile(CORE_DIR));
- core.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(CORE_DIR));
- core.add(Root.COLUMN_SUMMARY, "Core Data");
- core.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
- core.add(Root.COLUMN_TITLE, applicationName);
- core.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
- core.add(Root.COLUMN_AVAILABLE_BYTES, CORE_DIR.getFreeSpace());
- core.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
-
- final File USER_DIR = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + getContext().getPackageName() + "/files/RetroArch");
- final MatrixCursor.RowBuilder user = result.newRow();
- user.add(Root.COLUMN_ROOT_ID, getDocIdForFile(USER_DIR));
- user.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(USER_DIR));
- user.add(Root.COLUMN_SUMMARY, "User Data");
- user.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
- user.add(Root.COLUMN_TITLE, applicationName);
- user.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
- user.add(Root.COLUMN_AVAILABLE_BYTES, USER_DIR.getFreeSpace());
- user.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
-
+ final MatrixCursor.RowBuilder row = result.newRow();
+ row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
+ row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
+ row.add(Root.COLUMN_SUMMARY, null);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
+ row.add(Root.COLUMN_TITLE, applicationName);
+ row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
+ row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
return result;
}