addressed some deprecation warnings
This commit is contained in:
parent
e50dd952a8
commit
69d700674c
3 changed files with 51 additions and 44 deletions
|
@ -170,7 +170,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
return future
|
||||
}
|
||||
|
||||
if (requireAccessPermission(path)) {
|
||||
if (requireAccessPermission(context, path)) {
|
||||
// if the file is on SD card, calling the content resolver `delete()` removes the entry from the Media Store
|
||||
// but it doesn't delete the file, even if the app has the permission
|
||||
try {
|
||||
|
|
|
@ -127,7 +127,7 @@ object PermissionManager {
|
|||
val accessibleDirs = HashSet(getGrantedDirs(context))
|
||||
// from Android R, we no longer have access permission by default on primary volume
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||
accessibleDirs.add(StorageUtils.primaryVolumePath)
|
||||
accessibleDirs.add(StorageUtils.getPrimaryVolumePath(context))
|
||||
}
|
||||
Log.d(LOG_TAG, "getAccessibleDirs accessibleDirs=$accessibleDirs")
|
||||
return accessibleDirs
|
||||
|
|
|
@ -6,7 +6,6 @@ import android.content.Context
|
|||
import android.media.MediaMetadataRetriever
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.storage.StorageManager
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
|
@ -36,13 +35,13 @@ object StorageUtils {
|
|||
// primary volume path, with trailing "/"
|
||||
private var mPrimaryVolumePath: String? = null
|
||||
|
||||
val primaryVolumePath: String
|
||||
get() {
|
||||
if (mPrimaryVolumePath == null) {
|
||||
mPrimaryVolumePath = findPrimaryVolumePath()
|
||||
}
|
||||
return mPrimaryVolumePath!!
|
||||
@JvmStatic
|
||||
fun getPrimaryVolumePath(context: Context): String {
|
||||
if (mPrimaryVolumePath == null) {
|
||||
mPrimaryVolumePath = findPrimaryVolumePath(context)
|
||||
}
|
||||
return mPrimaryVolumePath!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getVolumePaths(context: Context): Array<String> {
|
||||
|
@ -76,8 +75,17 @@ object StorageUtils {
|
|||
return pathSteps.iterator()
|
||||
}
|
||||
|
||||
private fun findPrimaryVolumePath(): String {
|
||||
return ensureTrailingSeparator(Environment.getExternalStorageDirectory().absolutePath)
|
||||
private fun findPrimaryVolumePath(context: Context): String? {
|
||||
// we want:
|
||||
// /storage/emulated/0/
|
||||
// `Environment.getExternalStorageDirectory()` (deprecated) yields:
|
||||
// /storage/emulated/0
|
||||
// `context.getExternalFilesDir(null)` yields:
|
||||
// /storage/emulated/0/Android/data/{package_name}/files
|
||||
return context.getExternalFilesDir(null)?.let {
|
||||
val appSpecificPath = it.absolutePath
|
||||
return appSpecificPath.substring(0, appSpecificPath.indexOf("Android/data"))
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
|
@ -126,10 +134,10 @@ object StorageUtils {
|
|||
}
|
||||
} else {
|
||||
// Device has emulated storage; external storage paths should have userId burned into them.
|
||||
val path = Environment.getExternalStorageDirectory().absolutePath
|
||||
val rawUserId = path.split(File.separator).lastOrNull()?.takeIf { TextUtils.isDigitsOnly(it) } ?: ""
|
||||
// /storage/emulated/0[1,2,...]
|
||||
if (TextUtils.isEmpty(rawUserId)) {
|
||||
// /storage/emulated/[0,1,2,...]/
|
||||
val path = getPrimaryVolumePath(context)
|
||||
val rawUserId = path.split(File.separator).lastOrNull(String::isNotEmpty)?.takeIf { TextUtils.isDigitsOnly(it) } ?: ""
|
||||
if (rawUserId.isEmpty()) {
|
||||
paths.add(rawEmulatedStorageTarget)
|
||||
} else {
|
||||
paths.add(rawEmulatedStorageTarget + File.separator + rawUserId)
|
||||
|
@ -145,30 +153,29 @@ object StorageUtils {
|
|||
}
|
||||
|
||||
// return physicalPaths based on phone model
|
||||
private val physicalPaths: Array<String>
|
||||
@SuppressLint("SdCardPath")
|
||||
get() = arrayOf(
|
||||
"/storage/sdcard0",
|
||||
"/storage/sdcard1", //Motorola Xoom
|
||||
"/storage/extsdcard", //Samsung SGS3
|
||||
"/storage/sdcard0/external_sdcard", //User request
|
||||
"/mnt/extsdcard",
|
||||
"/mnt/sdcard/external_sd", //Samsung galaxy family
|
||||
"/mnt/external_sd",
|
||||
"/mnt/media_rw/sdcard1", //4.4.2 on CyanogenMod S3
|
||||
"/removable/microsd", //Asus transformer prime
|
||||
"/mnt/emmc",
|
||||
"/storage/external_SD", //LG
|
||||
"/storage/ext_sd", //HTC One Max
|
||||
"/storage/removable/sdcard1", //Sony Xperia Z1
|
||||
"/data/sdext",
|
||||
"/data/sdext2",
|
||||
"/data/sdext3",
|
||||
"/data/sdext4",
|
||||
"/sdcard1", //Sony Xperia Z
|
||||
"/sdcard2", //HTC One M8s
|
||||
"/storage/microsd" //ASUS ZenFone 2
|
||||
)
|
||||
@SuppressLint("SdCardPath")
|
||||
private val physicalPaths = arrayOf(
|
||||
"/storage/sdcard0",
|
||||
"/storage/sdcard1", //Motorola Xoom
|
||||
"/storage/extsdcard", //Samsung SGS3
|
||||
"/storage/sdcard0/external_sdcard", //User request
|
||||
"/mnt/extsdcard",
|
||||
"/mnt/sdcard/external_sd", //Samsung galaxy family
|
||||
"/mnt/external_sd",
|
||||
"/mnt/media_rw/sdcard1", //4.4.2 on CyanogenMod S3
|
||||
"/removable/microsd", //Asus transformer prime
|
||||
"/mnt/emmc",
|
||||
"/storage/external_SD", //LG
|
||||
"/storage/ext_sd", //HTC One Max
|
||||
"/storage/removable/sdcard1", //Sony Xperia Z1
|
||||
"/data/sdext",
|
||||
"/data/sdext2",
|
||||
"/data/sdext3",
|
||||
"/data/sdext4",
|
||||
"/sdcard1", //Sony Xperia Z
|
||||
"/sdcard2", //HTC One M8s
|
||||
"/storage/microsd" //ASUS ZenFone 2
|
||||
)
|
||||
|
||||
/**
|
||||
* Volume tree URIs
|
||||
|
@ -194,7 +201,7 @@ object StorageUtils {
|
|||
|
||||
private fun getVolumePathFromTreeUriUuid(context: Context, uuid: String): String? {
|
||||
if (uuid == "primary") {
|
||||
return primaryVolumePath
|
||||
return getPrimaryVolumePath(context)
|
||||
}
|
||||
val sm = context.getSystemService(StorageManager::class.java)
|
||||
if (sm != null) {
|
||||
|
@ -258,7 +265,7 @@ object StorageUtils {
|
|||
@JvmStatic
|
||||
fun getDocumentFile(context: Context, anyPath: String, mediaUri: Uri): DocumentFileCompat? {
|
||||
try {
|
||||
if (requireAccessPermission(anyPath)) {
|
||||
if (requireAccessPermission(context, anyPath)) {
|
||||
// need a document URI (not a media content URI) to open a `DocumentFile` output stream
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isMediaStoreContentUri(mediaUri)) {
|
||||
// cleanest API to get it
|
||||
|
@ -283,7 +290,7 @@ object StorageUtils {
|
|||
@JvmStatic
|
||||
fun createDirectoryIfAbsent(context: Context, dirPath: String): DocumentFileCompat? {
|
||||
val cleanDirPath = ensureTrailingSeparator(dirPath)
|
||||
return if (requireAccessPermission(cleanDirPath)) {
|
||||
return if (requireAccessPermission(context, cleanDirPath)) {
|
||||
val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null
|
||||
val rootTreeUri = convertDirPathToTreeUri(context, grantedDir) ?: return null
|
||||
var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeUri) ?: return null
|
||||
|
@ -357,12 +364,12 @@ object StorageUtils {
|
|||
*/
|
||||
|
||||
@JvmStatic
|
||||
fun requireAccessPermission(anyPath: String): Boolean {
|
||||
fun requireAccessPermission(context: Context, anyPath: String): Boolean {
|
||||
// on Android R, we should always require access permission, even on primary volume
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
|
||||
return true
|
||||
}
|
||||
val onPrimaryVolume = anyPath.startsWith(primaryVolumePath)
|
||||
val onPrimaryVolume = anyPath.startsWith(getPrimaryVolumePath(context))
|
||||
return !onPrimaryVolume
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue