OSDN Git Service

とりあえずコミットその3。
[gokigen/ThetaView.git] / app / src / main / java / jp / osdn / gokigen / thetaview / camera / theta / status / ThetaCameraStatusWatcher.kt
1 package jp.osdn.gokigen.thetaview.camera.theta.status
2
3 import android.graphics.Color
4 import android.util.Log
5 import jp.osdn.gokigen.thetaview.scene.IIndicator
6 import jp.osdn.gokigen.thetaview.utils.communication.SimpleHttpClient
7 import org.json.JSONObject
8
9 class ThetaCameraStatusWatcher(private val sessionIdProvider: IThetaSessionIdProvider, private val captureModeReceiver : ICaptureModeReceiver, private val executeUrl : String = "http://192.168.1.1") : ICameraStatusWatcher, IThetaStatusHolder
10 {
11     private val httpClient = SimpleHttpClient()
12     private var whileFetching = false
13     private var currentIsoSensitivity : Int = 0
14     private var currentBatteryLevel : Double = 0.0
15     private var currentAperture : Double = 0.0
16     private var currentShutterSpeed : Double = 0.0
17     private var currentExposureCompensation : Double = 0.0
18     private var currentCaptureMode : String = ""
19     private var currentExposureProgram : String = ""
20     private var currentCaptureStatus : String = ""
21     private var currentWhiteBalance : String = ""
22     private var currentFilter : String = ""
23
24     private var showInformation: IIndicator? = null
25
26     override fun startStatusWatch(indicator : IIndicator?)
27     {
28         if (whileFetching)
29         {
30             Log.v(TAG, "startStatusWatch() already starting.")
31             return
32         }
33         showInformation = indicator
34         whileFetching = true
35
36         try
37         {
38             setMessage(IIndicator.Area.AREA_1, Color.WHITE, "")
39             setMessage(IIndicator.Area.AREA_2, Color.WHITE, "")
40             setMessage(IIndicator.Area.AREA_3, Color.WHITE, "")
41             setMessage(IIndicator.Area.AREA_4, Color.WHITE, "")
42             setMessage(IIndicator.Area.AREA_5, Color.WHITE, "")
43             setMessage(IIndicator.Area.AREA_6, Color.WHITE, "")
44             setMessage(IIndicator.Area.AREA_7, Color.WHITE, "")
45             setMessage(IIndicator.Area.AREA_8, Color.WHITE, "")
46             setMessage(IIndicator.Area.AREA_9, Color.WHITE, "")
47             setMessage(IIndicator.Area.AREA_10, Color.WHITE, "")
48             setMessage(IIndicator.Area.AREA_11, Color.WHITE, "")
49         }
50         catch (e : Exception)
51         {
52             e.printStackTrace()
53         }
54
55         try
56         {
57             val thread = Thread {
58                 try
59                 {
60                     val getOptionsUrl = "$executeUrl/osc/commands/execute"
61                     val getStateUrl = "$executeUrl/osc/state"
62
63                     val postDataCaptureMode = if (sessionIdProvider.sessionId.isEmpty()) "{\"name\":\"camera.getOptions\",\"parameters\":{\"timeout\":0, \"optionNames\" : [ \"captureMode\"] }}" else "{\"name\":\"camera.getOptions\",\"parameters\":{\"sessionId\": \"" + sessionIdProvider.sessionId + "\", \"optionNames\" : [ \"captureMode\" ] }}"
64                     val postDataImage = if (sessionIdProvider.sessionId.isEmpty()) "{\"name\":\"camera.getOptions\",\"parameters\":{\"timeout\":0, \"optionNames\" : [ \"aperture\",\"captureMode\",\"exposureCompensation\",\"exposureProgram\",\"iso\",\"shutterSpeed\",\"_filter\",\"whiteBalance\"] }}" else "{\"name\":\"camera.getOptions\",\"parameters\":{\"sessionId\": \"" + sessionIdProvider.sessionId + "\", \"optionNames\" : [ \"aperture\",\"captureMode\",\"exposureCompensation\",\"exposureProgram\",\"iso\",\"shutterSpeed\",\"_filter\",\"whiteBalance\"] }}"
65                     val postDataVideo = if (sessionIdProvider.sessionId.isEmpty()) "{\"name\":\"camera.getOptions\",\"parameters\":{\"timeout\":0, \"optionNames\" : [ \"aperture\",\"captureMode\",\"exposureCompensation\",\"exposureProgram\",\"iso\",\"shutterSpeed\",\"whiteBalance\"] }}" else "{\"name\":\"camera.getOptions\",\"parameters\":{\"sessionId\": \"" + sessionIdProvider.sessionId + "\", \"optionNames\" : [ \"aperture\",\"captureMode\",\"exposureCompensation\",\"exposureProgram\",\"iso\",\"shutterSpeed\",\"_filter\",\"whiteBalance\"] }}"
66                     Log.v(TAG, " >>>>> START STATUS WATCH : $getOptionsUrl")
67                     while (whileFetching)
68                     {
69                         val response0: String? = httpClient.httpPostWithHeader(getOptionsUrl, postDataCaptureMode, null, "application/json;charset=utf-8", timeoutMs)
70                         if (!(response0.isNullOrEmpty()))
71                         {
72                             // 設定データ受信、解析する
73                             checkStatus0(response0)
74                         }
75                         val postData = if (currentCaptureMode != "image") { postDataVideo } else { postDataImage }
76                         val response1: String? = httpClient.httpPostWithHeader(getOptionsUrl, postData, null, "application/json;charset=utf-8", timeoutMs)
77                         if (!(response1.isNullOrEmpty()))
78                         {
79                             // 設定データ受信、解析する
80                             checkStatus1(response1)
81                         }
82                         val response2: String? = httpClient.httpPostWithHeader(getStateUrl, "", null, "application/json;charset=utf-8", timeoutMs)
83                         if (!(response2.isNullOrEmpty()))
84                         {
85                             // ステータスデータ受信、解析する
86                             checkStatus2(response2)
87                         }
88                         try
89                         {
90                             // 表示を更新する
91                             invalidate()
92
93                             // ちょっと休む
94                             Thread.sleep(loopWaitMs)
95                         }
96                         catch (e: Exception)
97                         {
98                             e.printStackTrace()
99                         }
100                     }
101                 }
102                 catch (e: Exception)
103                 {
104                     e.printStackTrace()
105                 }
106             }
107             thread.start()
108         }
109         catch (e: Exception)
110         {
111             e.printStackTrace()
112         }
113     }
114
115     private fun checkStatus0(response: String)
116     {
117         try
118         {
119             //Log.v(TAG, " STATUS0 : $response")
120             val stateObject = JSONObject(response).getJSONObject("results").getJSONObject("options")
121             try
122             {
123                 val captureMode = stateObject.getString(THETA_CAPTURE_MODE)
124                 if (captureMode != currentCaptureMode)
125                 {
126                     Log.v(TAG, " CapMode : $currentCaptureMode -> $captureMode")
127                     currentCaptureMode = captureMode
128                     captureModeReceiver.changedCaptureMode(captureMode)
129                     setMessage(IIndicator.Area.AREA_2, Color.WHITE, "Capture Mode : $captureMode")
130                 }
131             }
132             catch (e: Exception)
133             {
134                 e.printStackTrace()
135             }
136         }
137         catch (e : Exception)
138         {
139             e.printStackTrace()
140         }
141     }
142
143     private fun checkStatus1(response: String)
144     {
145         try
146         {
147             //Log.v(TAG, " STATUS1 : $response")
148             val stateObject = JSONObject(response).getJSONObject("results").getJSONObject("options")
149             try
150             {
151                 val exposureCompensation = stateObject.getDouble(THETA_EXPOSURE_COMPENSATION)
152                 if (exposureCompensation != currentExposureCompensation)
153                 {
154                     Log.v(TAG, " XV : $currentExposureCompensation => $exposureCompensation")
155                     currentExposureCompensation = exposureCompensation
156                     if (currentExposureCompensation == 0.0)
157                     {
158                         // 補正なしの時には数値を表示しない
159                         setMessage(IIndicator.Area.AREA_7, Color.WHITE, "")
160                     }
161                     else
162                     {
163                         setMessage(IIndicator.Area.AREA_7, Color.WHITE, String.format("%1.1f", currentExposureCompensation))
164                     }
165                 }
166             }
167             catch (e: Exception)
168             {
169                 e.printStackTrace()
170             }
171
172             try
173             {
174                 val whiteBalance = stateObject.getString(THETA_WHITE_BALANCE)
175                 if (whiteBalance != currentWhiteBalance)
176                 {
177                     Log.v(TAG, " WB : $currentWhiteBalance => $whiteBalance")
178                     currentWhiteBalance = whiteBalance
179                     setMessage(IIndicator.Area.AREA_6, Color.WHITE, "WB : $currentWhiteBalance")
180                 }
181             }
182             catch (e: Exception)
183             {
184                 e.printStackTrace()
185             }
186
187             try
188             {
189                 val exposureProgram = stateObject.getString(THETA_EXPOSURE_PROGRAM)
190                 if (exposureProgram != currentExposureProgram)
191                 {
192                     Log.v(TAG, " ExpPrg : $currentExposureProgram -> $exposureProgram")
193                     currentExposureProgram = exposureProgram
194
195                     var mode = ""
196                     when (currentExposureProgram) {
197                         "1" -> mode = "Manual"
198                         "2" -> mode = "Normal"
199                         "3" -> mode = "Aperture"
200                         "4" -> mode = "Shutter"
201                         "9" -> mode = "ISO"
202                     }
203                     setMessage(IIndicator.Area.AREA_3, Color.WHITE, "Exposure Program : $mode")
204                 }
205             }
206             catch (e: Exception)
207             {
208                 e.printStackTrace()
209             }
210
211             if (currentCaptureMode == "image")
212             {
213                 try
214                 {
215                     val filterValue = stateObject.getString(THETA_FILTER)
216                     if (filterValue != currentFilter)
217                     {
218                         Log.v(TAG, " FILTER : $currentFilter -> $filterValue")
219                         currentFilter = filterValue
220                         setMessage(IIndicator.Area.AREA_5, Color.WHITE, "FILTER : $currentFilter")
221                     }
222                 }
223                 catch (e: Exception)
224                 {
225                     e.printStackTrace()
226                 }
227             }
228             else
229             {
230                 currentFilter = ""
231             }
232
233             try
234             {
235                 val isoSensitivity = stateObject.getInt(THETA_ISO_SENSITIVITY)
236                 if (isoSensitivity != currentIsoSensitivity)
237                 {
238                     Log.v(TAG, " ISO : $currentIsoSensitivity -> $isoSensitivity")
239                     currentIsoSensitivity = isoSensitivity
240                     if (currentIsoSensitivity == 0)
241                     {
242                         setMessage(IIndicator.Area.AREA_8, Color.WHITE, "ISO : AUTO")
243                     }
244                     else
245                     {
246                         setMessage(IIndicator.Area.AREA_8, Color.WHITE, "ISO : $currentIsoSensitivity")
247                     }
248                 }
249             }
250             catch (e: Exception)
251             {
252                 e.printStackTrace()
253             }
254
255             try
256             {
257                 val aperture = stateObject.getDouble(THETA_APERTURE)
258                 if (aperture != currentAperture)
259                 {
260                     Log.v(TAG, " A : $currentAperture -> $aperture")
261                     currentAperture = aperture
262                     if ((currentExposureProgram == "1")||(currentExposureProgram == "3"))
263                     {
264                         if (currentAperture == 0.0)
265                         {
266                             setMessage(IIndicator.Area.AREA_10, Color.WHITE, "F:auto")
267                         }
268                         else
269                         {
270                             setMessage(IIndicator.Area.AREA_10, Color.WHITE, "F$currentAperture")
271                         }
272                     }
273                 }
274             }
275             catch (e: Exception)
276             {
277                 e.printStackTrace()
278             }
279
280             try
281             {
282                 val shutterSpeed = stateObject.getDouble(THETA_SHUTTER_SPEED)
283                 if (shutterSpeed != currentShutterSpeed)
284                 {
285                     Log.v(TAG, " SS : $currentShutterSpeed -> $shutterSpeed")
286                     currentShutterSpeed = shutterSpeed
287                     if (currentShutterSpeed == 0.0)
288                     {
289                         setMessage(IIndicator.Area.AREA_9, Color.WHITE, "")
290                     }
291                     else
292                     {
293                         setMessage(IIndicator.Area.AREA_9, Color.WHITE, convertShutterSpeedString(currentShutterSpeed))
294                     }
295                 }
296             }
297             catch (e: Exception)
298             {
299                 e.printStackTrace()
300             }
301
302         }
303         catch (ee: Exception)
304         {
305             ee.printStackTrace()
306         }
307     }
308
309     private fun convertShutterSpeedString(shutterSpeed : Double) : String
310     {
311         var inv = 0.0
312         var stringValue = ""
313         try
314         {
315             if (shutterSpeed  < 1.0)
316             {
317                 inv = 1.0 / shutterSpeed
318             }
319             if (inv < 2.0) // if (inv < 10.0)
320             {
321                 inv = 0.0
322             }
323             if (inv > 0.0f)
324             {
325                 // シャッター速度を分数で表示する
326                 var intValue = inv.toInt()
327                 val modValue = intValue % 10
328                 if (modValue == 9 || modValue == 4)
329                 {
330                     // ちょっと格好が悪いけど...切り上げ
331                     intValue++
332                 }
333                 stringValue = "1/$intValue"
334             }
335             else
336             {
337                 // シャッター速度を数値(秒数)で表示する
338                 stringValue = "${shutterSpeed}s "
339             }
340         }
341         catch (e : Exception)
342         {
343             e.printStackTrace()
344         }
345         return (stringValue)
346     }
347
348     private fun checkStatus2(response: String)
349     {
350         try
351         {
352             //Log.v(TAG, " STATUS2 : $response")
353             val stateObject = JSONObject(response).getJSONObject("state")
354             try
355             {
356                 val captureStatus = stateObject.getString(THETA_CAPTURE_STATUS)
357                 if (captureStatus != currentCaptureStatus)
358                 {
359                     Log.v(TAG, " CapStatus : $currentCaptureStatus -> $captureStatus")
360                     setMessage(IIndicator.Area.AREA_4, Color.WHITE, "STATUS : $captureStatus")
361                     currentCaptureStatus = captureStatus
362                 }
363             }
364             catch (e: Exception)
365             {
366                 e.printStackTrace()
367             }
368             try
369             {
370                 val batteryLevel = stateObject.getDouble(THETA_BATTERY_LEVEL)
371                 if (batteryLevel != currentBatteryLevel)
372                 {
373                     Log.v(TAG, " BATTERY : $currentBatteryLevel => $batteryLevel")
374                     currentBatteryLevel = batteryLevel
375                     updateRemainBattery(currentBatteryLevel)
376                 }
377             }
378             catch (e: Exception)
379             {
380                 e.printStackTrace()
381             }
382
383         }
384         catch (ee: Exception)
385         {
386             ee.printStackTrace()
387         }
388     }
389
390     private fun updateRemainBattery(percentageDouble: Double)
391     {
392         var color = Color.WHITE
393         if (percentageDouble < 0.5)
394         {
395             color = Color.YELLOW
396         }
397         if (percentageDouble < 0.3)
398         {
399                 color = Color.RED
400         }
401         try
402         {
403             val percentage = kotlin.math.ceil(percentageDouble * 100.0).toInt()
404             setMessage(IIndicator.Area.AREA_1, color, "BATTERY : $percentage%")
405         }
406         catch (ee: java.lang.Exception)
407         {
408             ee.printStackTrace()
409         }
410     }
411
412     private fun setMessage(area: IIndicator.Area, color: Int, message: String)
413     {
414         if (showInformation != null)
415         {
416             showInformation?.setMessage(area, color, message)
417         }
418     }
419
420     private fun invalidate()
421     {
422         if (showInformation != null)
423         {
424             showInformation?.invalidate()
425         }
426     }
427
428     override fun stopStatusWatch()
429     {
430         whileFetching = false
431     }
432
433     companion object
434     {
435         private val TAG = ThetaCameraStatusWatcher::class.java.simpleName
436         private const val timeoutMs = 3300
437         private const val loopWaitMs : Long = 400
438
439         private const val THETA_BATTERY_LEVEL = "batteryLevel"
440         private const val THETA_CAPTURE_STATUS = "_captureStatus"
441
442 /*
443         private const val THETA_BLUETOOTH_ROLE  = "_bluetoothRole"
444         private const val THETA_BLUETOOTH_POWER = "_bluetoothPower"
445         private const val THETA_BLUETOOTH_CLASSIC_ENABLE  = "_bluetoothClassicEnable"
446
447         private const val THETA_RECORDING_SEC = "_recordedTime"
448         private const val THETA_BATTERY_STATE = "_batteryState"
449         private const val THETA_CURRENT_API_LEVEL = "_apiVersion"
450         private const val THETA_SHOOTING_FUNCTION = "_function"
451         private const val THETA_CAMERA_ERROR = "_cameraError"
452  */
453
454         private const val THETA_APERTURE = "aperture"
455         private const val THETA_CAPTURE_MODE = "captureMode"
456         private const val THETA_EXPOSURE_COMPENSATION = "exposureCompensation"
457         private const val THETA_EXPOSURE_PROGRAM = "exposureProgram"
458         private const val THETA_ISO_SENSITIVITY = "iso"
459         private const val THETA_SHUTTER_SPEED = "shutterSpeed"
460         private const val THETA_WHITE_BALANCE = "whiteBalance"
461         private const val THETA_FILTER = "_filter"
462     }
463
464     override var captureMode: String
465         get() = currentCaptureMode
466         set(value) { currentCaptureMode = value }
467 }