OSDN Git Service

アイコンを調整する。
[gokigen/PKRemote.git] / app / src / main / java / net / osdn / gokigen / pkremote / playback / MyContentDownloader.kt
1 package net.osdn.gokigen.pkremote.playback
2
3 import android.app.Activity
4 import android.app.AlertDialog
5 import android.app.ProgressDialog
6 import android.content.ContentValues
7 import android.content.Intent
8 import android.database.DatabaseUtils
9 import android.net.Uri
10 import android.os.Build
11 import android.os.Environment
12 import android.provider.MediaStore
13 import android.util.Log
14 import android.view.View
15 import androidx.preference.PreferenceManager
16 import com.google.android.material.snackbar.Snackbar
17 import net.osdn.gokigen.pkremote.R
18 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContent
19 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback
20 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl
21 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IProgressEvent
22 import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor
23 import java.io.File
24 import java.io.OutputStream
25 import java.text.SimpleDateFormat
26 import java.util.*
27
28 class MyContentDownloader(private val activity : Activity, private val playbackControl : IPlaybackControl, private val receiver : IContentDownloadNotify?) : IDownloadContentCallback
29 {
30     private lateinit var downloadDialog : ProgressDialog //= ProgressDialog(activity)
31     private val dumpLog = false
32     private var outputStream: OutputStream? = null
33     private var targetFileName = ""
34     private var filepath = ""
35     private var mimeType = "image/jpeg"
36     private var isDownloading = false
37     private var imageUri : Uri? = null
38
39     private fun getExternalOutputDirectory(): File
40     {
41         val directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/" + activity.getString(R.string.app_name2) + "/"
42         val target = File(directoryPath)
43         try
44         {
45             target.mkdirs()
46         }
47         catch (e: Exception)
48         {
49             e.printStackTrace()
50         }
51         Log.v(TAG, "  ----- RECORD Directory PATH : $directoryPath -----")
52         return (target)
53     }
54
55     private fun isExternalStorageWritable(): Boolean
56     {
57         return (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)
58     }
59
60     /**
61      * ダウンロードの開始
62      *
63      */
64     fun startDownload(fileInfo: ICameraContent?, appendTitle: String, replaceJpegSuffix: String?, requestSmallSize: Boolean)
65     {
66         if (fileInfo == null)
67         {
68             Log.v(TAG, "startDownload() ICameraFileInfo is NULL...")
69             return
70         }
71
72         // Download the image.
73         var isSmallSize = requestSmallSize
74         try
75         {
76             isDownloading = true
77             var contentFileName = fileInfo.contentName.toUpperCase(Locale.US)
78             if (replaceJpegSuffix != null)
79             {
80                 contentFileName = contentFileName.replace(JPEG_SUFFIX, replaceJpegSuffix)
81                 targetFileName = contentFileName
82             }
83             else
84             {
85                 targetFileName = fileInfo.originalName.toUpperCase(Locale.US)
86             }
87             Log.v(TAG, "startDownload() $targetFileName")
88             when {
89                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_1) -> {
90                     mimeType = "image/x-adobe-dng"
91                     isSmallSize = false
92                 }
93                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_2) -> {
94                     mimeType = "image/x-olympus-orf"
95                     isSmallSize = false
96                 }
97                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_3) -> {
98                     mimeType = "image/x-pentax-pef"
99                     isSmallSize = false
100                 }
101                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_4) -> {
102                     mimeType = "image/x-panasonic-rw2"
103                     isSmallSize = false
104                 }
105                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_A) -> {
106                     // Panasonic
107                     mimeType = "image/x-panasonic-raw"
108                     isSmallSize = false
109                 }
110                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_5) -> {
111                     mimeType = "image/x-sony-arw"
112                     isSmallSize = false
113                 }
114                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_6) -> {
115                     mimeType = "image/x-canon-crw"
116                     isSmallSize = false
117                 }
118                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_7) -> {
119                     mimeType = "image/x-canon-cr2"
120                     isSmallSize = false
121                 }
122                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_8) -> {
123                     mimeType = "image/x-canon-cr3"
124                     isSmallSize = false
125                 }
126                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_9) -> {
127                     mimeType = "image/x-nikon-nef"
128                     isSmallSize = false
129                 }
130                 contentFileName.toUpperCase(Locale.US).contains(RAW_SUFFIX_0) -> {
131                     mimeType = "image/x-fuji-raf"
132                     isSmallSize = false
133                 }
134                 contentFileName.toUpperCase(Locale.US).contains(MOVIE_SUFFIX) -> {
135                     mimeType = "video/mp4"
136                     isSmallSize = false
137                 }
138                 contentFileName.toUpperCase(Locale.US).contains(MOVIE_SUFFIX_MP4) -> {
139                     mimeType = "video/mp4"
140                     isSmallSize = false
141                 }
142                 else -> {
143                     mimeType = "image/jpeg"
144                 }
145             }
146
147             ////// ダイアログの表示
148             activity.runOnUiThread {
149                 if (!::downloadDialog.isInitialized)
150                 {
151                     downloadDialog = ProgressDialog(activity)
152                 }
153                 downloadDialog.setTitle(activity.getString(R.string.dialog_download_file_title) + appendTitle)
154                 downloadDialog.setMessage(activity.getString(R.string.dialog_download_message) + " " + targetFileName)
155                 downloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
156                 downloadDialog.setCancelable(false)
157                 downloadDialog.show()
158             }
159             val resolver = activity.contentResolver
160             val directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + File.separator + activity.getString(R.string.app_name2)
161             val calendar = Calendar.getInstance()
162             val extendName = SimpleDateFormat("yyyyMMdd-HHmmss", Locale.getDefault()).format(calendar.time)
163             val periodPosition = targetFileName.indexOf(".")
164             val extension = targetFileName.substring(periodPosition)
165             val baseFileName = targetFileName.substring(0, periodPosition)
166             val outputFileName = baseFileName + "_" + extendName + extension
167
168
169             val values = ContentValues()
170             values.put(MediaStore.Images.Media.TITLE, outputFileName)
171             values.put(MediaStore.Images.Media.DISPLAY_NAME, outputFileName)
172             values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
173             val extStorageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
174                 values.put(MediaStore.Images.Media.RELATIVE_PATH, directoryPath)
175                 values.put(MediaStore.Images.Media.IS_PENDING, true)
176                 MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
177             } else {
178                 values.put(MediaStore.Images.Media.DATA, getExternalOutputDirectory().absolutePath + File.separator + outputFileName)
179                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI
180             }
181             imageUri = resolver.insert(extStorageUri, values)
182             if (imageUri != null)
183             {
184                 ////////////////////////////////////////////////////////////////
185                 if (dumpLog)
186                 {
187                     if (imageUri != null)
188                     {
189                         val cursor = resolver.query(imageUri!!, null, null, null, null)
190                         DatabaseUtils.dumpCursor(cursor)
191                         cursor?.close()
192                     }
193                 }
194                 ////////////////////////////////////////////////////////////////
195
196                 try
197                 {
198                     outputStream = resolver.openOutputStream(imageUri!!)
199                     val path = fileInfo.contentPath + "/" + contentFileName
200                     Log.v(TAG, "downloadContent : $path (small: $isSmallSize)")
201                     playbackControl.downloadContent(path, isSmallSize, this)
202                 }
203                 catch (e: Exception)
204                 {
205                     e.printStackTrace()
206                     val message = e.message
207                     activity.runOnUiThread {
208                         downloadDialog.dismiss()
209                         isDownloading = false
210                         presentMessage(activity.getString(R.string.download_control_save_failed), message)
211
212                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
213                         {
214                             values.put(MediaStore.Images.Media.IS_PENDING, false)
215                             if (imageUri != null)
216                             {
217                                 resolver.update(imageUri!!, values, null, null)
218                             }
219                         }
220                     }
221                 }
222
223             }
224         }
225         catch (t: Throwable)
226         {
227             t.printStackTrace()
228             dismiss()
229         }
230     }
231
232     private fun dismiss()
233     {
234         activity.runOnUiThread {
235             try
236             {
237                 downloadDialog.dismiss()
238             }
239             catch (e: Exception)
240             {
241                 e.printStackTrace()
242             }
243             isDownloading = false
244         }
245     }
246
247     override fun onProgress(bytes: ByteArray?, length: Int, progressEvent: IProgressEvent)
248     {
249         try
250         {
251             val percent = (progressEvent.progress * 100.0f).toInt()
252             downloadDialog.progress = percent
253             if ((outputStream != null)&&(bytes != null)&&(length > 0))
254             {
255                 outputStream?.write(bytes, 0, length)
256             }
257         }
258         catch (e: Exception)
259         {
260             e.printStackTrace()
261         }
262     }
263
264     override fun onCompleted()
265     {
266         try
267         {
268             outputStream?.flush()
269             outputStream?.close()
270
271             if (imageUri != null)
272             {
273                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
274                 {
275                     val values = ContentValues()
276                     val resolver = activity.contentResolver
277                     values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
278                     values.put(MediaStore.Images.Media.DATA, filepath)
279                     values.put(MediaStore.Images.Media.IS_PENDING, false)
280                     resolver.update(imageUri!!, values, null, null)
281                 }
282             }
283             try
284             {
285
286                 if (imageUri != null)
287                 {
288                     activity.runOnUiThread {
289                         val preferences = PreferenceManager.getDefaultSharedPreferences(activity)
290                         if (preferences.getBoolean(IPreferencePropertyAccessor.SHARE_AFTER_SAVE, false))
291                         {
292                             shareContent(imageUri, mimeType)
293                         }
294                         try
295                         {
296                             receiver?.downloadedImage(targetFileName, imageUri)
297                         }
298                         catch (e: Exception)
299                         {
300                             e.printStackTrace()
301                         }
302                     }
303                 }
304             }
305             catch (e: Exception)
306             {
307                 e.printStackTrace()
308             }
309             activity.runOnUiThread {
310                 downloadDialog.dismiss()
311                 isDownloading = false
312                 val view = activity.findViewById<View>(R.id.fragment1)
313                 Snackbar.make(view, activity.getString(R.string.download_control_save_success) + " " + targetFileName, Snackbar.LENGTH_SHORT).show()
314                 System.gc()
315             }
316         }
317         catch (e: Exception)
318         {
319             val message = e.message
320             activity.runOnUiThread {
321                 downloadDialog.dismiss()
322                 isDownloading = false
323                 presentMessage(activity.getString(R.string.download_control_save_failed), message)
324             }
325         }
326         System.gc()
327     }
328
329     override fun onErrorOccurred(e: Exception)
330     {
331         isDownloading = false
332         val message = e.message
333         try
334         {
335             e.printStackTrace()
336             if (outputStream != null)
337             {
338                 outputStream?.flush()
339                 outputStream?.close()
340             }
341         }
342         catch (ex: Exception)
343         {
344             ex.printStackTrace()
345         }
346         activity.runOnUiThread {
347             downloadDialog.dismiss()
348             isDownloading = false
349             presentMessage(activity.getString(R.string.download_control_download_failed), message)
350         }
351         System.gc()
352     }
353
354     fun isDownloading(): Boolean
355     {
356         return isDownloading
357     }
358
359     /**
360      * 共有の呼び出し
361      *
362      * @param fileUri  ファイルUri
363      */
364     private fun shareContent(fileUri: Uri?, contentType: String)
365     {
366         val intent = Intent()
367         intent.action = Intent.ACTION_SEND
368         try
369         {
370             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
371             intent.type = contentType // "video/mp4"  or "image/jpeg"  or "image/x-adobe-dng"
372             intent.putExtra(Intent.EXTRA_STREAM, fileUri)
373             activity.startActivityForResult(intent, 0)
374         }
375         catch (e: Exception)
376         {
377             e.printStackTrace()
378         }
379     }
380
381     private fun presentMessage(title: String, message: String?)
382     {
383         activity.runOnUiThread {
384             val builder = AlertDialog.Builder(activity)
385             builder.setTitle(title).setMessage(message)
386             builder.show()
387         }
388     }
389
390     companion object
391     {
392         private val TAG = this.toString()
393         private const val RAW_SUFFIX_1 = ".DNG" // RAW: Ricoh / Pentax
394         private const val RAW_SUFFIX_2 = ".ORF" // RAW: Olympus
395         private const val RAW_SUFFIX_3 = ".PEF" // RAW: Pentax
396         private const val RAW_SUFFIX_4 = ".RW2" // RAW: Panasonic
397         private const val RAW_SUFFIX_5 = ".ARW" // RAW: Sony
398         private const val RAW_SUFFIX_6 = ".CRW" // RAW: Canon
399         private const val RAW_SUFFIX_7 = ".CR2" // RAW: Canon
400         private const val RAW_SUFFIX_8 = ".CR3" // RAW: Canon
401         private const val RAW_SUFFIX_9 = ".NEF" // RAW: Nikon
402         private const val RAW_SUFFIX_0 = ".RAF" // RAW: Fuji
403         private const val RAW_SUFFIX_A = ".RAW" // RAW: Panasonic
404         private const val MOVIE_SUFFIX = ".MOV"
405         private const val MOVIE_SUFFIX_MP4 = ".MP4"
406         private const val JPEG_SUFFIX = ".JPG"
407     }
408
409 }