Skip permissions checking for saving and loading files

At some point I refactored to an API that doesn't require any permissions at all but never removed the permissions check. This corrects that
This commit is contained in:
William Brawner 2023-03-27 20:23:28 -06:00
parent 13bfe236a3
commit c5355d1565
5 changed files with 62 additions and 57 deletions

View file

@ -46,8 +46,8 @@ android {
applicationId = "com.wbrawner.simplemarkdown" applicationId = "com.wbrawner.simplemarkdown"
minSdk = 23 minSdk = 23
targetSdk = 33 targetSdk = 33
versionCode = 35 versionCode = 39
versionName = "0.8.13" versionName = "0.8.15"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["clearPackageData"] = "true" testInstrumentationRunnerArguments["clearPackageData"] = "true"
buildConfigField("boolean", "ENABLE_CUSTOM_CSS", "true") buildConfigField("boolean", "ENABLE_CUSTOM_CSS", "true")
@ -134,7 +134,7 @@ android.productFlavors.forEach { flavor ->
dependencies { dependencies {
implementation("com.android.billingclient:billing:5.1.0") implementation("com.android.billingclient:billing:5.1.0")
implementation("com.google.android.play:core-ktx:1.8.1") implementation("com.google.android.play:core-ktx:1.8.1")
implementation("com.google.firebase:firebase-crashlytics:18.3.3") implementation("com.google.firebase:firebase-crashlytics:18.3.5")
} }
} }
} }

View file

@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application

View file

