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
|
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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue