Set minSdk to 32 and remove code for old SDKs
We can't go to 33 yet, because roboelectric doesn't support that
This commit is contained in:
parent
c856048f8f
commit
82f23b7800
14 changed files with 36 additions and 101 deletions
|
@ -18,7 +18,7 @@ android {
|
||||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 29 // leave at 29 for robolectric tests
|
minSdkVersion 32 // leave at 32 for robolectric tests
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionNameSuffix "-$gitDescribe"
|
versionNameSuffix "-$gitDescribe"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.stevesoltys.seedvault.restore.install
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
|
@ -81,10 +80,8 @@ internal class InstallProgressAdapter(
|
||||||
IN_PROGRESS -> {
|
IN_PROGRESS -> {
|
||||||
appStatus.visibility = INVISIBLE
|
appStatus.visibility = INVISIBLE
|
||||||
progressBar.visibility = VISIBLE
|
progressBar.visibility = VISIBLE
|
||||||
if (SDK_INT >= 30) {
|
progressBar.stateDescription =
|
||||||
progressBar.stateDescription =
|
context.getString(R.string.restore_app_status_installing)
|
||||||
context.getString(R.string.restore_app_status_installing)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SUCCEEDED -> {
|
SUCCEEDED -> {
|
||||||
appStatus.setImageResource(R.drawable.ic_check_green)
|
appStatus.setImageResource(R.drawable.ic_check_green)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.stevesoltys.seedvault.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
|
@ -40,12 +39,10 @@ internal abstract class AppViewHolder(protected val v: View) : RecyclerView.View
|
||||||
appInfo.visibility = GONE
|
appInfo.visibility = GONE
|
||||||
appStatus.visibility = INVISIBLE
|
appStatus.visibility = INVISIBLE
|
||||||
progressBar.visibility = VISIBLE
|
progressBar.visibility = VISIBLE
|
||||||
if (SDK_INT >= 30) {
|
progressBar.stateDescription = context.getString(
|
||||||
progressBar.stateDescription = context.getString(
|
if (isRestore) R.string.restore_restoring
|
||||||
if (isRestore) R.string.restore_restoring
|
else R.string.backup_app_in_progress
|
||||||
else R.string.backup_app_in_progress
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
appStatus.visibility = VISIBLE
|
appStatus.visibility = VISIBLE
|
||||||
progressBar.visibility = INVISIBLE
|
progressBar.visibility = INVISIBLE
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.content.Intent
|
||||||
import android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
import android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||||
import android.hardware.biometrics.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
import android.hardware.biometrics.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||||
import android.hardware.biometrics.BiometricPrompt
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.CancellationSignal
|
import android.os.CancellationSignal
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -22,7 +21,6 @@ import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat.getMainExecutor
|
import androidx.core.content.ContextCompat.getMainExecutor
|
||||||
|
@ -122,9 +120,9 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
newCodeButton.visibility = if (forStoringNewCode) GONE else VISIBLE
|
newCodeButton.visibility = if (forStoringNewCode) GONE else VISIBLE
|
||||||
newCodeButton.setOnClickListener { generateNewCode() }
|
newCodeButton.setOnClickListener { generateNewCode() }
|
||||||
|
|
||||||
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner, { verified ->
|
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner) { verified ->
|
||||||
onExistingCodeChecked(verified)
|
onExistingCodeChecked(verified)
|
||||||
})
|
}
|
||||||
|
|
||||||
if (forStoringNewCode && isDebugBuild() && !viewModel.isRestore) debugPreFill()
|
if (forStoringNewCode && isDebugBuild() && !viewModel.isRestore) debugPreFill()
|
||||||
}
|
}
|
||||||
|
@ -147,7 +145,7 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
}
|
}
|
||||||
if (forStoringNewCode) {
|
if (forStoringNewCode) {
|
||||||
val keyguardManager = requireContext().getSystemService(KeyguardManager::class.java)
|
val keyguardManager = requireContext().getSystemService(KeyguardManager::class.java)
|
||||||
if (SDK_INT >= 30 && keyguardManager.isDeviceSecure) {
|
if (keyguardManager.isDeviceSecure) {
|
||||||
// if we have a lock-screen secret, we can ask for it before storing the code
|
// if we have a lock-screen secret, we can ask for it before storing the code
|
||||||
storeNewCodeAfterAuth(input)
|
storeNewCodeAfterAuth(input)
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,7 +157,6 @@ class RecoveryCodeInputFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(30)
|
|
||||||
private fun storeNewCodeAfterAuth(input: List<CharSequence>) {
|
private fun storeNewCodeAfterAuth(input: List<CharSequence>) {
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
val biometricPrompt = BiometricPrompt.Builder(context)
|
val biometricPrompt = BiometricPrompt.Builder(context)
|
||||||
|
|
|
@ -41,7 +41,7 @@ import kotlin.random.Random
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@Config(
|
@Config(
|
||||||
sdk = [29], // robolectric does not support 30, yet
|
sdk = [32], // robolectric does not support 33, yet
|
||||||
application = TestApp::class
|
application = TestApp::class
|
||||||
)
|
)
|
||||||
class MetadataManagerTest {
|
class MetadataManagerTest {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@Config(
|
@Config(
|
||||||
sdk = [29], // robolectric does not support 30, yet
|
sdk = [32], // robolectric does not support 33, yet
|
||||||
application = TestApp::class
|
application = TestApp::class
|
||||||
)
|
)
|
||||||
internal class DocumentFileTest {
|
internal class DocumentFileTest {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@Config(
|
@Config(
|
||||||
sdk = [29], // robolectric does not support 30, yet
|
sdk = [32], // robolectric does not support 33, yet
|
||||||
application = TestApp::class
|
application = TestApp::class
|
||||||
)
|
)
|
||||||
internal class DeviceInfoTest {
|
internal class DeviceInfoTest {
|
||||||
|
@ -62,12 +62,10 @@ internal class DeviceInfoTest {
|
||||||
assertFalse(deviceInfo.isSupportedLanguage("de"))
|
assertFalse(deviceInfo.isSupportedLanguage("de"))
|
||||||
|
|
||||||
// test areUnknownSplitsAllowed
|
// test areUnknownSplitsAllowed
|
||||||
val deviceName = "unknown robolectric"
|
assertTrue(deviceInfo.areUnknownSplitsAllowed("robolectric robolectric"))
|
||||||
if (onlyOnSameDevice) {
|
if (onlyOnSameDevice) {
|
||||||
assertTrue(deviceInfo.areUnknownSplitsAllowed(deviceName))
|
|
||||||
assertFalse(deviceInfo.areUnknownSplitsAllowed("foo bar"))
|
assertFalse(deviceInfo.areUnknownSplitsAllowed("foo bar"))
|
||||||
} else {
|
} else {
|
||||||
assertTrue(deviceInfo.areUnknownSplitsAllowed(deviceName))
|
|
||||||
assertTrue(deviceInfo.areUnknownSplitsAllowed("foo bar"))
|
assertTrue(deviceInfo.areUnknownSplitsAllowed("foo bar"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ buildscript {
|
||||||
ext {
|
ext {
|
||||||
buildToolsVersion = '33.0.0'
|
buildToolsVersion = '33.0.0'
|
||||||
compileSdkVersion = 33
|
compileSdkVersion = 33
|
||||||
minSdkVersion = 29
|
minSdkVersion = 32
|
||||||
targetSdkVersion = 33
|
targetSdkVersion = 33
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
package de.grobox.storagebackuptester
|
package de.grobox.storagebackuptester
|
||||||
|
|
||||||
import android.Manifest.permission.ACCESS_MEDIA_LOCATION
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
|
import android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
|
||||||
|
@ -21,7 +17,6 @@ import android.widget.Button
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_SHORT
|
import android.widget.Toast.LENGTH_SHORT
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -43,13 +38,6 @@ open class LogFragment : Fragment() {
|
||||||
private lateinit var button: Button
|
private lateinit var button: Button
|
||||||
private val adapter = LogAdapter()
|
private val adapter = LogAdapter()
|
||||||
|
|
||||||
private val permissionRequest =
|
|
||||||
registerForActivityResult(RequestMultiplePermissions()) { grantedMap ->
|
|
||||||
if (grantedMap[WRITE_EXTERNAL_STORAGE] == true) {
|
|
||||||
Toast.makeText(requireContext(), "Please try again now!", LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -62,19 +50,19 @@ open class LogFragment : Fragment() {
|
||||||
progressBar = v.findViewById(R.id.progressBar)
|
progressBar = v.findViewById(R.id.progressBar)
|
||||||
horizontalProgressBar = v.findViewById(R.id.horizontalProgressBar)
|
horizontalProgressBar = v.findViewById(R.id.horizontalProgressBar)
|
||||||
button = v.findViewById(R.id.button)
|
button = v.findViewById(R.id.button)
|
||||||
viewModel.backupLog.observe(viewLifecycleOwner, { progress ->
|
viewModel.backupLog.observe(viewLifecycleOwner) { progress ->
|
||||||
progress.text?.let { adapter.addItem(it) }
|
progress.text?.let { adapter.addItem(it) }
|
||||||
horizontalProgressBar.max = progress.total
|
horizontalProgressBar.max = progress.total
|
||||||
horizontalProgressBar.setProgress(progress.current, true)
|
horizontalProgressBar.setProgress(progress.current, true)
|
||||||
list.postDelayed({
|
list.postDelayed({
|
||||||
list.scrollToPosition(adapter.itemCount - 1)
|
list.scrollToPosition(adapter.itemCount - 1)
|
||||||
}, 50)
|
}, 50)
|
||||||
})
|
}
|
||||||
viewModel.backupButtonEnabled.observe(viewLifecycleOwner, { enabled ->
|
viewModel.backupButtonEnabled.observe(viewLifecycleOwner) { enabled ->
|
||||||
button.isEnabled = enabled
|
button.isEnabled = enabled
|
||||||
progressBar.visibility = if (enabled) INVISIBLE else VISIBLE
|
progressBar.visibility = if (enabled) INVISIBLE else VISIBLE
|
||||||
if (!enabled) adapter.clear()
|
if (!enabled) adapter.clear()
|
||||||
})
|
}
|
||||||
button.setOnClickListener {
|
button.setOnClickListener {
|
||||||
if (!checkPermission()) return@setOnClickListener
|
if (!checkPermission()) return@setOnClickListener
|
||||||
viewModel.simulateBackup()
|
viewModel.simulateBackup()
|
||||||
|
@ -120,23 +108,13 @@ open class LogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPermission(): Boolean {
|
private fun checkPermission(): Boolean {
|
||||||
return if (Build.VERSION.SDK_INT >= 30) {
|
if (Environment.isExternalStorageManager()) return true
|
||||||
if (Environment.isExternalStorageManager()) return true
|
Toast.makeText(requireContext(), "Permission needed", LENGTH_SHORT).show()
|
||||||
Toast.makeText(requireContext(), "Permission needed", LENGTH_SHORT).show()
|
val i = Intent(ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
|
||||||
val i = Intent(ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
|
data = Uri.parse("package:${requireContext().packageName}")
|
||||||
data = Uri.parse("package:${requireContext().packageName}")
|
|
||||||
}
|
|
||||||
startActivity(i)
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
if (requireContext().checkSelfPermission(WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
Toast.makeText(requireContext(), "No storage permission", LENGTH_SHORT).show()
|
|
||||||
permissionRequest.launch(arrayOf(WRITE_EXTERNAL_STORAGE, ACCESS_MEDIA_LOCATION))
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
startActivity(i)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package de.grobox.storagebackuptester.settings
|
package de.grobox.storagebackuptester.settings
|
||||||
|
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
@ -39,16 +38,14 @@ class InfoFragment : MediaScanFragment() {
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
e.toString()
|
e.toString()
|
||||||
}
|
}
|
||||||
val gen = if (SDK_INT >= 30) try {
|
val gen = try {
|
||||||
MediaStore.getGeneration(context, volumeName)
|
MediaStore.getGeneration(context, volumeName)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
e.toString()
|
e.toString()
|
||||||
} else null
|
}
|
||||||
sb.appendLine(" $volumeName")
|
sb.appendLine(" $volumeName")
|
||||||
sb.appendLine(" version: $version")
|
sb.appendLine(" version: $version")
|
||||||
if (gen != null) {
|
sb.appendLine(" generation: $gen")
|
||||||
sb.appendLine(" generation: $gen")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sb.appendLine()
|
sb.appendLine()
|
||||||
sb.appendLine("Media files smaller than 100 KB: ${mediaFilesSmallerThan(100 * 1024)}")
|
sb.appendLine("Media files smaller than 100 KB: ${mediaFilesSmallerThan(100 * 1024)}")
|
||||||
|
|
|
@ -3,13 +3,6 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.calyxos.backup.storage">
|
package="org.calyxos.backup.storage">
|
||||||
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
|
||||||
android:maxSdkVersion="29" />
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
|
||||||
android:maxSdkVersion="29" />
|
|
||||||
|
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||||
tools:ignore="ScopedStorage" />
|
tools:ignore="ScopedStorage" />
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.os.Environment.getExternalStorageDirectory
|
import android.os.Environment.getExternalStorageDirectory
|
||||||
import android.provider.MediaStore.MediaColumns
|
import android.provider.MediaStore.MediaColumns
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -39,13 +38,7 @@ internal class FileRestore(
|
||||||
val finalTag: String
|
val finalTag: String
|
||||||
when {
|
when {
|
||||||
file.mediaFile != null -> {
|
file.mediaFile != null -> {
|
||||||
bytes = if (SDK_INT < 30) {
|
bytes = restoreFile(file.mediaFile, streamWriter)
|
||||||
// MediaProvider on API 29 doesn't let us write files into any folders freely,
|
|
||||||
// so don't attempt to restore via MediaStore API
|
|
||||||
restoreFile(file, streamWriter)
|
|
||||||
} else {
|
|
||||||
restoreFile(file.mediaFile, streamWriter)
|
|
||||||
}
|
|
||||||
finalTag = "M$tag"
|
finalTag = "M$tag"
|
||||||
}
|
}
|
||||||
file.docFile != null -> {
|
file.docFile != null -> {
|
||||||
|
@ -112,10 +105,7 @@ internal class FileRestore(
|
||||||
// changing owner requires backup permission
|
// changing owner requires backup permission
|
||||||
put(MediaColumns.OWNER_PACKAGE_NAME, mediaFile.ownerPackageName)
|
put(MediaColumns.OWNER_PACKAGE_NAME, mediaFile.ownerPackageName)
|
||||||
put(MediaColumns.IS_PENDING, 1)
|
put(MediaColumns.IS_PENDING, 1)
|
||||||
if (SDK_INT >= 30) {
|
put(MediaColumns.IS_FAVORITE, if (mediaFile.isFavorite) 1 else 0)
|
||||||
val isFavorite = if (mediaFile.isFavorite) 1 else 0
|
|
||||||
put(MediaColumns.IS_FAVORITE, isFavorite)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val contentUri = MediaType.fromBackupMediaType(mediaFile.type).contentUri
|
val contentUri = MediaType.fromBackupMediaType(mediaFile.type).contentUri
|
||||||
val uri = contentResolver.insert(contentUri, contentValues)!!
|
val uri = contentResolver.insert(contentUri, contentValues)!!
|
||||||
|
|
|
@ -5,13 +5,11 @@ import android.content.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.MediaColumns.IS_DOWNLOAD
|
import android.provider.MediaStore.MediaColumns.IS_DOWNLOAD
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.database.getIntOrNull
|
import androidx.core.database.getIntOrNull
|
||||||
import androidx.core.database.getLongOrNull
|
import androidx.core.database.getLongOrNull
|
||||||
import androidx.core.database.getStringOrNull
|
import androidx.core.database.getStringOrNull
|
||||||
|
@ -23,7 +21,7 @@ import java.io.File
|
||||||
public class MediaScanner(context: Context) {
|
public class MediaScanner(context: Context) {
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val PROJECTION_29 = arrayOf(
|
private val PROJECTION = arrayOf(
|
||||||
MediaStore.MediaColumns._ID,
|
MediaStore.MediaColumns._ID,
|
||||||
MediaStore.MediaColumns.RELATIVE_PATH,
|
MediaStore.MediaColumns.RELATIVE_PATH,
|
||||||
MediaStore.MediaColumns.DISPLAY_NAME,
|
MediaStore.MediaColumns.DISPLAY_NAME,
|
||||||
|
@ -31,10 +29,6 @@ public class MediaScanner(context: Context) {
|
||||||
MediaStore.MediaColumns.SIZE,
|
MediaStore.MediaColumns.SIZE,
|
||||||
MediaStore.MediaColumns.OWNER_PACKAGE_NAME,
|
MediaStore.MediaColumns.OWNER_PACKAGE_NAME,
|
||||||
MediaStore.MediaColumns.VOLUME_NAME,
|
MediaStore.MediaColumns.VOLUME_NAME,
|
||||||
)
|
|
||||||
|
|
||||||
@RequiresApi(30)
|
|
||||||
private val PROJECTION_30 = arrayOf(
|
|
||||||
MediaStore.MediaColumns.IS_FAVORITE,
|
MediaStore.MediaColumns.IS_FAVORITE,
|
||||||
MediaStore.MediaColumns.GENERATION_MODIFIED,
|
MediaStore.MediaColumns.GENERATION_MODIFIED,
|
||||||
)
|
)
|
||||||
|
@ -59,7 +53,7 @@ public class MediaScanner(context: Context) {
|
||||||
internal fun scanMediaUri(uri: Uri, extraQuery: String? = null): List<MediaFile> {
|
internal fun scanMediaUri(uri: Uri, extraQuery: String? = null): List<MediaFile> {
|
||||||
val extras = Bundle().apply {
|
val extras = Bundle().apply {
|
||||||
val query = StringBuilder()
|
val query = StringBuilder()
|
||||||
if (SDK_INT >= 30 && uri != MediaType.Downloads.contentUri) {
|
if (uri != MediaType.Downloads.contentUri) {
|
||||||
query.append("$IS_DOWNLOAD=0")
|
query.append("$IS_DOWNLOAD=0")
|
||||||
}
|
}
|
||||||
extraQuery?.let {
|
extraQuery?.let {
|
||||||
|
@ -68,8 +62,7 @@ public class MediaScanner(context: Context) {
|
||||||
}
|
}
|
||||||
if (query.isNotEmpty()) putString(QUERY_ARG_SQL_SELECTION, query.toString())
|
if (query.isNotEmpty()) putString(QUERY_ARG_SQL_SELECTION, query.toString())
|
||||||
}
|
}
|
||||||
val projection = if (SDK_INT >= 30) PROJECTION_29 + PROJECTION_30 else PROJECTION_29
|
val cursor = contentResolver.query(uri, PROJECTION, extras, null)
|
||||||
val cursor = contentResolver.query(uri, projection, extras, null)
|
|
||||||
return ArrayList<MediaFile>(cursor?.count ?: 0).apply {
|
return ArrayList<MediaFile>(cursor?.count ?: 0).apply {
|
||||||
cursor?.use { c ->
|
cursor?.use { c ->
|
||||||
while (c.moveToNext()) add(createMediaFile(c, uri))
|
while (c.moveToNext()) add(createMediaFile(c, uri))
|
||||||
|
@ -94,13 +87,9 @@ public class MediaScanner(context: Context) {
|
||||||
dir = cursor.getString(PROJECTION_PATH),
|
dir = cursor.getString(PROJECTION_PATH),
|
||||||
fileName = cursor.getString(PROJECTION_NAME),
|
fileName = cursor.getString(PROJECTION_NAME),
|
||||||
dateModified = cursor.getLongOrNull(PROJECTION_DATE_MODIFIED),
|
dateModified = cursor.getLongOrNull(PROJECTION_DATE_MODIFIED),
|
||||||
generationModified = if (SDK_INT >= 30) cursor.getLongOrNull(
|
generationModified = cursor.getLongOrNull(PROJECTION_GENERATION_MODIFIED),
|
||||||
PROJECTION_GENERATION_MODIFIED
|
|
||||||
) else null,
|
|
||||||
size = cursor.getLong(PROJECTION_SIZE),
|
size = cursor.getLong(PROJECTION_SIZE),
|
||||||
isFavorite = if (SDK_INT >= 30) {
|
isFavorite = cursor.getIntOrNull(PROJECTION_IS_FAVORITE) == 1,
|
||||||
cursor.getIntOrNull(PROJECTION_IS_FAVORITE) == 1
|
|
||||||
} else false,
|
|
||||||
ownerPackageName = cursor.getStringOrNull(PROJECTION_OWNER_PACKAGE_NAME),
|
ownerPackageName = cursor.getStringOrNull(PROJECTION_OWNER_PACKAGE_NAME),
|
||||||
volume = cursor.getString(PROJECTION_VOLUME_NAME)
|
volume = cursor.getString(PROJECTION_VOLUME_NAME)
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import android.app.NotificationManager
|
||||||
import android.app.NotificationManager.IMPORTANCE_LOW
|
import android.app.NotificationManager.IMPORTANCE_LOW
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build.VERSION.SDK_INT
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
@ -145,7 +144,7 @@ internal class Notifications(private val context: Context) {
|
||||||
setShowWhen(false)
|
setShowWhen(false)
|
||||||
setWhen(System.currentTimeMillis())
|
setWhen(System.currentTimeMillis())
|
||||||
setProgress(expected, transferred, expected == 0)
|
setProgress(expected, transferred, expected == 0)
|
||||||
if (SDK_INT >= 31) setForegroundServiceBehavior(FOREGROUND_SERVICE_IMMEDIATE)
|
setForegroundServiceBehavior(FOREGROUND_SERVICE_IMMEDIATE)
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue