Skip to content

Commit d43a641

Browse files
authored
Use app-specific storage for Google Play versions of the Android app (#18321)
1 parent cd23c32 commit d43a641

5 files changed

Lines changed: 115 additions & 26 deletions

File tree

pkg/android/phoenix/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ android {
7272
}
7373
playStoreNormal {
7474
minSdkVersion 21
75-
targetSdkVersion 30
75+
targetSdkVersion 35
7676
versionCode getPlayStoreVersionCode()
7777
versionName getPlayStoreVersionName()
7878

@@ -83,7 +83,7 @@ android {
8383
}
8484
playStorePlus {
8585
minSdkVersion 26
86-
targetSdkVersion 30
86+
targetSdkVersion 35
8787
versionCode getPlayStoreVersionCode()
8888
versionName getPlayStoreVersionName()
8989

@@ -153,7 +153,7 @@ android {
153153
}
154154
}
155155

156-
def playCore = 'com.google.android.play:core:1.8.0'
156+
def playCore = 'com.google.android.play:core:1.10.3'
157157

158158
dependencies {
159159
playStoreNormalImplementation playCore

pkg/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuActivity.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.retroarch.browser.mainmenu;
22

3+
import com.retroarch.BuildConfig;
34
import com.retroarch.browser.preferences.util.UserPreferences;
45
import com.retroarch.browser.retroactivity.RetroActivityFuture;
56

@@ -116,15 +117,15 @@ public void onClick(DialogInterface dialog, int which)
116117
public void finalStartup()
117118
{
118119
Intent retro = new Intent(this, RetroActivityFuture.class);
119-
120+
120121
if (RetroActivityFuture.isRunning) {
121122
// RetroActivity is already running - just bring it to front
122123
retro.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
123124
} else {
124125
// RetroActivity not running - full setup with parameters
125126
retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
126127
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
127-
128+
128129
startRetroActivity(
129130
retro,
130131
null,
@@ -134,11 +135,11 @@ public void finalStartup()
134135
getApplicationInfo().dataDir,
135136
getApplicationInfo().sourceDir);
136137
}
137-
138+
138139
startActivity(retro);
139140
finish();
140141
}
141-
142+
142143

143144
@Override
144145
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
@@ -178,8 +179,8 @@ public static void startRetroActivity(Intent retro, String contentPath, String c
178179
retro.putExtra("IME", imePath);
179180
retro.putExtra("DATADIR", dataDirPath);
180181
retro.putExtra("APK", dataSourcePath);
181-
retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath());
182182
String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + PACKAGE_NAME + "/files";
183+
retro.putExtra("SDCARD", BuildConfig.PLAY_STORE_BUILD ? external : Environment.getExternalStorageDirectory().getAbsolutePath());
183184
retro.putExtra("EXTERNAL", external);
184185
}
185186

@@ -195,6 +196,9 @@ public void onCreate(Bundle savedInstanceState)
195196

196197
UserPreferences.updateConfigFile(this);
197198

198-
checkRuntimePermissions();
199+
if (BuildConfig.PLAY_STORE_BUILD)
200+
finalStartup();
201+
else
202+
checkRuntimePermissions();
199203
}
200204
}

pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java

Lines changed: 90 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
import android.graphics.Point;
1111
import android.os.Build;
1212
import android.os.CancellationSignal;
13+
import android.os.Environment;
1314
import android.os.ParcelFileDescriptor;
15+
import android.provider.DocumentsContract;
1416
import android.provider.DocumentsContract.Document;
1517
import android.provider.DocumentsContract.Root;
1618
import android.provider.DocumentsProvider;
1719
import android.webkit.MimeTypeMap;
1820

21+
import com.retroarch.BuildConfig;
1922
import com.retroarch.R;
2023

2124
import java.io.File;
@@ -35,11 +38,13 @@
3538
* offering two different ways of accessing your stored data. This would be confusing for users."
3639
* - http://developer.android.com/guide/topics/providers/document-provider.html#43
3740
*/
38-
@TargetApi(Build.VERSION_CODES.KITKAT)
41+
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
3942
public class RetroDocumentsProvider extends DocumentsProvider {
4043

4144
private static final String ALL_MIME_TYPES = "*/*";
4245

46+
private String DOCUMENTS_AUTHORITY;
47+
4348
// The default columns to return information about a root if no specific
4449
// columns are requested in a query.
4550
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
@@ -66,19 +71,44 @@ public class RetroDocumentsProvider extends DocumentsProvider {
6671

6772
@Override
6873
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
69-
final File BASE_DIR = new File(getContext().getFilesDir().getParent());
7074
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
7175
@SuppressWarnings("ConstantConditions") final String applicationName = getContext().getString(R.string.app_name);
7276

73-
final MatrixCursor.RowBuilder row = result.newRow();
74-
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
75-
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
76-
row.add(Root.COLUMN_SUMMARY, null);
77-
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
78-
row.add(Root.COLUMN_TITLE, applicationName);
79-
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
80-
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
81-
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
77+
if (BuildConfig.PLAY_STORE_BUILD) {
78+
final File CORE_DIR = new File(getContext().getFilesDir().getParent());
79+
final MatrixCursor.RowBuilder core = result.newRow();
80+
core.add(Root.COLUMN_ROOT_ID, getDocIdForFile(CORE_DIR));
81+
core.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(CORE_DIR));
82+
core.add(Root.COLUMN_SUMMARY, "Core Data");
83+
core.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
84+
core.add(Root.COLUMN_TITLE, applicationName);
85+
core.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
86+
core.add(Root.COLUMN_AVAILABLE_BYTES, CORE_DIR.getFreeSpace());
87+
core.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
88+
89+
final File USER_DIR = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + getContext().getPackageName() + "/files/RetroArch");
90+
final MatrixCursor.RowBuilder user = result.newRow();
91+
user.add(Root.COLUMN_ROOT_ID, getDocIdForFile(USER_DIR));
92+
user.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(USER_DIR));
93+
user.add(Root.COLUMN_SUMMARY, "User Data");
94+
user.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
95+
user.add(Root.COLUMN_TITLE, applicationName);
96+
user.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
97+
user.add(Root.COLUMN_AVAILABLE_BYTES, USER_DIR.getFreeSpace());
98+
user.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
99+
} else {
100+
final File BASE_DIR = new File(getContext().getFilesDir().getParent());
101+
final MatrixCursor.RowBuilder row = result.newRow();
102+
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
103+
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
104+
row.add(Root.COLUMN_SUMMARY, null);
105+
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
106+
row.add(Root.COLUMN_TITLE, applicationName);
107+
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
108+
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
109+
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
110+
}
111+
82112
return result;
83113
}
84114

