From 3f24782aa8fd6597e4c64b0f427209d57d6f056d Mon Sep 17 00:00:00 2001 From: cwyc Date: Sun, 28 Jan 2024 18:00:14 -0500 Subject: [PATCH 1/5] Android: Improvements to DocumentProvider Added move and rename methods Provider notifies viewer to refresh view when files are changed Bumped up TargetApi annotation for DocumentsContract.buildTreeDocumentUri. Could alternatively use androidx compat class. --- .../provider/RetroDocumentsProvider.java | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) 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 c49a7432ffdf..4d2f927835f7 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java @@ -11,6 +11,7 @@ import android.os.Build; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; @@ -35,11 +36,13 @@ * offering two different ways of accessing your stored data. This would be confusing for users." * - http://developer.android.com/guide/topics/providers/document-provider.html#43 */ -@TargetApi(Build.VERSION_CODES.KITKAT) +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class RetroDocumentsProvider extends DocumentsProvider { private static final String ALL_MIME_TYPES = "*/*"; + private String DOCUMENTS_AUTHORITY; + // The default columns to return information about a root if no specific // columns are requested in a query. private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{ @@ -89,6 +92,36 @@ public Cursor queryDocument(String documentId, String[] projection) throws FileN return result; } + @Override + public String moveDocument(String sourceDocumentId, String sourceParentDocumentId, String targetParentDocumentId) throws FileNotFoundException { + File sourceFile = getFileForDocId(sourceDocumentId); + File targetParentFile = getFileForDocId(targetParentDocumentId); + File destination = new File(targetParentFile, sourceFile.getName()); + + boolean success = sourceFile.renameTo(destination); + if(!success){ + throw new FileNotFoundException("Failed to move file " + sourceDocumentId + " to " + targetParentDocumentId); + } + + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, sourceParentDocumentId), null); + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, targetParentDocumentId), null); + return getDocIdForFile(destination); + } + + @Override + public String renameDocument(String documentId, String displayName) throws FileNotFoundException{ + File document = getFileForDocId(documentId); + File destination = new File(document.getParentFile(), displayName); + + boolean success = document.renameTo(destination); + if(!success){ + throw new FileNotFoundException("Failed to rename file " + documentId + " to " + displayName); + } + + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(document.getParentFile())), null); + return getDocIdForFile(destination); + } + @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION); @@ -96,6 +129,7 @@ public Cursor queryChildDocuments(String parentDocumentId, String[] projection, for (File file : parent.listFiles()) { includeFile(result, null, file); } + result.setNotificationUri(getContext().getContentResolver(), DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId)); return result; } @@ -115,6 +149,7 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHi @Override public boolean onCreate() { + DOCUMENTS_AUTHORITY = getContext().getPackageName() + ".documents"; return true; } @@ -138,14 +173,25 @@ public String createDocument(String parentDocumentId, String mimeType, String di } catch (IOException e) { throw new FileNotFoundException("Failed to create document with id " + newFile.getPath()); } + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId), null); return newFile.getPath(); } @Override public void deleteDocument(String documentId) throws FileNotFoundException { File file = getFileForDocId(documentId); - if (!file.delete()) { - throw new FileNotFoundException("Failed to delete document with id " + documentId); + rm_r(file); + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(file.getParentFile())), null); + } + + void rm_r (File file) throws FileNotFoundException{ + if(file.isDirectory()){ + for(File child : file.listFiles()) { + rm_r(child); + } + } + if(!file.delete()){ + throw new FileNotFoundException("Could not delete file " + file.getPath()); } } @@ -248,11 +294,11 @@ private void includeFile(MatrixCursor result, String docId, File file) int flags = 0; if (file.isDirectory()) { - if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE; - } else if (file.canWrite()) { - flags |= Document.FLAG_SUPPORTS_WRITE; + if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE | Document.FLAG_SUPPORTS_RENAME; + } else { + if (file.canWrite()) flags |= Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME; } - if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE; + if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_MOVE; final String displayName = file.getName(); final String mimeType = getMimeType(file); From 25d5e2aeb68293eb51900b86d499286bb60bf971 Mon Sep 17 00:00:00 2001 From: cwyc Date: Fri, 26 Jan 2024 13:32:34 -0500 Subject: [PATCH 2/5] Android: Remove External Storage permission --- pkg/android/phoenix/AndroidManifest.xml | 3 - .../browser/mainmenu/MainMenuActivity.java | 116 +----------------- .../provider/RetroDocumentsProvider.java | 33 +++-- 3 files changed, 25 insertions(+), 127 deletions(-) diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml index 11347221cdda..f3beff81a814 100644 --- a/pkg/android/phoenix/AndroidManifest.xml +++ b/pkg/android/phoenix/AndroidManifest.xml @@ -9,8 +9,6 @@ - - @@ -24,7 +22,6 @@ 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 7a7117c9017a..bc555a74f999 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java @@ -26,92 +26,7 @@ */ 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() { @@ -132,33 +47,6 @@ public void finalStartup() 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) { @@ -170,8 +58,8 @@ public static void startRetroActivity(Intent retro, String contentPath, String c 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); } @@ -187,6 +75,6 @@ public void onCreate(Bundle savedInstanceState) UserPreferences.updateConfigFile(this); - checkRuntimePermissions(); + finalStartup(); } } 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 4d2f927835f7..52bd33a058e4 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java @@ -10,6 +10,7 @@ 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; @@ -69,19 +70,31 @@ 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 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); + 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); + return result; } From 6b2555df8761220ceed8116fb858c617b8754d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Tue, 21 Oct 2025 14:11:17 -0400 Subject: [PATCH 3/5] Increase `targetSdkVersion` for Google Play Android builds to 35 It says on https://developer.android.com/google/play/requirements/target-sdk at time of writing that starting August 31 2025, "New apps and app updates must target Android 15 (API level 35) or higher to be submitted to Google Play". --- pkg/android/phoenix/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/android/phoenix/build.gradle b/pkg/android/phoenix/build.gradle index 7586969b00d9..7eb73b990f5e 100644 --- a/pkg/android/phoenix/build.gradle +++ b/pkg/android/phoenix/build.gradle @@ -72,7 +72,7 @@ android { } playStoreNormal { minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 35 versionCode getPlayStoreVersionCode() versionName getPlayStoreVersionName() @@ -83,7 +83,7 @@ android { } playStorePlus { minSdkVersion 26 - targetSdkVersion 30 + targetSdkVersion 35 versionCode getPlayStoreVersionCode() versionName getPlayStoreVersionName() From 8875de186ab37743d91eb607d626ad517c21771c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Tue, 21 Oct 2025 15:13:43 -0400 Subject: [PATCH 4/5] Upgrade com.google.android.play:core to 1.10.3 The old version of com.google.android.play:core doesn't work with Android API level 34 or later due to an incompatible change made to the registerReceiver() function in the Android API. --- pkg/android/phoenix/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/android/phoenix/build.gradle b/pkg/android/phoenix/build.gradle index 7eb73b990f5e..b2b3e4db253d 100644 --- a/pkg/android/phoenix/build.gradle +++ b/pkg/android/phoenix/build.gradle @@ -153,7 +153,7 @@ android { } } -def playCore = 'com.google.android.play:core:1.8.0' +def playCore = 'com.google.android.play:core:1.10.3' dependencies { playStoreNormalImplementation playCore From dae3c74607ad233a1f6a0d3f14fc5d18351d798a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Tue, 21 Oct 2025 18:22:38 -0400 Subject: [PATCH 5/5] Change non-Play Store Android builds to use external storage again --- pkg/android/phoenix/AndroidManifest.xml | 3 + .../browser/mainmenu/MainMenuActivity.java | 128 +++++++++++++++++- .../provider/RetroDocumentsProvider.java | 56 +++++--- .../src/playStoreNormal/AndroidManifest.xml | 6 + .../src/playStorePlus/AndroidManifest.xml | 6 + 5 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 pkg/android/phoenix/src/playStoreNormal/AndroidManifest.xml create mode 100644 pkg/android/phoenix/src/playStorePlus/AndroidManifest.xml diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml index 9d7eafdb38c3..5995869bcd93 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 63abde2f7612..35eaac836a96 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java @@ -1,5 +1,6 @@ package com.retroarch.browser.mainmenu; +import com.retroarch.BuildConfig; import com.retroarch.browser.preferences.util.UserPreferences; import com.retroarch.browser.retroactivity.RetroActivityFuture; @@ -26,12 +27,97 @@ */ 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() { Intent retro = new Intent(this, RetroActivityFuture.class); - + if (RetroActivityFuture.isRunning) { // RetroActivity is already running - just bring it to front retro.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); @@ -39,7 +125,7 @@ public void finalStartup() // RetroActivity not running - full setup with parameters retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - + startRetroActivity( retro, null, @@ -49,11 +135,38 @@ public void finalStartup() getApplicationInfo().dataDir, getApplicationInfo().sourceDir); } - + startActivity(retro); 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) @@ -67,7 +180,7 @@ public static void startRetroActivity(Intent retro, String contentPath, String c retro.putExtra("DATADIR", dataDirPath); retro.putExtra("APK", dataSourcePath); String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + PACKAGE_NAME + "/files"; - retro.putExtra("SDCARD", external); + retro.putExtra("SDCARD", BuildConfig.PLAY_STORE_BUILD ? external : Environment.getExternalStorageDirectory().getAbsolutePath()); retro.putExtra("EXTERNAL", external); } @@ -83,6 +196,9 @@ public void onCreate(Bundle savedInstanceState) UserPreferences.updateConfigFile(this); - finalStartup(); + if (BuildConfig.PLAY_STORE_BUILD) + finalStartup(); + else + 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 52bd33a058e4..259a2e5ccf0a 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java @@ -18,6 +18,7 @@ import android.provider.DocumentsProvider; import android.webkit.MimeTypeMap; +import com.retroarch.BuildConfig; import com.retroarch.R; import java.io.File; @@ -73,27 +74,40 @@ public Cursor queryRoots(String[] projection) throws FileNotFoundException { 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); + if (BuildConfig.PLAY_STORE_BUILD) { + 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); + } else { + final File BASE_DIR = new File(getContext().getFilesDir().getParent()); + 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; } diff --git a/pkg/android/phoenix/src/playStoreNormal/AndroidManifest.xml b/pkg/android/phoenix/src/playStoreNormal/AndroidManifest.xml new file mode 100644 index 000000000000..d12c18d770c5 --- /dev/null +++ b/pkg/android/phoenix/src/playStoreNormal/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/pkg/android/phoenix/src/playStorePlus/AndroidManifest.xml b/pkg/android/phoenix/src/playStorePlus/AndroidManifest.xml new file mode 100644 index 000000000000..d12c18d770c5 --- /dev/null +++ b/pkg/android/phoenix/src/playStorePlus/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + +