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;
17 import android.widget.Toast;
19 import androidx.annotation.NonNull;
20 import androidx.appcompat.app.AppCompatActivity;
21 import androidx.core.app.ActivityCompat;
22 import androidx.core.content.ContextCompat;
24 import jp.sfjp.gokigen.a01c.liveview.CameraLiveImageView;
25 import jp.sfjp.gokigen.a01c.liveview.CameraLiveViewListenerImpl;
26 import jp.sfjp.gokigen.a01c.liveview.dialog.FavoriteSettingSelectionDialog;
27 import jp.sfjp.gokigen.a01c.liveview.dialog.IDialogDismissedNotifier;
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, IWifiConnection
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 WifiConnection wifiConnection = null;
58 //private boolean ambientMode = false;
64 protected void onCreate(Bundle savedInstanceState)
66 super.onCreate(savedInstanceState);
67 Log.v(TAG, "onCreate()");
69 // Ambientモードを許してみる...
70 //setAmbientEnabled();
73 setContentView(R.layout.activity_main);
76 if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED)||
77 (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE) != PackageManager.PERMISSION_GRANTED)||
78 (ContextCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE) != PackageManager.PERMISSION_GRANTED)||
79 (ContextCompat.checkSelfPermission(this, Manifest.permission.CHANGE_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED)||
80 (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_SETTINGS) != PackageManager.PERMISSION_GRANTED)||
81 (ContextCompat.checkSelfPermission(this, Manifest.permission.WAKE_LOCK) != PackageManager.PERMISSION_GRANTED)||
82 (ContextCompat.checkSelfPermission(this, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED)||
83 (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED))
85 ActivityCompat.requestPermissions(this,
87 Manifest.permission.ACCESS_NETWORK_STATE,
88 Manifest.permission.ACCESS_WIFI_STATE,
89 Manifest.permission.CHANGE_WIFI_STATE,
90 Manifest.permission.CHANGE_NETWORK_STATE,
91 Manifest.permission.WRITE_SETTINGS,
92 Manifest.permission.WAKE_LOCK,
93 Manifest.permission.INTERNET,
95 REQUEST_NEED_PERMISSIONS);
102 // GPS機能が搭載されていない場合...
103 Log.d(TAG, "This hardware doesn't have GPS.");
104 // Fall back to functionality that does not use location or
105 // warn the user that location function is not available.
109 vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
112 powerManager = (PowerManager) getSystemService(POWER_SERVICE);
114 setupCameraCoordinator();
115 setupInitialButtonIcons();
116 setupActionListener();
118 wifiConnection = new WifiConnection(this, this);
130 protected void onResume()
133 Log.v(TAG, "onResume()");
134 if (wifiConnection != null)
137 wifiConnection.requestNetwork();
138 wifiConnection.startWatchWifiStatus();
146 protected void onPause()
149 Log.v(TAG, "onPause()");
157 public void onStart()
160 Log.v(TAG, "onStart()");
171 Log.v(TAG, "onStop()");
177 public void onEnterAmbient(Bundle ambientDetails)
179 super.onEnterAmbient(ambientDetails);
180 Log.v(TAG, "onEnterAmbient()");
185 public void onExitAmbient()
187 super.onExitAmbient();
188 Log.v(TAG, "onExitAmbient()");
193 public void onUpdateAmbient()
195 super.onUpdateAmbient();
196 Log.v(TAG, "onUpdateAmbient()");
201 * ボタンが押された、画面がタッチされた、、は、リスナクラスで処理するよう紐づける
204 private void setupActionListener()
208 final ImageButton btn1 = findViewById(R.id.btn_1);
209 btn1.setOnClickListener(listener);
210 btn1.setOnLongClickListener(listener);
212 final ImageButton btn2 = findViewById(R.id.btn_2);
213 btn2.setOnClickListener(listener);
214 btn2.setOnLongClickListener(listener);
216 final ImageButton btn3 = findViewById(R.id.btn_3);
217 btn3.setOnClickListener(listener);
218 btn3.setOnLongClickListener(listener);
220 final ImageButton btn4 = findViewById(R.id.btn_4);
221 btn4.setOnClickListener(listener);
222 btn4.setOnLongClickListener(listener);
224 final ImageButton btn5 = findViewById(R.id.btn_5);
225 btn5.setOnClickListener(listener);
226 btn5.setOnLongClickListener(listener);
228 final ImageButton btn6 = findViewById(R.id.btn_6);
229 btn6.setOnClickListener(listener);
230 btn6.setOnLongClickListener(listener);
232 final TextView textArea1 = findViewById(R.id.text_1);
233 textArea1.setOnClickListener(listener);
234 textArea1.setOnLongClickListener(listener);
236 final TextView textArea2 = findViewById(R.id.text_2);
237 textArea2.setOnClickListener(listener);
238 textArea2.setOnLongClickListener(listener);
240 final TextView textArea3 = findViewById(R.id.text_3);
241 textArea3.setOnClickListener(listener);
242 textArea3.setOnLongClickListener(listener);
244 final TextView textArea4 = findViewById(R.id.text_4);
245 textArea4.setOnClickListener(listener);
246 textArea4.setOnLongClickListener(listener);
248 if (liveView == null)
250 liveView = findViewById(R.id.liveview);
252 liveView.setOnTouchListener(listener);
253 messageDrawer = liveView.getMessageDrawer();
254 messageDrawer.setLevelGauge(currentCoordinator.getLevelGauge());
266 private void setupInitialButtonIcons()
270 if (currentCoordinator != null)
273 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
274 if (preferences.getBoolean(IPreferenceCameraPropertyAccessor.SHOW_GRID_STATUS, true)) {
275 // ボタンをGrid OFFアイコンにする
276 resId = R.drawable.btn_ic_grid_off;
278 // ボタンをGrid ONアイコンにする
279 resId = R.drawable.btn_ic_grid_on;
281 setButtonDrawable(IShowInformation.BUTTON_1, resId);
291 * Intentを使ってWiFi設定画面を開く
294 private boolean launchWifiSettingScreen()
296 Log.v(TAG, "launchWifiSettingScreen()");
299 // Wifi 設定画面を表示する... (SONY Smart Watch 3では開かないけど...)
300 startActivity(new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"));
307 Log.v(TAG, "launchWifiSettingScreen() : ACTION_WIFI_SETTINGS");
308 startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
313 Log.v(TAG, "android.content.ActivityNotFoundException... " + "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS");
316 // SONY Smart Watch 3で開く場合のIntent...
317 Intent intent = new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS");
318 intent.setClassName("com.google.android.apps.wearable.settings", "com.google.android.clockwork.settings.wifi.WifiSettingsActivity");
319 startActivity(intent);
322 catch (Exception ex2)
326 // Wifi 設定画面を表示する...普通のAndroidの場合
327 startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
332 ee.printStackTrace();
335 // LG G Watch Rで開く場合のIntent...
336 Intent intent = new Intent("android.intent.action.MAIN");
337 intent.setClassName("com.google.android.apps.wearable.settings", "com.google.android.clockwork.settings.MainSettingsActivity");
338 startActivity(intent);
341 catch (android.content.ActivityNotFoundException ex3)
343 ex3.printStackTrace();
353 * Olympus Cameraクラスとのやりとりをするクラスを準備する
354 * (カメラとの接続も、ここでスレッドを起こして開始する)
356 private void setupCameraCoordinator()
360 preferences = new PreferenceAccessWrapper(this);
361 preferences.initialize();
362 String connectionMethod = preferences.getString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE);
363 if (liveView == null)
365 liveView = findViewById(R.id.liveview);
367 olyAirCoordinator = new OlyCameraCoordinator(this, liveView, this, this);
368 thetaCoordinator = new ThetaCameraController(this, this, this);
369 currentCoordinator = (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? thetaCoordinator : olyAirCoordinator;
370 currentCoordinator.setLiveViewListener(new CameraLiveViewListenerImpl(liveView));
371 listener = new CameraLiveViewOnTouchListener(this, currentCoordinator.getFeatureDispatcher(this, this, currentCoordinator, preferences, liveView), this);
372 selectionDialog = new FavoriteSettingSelectionDialog(this, currentCoordinator.getCameraPropertyLoadSaveOperations(), this);
385 private void connectToCamera()
387 Thread thread = new Thread(new Runnable()
392 currentCoordinator.getConnectionInterface().connect();
406 * カメラの電源をOFFいして、アプリを抜ける処理
410 public void exitApplication()
414 Log.v(TAG, "exitApplication()");
418 // アンビエントモードの時(≒自分でアプリを終了しなかったとき)は、何もしない
420 Log.v(TAG, "keep liveview.");
425 // パワーマネージャを確認し、interactive modeではない場合は、ライブビューも止めず、カメラの電源も切らない
426 if ((powerManager != null) && (!powerManager.isInteractive()))
428 Log.v(TAG, "not interactive, keep liveview.");
433 currentCoordinator.stopLiveView();
436 ICameraStatusWatcher watcher = currentCoordinator.getStatusWatcher();
439 watcher.stopStatusWatch();
442 // パラメータを確認し、カメラの電源を切る
443 if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(IPreferenceCameraPropertyAccessor.EXIT_APPLICATION_WITH_DISCONNECT, true))
445 Log.v(TAG, "Shutdown camera...");
448 currentCoordinator.getConnectionInterface().disconnect(true);
451 //finishAndRemoveTask();
452 //android.os.Process.killProcess(android.os.Process.myPid());
464 public boolean checkConnectionFeature(int id, int btnId)
470 ret = launchWifiSettingScreen();
475 changeConnectionMethod();
483 * @param posX X座標位置 (0.0f - 1.0f)
484 * @param posY Y座標位置 (0.0f - 1.0f)
485 * @return true / false
488 public boolean touchedPosition(float posX, float posY)
490 Log.v(TAG, "touchedPosition (" + posX + ", " + posY);
491 return ((liveView != null)&&(liveView.touchedPosition(posX, posY)));
498 public boolean showConnectionStatus()
502 if ((listener.isEnabledOperation() == IShowInformation.operation.ONLY_CONNECT) && (cameraDisconnectedHappened)) {
503 // カメラが切断されたとき、再接続を指示する
505 cameraDisconnectedHappened = false;
520 public void onStatusNotify(String message)
522 setMessage(IShowInformation.AREA_C, Color.WHITE, message);
529 public void onCameraConnected()
531 Log.v(TAG, "onCameraConnected()");
534 // ライブビューの開始 & タッチ/ボタンの操作を可能にする
535 currentCoordinator.connectFinished();
536 currentCoordinator.startLiveView();
537 currentCoordinator.setRecViewMode(false);
538 listener.setEnableOperation(operation.ENABLE);
539 setMessage(IShowInformation.AREA_C, Color.WHITE, "");
540 currentCoordinator.updateStatusAll();
541 ICameraStatusWatcher watcher = currentCoordinator.getStatusWatcher();
544 watcher.startStatusWatch();
554 * カメラとの接続が切れたとき...何もしない
558 public void onCameraDisconnected()
560 Log.v(TAG, "onCameraDisconnected()");
563 setMessage(IShowInformation.AREA_C, Color.YELLOW, getString(R.string.camera_disconnected));
564 listener.setEnableOperation(operation.ONLY_CONNECT);
565 cameraDisconnectedHappened = true;
577 public void onCameraConnectError(@NonNull String message)
579 Log.v(TAG, "onCameraOccursException()");
582 setMessage(IShowInformation.AREA_C, Color.YELLOW, message);
583 listener.setEnableOperation(operation.ONLY_CONNECT);
584 cameraDisconnectedHappened = true;
588 ee.printStackTrace();
596 public void onCameraOccursException(@NonNull String message, Exception e)
598 Log.v(TAG, "onCameraOccursException()");
601 setMessage(IShowInformation.AREA_C, Color.YELLOW, message);
602 listener.setEnableOperation(operation.ONLY_CONNECT);
603 cameraDisconnectedHappened = true;
608 ee.printStackTrace();
615 * @param area 表示エリア (AREA_1 ~ AREA_6, AREA_C)
617 * @param message 表示するメッセージ
620 public void setMessage(final int area, final int color, final String message)
625 case IShowInformation.AREA_1:
628 case IShowInformation.AREA_2:
631 case IShowInformation.AREA_3:
634 case IShowInformation.AREA_4:
637 case IShowInformation.AREA_NONE:
642 if (messageDrawer != null)
644 if (area == IShowInformation.AREA_C)
646 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTER, color, IMessageDrawer.SIZE_LARGE, message);
649 if (area == IShowInformation.AREA_5)
651 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPLEFT, color, IMessageDrawer.SIZE_STD, message);
654 if (area == IShowInformation.AREA_6)
656 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWLEFT, color, IMessageDrawer.SIZE_STD, message);
659 if (area == IShowInformation.AREA_7)
661 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPRIGHT, color, IMessageDrawer.SIZE_STD, message);
664 if (area == IShowInformation.AREA_8)
666 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWRIGHT, color, IMessageDrawer.SIZE_STD, message);
669 if (area == IShowInformation.AREA_9)
671 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.UPCENTER, color, IMessageDrawer.SIZE_STD, message);
674 if (area == IShowInformation.AREA_A)
676 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.LOWCENTER, color, IMessageDrawer.SIZE_STD, message);
679 if (area == IShowInformation.AREA_B)
681 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTERLEFT, color, IMessageDrawer.SIZE_STD, message);
684 if (area == IShowInformation.AREA_D)
686 messageDrawer.setMessageToShow(IMessageDrawer.MessageArea.CENTERRIGHT, color, IMessageDrawer.SIZE_STD, message);
697 final int areaId = id;
698 runOnUiThread(new Runnable()
703 final TextView textArea = findViewById(areaId);
704 if (textArea != null)
706 textArea.setTextColor(color);
707 textArea.setText(message);
708 textArea.invalidate();
717 * @param button ボタンの場所
718 * @param labelId 変更する内容
721 public void setButtonDrawable(final int button, final int labelId)
726 case IShowInformation.BUTTON_1:
729 case IShowInformation.BUTTON_2:
732 case IShowInformation.BUTTON_3:
735 case IShowInformation.BUTTON_4:
738 case IShowInformation.BUTTON_5:
741 case IShowInformation.BUTTON_6:
747 final int areaId = id;
748 runOnUiThread(new Runnable()
755 final ImageButton button = findViewById(areaId);
756 final Drawable drawTarget = ContextCompat.getDrawable(getApplicationContext(), labelId);
759 button.setImageDrawable(drawTarget);
773 * @return true GPS搭載, false GPS非搭載
775 private boolean hasGps()
777 return (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS));
785 public void vibrate(final int vibratePattern)
789 if ((vibrator == null)||(!vibrator.hasVibrator()))
794 Thread thread = new Thread(new Runnable() {
797 switch (vibratePattern)
799 case IShowInformation.VIBRATE_PATTERN_SIMPLE_LONGLONG:
800 vibrator.vibrate(300);
802 case IShowInformation.VIBRATE_PATTERN_SIMPLE_LONG:
803 vibrator.vibrate(150);
805 case IShowInformation.VIBRATE_PATTERN_SIMPLE_MIDDLE:
806 vibrator.vibrate(80);
808 case IShowInformation.VIBRATE_PATTERN_SIMPLE_SHORT:
809 vibrator.vibrate(30);
811 case IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE:
812 long[] pattern = { 10, 35, 30, 35, 0 };
813 vibrator.vibrate(pattern, -1);
815 case IShowInformation.VIBRATE_PATTERN_NONE:
831 public void setEnabledOperation(IShowInformation.operation operation)
833 if (listener != null)
835 listener.setEnableOperation(operation);
844 public void showFavoriteSettingsDialog()
846 if ((liveView != null)&&(listener != null)&&(listener.isEnabledOperation() != operation.ONLY_CONNECT))
848 listener.setEnableOperation(operation.ENABLE_ONLY_TOUCHED_POSITION);
849 liveView.showDialog(selectionDialog);
854 public void showToast(final int rscId, @NonNull final String appendMessage, final int duration)
858 runOnUiThread(new Runnable() {
863 String message = (rscId != 0) ? getString(rscId) + appendMessage : appendMessage;
864 Toast.makeText(getApplicationContext(), message, duration).show();
881 public void invalidate()
885 runOnUiThread(new Runnable() {
888 if (liveView != null)
890 liveView.invalidate();
906 public void dialogDismissed(boolean isExecuted)
910 if ((liveView != null) && (listener != null))
912 liveView.hideDialog();
913 listener.setEnableOperation(operation.ENABLE);
922 private void updateConnectionMethodMessage()
926 String connectionMethod = preferences.getString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE);
927 int methodId = (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? R.string.connection_method_theta : R.string.connection_method_opc;
928 setMessage(IShowInformation.AREA_7, Color.MAGENTA, getString(methodId));
929 if (liveView == null)
931 liveView = findViewById(R.id.liveview);
933 liveView.setupInitialBackgroundImage(this);
934 liveView.invalidate();
942 private void updateConnectionMethod(String parameter, ICameraController method)
946 currentCoordinator = method;
947 preferences.putString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, parameter);
948 vibrate(IShowInformation.VIBRATE_PATTERN_SHORT_DOUBLE);
957 * 接続方式を変更するか確認する (OPC ⇔ THETA)
960 private void changeConnectionMethod()
962 final AppCompatActivity activity = this;
963 runOnUiThread(new Runnable() {
968 int titleId = R.string.change_title_from_opc_to_theta;
969 int messageId = R.string.change_message_from_opc_to_theta;
970 boolean method = false;
971 String connectionMethod = preferences.getString(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD, IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE);
972 if (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA))
974 titleId = R.string.change_title_from_theta_to_opc;
975 messageId = R.string.change_message_from_theta_to_opc;
978 final boolean isTheta = method;
979 ConfirmationDialog confirmation = new ConfirmationDialog(activity);
980 confirmation.show(titleId, messageId, new ConfirmationDialog.Callback() {
982 public void confirm() {
983 Log.v(TAG, " --- CONFIRMED! --- (theta:" + isTheta + ")");
987 updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_OPC, olyAirCoordinator);
991 // 接続方式を Theta に切り替える
992 updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA, thetaCoordinator);
994 updateConnectionMethodMessage();
1000 e.printStackTrace();
1007 public void onConnectedToWifi()
1011 Log.v(TAG, "onConnectedToWifi()");
1015 e.printStackTrace();