OSDN Git Service

ロータリー入力に対応。
[gokigen/A01c.git] / wear / src / main / java / jp / sfjp / gokigen / a01c / ManinActivity.kt
1 package jp.sfjp.gokigen.a01c
2
3 import android.Manifest
4 import android.content.ActivityNotFoundException
5 import android.content.Intent
6 import android.content.pm.PackageManager
7 import android.graphics.Color
8 import android.os.*
9 import android.provider.Settings
10 import android.util.Log
11 import android.view.MotionEvent
12 import android.view.View
13 import android.view.ViewConfiguration
14 import android.view.WindowManager
15 import android.widget.ImageButton
16 import android.widget.TextView
17 import android.widget.Toast
18 import androidx.appcompat.app.AppCompatActivity
19 import androidx.core.app.ActivityCompat
20 import androidx.core.content.ContextCompat
21 import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
22 import androidx.core.view.InputDeviceCompat
23 import androidx.core.view.MotionEventCompat
24 import androidx.core.view.ViewConfigurationCompat
25 import androidx.core.widget.NestedScrollView
26 import androidx.preference.PreferenceManager
27 import jp.sfjp.gokigen.a01c.IShowInformation.operation
28 import jp.sfjp.gokigen.a01c.liveview.*
29 import jp.sfjp.gokigen.a01c.liveview.dialog.FavoriteSettingSelectionDialog
30 import jp.sfjp.gokigen.a01c.liveview.dialog.IDialogDismissedNotifier
31 import jp.sfjp.gokigen.a01c.liveview.glview.GokigenGLView
32 import jp.sfjp.gokigen.a01c.olycamerawrapper.OlyCameraCoordinator
33 import jp.sfjp.gokigen.a01c.preference.IPreferenceCameraPropertyAccessor
34 import jp.sfjp.gokigen.a01c.preference.PreferenceAccessWrapper
35 import jp.sfjp.gokigen.a01c.thetacamerawrapper.ThetaCameraController
36 import jp.sfjp.gokigen.a01c.utils.GestureParser
37 import kotlin.math.roundToInt
38
39 /**
40  * メインのActivity
41  *
42  */
43 class MainActivity : AppCompatActivity(), IChangeScene, IShowInformation, ICameraStatusReceiver, IDialogDismissedNotifier, IWifiConnection
44 {
45     private lateinit var preferences: PreferenceAccessWrapper
46     private var liveView: CameraLiveImageView? = null
47     private var glView: GokigenGLView? = null
48     private var powerManager: PowerManager? = null
49     private var gestureParser: GestureParser? = null
50     private var currentCoordinator: ICameraController? = null
51     private var olyAirCoordinator: ICameraController? = null
52     private var thetaCoordinator: ICameraController? = null
53     private var messageDrawer: IMessageDrawer? = null
54     private var listener: CameraLiveViewOnTouchListener? = null
55     private var selectionDialog: FavoriteSettingSelectionDialog? = null
56     private var cameraDisconnectedHappened = false
57     private var wifiConnection: WifiConnection? = null
58     private var liveViewListener: CameraLiveViewListenerImpl? = null
59     private var enableGlView = false
60
61     /**
62      *
63      */
64     override fun onCreate(savedInstanceState: Bundle?)
65     {
66         Log.v(TAG, "onCreate()")
67         super.onCreate(savedInstanceState)
68         try
69         {
70             ///////// SHOW SPLASH SCREEN /////////
71             installSplashScreen()
72         }
73         catch (e: Exception)
74         {
75             e.printStackTrace()
76         }
77
78         //  画面全体の設定
79         setContentView(R.layout.activity_main)
80         supportActionBar?.hide()
81         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
82
83         try
84         {
85             if (!hasGps())
86             {
87                 // GPS機能が搭載されていない場合...ログに出力する
88                 Log.d(TAG, " ----- This hardware doesn't have GPS.")
89             }
90             // パワーマネージャをつかまえる
91             powerManager = getSystemService(POWER_SERVICE) as PowerManager
92
93             setupCameraCoordinator()
94             setupInitialButtonIcons()
95             setupActionListener()
96         }
97         catch (e: Exception)
98         {
99             e.printStackTrace()
100         }
101
102         try
103         {
104             if (allPermissionsGranted())
105             {
106                 wifiConnection = WifiConnection(this, this)
107                 wifiConnection?.requestNetwork()
108             }
109             else
110             {
111                 Log.v(TAG, ">>> Request Permissions...")
112                 ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
113             }
114         }
115         catch (ex: Exception)
116         {
117             ex.printStackTrace()
118         }
119     }
120
121     private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
122         ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
123     }
124
125     /**
126      *
127      */
128     override fun onResume()
129     {
130         super.onResume()
131         Log.v(TAG, "onResume()")
132         try
133         {
134             if (wifiConnection != null)
135             {
136                 // ネットワークを要求する!
137                 wifiConnection?.requestNetwork()
138                 wifiConnection?.startWatchWifiStatus()
139             }
140         }
141         catch (e: Exception)
142         {
143             e.printStackTrace()
144         }
145     }
146
147     /**
148      *
149      */
150     override fun onPause()
151     {
152         super.onPause()
153         Log.v(TAG, "onPause()")
154     }
155
156     /**
157      *
158      *
159      */
160     public override fun onStart()
161     {
162         super.onStart()
163         Log.v(TAG, "onStart()")
164     }
165
166     /**
167      *
168      *
169      */
170     public override fun onStop()
171     {
172         super.onStop()
173         Log.v(TAG, "onStop()")
174         exitApplication()
175     }
176
177     /**
178      * ボタンが押された、画面がタッチされた、、は、リスナクラスで処理するよう紐づける
179      *
180      */
181     private fun setupActionListener()
182     {
183         try
184         {
185             Log.v(TAG, "setupActionListener()")
186             val btn1 = findViewById<ImageButton>(R.id.btn_1)
187             btn1.setOnClickListener(listener)
188             btn1.setOnLongClickListener(listener)
189             val btn2 = findViewById<ImageButton>(R.id.btn_2)
190             btn2.setOnClickListener(listener)
191             btn2.setOnLongClickListener(listener)
192             val btn3 = findViewById<ImageButton>(R.id.btn_3)
193             btn3.setOnClickListener(listener)
194             btn3.setOnLongClickListener(listener)
195             val btn4 = findViewById<ImageButton>(R.id.btn_4)
196             btn4.setOnClickListener(listener)
197             btn4.setOnLongClickListener(listener)
198             val btn5 = findViewById<ImageButton>(R.id.btn_5)
199             btn5.setOnClickListener(listener)
200             btn5.setOnLongClickListener(listener)
201             val btn6 = findViewById<ImageButton>(R.id.btn_6)
202             btn6.setOnClickListener(listener)
203             btn6.setOnLongClickListener(listener)
204             val textArea1 = findViewById<ImageButton>(R.id.btn_021)
205             textArea1.setOnClickListener(listener)
206             textArea1.setOnLongClickListener(listener)
207             val textArea2 = findViewById<ImageButton>(R.id.btn_022)
208             textArea2.setOnClickListener(listener)
209             textArea2.setOnLongClickListener(listener)
210             val textArea3 = findViewById<ImageButton>(R.id.btn_023)
211             textArea3.setOnClickListener(listener)
212             textArea3.setOnLongClickListener(listener)
213             val textArea4 = findViewById<ImageButton>(R.id.btn_024)
214             textArea4.setOnClickListener(listener)
215             textArea4.setOnLongClickListener(listener)
216             if (liveView == null)
217             {
218                 liveView = findViewById(R.id.liveview)
219             }
220             liveView?.setOnTouchListener(listener)
221             messageDrawer = liveView?.messageDrawer
222             messageDrawer?.setLevelGauge(currentCoordinator?.levelGauge)
223
224
225         }
226         catch (e: Exception)
227         {
228             e.printStackTrace()
229         }
230     }
231
232     /**
233      * ボタンアイコンの初期設定
234      *
235      */
236     private fun setupInitialButtonIcons()
237     {
238         try
239         {
240             if (currentCoordinator != null)
241             {
242                 val resId: Int
243                 val preferences = PreferenceManager.getDefaultSharedPreferences(this)
244                 resId = if (preferences.getBoolean(
245                         IPreferenceCameraPropertyAccessor.SHOW_GRID_STATUS,
246                         true
247                     )
248                 ) {
249                     // ボタンをGrid OFFアイコンにする
250                     R.drawable.btn_ic_grid_off
251                 } else {
252                     // ボタンをGrid ONアイコンにする
253                     R.drawable.btn_ic_grid_on
254                 }
255                 setButtonDrawable(IShowInformation.BUTTON_1, resId)
256             }
257         }
258         catch (e: Exception)
259         {
260             e.printStackTrace()
261         }
262     }
263
264     override fun onGenericMotionEvent(ev: MotionEvent?): Boolean
265     {
266         try
267         {
268             if ((ev?.action == MotionEvent.ACTION_SCROLL)&& (ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)))
269             {
270                 // ロータリー入力でスクロールする
271                 // Log.v(TAG, "Rotary Encoder Input")
272                 val view = findViewById<NestedScrollView>(R.id.main_screen)
273                 val delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
274                         ViewConfigurationCompat.getScaledVerticalScrollFactor(ViewConfiguration.get(this), this)
275                 view.scrollBy(0, delta.roundToInt())
276                 return (true)
277             }
278         }
279         catch (e: Exception)
280         {
281             e.printStackTrace()
282         }
283         return (super.onGenericMotionEvent(ev))
284     }
285
286     /**
287      * Intentを使ってWiFi設定画面を開く
288      *
289      */
290     private fun launchWifiSettingScreen(): Boolean
291     {
292         Log.v(TAG, "launchWifiSettingScreen() : ACTION_WIFI_SETTINGS")
293         try
294         {
295             // Wifi 設定画面を表示する
296             startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
297
298             return true
299         }
300         catch (ex: Exception)
301         {
302             try
303             {
304                 Log.v(TAG, "launchWifiSettingScreen() : ADD_NETWORK_SETTINGS")
305                 startActivity(Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"))
306                 return true
307             }
308             catch (e: Exception)
309             {
310                 Log.v(
311                     TAG,
312                     "android.content.ActivityNotFoundException... " + "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"
313                 )
314                 try {
315                     // SONY Smart Watch 3で開く場合のIntent...
316                     val intent =
317                         Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS")
318                     intent.setClassName(
319                         "com.google.android.apps.wearable.settings",
320                         "com.google.android.clockwork.settings.wifi.WifiSettingsActivity"
321                     )
322                     startActivity(intent)
323                     return true
324                 } catch (ex2: Exception) {
325                     try {
326                         // Wifi 設定画面を表示する...普通のAndroidの場合
327                         startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
328                         return true
329                     } catch (ee: Exception) {
330                         ee.printStackTrace()
331                         try {
332                             // LG G Watch Rで開く場合のIntent...
333                             val intent = Intent("android.intent.action.MAIN")
334                             intent.setClassName(
335                                 "com.google.android.apps.wearable.settings",
336                                 "com.google.android.clockwork.settings.MainSettingsActivity"
337                             )
338                             startActivity(intent)
339                             return true
340                         } catch (ex3: ActivityNotFoundException) {
341                             ex3.printStackTrace()
342                         }
343                     }
344                 }
345             }
346         }
347         return false
348     }
349
350     /**
351      * Olympus Cameraクラスとのやりとりをするクラスを準備する
352      * (カメラとの接続も、ここでスレッドを起こして開始する)
353      */
354     private fun setupCameraCoordinator()
355     {
356         try
357         {
358             preferences = PreferenceAccessWrapper(this)
359             preferences.initialize()
360             val connectionMethod = preferences.getString(
361                 IPreferenceCameraPropertyAccessor.CONNECTION_METHOD,
362                 IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE
363             )
364             if (liveView == null)
365             {
366                 liveView = findViewById(R.id.liveview)
367                 liveView?.visibility = View.VISIBLE
368             }
369             if (liveView != null)
370             {
371                 liveViewListener = CameraLiveViewListenerImpl(liveView!!)
372             }
373             if (glView == null)
374             {
375                 glView = findViewById(R.id.glview)
376             }
377             if (glView != null)
378             {
379                 if (gestureParser == null)
380                 {
381                     gestureParser = GestureParser(applicationContext, glView!!)
382                 }
383                 enableGlView = preferences.getBoolean(IPreferenceCameraPropertyAccessor.THETA_GL_VIEW, false)
384                 if (enableGlView && connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA))
385                 {
386                     // GL VIEW に切り替える
387                     glView?.setImageProvider(liveViewListener!!)
388                     glView?.visibility = View.VISIBLE
389                     liveView?.visibility = View.GONE
390                 }
391             }
392             olyAirCoordinator = OlyCameraCoordinator(this, liveView, this, this)
393             thetaCoordinator = ThetaCameraController(this, this, this)
394             currentCoordinator =
395                 if (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) thetaCoordinator else olyAirCoordinator
396             currentCoordinator?.setLiveViewListener(liveViewListener!!)
397             listener = CameraLiveViewOnTouchListener(
398                 this, currentCoordinator?.getFeatureDispatcher(
399                     this, this,
400                     currentCoordinator!!,
401                     preferences,
402                     liveView!!
403                 ), this
404             )
405             selectionDialog = FavoriteSettingSelectionDialog(
406                 this,
407                 currentCoordinator?.cameraPropertyLoadSaveOperations,
408                 this
409             )
410             connectToCamera()
411         } catch (e: Exception) {
412             e.printStackTrace()
413         }
414     }
415
416     /**
417      * カメラと接続する
418      *
419      */
420     private fun connectToCamera()
421     {
422         val thread = Thread { currentCoordinator?.connectionInterface?.connect() }
423         try
424         {
425             thread.start()
426         }
427         catch (e: Exception)
428         {
429             e.printStackTrace()
430         }
431     }
432
433     /**
434      * カメラの電源をOFFいして、アプリを抜ける処理
435      *
436      */
437     override fun exitApplication()
438     {
439         try {
440             Log.v(TAG, "exitApplication()")
441
442             // パワーマネージャを確認し、interactive modeではない場合は、ライブビューも止めず、カメラの電源も切らない
443             if (powerManager?.isInteractive != true)
444             {
445                 Log.v(TAG, "not interactive, keep liveview.")
446                 return
447             }
448
449             // ライブビューを停止させる
450             currentCoordinator?.stopLiveView()
451
452             // ステータス監視を止める
453             val watcher = currentCoordinator?.statusWatcher
454             watcher?.stopStatusWatch()
455
456             //  パラメータを確認し、カメラの電源を切る
457             if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
458                     IPreferenceCameraPropertyAccessor.EXIT_APPLICATION_WITH_DISCONNECT,
459                     true
460                 )
461             ) {
462                 Log.v(TAG, "Shutdown camera...")
463
464                 // カメラの電源をOFFにする
465                 currentCoordinator?.connectionInterface?.disconnect(true)
466             }
467             //finish();
468             //finishAndRemoveTask();
469             //android.os.Process.killProcess(android.os.Process.myPid());
470         } catch (e: Exception) {
471             e.printStackTrace()
472         }
473     }
474
475     /**
476      * 接続機能を確認する
477      */
478     override fun checkConnectionFeature(id: Int, btnId: Int): Boolean
479     {
480         var ret = false
481         if (id == 0)
482         {
483             // Wifi 設定画面を開く
484             ret = launchWifiSettingScreen()
485         } else if (id == 1) {
486             // 接続の変更を確認する
487             changeConnectionMethod()
488         }
489         return ret
490     }
491
492     /**
493      * 画面をタッチした場所を受信する
494      *
495      * @param posX  X座標位置 (0.0f - 1.0f)
496      * @param posY  Y座標位置 (0.0f - 1.0f)
497      * @return true / false
498      */
499     override fun touchedPosition(posX: Float, posY: Float): Boolean
500     {
501         Log.v(TAG, "touchedPosition ($posX, $posY)")
502         return (liveView?.touchedPosition(posX, posY) ?: false)
503     }
504
505     /**
506      * 接続状態を見る or 再接続する
507      */
508     override fun showConnectionStatus(): Boolean
509     {
510         try
511         {
512             if (listener?.isEnabledOperation == operation.ONLY_CONNECT && cameraDisconnectedHappened) {
513                 // カメラが切断されたとき、再接続を指示する
514                 connectToCamera()
515                 cameraDisconnectedHappened = false
516                 return true
517             }
518         }
519         catch (e: Exception)
520         {
521             e.printStackTrace()
522         }
523         return false
524     }
525
526     /**
527      *
528      */
529     override fun onStatusNotify(message: String)
530     {
531         setMessage(IShowInformation.AREA_C, Color.WHITE, message)
532     }
533
534     /**
535      *
536      */
537     override fun onCameraConnected()
538     {
539         Log.v(TAG, "onCameraConnected()")
540         try
541         {
542             // ライブビューの開始 & タッチ/ボタンの操作を可能にする
543             currentCoordinator?.connectFinished()
544             currentCoordinator?.startLiveView()
545             currentCoordinator?.setRecViewMode(false)
546             listener!!.setEnableOperation(operation.ENABLE)
547             setMessage(IShowInformation.AREA_C, Color.WHITE, "")
548             currentCoordinator?.updateStatusAll()
549             val watcher = currentCoordinator?.statusWatcher
550             watcher?.startStatusWatch()
551         }
552         catch (e: Exception)
553         {
554             e.printStackTrace()
555         }
556     }
557
558     /**
559      * カメラとの接続が切れたとき...何もしない
560      *
561      */
562     override fun onCameraDisconnected()
563     {
564         Log.v(TAG, "onCameraDisconnected()")
565         try
566         {
567             setMessage(
568                 IShowInformation.AREA_C,
569                 Color.YELLOW,
570                 getString(R.string.camera_disconnected)
571             )
572             listener?.setEnableOperation(operation.ONLY_CONNECT)
573             cameraDisconnectedHappened = true
574         }
575         catch (e: Exception)
576         {
577             e.printStackTrace()
578         }
579     }
580
581     /**
582      * カメラと接続失敗
583      */
584     override fun onCameraConnectError(message: String)
585     {
586         Log.v(TAG, "onCameraOccursException()")
587         try
588         {
589             setMessage(IShowInformation.AREA_C, Color.YELLOW, message)
590             listener?.setEnableOperation(operation.ONLY_CONNECT)
591             cameraDisconnectedHappened = true
592         }
593         catch (ee: Exception)
594         {
595             ee.printStackTrace()
596         }
597     }
598
599     /**
600      * カメラに例外発生
601      */
602     override fun onCameraOccursException(message: String, e: Exception)
603     {
604         Log.v(TAG, "onCameraOccursException()")
605         try
606         {
607             setMessage(IShowInformation.AREA_C, Color.YELLOW, message)
608             listener?.setEnableOperation(operation.ONLY_CONNECT)
609             cameraDisconnectedHappened = true
610         }
611         catch (ee: Exception)
612         {
613             e.printStackTrace()
614             ee.printStackTrace()
615         }
616     }
617
618     /**
619      * メッセージの表示
620      *
621      * @param area    表示エリア (AREA_1 ~ AREA_6, AREA_C)
622      * @param color  表示色
623      * @param message 表示するメッセージ
624      */
625     override fun setMessage(area: Int, color: Int, message: String)
626     {
627         var id = 0
628         when (area) {
629             IShowInformation.AREA_1 -> {
630                 id = R.id.text_1
631                 setMessage(IShowInformation.AREA_1_2, color, message)
632             }
633             IShowInformation.AREA_2 -> {
634                 id = R.id.text_2
635                 setMessage(IShowInformation.AREA_2_2, color, message)
636             }
637             IShowInformation.AREA_3 -> {
638                 id = R.id.text_3
639                 setMessage(IShowInformation.AREA_3_2, color, message)
640             }
641             IShowInformation.AREA_4 -> {
642                 id = R.id.text_4
643                 setMessage(IShowInformation.AREA_4_2, color, message)
644                 setMessage(IShowInformation.AREA_5_2, color, message)
645             }
646             IShowInformation.AREA_1_2 -> id = R.id.text_11
647             IShowInformation.AREA_2_2 -> id = R.id.text_12
648             IShowInformation.AREA_3_2 -> id = R.id.text_13
649             IShowInformation.AREA_4_2 -> id = R.id.text_14
650             IShowInformation.AREA_5_2 -> id = R.id.text_15
651             IShowInformation.AREA_NONE -> {}
652             else -> {}
653         }
654
655         if (messageDrawer != null)
656         {
657             if (area == IShowInformation.AREA_C)
658             {
659                 messageDrawer?.setMessageToShow(
660                     IMessageDrawer.MessageArea.CENTER,
661                     color,
662                     IMessageDrawer.SIZE_LARGE,
663                     message
664                 )
665                 return
666             }
667             if (area == IShowInformation.AREA_5)
668             {
669                 messageDrawer?.setMessageToShow(
670                     IMessageDrawer.MessageArea.UPLEFT,
671                     color,
672                     IMessageDrawer.SIZE_STD,
673                     message
674                 )
675                 return
676             }
677             if (area == IShowInformation.AREA_6)
678             {
679                 messageDrawer?.setMessageToShow(
680                     IMessageDrawer.MessageArea.LOWLEFT,
681                     color,
682                     IMessageDrawer.SIZE_STD,
683                     message
684                 )
685                 return
686             }
687             if (area == IShowInformation.AREA_7)
688             {
689                 messageDrawer?.setMessageToShow(
690                     IMessageDrawer.MessageArea.UPRIGHT,
691                     color,
692                     IMessageDrawer.SIZE_STD,
693                     message
694                 )
695                 return
696             }
697             if (area == IShowInformation.AREA_8)
698             {
699                 messageDrawer?.setMessageToShow(
700                     IMessageDrawer.MessageArea.LOWRIGHT,
701                     color,
702                     IMessageDrawer.SIZE_STD,
703                     message
704                 )
705                 return
706             }
707             if (area == IShowInformation.AREA_9)
708             {
709                 messageDrawer?.setMessageToShow(
710                     IMessageDrawer.MessageArea.UPCENTER,
711                     color,
712                     IMessageDrawer.SIZE_STD,
713                     message
714                 )
715                 return
716             }
717             if (area == IShowInformation.AREA_A)
718             {
719                 messageDrawer?.setMessageToShow(
720                     IMessageDrawer.MessageArea.LOWCENTER,
721                     color,
722                     IMessageDrawer.SIZE_STD,
723                     message
724                 )
725                 return
726             }
727             if (area == IShowInformation.AREA_B)
728             {
729                 messageDrawer?.setMessageToShow(
730                     IMessageDrawer.MessageArea.CENTERLEFT,
731                     color,
732                     IMessageDrawer.SIZE_STD,
733                     message
734                 )
735                 return
736             }
737             if (area == IShowInformation.AREA_D)
738             {
739                 messageDrawer?.setMessageToShow(
740                     IMessageDrawer.MessageArea.CENTERRIGHT,
741                     color,
742                     IMessageDrawer.SIZE_STD,
743                     message
744                 )
745                 return
746             }
747             if (id == 0)
748             {
749                 // 描画エリアが不定の場合...
750                 return
751             }
752         }
753         val areaId = id
754         runOnUiThread {
755             val textArea = findViewById<TextView>(areaId)
756             if (textArea != null)
757             {
758                 textArea.setTextColor(color)
759                 textArea.text = message
760                 textArea.invalidate()
761             }
762         }
763     }
764
765     /**
766      * ボタンの表示イメージを変更する
767      *
768      * @param button  ボタンの場所
769      * @param labelId 変更する内容
770      */
771     override fun setButtonDrawable(button: Int, labelId: Int)
772     {
773         val id = when (button)
774         {
775             IShowInformation.BUTTON_1 -> R.id.btn_1
776             IShowInformation.BUTTON_2 -> R.id.btn_2
777             IShowInformation.BUTTON_3 -> R.id.btn_3
778             IShowInformation.BUTTON_4 -> R.id.btn_4
779             IShowInformation.BUTTON_5 -> R.id.btn_5
780             IShowInformation.BUTTON_6 -> R.id.btn_6
781             IShowInformation.BUTTON_7 -> R.id.btn_025
782             IShowInformation.BUTTON_8 -> R.id.btn_026
783             else -> R.id.btn_6
784         }
785         runOnUiThread {
786             try
787             {
788                 val btn = findViewById<ImageButton>(id)
789                 val drawTarget = ContextCompat.getDrawable(applicationContext, labelId)
790                 if (btn != null)
791                 {
792                     btn.setImageDrawable(drawTarget)
793                     btn.invalidate()
794                 }
795             }
796             catch (e: Exception)
797             {
798                 e.printStackTrace()
799             }
800         }
801     }
802
803     /**
804      *
805      * @return true GPS搭載, false GPS非搭載
806      */
807     private fun hasGps(): Boolean
808     {
809         return (packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS))
810     }
811
812
813     /**
814      * タッチイベントをフックする
815      *
816      *
817      */
818     override fun dispatchTouchEvent(event: MotionEvent): Boolean
819     {
820         //Log.v(TAG, " dispatchTouchEvent() ");
821         if (enableGlView)
822         {
823             //Log.v(TAG, " onTouch() ");
824             gestureParser?.onTouch(event)
825         }
826         return (super.dispatchTouchEvent(event))
827     }
828
829     override fun vibrate(vibratePattern: Int)
830     {
831         try
832         {
833             // バイブレータをつかまえる
834             val vibrator  = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
835             {
836                 val vibratorManager =  this.getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
837                 vibratorManager.defaultVibrator
838             }
839             else
840             {
841                 @Suppress("DEPRECATION")
842                 getSystemService(VIBRATOR_SERVICE) as Vibrator
843             }
844             if (!vibrator.hasVibrator())
845             {
846                 Log.v(TAG, " not have Vibrator...")
847                 return
848             }
849             @Suppress("DEPRECATION") val thread = Thread {
850                 try
851                 {
852                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
853                     {
854                         vibrator.vibrate(VibrationEffect.createOneShot(30, VibrationEffect.DEFAULT_AMPLITUDE))
855                     }
856                     else
857                     {
858                         when (vibratePattern)
859                         {
860                             IShowInformation.VIBRATE_PATTERN_SIMPLE_SHORT -> vibrator.vibrate(30)
861                             IShowInformation.VIBRATE_PATTERN_SIMPLE_MIDDLE -> vibrator.vibrate(80)
862                             IShowInformation.VIBRATE_PATTERN_SIMPLE_LONG ->  vibrator.vibrate(150)
863                             IShowInformation.VIBRATE_PATTERN_SIMPLE_LONGLONG ->  vibrator.vibrate(300)
864                             IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE -> {
865                                 val pattern = longArrayOf(10, 35, 30, 35, 0)
866                                 vibrator.vibrate(pattern, -1)
867                             }
868                             else -> { }
869                         }
870                     }
871                 }
872                 catch (e : Exception)
873                 {
874                     e.printStackTrace()
875                 }
876             }
877             thread.start()
878         }
879         catch (e: java.lang.Exception)
880         {
881             e.printStackTrace()
882         }
883     }
884
885     override fun setEnabledOperation(operation: operation)
886     {
887         listener?.setEnableOperation(operation)
888     }
889
890     /**
891      * 「お気に入り設定」表示画面を開く
892      *
893      */
894     override fun showFavoriteSettingsDialog()
895     {
896         if ((liveView != null)&&(listener != null)&&(listener!!.isEnabledOperation != operation.ONLY_CONNECT))
897         {
898             listener?.setEnableOperation(operation.ENABLE_ONLY_TOUCHED_POSITION)
899             liveView?.showDialog(selectionDialog)
900         }
901     }
902
903     override fun showToast(rscId: Int, appendMessage: String, duration: Int)
904     {
905         try
906         {
907             runOnUiThread {
908                 try
909                 {
910                     val message = if (rscId != 0) getString(rscId) + appendMessage else appendMessage
911                     Toast.makeText(applicationContext, message, duration).show()
912                 }
913                 catch (e: Exception)
914                 {
915                     e.printStackTrace()
916                 }
917             }
918         }
919         catch (e: Exception)
920         {
921             e.printStackTrace()
922         }
923     }
924
925     override fun invalidate()
926     {
927         try
928         {
929             runOnUiThread { liveView?.invalidate() }
930         }
931         catch (e: Exception)
932         {
933             e.printStackTrace()
934         }
935     }
936
937     /**
938      * 「お気に入り設定」表示画面を閉じる
939      *
940      */
941     override fun dialogDismissed(isExecuted: Boolean)
942     {
943         try
944         {
945             if ((liveView != null) && (listener != null))
946             {
947                 liveView?.hideDialog()
948                 listener?.setEnableOperation(operation.ENABLE)
949             }
950         }
951         catch (e: Exception)
952         {
953             e.printStackTrace()
954         }
955     }
956
957     private fun updateConnectionMethodMessage()
958     {
959         try
960         {
961             val connectionMethod = preferences.getString(
962                 IPreferenceCameraPropertyAccessor.CONNECTION_METHOD,
963                 IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE
964             )
965             val methodId = if (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) R.string.connection_method_theta else R.string.connection_method_opc
966             setMessage(IShowInformation.AREA_7, Color.MAGENTA, getString(methodId))
967             liveView?.setupInitialBackgroundImage(this)
968             liveView?.visibility = View.VISIBLE
969             liveView?.invalidate()
970         }
971         catch (e: Exception)
972         {
973             e.printStackTrace()
974         }
975     }
976
977     private fun updateConnectionMethod(parameter: String, method: ICameraController?)
978     {
979         try
980         {
981             currentCoordinator = method
982             preferences.putString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, parameter)
983             vibrate(IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE)
984             enableGlView = preferences.getBoolean(IPreferenceCameraPropertyAccessor.THETA_GL_VIEW, false)
985             if ((enableGlView)&&(parameter.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)))
986             {
987                 if (glView == null)
988                 {
989                     // GL VIEW に切り替える
990                     glView = findViewById(R.id.glview)
991                 }
992                 if (glView != null)
993                 {
994                     // GL VIEW に切り替える
995                     gestureParser = GestureParser(applicationContext, glView!!)
996                     glView?.setImageProvider(liveViewListener!!)
997                     glView?.visibility = View.VISIBLE
998                     liveView?.visibility = View.GONE
999                 }
1000             }
1001             else
1002             {
1003                 if (liveView == null)
1004                 {
1005                     liveView = findViewById(R.id.liveview)
1006                 }
1007                 if (liveView != null)
1008                 {
1009                     glView?.visibility = View.GONE
1010                     liveView?.visibility = View.VISIBLE
1011                 }
1012             }
1013         }
1014         catch (e: Exception)
1015         {
1016             e.printStackTrace()
1017         }
1018     }
1019
1020     /**
1021      * 接続方式を変更するか確認する (OPC ⇔ THETA)
1022      *
1023      */
1024     private fun changeConnectionMethod() {
1025         val activity: AppCompatActivity = this
1026         runOnUiThread {
1027             try {
1028                 var titleId = R.string.change_title_from_opc_to_theta
1029                 var messageId = R.string.change_message_from_opc_to_theta
1030                 var method = false
1031                 val connectionMethod = preferences.getString(
1032                     IPreferenceCameraPropertyAccessor.CONNECTION_METHOD,
1033                     IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE
1034                 )
1035                 if (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) {
1036                     titleId = R.string.change_title_from_theta_to_opc
1037                     messageId = R.string.change_message_from_theta_to_opc
1038                     method = true
1039                 }
1040                 val isTheta = method
1041                 val confirmation = ConfirmationDialog(activity)
1042                 confirmation.show(titleId, messageId) {
1043                     Log.v(TAG, " --- CONFIRMED! --- (theta:$isTheta)")
1044                     if (isTheta) {
1045                         // 接続方式を OPC に切り替える
1046                         updateConnectionMethod(
1047                             IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_OPC,
1048                             olyAirCoordinator
1049                         )
1050                     } else {
1051                         // 接続方式を Theta に切り替える
1052                         updateConnectionMethod(
1053                             IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA,
1054                             thetaCoordinator
1055                         )
1056                     }
1057                     updateConnectionMethodMessage()
1058                 }
1059             } catch (e: Exception) {
1060                 e.printStackTrace()
1061             }
1062         }
1063     }
1064
1065     override fun onConnectedToWifi()
1066     {
1067         try
1068         {
1069             Log.v(TAG, "onConnectedToWifi()")
1070         }
1071         catch (e: Exception)
1072         {
1073             e.printStackTrace()
1074         }
1075     }
1076
1077     companion object
1078     {
1079         private val TAG = MainActivity::class.java.simpleName
1080         //const val REQUEST_NEED_PERMISSIONS = 1010
1081         private const val REQUEST_CODE_PERMISSIONS = 10
1082         private val REQUIRED_PERMISSIONS = arrayOf(
1083             Manifest.permission.VIBRATE,
1084             Manifest.permission.WAKE_LOCK,
1085             Manifest.permission.INTERNET,
1086             Manifest.permission.ACCESS_NETWORK_STATE,
1087             Manifest.permission.ACCESS_WIFI_STATE,
1088             Manifest.permission.CHANGE_WIFI_STATE,
1089             Manifest.permission.CHANGE_NETWORK_STATE,
1090             Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
1091         )
1092     }
1093 }