mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
Fixed the issue where files would not open on Huawei phones when directly accessed from the file manager.
* Improved the method for resolving content type URIs to properly return the file path of the selected URI. * Refined the code and methods for improved clarity in their operations.
This commit is contained in:
parent
777c0fff4b
commit
b4bb0f98c8
@ -25,6 +25,7 @@ import android.database.Cursor
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.os.Environment.DIRECTORY_DOWNLOADS
|
||||||
import android.os.storage.StorageManager
|
import android.os.storage.StorageManager
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
@ -157,29 +158,39 @@ object FileUtils {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the file path from a given content URI. This method first attempts to get the path
|
||||||
|
* using the content resolver (via `contentQuery`). If that returns null or empty, it falls back
|
||||||
|
* to a secondary method to resolve the actual path.
|
||||||
|
*
|
||||||
|
* This fallback is especially necessary when:
|
||||||
|
* 1. The user clicks directly on a downloaded file from browsers, where different browsers
|
||||||
|
* return URIs using their own file providers.
|
||||||
|
* 2. On devices below Android 11, when files are clicked directly in the file manager, the content
|
||||||
|
* resolver may not be able to retrieve the path for certain URIs.
|
||||||
|
*/
|
||||||
private fun getFilePathOfContentUri(context: Context, uri: Uri): String? {
|
private fun getFilePathOfContentUri(context: Context, uri: Uri): String? {
|
||||||
val filePath = contentQuery(context, uri)
|
val filePath = contentQuery(context, uri)
|
||||||
return if (!filePath.isNullOrEmpty()) {
|
return if (!filePath.isNullOrEmpty()) {
|
||||||
filePath
|
filePath
|
||||||
} else {
|
} else {
|
||||||
// Fallback method to get the actual path of the URI. This will be called
|
// Fallback method to get the actual path of the URI
|
||||||
// when contentQuery returns null, especially in cases where the user directly clicks
|
getActualFilePathOfContentUri(context, uri)
|
||||||
// on the downloaded file within browsers (since different browsers provide URIs with their
|
|
||||||
// own file providers, the content resolver cannot directly retrieve paths for those URIs).
|
|
||||||
val fileName = getFileNameFromUri(context, uri)
|
|
||||||
getFilePathFromFileName(context, fileName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFilePathFromFileName(context: Context, fileName: String?): String? {
|
private fun getFullFilePathFromFilePath(
|
||||||
var filePath: String? = null
|
context: Context,
|
||||||
|
filePath: String?
|
||||||
|
): String? {
|
||||||
|
var actualFilePath: String? = null
|
||||||
getStorageVolumesList(context).forEach { volume ->
|
getStorageVolumesList(context).forEach { volume ->
|
||||||
val file = File("$volume/Download/$fileName")
|
val file = File("$volume/$filePath")
|
||||||
if (file.isFileExist()) {
|
if (file.isFileExist()) {
|
||||||
filePath = file.path
|
actualFilePath = file.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filePath
|
return actualFilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStorageVolumesList(context: Context): HashSet<String> {
|
private fun getStorageVolumesList(context: Context): HashSet<String> {
|
||||||
@ -194,14 +205,13 @@ object FileUtils {
|
|||||||
} ?: kotlin.run {
|
} ?: kotlin.run {
|
||||||
"/${it.getDescription(context)}/"
|
"/${it.getDescription(context)}/"
|
||||||
}
|
}
|
||||||
storageVolumesList.add(externalStorageName)
|
storageVolumesList.add("/storage$externalStorageName")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return storageVolumesList
|
return storageVolumesList
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFileNameFromUri(context: Context, uri: Uri?): String? {
|
private fun getFileNameFromUri(context: Context, uri: Uri): String? {
|
||||||
if (uri == null) return null
|
|
||||||
var cursor: Cursor? = null
|
var cursor: Cursor? = null
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
MediaStore.MediaColumns.DISPLAY_NAME
|
MediaStore.MediaColumns.DISPLAY_NAME
|
||||||
@ -224,6 +234,61 @@ object FileUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the actual file path from a given content URI. This method handles various cases based on
|
||||||
|
* the type of URI and the source (file managers, browser downloads, etc.).
|
||||||
|
*
|
||||||
|
* 1. For file managers that include the full file path in the URI (common in devices below Android 11),
|
||||||
|
* it triggers when the user clicks directly on the ZIM file in the file manager. The file manager may
|
||||||
|
* return the path with their own file provider, and we extract the path.
|
||||||
|
*
|
||||||
|
* 2. For URIs from the download provider (e.g., when opening files directly from browsers), this method
|
||||||
|
* constructs the full path using the `DIRECTORY_DOWNLOADS` directory and the file name.
|
||||||
|
*
|
||||||
|
* 3. For other URIs, it attempts to resolve the full file path from the provided URI using a custom
|
||||||
|
* method to retrieve the folder and file path.
|
||||||
|
*/
|
||||||
|
private fun getActualFilePathOfContentUri(context: Context, uri: Uri): String? {
|
||||||
|
return when {
|
||||||
|
// For file managers that provide the full path in the URI (common on devices below Android 11).
|
||||||
|
// This triggers when the user clicks directly on a ZIM file in the file manager, and the file
|
||||||
|
// manager returns the path via its own file provider.
|
||||||
|
"$uri".contains("root") && "$uri".endsWith("zim") -> {
|
||||||
|
"$uri".substringAfter("/root")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles URIs from the download provider, commonly used when files are opened from browsers.
|
||||||
|
// Some browsers return URIs with their DownloadProvider.
|
||||||
|
isDownloadProviderUri(uri) -> {
|
||||||
|
getFullFilePathFromFilePath(
|
||||||
|
context,
|
||||||
|
"$DIRECTORY_DOWNLOADS/${getFileNameFromUri(context, uri)}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
// Attempts to retrieve the full path from the URI using a custom method.
|
||||||
|
getFullFilePathFromFilePath(
|
||||||
|
context,
|
||||||
|
getFilePathWithFolderFromUri(uri)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFilePathWithFolderFromUri(uri: Uri): String? {
|
||||||
|
val pathSegments = uri.pathSegments
|
||||||
|
if (pathSegments.isNotEmpty()) {
|
||||||
|
// Returns the path of the folder containing the file with the specified fileName,
|
||||||
|
// from which the user selects the file.
|
||||||
|
return pathSegments.drop(1).joinToString(separator = "/")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDownloadProviderUri(uri: Uri): Boolean =
|
||||||
|
"$uri".contains("DownloadProvider") || "$uri".contains("/downloads")
|
||||||
|
|
||||||
fun documentProviderContentQuery(
|
fun documentProviderContentQuery(
|
||||||
context: Context,
|
context: Context,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
@ -259,7 +324,7 @@ object FileUtils {
|
|||||||
// the file from the file manager in the downloads folder, and the URI contains a different
|
// the file from the file manager in the downloads folder, and the URI contains a different
|
||||||
// document ID (particularly on tablets). See https://github.com/kiwix/kiwix-android/issues/4008
|
// document ID (particularly on tablets). See https://github.com/kiwix/kiwix-android/issues/4008
|
||||||
val fileName = getFileNameFromUri(context, uri)
|
val fileName = getFileNameFromUri(context, uri)
|
||||||
getFilePathFromFileName(context, fileName)
|
getFullFilePathFromFilePath(context, "$DIRECTORY_DOWNLOADS/$fileName")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user