OSDN Git Service

11e8c02f9a5af5df27b3c6bb0e563bc351ed7a56
[gokigen/ThetaView.git] / app / src / main / java / jp / osdn / gokigen / thetaview / liveview / storeimage / StoreImage.kt
1 package jp.osdn.gokigen.thetaview.liveview.storeimage
2
3 import android.content.ContentValues
4 import android.database.DatabaseUtils
5 import android.graphics.Bitmap
6 import android.os.Build
7 import android.os.Environment
8 import android.provider.MediaStore
9 import android.util.Log
10 import androidx.fragment.app.FragmentActivity
11 import jp.osdn.gokigen.thetaview.R
12 import jp.osdn.gokigen.thetaview.liveview.image.IImageProvider
13 import jp.osdn.gokigen.thetaview.preference.IPreferencePropertyAccessor
14 import jp.osdn.gokigen.thetaview.preference.PreferenceAccessWrapper
15
16 import java.io.File
17 import java.io.FileOutputStream
18 import java.text.SimpleDateFormat
19 import java.util.*
20
21 class StoreImage(private val context: FragmentActivity, private val imageProvider: IImageProvider, private val dumpLog : Boolean = false) : IStoreImage
22 {
23
24     override fun doStore(target: Bitmap?)
25     {
26         try
27         {
28             // 保存処理(プログレスダイアログ(「保存中...」)を表示
29
30             val bitmapToStore = target ?: imageProvider.getImage()
31             val isLocalLocation  = PreferenceAccessWrapper(context).getBoolean(IPreferencePropertyAccessor.PREFERENCE_SAVE_LOCAL_LOCATION, IPreferencePropertyAccessor.PREFERENCE_SAVE_LOCAL_LOCATION_DEFAULT_VALUE)
32             if (isLocalLocation)
33             {
34                 saveImageLocal(bitmapToStore)
35             }
36             else
37             {
38                 saveImageExternal(bitmapToStore)
39             }
40
41             // 保存処理(プログレスダイアログ(「保存中...」)を削除
42         }
43         catch (t: Throwable)
44         {
45             t.printStackTrace()
46         }
47     }
48
49     private fun storeImageImpl(target: Bitmap)
50     {
51 /*
52         // 保存処理(プログレスダイアログ(「保存中...」)を表示して処理する)
53         val saveDialog = ProgressDialog(context)
54         saveDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER)
55         saveDialog.setMessage(context!!.getString(R.string.data_saving))
56         saveDialog.isIndeterminate = true
57         saveDialog.setCancelable(false)
58         saveDialog.show()
59         val thread = Thread {
60             System.gc()
61             saveImageImpl(target)
62             System.gc()
63             saveDialog.dismiss()
64         }
65         try
66         {
67             thread.start()
68         }
69         catch (t: Throwable)
70         {
71             t.printStackTrace()
72             System.gc()
73         }
74 */
75         try
76         {
77             val isLocalLocation  = PreferenceAccessWrapper(context).getBoolean(IPreferencePropertyAccessor.PREFERENCE_SAVE_LOCAL_LOCATION, IPreferencePropertyAccessor.PREFERENCE_SAVE_LOCAL_LOCATION_DEFAULT_VALUE)
78             if (isLocalLocation)
79             {
80                 saveImageLocal(target)
81             }
82             else
83             {
84                 saveImageExternal(target)
85             }
86         }
87         catch (t: Throwable)
88         {
89             t.printStackTrace()
90         }
91     }
92
93     private fun prepareLocalOutputDirectory(): File
94     {
95         val mediaDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
96         mediaDir?.mkdirs()
97         return (if (mediaDir != null && mediaDir.exists()) mediaDir else context.filesDir)
98     }
99
100     /**
101      * ビットマップイメージをファイルに出力する
102      *
103      * @param targetImage  出力するビットマップイメージ
104      */
105     private fun saveImageLocal(targetImage: Bitmap)
106     {
107         try
108         {
109             val fileName = "L" + SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()) + ".jpg"
110             val photoFile = File(prepareLocalOutputDirectory(), fileName)
111             val outputStream = FileOutputStream(photoFile)
112             targetImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
113             outputStream.flush()
114             outputStream.close()
115         }
116         catch (t: Throwable)
117         {
118             t.printStackTrace()
119         }
120     }
121
122     private fun getExternalOutputDirectory(): File
123     {
124         @Suppress("DEPRECATION") val directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/" + context.getString(R.string.app_location) + "/"
125         val target = File(directoryPath)
126         try
127         {
128             target.mkdirs()
129         }
130         catch (e: Exception)
131         {
132             e.printStackTrace()
133         }
134         if (dumpLog)
135         {
136             Log.v(TAG, "  ----- RECORD Directory PATH : $directoryPath -----")
137         }
138         return (target)
139     }
140
141     /**
142      * ビットマップイメージを外部ストレージのファイルに出力する
143      *
144      * @param targetImage  出力するビットマップイメージ
145      */
146     private fun saveImageExternal(targetImage: Bitmap)
147     {
148         try
149         {
150             if (!isExternalStorageWritable())
151             {
152
153                 saveImageLocal(targetImage)
154                 return
155             }
156
157             val outputDir = getExternalOutputDirectory()
158             val resolver = context.contentResolver
159             val mimeType = "image/jpeg"
160             val now = System.currentTimeMillis()
161             val path = Environment.DIRECTORY_DCIM + File.separator + context.getString(R.string.app_location) // Environment.DIRECTORY_PICTURES  + File.separator + "gokigen" //"DCIM/aira01a/"
162             val fileName = "L" + SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(now) + ".jpg"
163
164             val values = ContentValues()
165             values.put(MediaStore.Images.Media.TITLE, fileName)
166             values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
167             values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
168             val extStorageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
169                 values.put(MediaStore.Images.Media.RELATIVE_PATH, path)
170                 values.put(MediaStore.Images.Media.IS_PENDING, true)
171                 MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
172             } else {
173                 @Suppress("DEPRECATION")
174                 values.put(MediaStore.Images.Media.DATA, outputDir.absolutePath + File.separator + fileName)
175                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI
176             }
177             val imageUri = resolver.insert(extStorageUri, values)
178             if (imageUri != null)
179             {
180                 //resolver.update(imageUri, values, null, null)
181                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
182                 {
183                     Log.v(TAG, "  ===== StorageOperationWithPermission() : $imageUri =====")
184                     //StorageOperationWithPermission(context).requestAndroidRMediaPermission(imageUri)
185                 }
186
187                 ////////////////////////////////////////////////////////////////
188                 if (dumpLog)
189                 {
190                     val cursor = resolver.query(imageUri, null, null, null, null)
191                     DatabaseUtils.dumpCursor(cursor)
192                     cursor!!.close()
193                 }
194                 ////////////////////////////////////////////////////////////////
195
196                 val outputStream = resolver.openOutputStream(imageUri)
197                 if (outputStream != null)
198                 {
199                     targetImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
200                     outputStream.flush()
201                     outputStream.close()
202                 }
203                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
204                 {
205                     values.put(MediaStore.Images.Media.IS_PENDING, false)
206                     resolver.update(imageUri, values, null, null)
207
208                 }
209             }
210         }
211         catch (t: Throwable)
212         {
213             t.printStackTrace()
214         }
215     }
216
217     private fun isExternalStorageWritable(): Boolean
218     {
219         return (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)
220     }
221
222     companion object
223     {
224         private val  TAG = this.toString()
225         private const val FILENAME_FORMAT = "yyyyMMdd_HHmmss"
226     }
227
228 }