@ -57,12 +57,17 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_edit, menu) inflater.inflate(R.menu.menu_edit, menu)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
menu.findItem(R.id.action_save_as)?.setAlphabeticShortcut('S', KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON) menu.findItem(R.id.action_save_as)
?.setAlphabeticShortcut('S', KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON)
} }
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = override fun onCreateView(
inflater.inflate(R.layout.fragment_main, container, false) inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? =
inflater.inflate(R.layout.fragment_main, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
with(findNavController()) { with(findNavController()) {
@ -92,6 +97,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
drawerLayout.open() drawerLayout.open()
true true
} }
R.id.action_save -> { R.id.action_save -> {
Timber.d("Save clicked") Timber.d("Save clicked")
lifecycleScope.launch { lifecycleScope.launch {
@ -99,46 +105,54 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
requestFileOp(REQUEST_SAVE_FILE) requestFileOp(REQUEST_SAVE_FILE)
} else { } else {
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
getString(R.string.file_saved, viewModel.fileName.value), getString(R.string.file_saved, viewModel.fileName.value),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
} }
true true
} }
R.id.action_save_as -> { R.id.action_save_as -> {
Timber.d("Save as clicked") Timber.d("Save as clicked")
requestFileOp(REQUEST_SAVE_FILE) requestFileOp(REQUEST_SAVE_FILE)
true true
} }
R.id.action_share -> { R.id.action_share -> {
Timber.d("Share clicked") Timber.d("Share clicked")
val shareIntent = Intent(Intent.ACTION_SEND) val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_TEXT, viewModel.markdownUpdates.value) shareIntent.putExtra(Intent.EXTRA_TEXT, viewModel.markdownUpdates.value)
shareIntent.type = "text/plain" shareIntent.type = "text/plain"
startActivity(Intent.createChooser( startActivity(
Intent.createChooser(
shareIntent, shareIntent,
getString(R.string.share_file) getString(R.string.share_file)
)) )
)
true true
} }
R.id.action_load -> { R.id.action_load -> {
Timber.d("Load clicked") Timber.d("Load clicked")
requestFileOp(REQUEST_OPEN_FILE) requestFileOp(REQUEST_OPEN_FILE)
true true
} }
R.id.action_new -> { R.id.action_new -> {
Timber.d("New clicked") Timber.d("New clicked")
promptSaveOrDiscardChanges() promptSaveOrDiscardChanges()
true true
} }
R.id.action_lock_swipe -> { R.id.action_lock_swipe -> {
Timber.d("Lock swiping clicked") Timber.d("Lock swiping clicked")
item.isChecked = !item.isChecked item.isChecked = !item.isChecked
pager!!.setSwipeLocked(item.isChecked) pager!!.setSwipeLocked(item.isChecked)
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
@ -148,7 +162,8 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
Plausible.pageView("") Plausible.pageView("")
lifecycleScope.launch { lifecycleScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(requireContext()) val enableErrorReports =
PreferenceManager.getDefaultSharedPreferences(requireContext())
.getBoolean(getString(R.string.pref_key_error_reports_enabled), true) .getBoolean(getString(R.string.pref_key_error_reports_enabled), true)
Timber.d("MainFragment started. Error reports enabled? $enableErrorReports") Timber.d("MainFragment started. Error reports enabled? $enableErrorReports")
errorHandler.enable(enableErrorReports) errorHandler.enable(enableErrorReports)
@ -176,9 +191,9 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
requestCode: Int, requestCode: Int,
permissions: Array<String>, permissions: Array<String>,
grantResults: IntArray grantResults: IntArray
) { ) {
when (requestCode) { when (requestCode) {
REQUEST_SAVE_FILE, REQUEST_OPEN_FILE -> { REQUEST_SAVE_FILE, REQUEST_OPEN_FILE -> {
@ -192,7 +207,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
Timber.d("Storage permissions denied, unable to save or load files") Timber.d("Storage permissions denied, unable to save or load files")
context?.let { context?.let {
Toast.makeText(it, R.string.no_permissions, Toast.LENGTH_SHORT) Toast.makeText(it, R.string.no_permissions, Toast.LENGTH_SHORT)
.show() .show()
} }
} }
} }
@ -204,9 +219,9 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
REQUEST_OPEN_FILE -> { REQUEST_OPEN_FILE -> {
if (resultCode != Activity.RESULT_OK || data?.data == null) { if (resultCode != Activity.RESULT_OK || data?.data == null) {
Timber.w( Timber.w(
"Unable to open file. Result ok? %b Intent uri: %s", "Unable to open file. Result ok? %b Intent uri: %s",
resultCode == Activity.RESULT_OK, resultCode == Activity.RESULT_OK,
data?.data?.toString() data?.data?.toString()
) )
return return
} }
@ -219,12 +234,13 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
} }
} }
REQUEST_SAVE_FILE -> { REQUEST_SAVE_FILE -> {
if (resultCode != Activity.RESULT_OK || data?.data == null) { if (resultCode != Activity.RESULT_OK || data?.data == null) {
Timber.w( Timber.w(
"Unable to save file. Result ok? %b Intent uri: %s", "Unable to save file. Result ok? %b Intent uri: %s",
resultCode == Activity.RESULT_OK, resultCode == Activity.RESULT_OK,
data?.data?.toString() data?.data?.toString()
) )
return return
} }
@ -242,8 +258,8 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
private fun promptSaveOrDiscardChanges() { private fun promptSaveOrDiscardChanges() {
if (!viewModel.shouldPromptSave()) { if (!viewModel.shouldPromptSave()) {
viewModel.reset( viewModel.reset(
"Untitled.md", "Untitled.md",
PreferenceManager.getDefaultSharedPreferences(requireContext()) PreferenceManager.getDefaultSharedPreferences(requireContext())
) )
return return
} }
@ -252,37 +268,24 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
return return
} }
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setTitle(R.string.save_changes) .setTitle(R.string.save_changes)
.setMessage(R.string.prompt_save_changes) .setMessage(R.string.prompt_save_changes)
.setNegativeButton(R.string.action_discard) { _, _ -> .setNegativeButton(R.string.action_discard) { _, _ ->
Timber.d("Discarding changes") Timber.d("Discarding changes")
viewModel.reset( viewModel.reset(
"Untitled.md", "Untitled.md",
PreferenceManager.getDefaultSharedPreferences(requireContext()) PreferenceManager.getDefaultSharedPreferences(requireContext())
) )
} }
.setPositiveButton(R.string.action_save) { _, _ -> .setPositiveButton(R.string.action_save) { _, _ ->
Timber.d("Saving changes") Timber.d("Saving changes")
requestFileOp(REQUEST_SAVE_FILE) requestFileOp(REQUEST_SAVE_FILE)
} }
.create() .create()
.show() .show()
} }
private fun requestFileOp(requestType: Int) { private fun requestFileOp(requestType: Int) {
val context = context ?: run {
Timber.w("File op requested but context was null, aborting")
return
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
Timber.i("Storage permission not granted, requesting")
requestPermissions(
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
requestType
)
return
}
val intent = when (requestType) { val intent = when (requestType) {
REQUEST_SAVE_FILE -> { REQUEST_SAVE_FILE -> {
Timber.d("Requesting save op") Timber.d("Requesting save op")
@ -291,6 +294,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
putExtra(Intent.EXTRA_TITLE, viewModel.fileName.value) putExtra(Intent.EXTRA_TITLE, viewModel.fileName.value)
} }
} }
REQUEST_OPEN_FILE -> { REQUEST_OPEN_FILE -> {
Timber.d("Requesting open op") Timber.d("Requesting open op")
Intent(Intent.ACTION_OPEN_DOCUMENT).apply { Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
@ -302,6 +306,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
} }
} }
else -> { else -> {
Timber.w("Ignoring unknown file op request: $requestType") Timber.w("Ignoring unknown file op request: $requestType")
null null
@ -309,8 +314,8 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} ?: return } ?: return
intent.addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult( startActivityForResult(
intent, intent,
requestType requestType
) )
} }

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission android:name="com.android.vending.BILLING" /> <uses-permission android:name="com.android.vending.BILLING" />
<application> <application>

View file

@ -7,9 +7,9 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.4.0") classpath("com.android.tools.build:gradle:7.4.2")
classpath("com.google.gms:google-services:4.3.15") classpath("com.google.gms:google-services:4.3.15")
classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.2") classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
classpath("com.osacky.flank.gradle:fladle:0.17.4") classpath("com.osacky.flank.gradle:fladle:0.17.4")
} }