# HG changeset patch # User David Barts # Date 1618199703 25200 # Node ID 2b91619da6503365c7aa9353c85b4d9edd1b96ad # Parent 9cb9bb5da24737b5cb82516c80113fece0976106 No cruft file; just use standard file names always and avoid double-saving. diff -r 9cb9bb5da247 -r 2b91619da650 app/src/main/java/com/bartsent/simpleresizer/EditImage.kt --- a/app/src/main/java/com/bartsent/simpleresizer/EditImage.kt Sat Apr 10 17:29:08 2021 -0700 +++ b/app/src/main/java/com/bartsent/simpleresizer/EditImage.kt Sun Apr 11 20:55:03 2021 -0700 @@ -1,7 +1,6 @@ package com.bartsent.simpleresizer import android.Manifest -import android.content.ContentUris import android.content.ContentValues import android.content.Intent import android.content.pm.PackageManager @@ -41,8 +40,8 @@ var uri: Uri? = null var bitmap: Bitmap? = null var reader: Future? = null - var permissionsCallback: (() -> Unit)? = null var sharable: Boolean = false + var savedAs: Uri? = null } private lateinit var viewModel: State @@ -50,8 +49,6 @@ sort() } - private val IMAGE_TO_SEND = "simple_resizer_sent_image.jpg" - private lateinit var binding: ActivityEditImageBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -246,6 +243,7 @@ binding.progressBar.visibility = ProgressBar.INVISIBLE setImage(newBitmap) makeFabulous() + viewModel.savedAs = null } } } @@ -317,6 +315,7 @@ runOnUiThread { binding.progressBar.visibility = ProgressBar.INVISIBLE setImage(newBitmap) + viewModel.savedAs = null } } } @@ -337,147 +336,101 @@ viewModel.sharable = false } - private val REQUEST_WRITE_EXTERNAL = 42 + private val SHARE_OPERATION = 43 + private val DONE_OPERATION = 77 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray): Unit { - if (requestCode != REQUEST_WRITE_EXTERNAL) { - Log.e("EditImage", "unexpected request code in onRequestPermissionsResult!") - return - } if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { - val cb = viewModel.permissionsCallback - if (cb != null) { - viewModel.permissionsCallback = null - cb() - } + saveOperation(requestCode) } else { showError(getString(R.string.error_unable_no_permissions)) } } - private fun requestWritePermission(): Unit { - requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_EXTERNAL) + private fun requestWritePermission(requestCode: Int): Unit { + requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), requestCode) + } + + fun shareClicked(view: View): Unit = saveOperation(SHARE_OPERATION) + + private fun doShare(uri: Uri): Unit { + val shareIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_STREAM, uri) + type = "image/jpeg" + } + startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.share_text))) } - private fun needsWritePermission(callback: () -> Unit): Boolean { + fun doneClicked(view: View): Unit = saveOperation(DONE_OPERATION) + + private fun doDone(): Unit { + unsetImage() + makeMundane() + finish() + } + + private fun doSaveOperation(requestCode: Int, uri: Uri) { + when (requestCode) { + SHARE_OPERATION -> doShare(uri) + DONE_OPERATION -> doDone() + else -> Log.e("EditImage", "invalid requestCode: $requestCode") + } + } + + private fun saveOperation(requestCode: Int): Unit { + // Trivial case: no edits since the last save. + val savedAs = viewModel.savedAs + if (savedAs != null) { + doSaveOperation(requestCode, savedAs) + return + } + + // If we get here, we must save. We might need (but lack) + // WRITE_EXTERNAL_STORAGE permission. If so, request it, and arrange to + // be called again when it is granted. if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q) { if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { - viewModel.permissionsCallback = callback if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) AlertDialog.Builder(this).also { - it.setMessage( - getString( - R.string.permission_needed, - getString(R.string.app_name) - ) - ) + it.setMessage(getString(R.string.permission_needed, getString(R.string.app_name))) it.setNeutralButton(R.string.ok_text) { dialog, _ -> dialog.dismiss() - requestWritePermission() + requestWritePermission(requestCode) } it.create() }.show() else - requestWritePermission() - return true + requestWritePermission(requestCode) + return } } - return false - } - fun shareClicked(view: View): Unit { - // If we need WRITE_EXTERNAL_STORAGE, request it and bail. We will be called again - // (with the permission) if it is granted. - if (needsWritePermission({ shareClicked(view) })) - return - - // If we get here, we have permission to save (if we need it). - val contentValues = makeContentValues(IMAGE_TO_SEND) - - // Delete any old file(s) - val cols = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.MIME_TYPE) - val query = StringBuilder().run { - for (col in cols) { - if (isNotEmpty()) - append(" and ") - append(col) - append(" = ?") - } - toString() - } - try { - val cursor = contentResolver.query( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - arrayOf(MediaStore.MediaColumns._ID), - query, - cols.map { contentValues.getAsString(it) }.toTypedArray(), - null) - var deleted = 0 - cursor?.use { - // Log.d("EditImage", "${it.count} entries matched") - while (it.moveToNext()) { - val uri = - ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, it.getLong(0)) - deleted += contentResolver.delete(uri, null, null) - } - } - // Log.d("EditImage", "$deleted entries deleted") - } catch (e: Exception) { - Log.e("EditImage", "unexpected exception when sharing!", e) - } - - // Save new file, use it to share data. - saveAs(contentValues) { - val shareIntent: Intent = Intent().apply { - action = Intent.ACTION_SEND - putExtra(Intent.EXTRA_STREAM, it) - type = "image/jpeg" - } - startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.share_text))) - } - } - - fun doneClicked(view: View): Unit { - // If we need WRITE_EXTERNAL_STORAGE, request it and bail. We will be called again - // (with the permission) if it is granted. - if (needsWritePermission({ doneClicked(view) })) - return - - // If we get here, we have permission to save (if we need it). - val image = viewModel.bitmap!! - var fileName = getFileName(viewModel.uri!!) - if (fileName == null) { - val d = java.util.Date() - fileName = "IMG_%tY%tm%td_%tH%tM%tS".format(d, d, d, d, d, d) - } - val dot = fileName.lastIndexOf('.') - if (dot != -1) - fileName = fileName.substring(0, dot) - fileName = "${fileName}_${image.width}x${image.height}.jpg" - saveAs(makeContentValues(fileName)) { - unsetImage() - makeMundane() - finish() - } - } - - private fun makeContentValues(fileName: String): ContentValues = ContentValues().apply { - put(MediaStore.MediaColumns.DISPLAY_NAME, fileName) - put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { - put(MediaStore.MediaColumns.RELATIVE_PATH, - File(Environment.DIRECTORY_PICTURES, getString(R.string.app_name)).path) - } - } - - private fun saveAs(contentValues: ContentValues, callback: (Uri) -> Unit) { + // If we get here, we both need to save, and have permission to save. val image = viewModel.bitmap!! binding.progressBar.visibility = ProgressBar.VISIBLE ThreadPools.WORKERS.execute { + val contentValues = ContentValues().apply { + var fileName = getFileName(viewModel.uri!!) + if (fileName == null) { + val d = java.util.Date() + fileName = "IMG_%tY%tm%td_%tH%tM%tS".format(d, d, d, d, d, d) + } + val dot = fileName.lastIndexOf('.') + if (dot != -1) + fileName = fileName.substring(0, dot) + fileName = "${fileName}_${image.width}x${image.height}.jpg" + put(MediaStore.MediaColumns.DISPLAY_NAME, fileName) + put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + put(MediaStore.MediaColumns.RELATIVE_PATH, + File(Environment.DIRECTORY_PICTURES, getString(R.string.app_name)).path) + } + } var errorMessage: String? = null val myUri = try { contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) - } catch(e: Exception) { + } catch (e: Exception) { Log.e("EditImage", "unexpected exception when saving!", e) null } @@ -490,9 +443,9 @@ throw IOException(getString(R.string.error_get_output)) } val quality = maxOf(0, minOf(100, - PreferenceManager.getDefaultSharedPreferences(applicationContext).getInt( - "jpeg_quality", 85))) - // Log.d("EditImage", "saving, jpeg_quality = $quality") + PreferenceManager.getDefaultSharedPreferences(applicationContext).getInt( + "jpeg_quality", 85))) + Log.d("EditImage", "saving, jpeg_quality = $quality") stream.use { if (!image.compress(Bitmap.CompressFormat.JPEG, quality, it)) { throw IOException(getString(R.string.error_save_bitmap)) @@ -509,7 +462,8 @@ runOnUiThread { binding.progressBar.visibility = ProgressBar.INVISIBLE if (errorMessage == null) { - callback(myUri!!) + viewModel.savedAs = myUri + doSaveOperation(requestCode, myUri!!) } else { showError(errorMessage) }