OSDN Git Service

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