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 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 // 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 // but it doesn't delete the file, even if the app has the permission
try { try {

View file

@ -127,7 +127,7 @@ object PermissionManager {
val accessibleDirs = HashSet(getGrantedDirs(context)) val accessibleDirs = HashSet(getGrantedDirs(context))
// from Android R, we no longer have access permission by default on primary volume // from Android R, we no longer have access permission by default on primary volume
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { 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") Log.d(LOG_TAG, "getAccessibleDirs accessibleDirs=$accessibleDirs")
return accessibleDirs return accessibleDirs

View file

@ -6,7 +6,6 @@ import android.content.Context
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment
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
@ -36,10 +35,10 @@ object StorageUtils {
// primary volume path, with trailing "/" // primary volume path, with trailing "/"
private var mPrimaryVolumePath: String? = null private var mPrimaryVolumePath: String? = null
val primaryVolumePath: String @JvmStatic
get() { fun getPrimaryVolumePath(context: Context): String {
if (mPrimaryVolumePath == null) { if (mPrimaryVolumePath == null) {
mPrimaryVolumePath = findPrimaryVolumePath() mPrimaryVolumePath = findPrimaryVolumePath(context)
} }
return mPrimaryVolumePath!! return mPrimaryVolumePath!!
} }
@ -76,8 +75,17 @@ object StorageUtils {
return pathSteps.iterator() return pathSteps.iterator()
} }
private fun findPrimaryVolumePath(): String { private fun findPrimaryVolumePath(context: Context): String? {
return ensureTrailingSeparator(Environment.getExternalStorageDirectory().absolutePath) // 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") @SuppressLint("ObsoleteSdkInt")
@ -126,10 +134,10 @@ object StorageUtils {
} }
} else { } else {
// Device has emulated storage; external storage paths should have userId burned into them. // Device has emulated storage; external storage paths should have userId burned into them.
val path = Environment.getExternalStorageDirectory().absolutePath // /storage/emulated/[0,1,2,...]/
val rawUserId = path.split(File.separator).lastOrNull()?.takeIf { TextUtils.isDigitsOnly(it) } ?: "" val path = getPrimaryVolumePath(context)
// /storage/emulated/0[1,2,...] val rawUserId = path.split(File.separator).lastOrNull(String::isNotEmpty)?.takeIf { TextUtils.isDigitsOnly(it) } ?: ""
if (TextUtils.isEmpty(rawUserId)) { if (rawUserId.isEmpty()) {
paths.add(rawEmulatedStorageTarget) paths.add(rawEmulatedStorageTarget)
} else { } else {
paths.add(rawEmulatedStorageTarget + File.separator + rawUserId) paths.add(rawEmulatedStorageTarget + File.separator + rawUserId)
@ -145,9 +153,8 @@ object StorageUtils {
} }
// return physicalPaths based on phone model // return physicalPaths based on phone model
private val physicalPaths: Array<String>
@SuppressLint("SdCardPath") @SuppressLint("SdCardPath")
get() = arrayOf( private val physicalPaths = arrayOf(
"/storage/sdcard0", "/storage/sdcard0",
"/storage/sdcard1", //Motorola Xoom "/storage/sdcard1", //Motorola Xoom
"/storage/extsdcard", //Samsung SGS3 "/storage/extsdcard", //Samsung SGS3
@ -194,7 +201,7 @@ object StorageUtils {
private fun getVolumePathFromTreeUriUuid(context: Context, uuid: String): String? { private fun getVolumePathFromTreeUriUuid(context: Context, uuid: String): String? {
if (uuid == "primary") { if (uuid == "primary") {
return primaryVolumePath return getPrimaryVolumePath(context)
} }
val sm = context.getSystemService(StorageManager::class.java) val sm = context.getSystemService(StorageManager::class.java)
if (sm != null) { if (sm != null) {
@ -258,7 +265,7 @@ object StorageUtils {
@JvmStatic @JvmStatic
fun getDocumentFile(context: Context, anyPath: String, mediaUri: Uri): DocumentFileCompat? { fun getDocumentFile(context: Context, anyPath: String, mediaUri: Uri): DocumentFileCompat? {
try { try {
if (requireAccessPermission(anyPath)) { if (requireAccessPermission(context, anyPath)) {
// need a document URI (not a media content URI) to open a `DocumentFile` output stream // 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)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isMediaStoreContentUri(mediaUri)) {
// cleanest API to get it // cleanest API to get it
@ -283,7 +290,7 @@ object StorageUtils {
@JvmStatic @JvmStatic
fun createDirectoryIfAbsent(context: Context, dirPath: String): DocumentFileCompat? { fun createDirectoryIfAbsent(context: Context, dirPath: String): DocumentFileCompat? {
val cleanDirPath = ensureTrailingSeparator(dirPath) val cleanDirPath = ensureTrailingSeparator(dirPath)
return if (requireAccessPermission(cleanDirPath)) { return if (requireAccessPermission(context, cleanDirPath)) {
val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null
val rootTreeUri = convertDirPathToTreeUri(context, grantedDir) ?: return null val rootTreeUri = convertDirPathToTreeUri(context, grantedDir) ?: return null
var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeUri) ?: return null var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeUri) ?: return null
@ -357,12 +364,12 @@ object StorageUtils {
*/ */
@JvmStatic @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 // on Android R, we should always require access permission, even on primary volume
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
return true return true
} }
val onPrimaryVolume = anyPath.startsWith(primaryVolumePath) val onPrimaryVolume = anyPath.startsWith(getPrimaryVolumePath(context))
return !onPrimaryVolume return !onPrimaryVolume
} }