Request write permission to save to external storage

This commit is contained in:
William Brawner 2020-09-19 18:23:38 -07:00
parent 0211f47a6c
commit f3527912f2
3 changed files with 46 additions and 6 deletions

View file

@ -6,6 +6,7 @@
<uses-sdk/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"

View file

@ -1,6 +1,7 @@
package com.unciv.app
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Build
import android.os.Bundle
import androidx.core.app.NotificationManagerCompat
@ -84,6 +85,13 @@ class AndroidLauncher : AndroidApplication() {
super.onResume()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && requestCode == REQ_WRITE_STORAGE && grantResults[0] == PERMISSION_GRANTED) {
customSaveLocationHelper?.continuePreviousRequest()
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// This should only happen on API 19+ but it's wrapped in the if check to keep the

View file

@ -1,10 +1,13 @@
package com.unciv.app
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import com.unciv.logic.CustomSaveLocationHelper
import com.unciv.logic.GameInfo
import com.unciv.logic.GameSaver
@ -13,12 +16,16 @@ import java.util.concurrent.atomic.AtomicReference
const val REQ_SAVE_GAME = 1
const val REQ_LOAD_GAME = 2
const val REQ_WRITE_STORAGE = 3
// The Storage Access Framework is available from API 19 and up:
// https://developer.android.com/guide/topics/providers/document-provider
@RequiresApi(Build.VERSION_CODES.KITKAT)
class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSaveLocationHelper {
private val callback = AtomicReference<Pair<Thread, (Uri?) -> Unit>?>()
private var cachedSaveRequest: SaveRequest? = null
@Synchronized get
@Synchronized set
override fun saveGame(gameInfo: GameInfo, gameName: String, forcePrompt: Boolean, block: (() -> Unit)?) {
callback.set(Thread.currentThread() to { uri ->
@ -33,6 +40,17 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
return
}
}
// For some reason it seems you can save to an existing file that you open without the
// permission, but you can't write to a file that you've requested be created so if this is
// a "Save as" operation then we need to get permission to write first
if (ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cachedSaveRequest = SaveRequest(gameInfo, gameName, forcePrompt, block)
activity.requestPermissions(arrayOf(WRITE_EXTERNAL_STORAGE), REQ_WRITE_STORAGE)
return
}
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
type = "application/json"
putExtra(Intent.EXTRA_TITLE, gameName)
@ -40,6 +58,12 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
}
}
fun continuePreviousRequest() {
cachedSaveRequest?.let {
saveGame(it.gameInfo, it.gameName, it.forcePrompt, it.block)
cachedSaveRequest = null
}
}
// This will be called on the main thread
fun handleIntentData(uri: Uri?) {
@ -63,11 +87,11 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
callback.set(Thread.currentThread() to { uri ->
uri?.let {
val game = activity.contentResolver.openInputStream(it)
?.reader()
?.readText()
?.run {
GameSaver.gameInfoFromString(this)
}?: return@let
?.reader()
?.readText()
?.run {
GameSaver.gameInfoFromString(this)
} ?: return@let
// If the user has saved the game from another platform (like Android),
// then the save location might not be right so we have to correct for that
// here
@ -82,3 +106,10 @@ class CustomSaveLocationHelperAndroid(private val activity: Activity) : CustomSa
}
}
}
data class SaveRequest(
val gameInfo: GameInfo,
val gameName: String,
val forcePrompt: Boolean,
val block: (() -> Unit)?
)