1 package jp.osdn.gokigen.gokigenassets.utils.imagefile
3 import android.content.ContentValues
4 import android.database.DatabaseUtils
6 import android.os.Build
7 import android.os.Environment
8 import android.provider.MediaStore
9 import android.util.Log
10 import android.widget.Toast
11 import androidx.annotation.RequiresApi
12 import androidx.camera.core.ImageCapture
13 import androidx.camera.core.ImageCaptureException
14 import androidx.core.content.ContextCompat
15 import androidx.fragment.app.FragmentActivity
16 import jp.osdn.gokigen.gokigenassets.constants.IStringResourceConstantConvert.Companion.ID_LABEL_APP_LOCATION
17 import jp.osdn.gokigen.gokigenassets.constants.IStringResourceConstantConvert.Companion.ID_MESSAGE_LABEL_CAPTURE_SUCCESS
18 import jp.osdn.gokigen.gokigenassets.constants.IPreferenceConstantConvert.Companion.ID_PREFERENCE_EXTERNAL_STORAGE_LOCATION
19 import jp.osdn.gokigen.gokigenassets.constants.IPreferenceConstantConvert.Companion.ID_PREFERENCE_EXTERNAL_STORAGE_LOCATION_DEFAULT_VALUE
20 import jp.osdn.gokigen.gokigenassets.preference.PreferenceAccessWrapper
22 import java.io.OutputStream
23 import java.text.SimpleDateFormat
26 @RequiresApi(api = Build.VERSION_CODES.Q)
27 class ImageStoreExternal(private val context: FragmentActivity) : IImageStore, IImageStoreGrant
29 private fun getExternalOutputDirectory(): String
32 var prefString : String? = ""
35 prefString = PreferenceAccessWrapper(context).getString(ID_PREFERENCE_EXTERNAL_STORAGE_LOCATION, ID_PREFERENCE_EXTERNAL_STORAGE_LOCATION_DEFAULT_VALUE)
36 uriString = Uri.decode(prefString)
37 if (uriString.isEmpty())
39 // 設定がない場合はデフォルトの場所に...
40 @Suppress("DEPRECATION")
41 uriString = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/" + context.getString(ID_LABEL_APP_LOCATION) + "/"
51 File(uriString).mkdirs()
57 Log.v(TAG, " ----- RECORD Directory PATH : ${uriString} : ${prefString} -----")
61 override fun takePhoto(id : Int, imageCapture : ImageCapture?) : Boolean {
62 if ((!isExternalStorageWritable()) || (imageCapture == null)) {
63 Log.v(TAG, " takePhotoExternal() : cannot write image to external.")
66 Log.v(TAG, " takePhotoExternal()")
68 val outputDirString = getExternalOutputDirectory()
69 if (outputDirString.isEmpty()) {
72 val outputDir = File(outputDirString)
73 val resolver = context.contentResolver
75 val mimeType = "image/jpeg"
76 val now = System.currentTimeMillis()
78 Environment.DIRECTORY_DCIM + File.separator + context.getString(ID_LABEL_APP_LOCATION) // Environment.DIRECTORY_PICTURES + File.separator + "gokigen" //"DCIM/aira01a/"
79 val photoFile = "P" + SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(now) + "_" + id + ".jpg"
81 val extStorageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
82 val values = ContentValues()
83 values.put(MediaStore.Images.Media.TITLE, photoFile)
84 values.put(MediaStore.Images.Media.DISPLAY_NAME, photoFile)
85 values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
86 values.put(MediaStore.Images.Media.RELATIVE_PATH, path)
87 values.put(MediaStore.Images.Media.IS_PENDING, true)
88 @Suppress("DEPRECATION")
89 values.put(MediaStore.Images.Media.DATA, outputDir.absolutePath + File.separator + photoFile)
91 var imageUri: Uri? = null
94 imageUri = resolver.insert(extStorageUri, values)
100 if (imageUri == null)
105 /////////////////////////////
106 Log.v(TAG, " ===== imageUri : $imageUri =====")
107 val cursor = resolver.query(imageUri, null, null, null, null)
108 DatabaseUtils.dumpCursor(cursor)
110 /////////////////////////////
112 var openStream : OutputStream? = null
115 openStream = resolver.openOutputStream(imageUri)
117 catch (e : Exception)
119 values.put(MediaStore.Images.Media.IS_PENDING, false)
120 resolver.update(imageUri, values, null, null)
126 if (openStream != null)
128 val outputOptions = ImageCapture.OutputFileOptions.Builder(openStream).build()
129 imageCapture.takePicture(
131 ContextCompat.getMainExecutor(context),
132 object : ImageCapture.OnImageSavedCallback {
133 override fun onError(e: ImageCaptureException) {
134 Log.e(TAG, "Photo capture failed: ${e.message} ", e)
135 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
137 values.put(MediaStore.Images.Media.IS_PENDING, false)
138 resolver.update(imageUri, values, null, null)
143 override fun onImageSaved(output: ImageCapture.OutputFileResults) {
144 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
146 values.put(MediaStore.Images.Media.IS_PENDING, false)
147 resolver.update(imageUri, values, null, null)
149 val msg = context.getString(ID_MESSAGE_LABEL_CAPTURE_SUCCESS) + " $path/$photoFile"
150 Toast.makeText(context.baseContext, msg, Toast.LENGTH_SHORT).show()
152 // context.findViewById<androidx.constraintlayout.widget.ConstraintLayout>(
153 // ID_MAIN_ACTIVITY_LAYOUT
154 // ), msg, Snackbar.LENGTH_SHORT
162 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
165 values.put(MediaStore.Images.Media.IS_PENDING, false)
166 resolver.update(imageUri, values, null, null)
170 catch (e : Exception)
177 override fun grantStoreImage()
182 private fun isExternalStorageWritable(): Boolean
184 return (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)
188 private fun isExternalStorageReadable(): Boolean
190 return (Environment.getExternalStorageState() in setOf(
191 Environment.MEDIA_MOUNTED,
192 Environment.MEDIA_MOUNTED_READ_ONLY
199 private val TAG = ImageStoreExternal::class.java.simpleName
200 private const val FILENAME_FORMAT = "yyyyMMdd_HHmmss"