Merge pull request #11742 from K0bin/document-provider-2

Android: Document Provider improvements
This commit is contained in:
Mai 2023-04-16 04:21:33 -04:00 committed by GitHub
commit 1a2dcc53f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 61 deletions

View File

@ -40,7 +40,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId "org.dolphinemu.dolphinemu" applicationId "org.dolphinemu.dolphinemu"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
@ -74,6 +73,7 @@ android {
signingConfig signingConfigs.release signingConfig signingConfigs.release
} }
resValue 'string', 'app_name_suffixed', 'Dolphin Emulator'
minifyEnabled true minifyEnabled true
shrinkResources true shrinkResources true
proguardFiles getDefaultProguardFile( proguardFiles getDefaultProguardFile(
@ -86,13 +86,14 @@ android {
// Signed by debug key disallowing distribution on Play Store. // Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug { debug {
// TODO If this is ever modified, change application_id in debug/strings.xml resValue 'string', 'app_name_suffixed', 'Dolphin Debug'
applicationIdSuffix ".debug" applicationIdSuffix ".debug"
versionNameSuffix '-debug' versionNameSuffix '-debug'
jniDebuggable true jniDebuggable true
} }
benchmark { benchmark {
resValue 'string', 'app_name_suffixed', 'Dolphin Benchmark'
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
matchingFallbacks = ['release'] matchingFallbacks = ['release']
debuggable false debuggable false

View File

@ -31,7 +31,7 @@
<application <application
android:name=".DolphinApplication" android:name=".DolphinApplication"
android:label="@string/app_name" android:label="@string/app_name_suffixed"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true" android:preserveLegacyExternalStorage="true"
@ -97,7 +97,7 @@
<activity <activity
android:name=".activities.CustomFilePickerActivity" android:name=".activities.CustomFilePickerActivity"
android:exported="false" android:exported="false"
android:label="@string/app_name" android:label="@string/app_name_suffixed"
android:theme="@style/Theme.Dolphin.FilePicker"> android:theme="@style/Theme.Dolphin.FilePicker">
<intent-filter> <intent-filter>

View File

@ -54,12 +54,11 @@ class DocumentProvider : DocumentsProvider() {
override fun queryRoots(projection: Array<String>?): Cursor { override fun queryRoots(projection: Array<String>?): Cursor {
val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION) val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION)
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
rootDirectory ?: return result rootDirectory ?: return result
result.newRow().apply { result.newRow().apply {
add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID) add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID)
add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name)) add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name_suffixed))
add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin) add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin)
add( add(
DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.COLUMN_FLAGS,
@ -73,7 +72,6 @@ class DocumentProvider : DocumentsProvider() {
override fun queryDocument(documentId: String, projection: Array<String>?): Cursor { override fun queryDocument(documentId: String, projection: Array<String>?): Cursor {
val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION) val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
rootDirectory ?: return result rootDirectory ?: return result
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
appendDocument(file, result) appendDocument(file, result)
@ -102,7 +100,9 @@ class DocumentProvider : DocumentsProvider() {
documentId: String, documentId: String,
mode: String, mode: String,
signal: CancellationSignal? signal: CancellationSignal?
): ParcelFileDescriptor { ): ParcelFileDescriptor? {
rootDirectory ?: return null
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode)) return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
} }
@ -111,7 +111,9 @@ class DocumentProvider : DocumentsProvider() {
parentDocumentId: String, parentDocumentId: String,
mimeType: String, mimeType: String,
displayName: String displayName: String
): String { ): String? {
rootDirectory ?: return null
val folder = documentIdToPath(parentDocumentId) val folder = documentIdToPath(parentDocumentId)
val file = findFileNameForNewFile(File(folder, displayName)) val file = findFileNameForNewFile(File(folder, displayName))
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) { if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
@ -122,56 +124,40 @@ class DocumentProvider : DocumentsProvider() {
return pathToDocumentId(file) return pathToDocumentId(file)
} }
override fun copyDocument(sourceDocumentId: String, targetParentDocumentId: String): String { override fun deleteDocument(documentId: String) {
val file = documentIdToPath(sourceDocumentId) rootDirectory ?: return
val target = documentIdToPath(targetParentDocumentId)
val copy = copyRecursively(file, File(target, file.name))
return pathToDocumentId(copy)
}
override fun removeDocument(documentId: String, parentDocumentId: String) {
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
file.deleteRecursively() file.deleteRecursively()
} }
override fun moveDocument( override fun renameDocument(documentId: String, displayName: String): String? {
sourceDocumentId: String, rootDirectory ?: return null
sourceParentDocumentId: String,
targetParentDocumentId: String val file = documentIdToPath(documentId)
): String { val dest = findFileNameForNewFile(File(file.parentFile, displayName))
val copy = copyDocument(sourceDocumentId, targetParentDocumentId) file.renameTo(dest)
val file = documentIdToPath(sourceDocumentId) return pathToDocumentId(dest)
file.delete()
return copy
} }
override fun renameDocument(documentId: String, displayName: String): String { override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean
val file = documentIdToPath(documentId) = documentId.startsWith(parentDocumentId)
file.renameTo(findFileNameForNewFile(File(file.parentFile, displayName)))
return pathToDocumentId(file)
}
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean {
val file = documentIdToPath(documentId)
val folder = documentIdToPath(parentDocumentId)
return file.relativeToOrNull(folder) != null
}
private fun appendDocument(file: File, cursor: MatrixCursor) { private fun appendDocument(file: File, cursor: MatrixCursor) {
var flags = 0 var flags = 0
if (file.isDirectory && file.canWrite()) { if (file.canWrite()) {
flags = DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE flags = if (file.isDirectory) {
} else if (file.canWrite()) { DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE
flags = DocumentsContract.Document.FLAG_SUPPORTS_WRITE } else {
DocumentsContract.Document.FLAG_SUPPORTS_WRITE
}
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_REMOVE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_MOVE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_COPY
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME
// The system will handle copy + move for us
} }
val name = if (file == rootDirectory) { val name = if (file == rootDirectory) {
context!!.getString(R.string.app_name) context!!.getString(R.string.app_name_suffixed)
} else { } else {
file.name file.name
} }
@ -217,22 +203,6 @@ class DocumentProvider : DocumentsProvider() {
unusedFile = File("$pathWithoutExtension.$i.$extension") unusedFile = File("$pathWithoutExtension.$i.$extension")
i++ i++
} }
return file return unusedFile
}
private fun copyRecursively(src: File, dst: File): File {
val actualDst = findFileNameForNewFile(dst)
if (src.isDirectory) {
actualDst.mkdirs()
val children = src.listFiles()
if (children !== null) {
for (file in children) {
copyRecursively(file, File(actualDst, file.name))
}
}
} else {
src.copyTo(actualDst)
}
return actualDst
} }
} }

View File

@ -77,6 +77,7 @@ public final class MainActivity extends AppCompatActivity
setInsets(); setInsets();
ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain); ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain);
mBinding.toolbarMain.setTitle(R.string.app_name);
setSupportActionBar(mBinding.toolbarMain); setSupportActionBar(mBinding.toolbarMain);
// Set up the FAB. // Set up the FAB.