addressed some deprecation warnings

This commit is contained in:
Thibault Deckers 2020-10-20 22:50:32 +09:00
parent e50dd952a8
commit 69d700674c
3 changed files with 51 additions and 44 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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
}