1 package jp.sfjp.gokigen.a01c;
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;
18 import androidx.annotation.NonNull;
19 import androidx.appcompat.app.AppCompatActivity;
20 import androidx.core.app.ActivityCompat;
21 import androidx.core.content.ContextCompat;
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;
40 public class MainActivity extends AppCompatActivity implements IChangeScene, IShowInformation, ICameraStatusReceiver, IDialogDismissedNotifier, ICameraStatusUpdateNotify
42 private final String TAG = toString();
43 static final int REQUEST_NEED_PERMISSIONS = 1010;
44 //static final int COMMAND_MY_PROPERTY = 0x00000100;
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;
63 protected void onCreate(Bundle savedInstanceState)
65 super.onCreate(savedInstanceState);
66 Log.v(TAG, "onCreate()");
68 // Ambientモードを許してみる...
69 //setAmbientEnabled();
72 setContentView(R.layout.activity_main);
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))
84 ActivityCompat.requestPermissions(this,
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,
94 REQUEST_NEED_PERMISSIONS);
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.
108 vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
111 powerManager = (PowerManager) getSystemService(POWER_SERVICE);
113 setupCameraCoordinator();
114 setupInitialButtonIcons();
115 setupActionListener();
127 protected void onResume()
130 Log.v(TAG, "onResume()");
137 protected void onPause()
140 Log.v(TAG, "onPause()");
148 public void onStart()
151 Log.v(TAG, "onStart()");
162 Log.v(TAG, "onStop()");
168 public void onEnterAmbient(Bundle ambientDetails)
170 super.onEnterAmbient(ambientDetails);
171 Log.v(TAG, "onEnterAmbient()");
176 public void onExitAmbient()
178 super.onExitAmbient();
179 Log.v(TAG, "onExitAmbient()");
184 public void onUpdateAmbient()
186 super.onUpdateAmbient();
187 Log.v(TAG, "onUpdateAmbient()");
192 * ボタンが押された、画面がタッチされた、、は、リスナクラスで処理するよう紐づける
195 private void setupActionListener()
199 final ImageButton btn1 = findViewById(R.id.btn_1);
200 btn1.setOnClickListener(listener);
201 btn1.setOnLongClickListener(listener);
203 final ImageButton btn2 = findViewById(R.id.btn_2);
204 btn2.setOnClickListener(listener);
205 btn2.setOnLongClickListener(listener);
207 final ImageButton btn3 = findViewById(R.id.btn_3);
208 btn3.setOnClickListener(listener);
209 btn3.setOnLongClickListener(listener);
211 final ImageButton btn4 = findViewById(R.id.btn_4);
212 btn4.setOnClickListener(listener);
213 btn4.setOnLongClickListener(listener);
215 final ImageButton btn5 = findViewById(R.id.btn_5);
216 btn5.setOnClickListener(listener);
217 btn5.setOnLongClickListener(listener);
219 final ImageButton btn6 = findViewById(R.id.btn_6);
220 btn6.setOnClickListener(listener);
221 btn6.setOnLongClickListener(listener);
223 final TextView textArea1 = findViewById(R.id.text_1);
224 textArea1.setOnClickListener(listener);
225 textArea1.setOnLongClickListener(listener);
227 final TextView textArea2 = findViewById(R.id.text_2);
228 textArea2.setOnClickListener(listener);
229 textArea2.setOnLongClickListener(listener);
231 final TextView textArea3 = findViewById(R.id.text_3);
232 textArea3.setOnClickListener(listener);
233 textArea3.setOnLongClickListener(listener);
235 final TextView textArea4 = findViewById(R.id.text_4);
236 textArea4.setOnClickListener(listener);
237 textArea4.setOnLongClickListener(listener);
239 if (liveView == null)
241 liveView = findViewById(R.id.liveview);
243 liveView.setOnTouchListener(listener);
244 messageDrawer = liveView.getMessageDrawer();
245 messageDrawer.setLevelGauge(currentCoordinator.getLevelGauge());
257 private void setupInitialButtonIcons()
261 if (currentCoordinator != null)
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;
269 // ボタンをGrid ONアイコンにする
270 resId = R.drawable.btn_ic_grid_on;
272 setButtonDrawable(IShowInformation.BUTTON_1, resId);
282 * Intentを使ってWiFi設定画面を開く
285 private boolean launchWifiSettingScreen()
287 Log.v(TAG, "launchWifiSettingScreen()");
290 // Wifi 設定画面を表示する... (SONY Smart Watch 3では開かないけど...)
291 startActivity(new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"));
298 Log.v(TAG, "launchWifiSettingScreen() : ACTION_WIFI_SETTINGS");
299 startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
304 Log.v(TAG, "android.content.ActivityNotFoundException... " + "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS");
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);
313 catch (Exception ex2)
317 // Wifi 設定画面を表示する...普通のAndroidの場合
318 startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
323 ee.printStackTrace();
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);
332 catch (android.content.ActivityNotFoundException ex3)
334 ex3.printStackTrace();
344 * Olympus Cameraクラスとのやりとりをするクラスを準備する
345 * (カメラとの接続も、ここでスレッドを起こして開始する)
347 private void setupCameraCoordinator()
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)
356 liveView = findViewById(R.id.liveview);
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);
376 private void connectToCamera()
378 Thread thread = new Thread(new Runnable()
383 currentCoordinator.getConnectionInterface().connect();
397 * カメラの電源をOFFいして、アプリを抜ける処理
401 public void exitApplication()
405 Log.v(TAG, "exitApplication()");
409 // アンビエントモードの時(≒自分でアプリを終了しなかったとき)は、何もしない
411 Log.v(TAG, "keep liveview.");
416 // パワーマネージャを確認し、interactive modeではない場合は、ライブビューも止めず、カメラの電源も切らない
417 if ((powerManager != null) && (!powerManager.isInteractive()))
419 Log.v(TAG, "not interactive, keep liveview.");
424 currentCoordinator.stopLiveView();
427 ICameraStatusWatcher watcher = currentCoordinator.getStatusWatcher();
430 watcher.stopStatusWatch();
433 // パラメータを確認し、カメラの電源を切る
434 if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(IPreferenceCameraPropertyAccessor.EXIT_APPLICATION_WITH_DISCONNECT, true))
436 Log.v(TAG, "Shutdown camera...");
439 currentCoordinator.getConnectionInterface().disconnect(true);
442 //finishAndRemoveTask();
443 //android.os.Process.killProcess(android.os.Process.myPid());
455 public boolean checkConnectionFeature(int id, int btnId)
461 ret = launchWifiSettingScreen();
466 changeConnectionMethod();
474 * @param posX X座標位置 (0.0f - 1.0f)
475 * @param posY Y座標位置 (0.0f - 1.0f)
476 * @return true / false
479 public boolean touchedPosition(float posX, float posY)
481 Log.v(TAG, "touchedPosition (" + posX + ", " + posY);
482 return ((liveView != null)&&(liveView.touchedPosition(posX, posY)));
489 public boolean showConnectionStatus()
493 if ((listener.isEnabledOperation() == IShowInformation.operation.ONLY_CONNECT) && (cameraDisconnectedHappened)) {
494 // カメラが切断されたとき、再接続を指示する
496 cameraDisconnectedHappened = false;
511 public void onStatusNotify(String message)
513 setMessage(IShowInformation.AREA_C, Color.WHITE, message);
520 public void onCameraConnected()
522 Log.v(TAG, "onCameraConnected()");
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();
535 watcher.startStatusWatch(this);
545 * カメラとの接続が切れたとき...何もしない
549 public void onCameraDisconnected()
551 Log.v(TAG, "onCameraDisconnected()");
554 setMessage(IShowInformation.AREA_C, Color.YELLOW, getString(R.string.camera_disconnected));
555 listener.setEnableOperation(operation.ONLY_CONNECT);
556 cameraDisconnectedHappened = true;
568 public void onCameraConnectError(@NonNull String message)
570 Log.v(TAG, "onCameraOccursException()");
573 setMessage(IShowInformation.AREA_C, Color.YELLOW, message);
574 listener.setEnableOperation(operation.ONLY_CONNECT);
575 cameraDisconnectedHappened = true;
579 ee.printStackTrace();
587 public void onCameraOccursException(@NonNull String message, Exception e)
589 Log.v(TAG, "onCameraOccursException()");
592 setMessage(IShowInformation.AREA_C, Color.YELLOW, message);
593 listener.setEnableOperation(operation.ONLY_CONNECT);
594 cameraDisconnectedHappened = true;
599 ee.printStackTrace();
606 * @param area 表示エリア (AREA_1 ~ AREA_6, AREA_C)
608 * @param message 表示するメッセージ
611 public void setMessage(final int area, final int color, final String message)
616 case IShowInformation.AREA_1:
619 case IShowInformation.AREA_2:
622 case IShowInformation.AREA_3:
625 case IShowInformation.AREA_4:
628 case IShowInformation.AREA_NONE:
633 if (messageDrawer != null)
635 if (area == IShowInformation.AREA_C)
637 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTER, color, IMessageDrawer.SIZE_LARGE, message);
640 if (area == IShowInformation.AREA_5)
642 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPLEFT, color, IMessageDrawer.SIZE_STD, message);
645 if (area == IShowInformation.AREA_6)
647 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWLEFT, color, IMessageDrawer.SIZE_STD, message);
650 if (area == IShowInformation.AREA_7)
652 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPRIGHT, color, IMessageDrawer.SIZE_STD, message);
655 if (area == IShowInformation.AREA_8)
657 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWRIGHT, color, IMessageDrawer.SIZE_STD, message);
660 if (area == IShowInformation.AREA_9)
662 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPCENTER, color, IMessageDrawer.SIZE_STD, message);
665 if (area == IShowInformation.AREA_A)
667 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWCENTER, color, IMessageDrawer.SIZE_STD, message);
670 if (area == IShowInformation.AREA_B)
672 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTERLEFT, color, IMessageDrawer.SIZE_STD, message);
675 if (area == IShowInformation.AREA_D)
677 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTERRIGHT, color, IMessageDrawer.SIZE_STD, message);
688 final int areaId = id;
689 runOnUiThread(new Runnable()
694 final TextView textArea = findViewById(areaId);
695 if (textArea != null)
697 textArea.setTextColor(color);
698 textArea.setText(message);
699 textArea.invalidate();
708 * @param button ボタンの場所
709 * @param labelId 変更する内容
712 public void setButtonDrawable(final int button, final int labelId)
717 case IShowInformation.BUTTON_1:
720 case IShowInformation.BUTTON_2:
723 case IShowInformation.BUTTON_3:
726 case IShowInformation.BUTTON_4:
729 case IShowInformation.BUTTON_5:
732 case IShowInformation.BUTTON_6:
738 final int areaId = id;
739 runOnUiThread(new Runnable()
746 final ImageButton button = findViewById(areaId);
747 final Drawable drawTarget = ContextCompat.getDrawable(getApplicationContext(), labelId);
750 button.setImageDrawable(drawTarget);
764 * @return true GPS搭載, false GPS非搭載
766 private boolean hasGps()
768 return (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS));
776 public void vibrate(final int vibratePattern)
780 if ((vibrator == null)||(!vibrator.hasVibrator()))
785 Thread thread = new Thread(new Runnable() {
788 switch (vibratePattern)
790 case IShowInformation.VIBRATE_PATTERN_SIMPLE_LONGLONG:
791 vibrator.vibrate(300);
793 case IShowInformation.VIBRATE_PATTERN_SIMPLE_LONG:
794 vibrator.vibrate(150);
796 case IShowInformation.VIBRATE_PATTERN_SIMPLE_MIDDLE:
797 vibrator.vibrate(80);
799 case IShowInformation.VIBRATE_PATTERN_SIMPLE_SHORT:
800 vibrator.vibrate(30);
802 case IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE:
803 long[] pattern = { 10, 35, 30, 35, 0 };
804 vibrator.vibrate(pattern, -1);
806 case IShowInformation.VIBRATE_PATTERN_NONE:
822 public void setEnabledOperation(IShowInformation.operation operation)
824 if (listener != null)
826 listener.setEnableOperation(operation);
835 public void showFavoriteSettingsDialog()
837 if ((liveView != null)&&(listener != null)&&(listener.isEnabledOperation() != operation.ONLY_CONNECT))
839 listener.setEnableOperation(operation.ENABLE_ONLY_TOUCHED_POSITION);
840 liveView.showDialog(selectionDialog);
849 public void dialogDismissed(boolean isExecuted)
853 if ((liveView != null) && (listener != null))
855 liveView.hideDialog();
856 listener.setEnableOperation(operation.ENABLE);
865 private void updateConnectionMethodMessage()
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)
874 liveView = findViewById(R.id.liveview);
876 liveView.setupInitialBackgroundImage(this);
877 liveView.invalidate();
885 private void updateConnectionMethod(String parameter, ICameraController method)
889 currentCoordinator = method;
890 preferences.putString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, parameter);
891 vibrate(IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE);
900 * 接続方式を変更するか確認する (OPC ⇔ THETA)
903 private void changeConnectionMethod()
905 final AppCompatActivity activity = this;
906 runOnUiThread(new Runnable() {
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))
917 titleId = R.string.change_title_from_theta_to_opc;
918 messageId = R.string.change_message_from_theta_to_opc;
921 final boolean isTheta = method;
922 ConfirmationDialog confirmation = new ConfirmationDialog(activity);
923 confirmation.show(titleId, messageId, new ConfirmationDialog.Callback() {
925 public void confirm() {
926 Log.v(TAG, " --- CONFIRMED! --- (theta:" + isTheta + ")");
930 updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_OPC, olyAirCoordinator);
934 // 接続方式を Theta に切り替える
935 updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA, thetaCoordinator);
937 updateConnectionMethodMessage();
950 public void updateCameraStatus(String message)
954 setMessage(IShowInformation.AREA_8, Color.WHITE, message);
958 ee.printStackTrace();
963 public void updateRemainBattery(double percentageDouble)
965 int color = Color.YELLOW;
966 if (percentageDouble < 0.5d)
968 if (percentageDouble < 0.3d)
974 int percentage = (int) Math.ceil(percentageDouble * 100.0d);
975 setMessage(IShowInformation.AREA_7, color, "Bat: " + percentage + "%");
979 ee.printStackTrace();