@@ -89,13 +119,44 @@ public Cursor queryDocument(String documentId, String[] projection) throws FileN
89119
return result;
90120
}
91121

122+
@Override
123+
public String moveDocument(String sourceDocumentId, String sourceParentDocumentId, String targetParentDocumentId) throws FileNotFoundException {
124+
File sourceFile = getFileForDocId(sourceDocumentId);
125+
File targetParentFile = getFileForDocId(targetParentDocumentId);
126+
File destination = new File(targetParentFile, sourceFile.getName());
127+
128+
boolean success = sourceFile.renameTo(destination);
129+
if(!success){
130+
throw new FileNotFoundException("Failed to move file " + sourceDocumentId + " to " + targetParentDocumentId);
131+
}
132+
133+
getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, sourceParentDocumentId), null);
134+
getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, targetParentDocumentId), null);
135+
return getDocIdForFile(destination);
136+
}
137+
138+
@Override
139+
public String renameDocument(String documentId, String displayName) throws FileNotFoundException{
140+
File document = getFileForDocId(documentId);
141+
File destination = new File(document.getParentFile(), displayName);
142+
143+
boolean success = document.renameTo(destination);
144+
if(!success){
145+
throw new FileNotFoundException("Failed to rename file " + documentId + " to " + displayName);
146+
}
147+
148+
getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(document.getParentFile())), null);
149+
return getDocIdForFile(destination);
150+
}
151+
92152
@Override
93153
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
94154
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
95155
final File parent = getFileForDocId(parentDocumentId);
96156
for (File file : parent.listFiles()) {
97157
includeFile(result, null, file);
98158
}
159+
result.setNotificationUri(getContext().getContentResolver(), DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId));
99160
return result;
100161
}
101162

@@ -115,6 +176,7 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHi
115176

116177
@Override
117178
public boolean onCreate() {
179+
DOCUMENTS_AUTHORITY = getContext().getPackageName() + ".documents";
118180
return true;
119181
}
120182

@@ -138,14 +200,25 @@ public String createDocument(String parentDocumentId, String mimeType, String di
138200
} catch (IOException e) {
139201
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
140202
}
203+
getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId), null);
141204
return newFile.getPath();
142205
}
143206

144207
@Override
145208
public void deleteDocument(String documentId) throws FileNotFoundException {
146209
File file = getFileForDocId(documentId);
147-
if (!file.delete()) {
148-
throw new FileNotFoundException("Failed to delete document with id " + documentId);
210+
rm_r(file);
211+
getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(file.getParentFile())), null);
212+
}
213+
214+
void rm_r (File file) throws FileNotFoundException{
215+
if(file.isDirectory()){
216+
for(File child : file.listFiles()) {
217+
rm_r(child);
218+
}
219+
}
220+
if(!file.delete()){
221+
throw new FileNotFoundException("Could not delete file " + file.getPath());
149222
}
150223
}
151224

@@ -248,11 +321,11 @@ private void includeFile(MatrixCursor result, String docId, File file)
248321

249322
int flags = 0;
250323
if (file.isDirectory()) {
251-
if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
252-
} else if (file.canWrite()) {
253-
flags |= Document.FLAG_SUPPORTS_WRITE;
324+
if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE | Document.FLAG_SUPPORTS_RENAME;
325+
} else {
326+
if (file.canWrite()) flags |= Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME;
254327
}
255-
if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE;
328+
if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_MOVE;
256329

257330
final String displayName = file.getName();
258331
final String mimeType = getMimeType(file);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:tools="http://schemas.android.com/tools">
3+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
4+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
5+
<application tools:remove="requestLegacyExternalStorage"/>
6+
</manifest>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:tools="http://schemas.android.com/tools">
3+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
4+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
5+
<application tools:remove="requestLegacyExternalStorage"/>
6+
</manifest>

0 commit comments

Comments
 (0)