OSDN Git Service

Thetaのプレビューまで。
authorMRSa <mrsa@myad.jp>
Sun, 10 Jan 2021 14:28:44 +0000 (23:28 +0900)
committerMRSa <mrsa@myad.jp>
Sun, 10 Jan 2021 14:28:44 +0000 (23:28 +0900)
21 files changed:
wear/src/main/java/jp/sfjp/gokigen/a01c/ICameraConnection.java
wear/src/main/java/jp/sfjp/gokigen/a01c/MainActivity.java
wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveImageView.java
wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/CameraLiveViewListenerImpl.java
wear/src/main/java/jp/sfjp/gokigen/a01c/liveview/ICameraStatusReceiver.java
wear/src/main/java/jp/sfjp/gokigen/a01c/olycamerawrapper/IIndicatorControl.java
wear/src/main/java/jp/sfjp/gokigen/a01c/olycamerawrapper/OlyCameraCoordinator.java
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdNotifier.java [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdProvider.java [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/ThetaCameraController.kt
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/ThetaSessionHolder.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnectSequence.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnection.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraDisconnectSequence.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/liveview/ThetaLiveViewControl.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaDummyOperation.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaSingleShotControl.kt [new file with mode: 0644]
wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleHttpClient.kt
wear/src/main/java/jp/sfjp/gokigen/a01c/utils/SimpleLiveviewSlicer.java
wear/src/main/res/values-ja/strings.xml
wear/src/main/res/values/strings.xml

index 5ded1d3..643c160 100644 (file)
@@ -7,10 +7,17 @@ import androidx.annotation.NonNull;
 /**
  *   カメラの接続/切断
  *
- * Created by MRSa on 2017/02/28.
  */
 public interface ICameraConnection
 {
+    enum CameraConnectionStatus
+    {
+        UNKNOWN,
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED
+    };
+
     // WIFI 接続系
     void startWatchWifiStatus(@NonNull Context context);
     void stopWatchWifiStatus(@NonNull Context context);
index 5b7e694..07e74d5 100644 (file)
@@ -15,6 +15,7 @@ import android.widget.TextView;
 import android.Manifest;
 import android.content.pm.PackageManager;
 
+import androidx.annotation.NonNull;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
@@ -355,8 +356,8 @@ public class MainActivity extends AppCompatActivity implements  IChangeScene, IS
                 liveView = findViewById(R.id.liveview);
             }
             olyAirCoordinator = new OlyCameraCoordinator(this, liveView, this, this);
-            thetaCoordinator = new ThetaCameraController(this, liveView, this, this);
-            currentCoordinator = olyAirCoordinator; // (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? thetaCoordinator : olyAirCoordinator;
+            thetaCoordinator = new ThetaCameraController(this, liveView, this, this, preferences);
+            currentCoordinator = (connectionMethod.contains(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA)) ? thetaCoordinator : olyAirCoordinator;
             currentCoordinator.setLiveViewListener(new CameraLiveViewListenerImpl(liveView));
             listener = new CameraLiveViewOnTouchListener(this, new FeatureDispatcher(this, this, currentCoordinator, preferences, liveView), this);
             selectionDialog = new FavoriteSettingSelectionDialog(this, currentCoordinator.getCameraPropertyLoadSaveOperations(), this);
@@ -548,10 +549,29 @@ public class MainActivity extends AppCompatActivity implements  IChangeScene, IS
     }
 
     /**
+     *  カメラと接続失敗
+     */
+    @Override
+    public void onCameraConnectError(@NonNull String message)
+    {
+        Log.v(TAG, "onCameraOccursException()");
+        try
+        {
+            setMessage(IShowInformation.AREA_C, Color.YELLOW, message);
+            listener.setEnableOperation(operation.ONLY_CONNECT);
+            cameraDisconnectedHappened = true;
+        }
+        catch (Exception ee)
+        {
+            ee.printStackTrace();
+        }
+    }
+
+    /**
      *  カメラに例外発生
      */
     @Override
-    public void onCameraOccursException(String message, Exception e)
+    public void onCameraOccursException(@NonNull String message, Exception e)
     {
         Log.v(TAG, "onCameraOccursException()");
         try
@@ -899,7 +919,7 @@ public class MainActivity extends AppCompatActivity implements  IChangeScene, IS
                             else
                             {
                                 // 接続方式を Theta に切り替える
-                                updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA, olyAirCoordinator);  // thetaCoordinator
+                                updateConnectionMethod(IPreferenceCameraPropertyAccessor.CONNECTION_METHOD_THETA, thetaCoordinator);
                             }
                             updateConnectionMethodMessage();
                         }
index 5c15d9a..9c9df94 100644 (file)
@@ -233,49 +233,54 @@ public class CameraLiveImageView extends View implements IImageDataReceiver, IAu
     public void setImageData(byte[] data, Map<String, Object> metadata)
     {
         Bitmap bitmap;
-        int rotationDegrees;
+        int rotationDegrees = 0;
 
-        if (data != null && metadata != null)
+        if (data != null)
         {
-            // Create a bitmap.
             try
             {
                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
             }
-            catch (OutOfMemoryError e)
+            catch (Throwable e)
             {
                 e.printStackTrace();
                 return;
             }
 
-            // Acquire a rotation degree of image.
-            int orientation = ExifInterface.ORIENTATION_UNDEFINED;
-            try
+            if (metadata != null)
             {
-                if (metadata.containsKey(EXIF_ORIENTATION))
+                int orientation = ExifInterface.ORIENTATION_UNDEFINED;
+                try
                 {
-                    orientation = Integer.parseInt((String) metadata.get(EXIF_ORIENTATION));
+                    if (metadata.containsKey(EXIF_ORIENTATION))
+                    {
+                        String degree = (String) metadata.get(EXIF_ORIENTATION);
+                        if (degree != null)
+                        {
+                            orientation = Integer.parseInt(degree);
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                    e.printStackTrace();
+                }
+                switch (orientation)
+                {
+                    case ExifInterface.ORIENTATION_ROTATE_90:
+                        rotationDegrees = 90;
+                        break;
+                    case ExifInterface.ORIENTATION_ROTATE_180:
+                        rotationDegrees = 180;
+                        break;
+                    case ExifInterface.ORIENTATION_ROTATE_270:
+                        rotationDegrees = 270;
+                        break;
+                    case ExifInterface.ORIENTATION_NORMAL:
+                    default:
+                        rotationDegrees = 0;
+                        break;
                 }
-            }
-            catch (Exception e)
-            {
-                e.printStackTrace();
-            }
-            switch (orientation)
-            {
-                case ExifInterface.ORIENTATION_ROTATE_90:
-                    rotationDegrees = 90;
-                    break;
-                case ExifInterface.ORIENTATION_ROTATE_180:
-                    rotationDegrees = 180;
-                    break;
-                case ExifInterface.ORIENTATION_ROTATE_270:
-                    rotationDegrees = 270;
-                    break;
-                case ExifInterface.ORIENTATION_NORMAL:
-                default:
-                    rotationDegrees = 0;
-                    break;
             }
             imageBitmap = bitmap;
             imageRotationDegrees = rotationDegrees;
index fad67de..b2e2b7e 100644 (file)
@@ -16,6 +16,7 @@ import jp.co.olympus.camerakit.OLYCameraLiveViewListener;
  */
 public class CameraLiveViewListenerImpl implements OLYCameraLiveViewListener, IImageDataReceiver
 {
+    private final String TAG = toString();
     private final IImageDataReceiver imageView;
 
     /**
@@ -43,9 +44,10 @@ public class CameraLiveViewListenerImpl implements OLYCameraLiveViewListener, II
     @Override
     public void setImageData(byte[] data, Map<String, Object> metadata)
     {
+        // Log.v(TAG, " setImageData len : " + data.length);
         if (imageView != null)
         {
-            imageView.setImageData(data, metadata);
+            imageView.setImageData(data, null);
         }
     }
 }
index 78e64a1..3a6cdad 100644 (file)
@@ -1,5 +1,7 @@
 package jp.sfjp.gokigen.a01c.liveview;
 
+import androidx.annotation.NonNull;
+
 /**
  *
  *
@@ -9,5 +11,6 @@ public interface ICameraStatusReceiver
     void onStatusNotify(String message);
     void onCameraConnected();
     void onCameraDisconnected();
-    void onCameraOccursException(String message, Exception e);
+    void onCameraConnectError(@NonNull String message);
+    void onCameraOccursException(@NonNull String message, Exception e);
 }
index d65d376..3bd7f4b 100644 (file)
@@ -3,5 +3,15 @@ package jp.sfjp.gokigen.a01c.olycamerawrapper;
 
 public interface IIndicatorControl
 {
+    // 撮影状態の記録
+    enum shootingStatus
+    {
+        Unknown,
+        Starting,
+        Stopping,
+    }
+
     void onAfLockUpdate(boolean isAfLocked);
+    void onShootingStatusUpdate(shootingStatus status);
+
 }
index fe31486..01c0676 100644 (file)
@@ -498,6 +498,12 @@ public class OlyCameraCoordinator implements ICameraController, IIndicatorContro
     }
 
     @Override
+    public void onShootingStatusUpdate(shootingStatus status)
+    {
+        Log.v(TAG, " ShootingStatus : " + status);
+    }
+
+    @Override
     public OLYCamera getOLYCamera()
     {
         return (camera);
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdNotifier.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdNotifier.java
new file mode 100644 (file)
index 0000000..9991b80
--- /dev/null
@@ -0,0 +1,6 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper;
+
+public interface IThetaSessionIdNotifier
+{
+    void receivedSessionId(String sessionId);
+}
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdProvider.java b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/IThetaSessionIdProvider.java
new file mode 100644 (file)
index 0000000..cf137b2
--- /dev/null
@@ -0,0 +1,8 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper;
+
+import androidx.annotation.NonNull;
+
+public interface IThetaSessionIdProvider
+{
+    @NonNull String getSessionId();
+}
index 1a8c2de..9d8c23b 100644 (file)
@@ -10,19 +10,30 @@ import jp.sfjp.gokigen.a01c.liveview.CameraLiveViewListenerImpl
 import jp.sfjp.gokigen.a01c.liveview.IAutoFocusFrameDisplay
 import jp.sfjp.gokigen.a01c.liveview.ICameraStatusReceiver
 import jp.sfjp.gokigen.a01c.olycamerawrapper.ICameraRunMode
+import jp.sfjp.gokigen.a01c.olycamerawrapper.IIndicatorControl
 import jp.sfjp.gokigen.a01c.olycamerawrapper.ILevelGauge
 import jp.sfjp.gokigen.a01c.olycamerawrapper.IZoomLensHolder
 import jp.sfjp.gokigen.a01c.olycamerawrapper.property.ICameraPropertyLoadSaveOperations
 import jp.sfjp.gokigen.a01c.olycamerawrapper.property.ILoadSaveCameraProperties
 import jp.sfjp.gokigen.a01c.olycamerawrapper.property.IOlyCameraPropertyProvider
+import jp.sfjp.gokigen.a01c.preference.PreferenceAccessWrapper
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.connection.ThetaCameraConnection
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.liveview.ThetaLiveViewControl
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.operation.ThetaDummyOperation
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.operation.ThetaSingleShotControl
 
-class ThetaCameraController(val context : AppCompatActivity, val focusFrameDisplay : IAutoFocusFrameDisplay, val showInformation : IShowInformation, val receiver : ICameraStatusReceiver) : ICameraController
+class ThetaCameraController(val context: AppCompatActivity, private val focusFrameDisplay: IAutoFocusFrameDisplay, private val showInformation: IShowInformation, private val receiver: ICameraStatusReceiver, private val preferences: PreferenceAccessWrapper) : ICameraController, IIndicatorControl
 {
-    private lateinit var listener : CameraLiveViewListenerImpl
+    //private lateinit var listener : CameraLiveViewListenerImpl
+    private lateinit var liveViewControl : ThetaLiveViewControl
+    private val dummyOperation = ThetaDummyOperation()
+    private val sessionIdHolder = ThetaSessionHolder()
+    private val cameraConnection = ThetaCameraConnection(context, receiver, sessionIdHolder)
+    private val singleShot = ThetaSingleShotControl(sessionIdHolder, this, this)
 
     override fun setLiveViewListener(listener: CameraLiveViewListenerImpl)
     {
-        this.listener = listener
+        this.liveViewControl = ThetaLiveViewControl(sessionIdHolder, listener)
     }
 
     override fun changeLiveViewSize(size: String?)
@@ -31,97 +42,134 @@ class ThetaCameraController(val context : AppCompatActivity, val focusFrameDispl
         Log.v(toString(), " changeLiveViewSize: $size")
     }
 
-    override fun startLiveView() {
-        TODO("Not yet implemented")
+    override fun startLiveView()
+    {
+        if (::liveViewControl.isInitialized)
+        {
+            liveViewControl.startLiveView()
+        }
     }
 
-    override fun stopLiveView() {
-        TODO("Not yet implemented")
+    override fun stopLiveView()
+    {
+        if (::liveViewControl.isInitialized)
+        {
+            liveViewControl.stopLiveView()
+        }
     }
 
-    override fun updateTakeMode() {
-        TODO("Not yet implemented")
+    override fun updateTakeMode()
+    {
+        // なにもしない
     }
 
-    override fun driveAutoFocus(event: MotionEvent?): Boolean {
-        TODO("Not yet implemented")
+    override fun driveAutoFocus(event: MotionEvent?): Boolean
+    {
+        return (true)
     }
 
-    override fun unlockAutoFocus() {
-        TODO("Not yet implemented")
+    override fun unlockAutoFocus()
+    {
+        // なにもしない
     }
 
-    override fun isContainsAutoFocusPoint(event: MotionEvent?): Boolean {
-        TODO("Not yet implemented")
+    override fun isContainsAutoFocusPoint(event: MotionEvent?): Boolean
+    {
+        return (false)
     }
 
-    override fun singleShot() {
-        TODO("Not yet implemented")
+    override fun singleShot()
+    {
+        singleShot.singleShot(sessionIdHolder.isApiLevelV21())
     }
 
-    override fun movieControl() {
-        TODO("Not yet implemented")
+    override fun movieControl()
+    {
+        // TODO("Not yet implemented")
     }
 
-    override fun bracketingShot(bracketingStyle: Int, bracketingCount: Int, durationSeconds: Int) {
-        TODO("Not yet implemented")
+    override fun bracketingShot(bracketingStyle: Int, bracketingCount: Int, durationSeconds: Int)
+    {
+        // TODO("Not yet implemented")
     }
 
-    override fun setRecViewMode(isRecViewMode: Boolean) {
-        TODO("Not yet implemented")
+    override fun setRecViewMode(isRecViewMode: Boolean)
+    {
+        // なにもしない
     }
 
-    override fun toggleAutoExposure() {
-        TODO("Not yet implemented")
+    override fun toggleAutoExposure()
+    {
+        // なにもしない
     }
 
-    override fun toggleManualFocus() {
-        TODO("Not yet implemented")
+    override fun toggleManualFocus()
+    {
+        // なにもしない
     }
 
-    override fun isManualFocus(): Boolean {
-        TODO("Not yet implemented")
+    override fun isManualFocus(): Boolean
+    {
+        return (false)
     }
 
-    override fun isAFLock(): Boolean {
-        TODO("Not yet implemented")
+    override fun isAFLock(): Boolean
+    {
+        return (false)
     }
 
-    override fun isAELock(): Boolean {
-        TODO("Not yet implemented")
+    override fun isAELock(): Boolean
+    {
+        return (false)
     }
 
-    override fun updateStatusAll() {
-        TODO("Not yet implemented")
+    override fun updateStatusAll()
+    {
+        // なにもしない
     }
 
-    override fun getCameraPropertyProvider(): IOlyCameraPropertyProvider {
-        TODO("Not yet implemented")
+    override fun getCameraPropertyProvider(): IOlyCameraPropertyProvider
+    {
+        return (dummyOperation)
     }
 
-    override fun getCameraPropertyLoadSaveOperations(): ICameraPropertyLoadSaveOperations {
-        TODO("Not yet implemented")
+    override fun getCameraPropertyLoadSaveOperations(): ICameraPropertyLoadSaveOperations
+    {
+        return (dummyOperation)
     }
 
-    override fun getLoadSaveCameraProperties(): ILoadSaveCameraProperties {
-        TODO("Not yet implemented")
+    override fun getLoadSaveCameraProperties(): ILoadSaveCameraProperties
+    {
+        return (dummyOperation)
     }
 
-    override fun getChangeRunModeExecutor(): ICameraRunMode {
-        TODO("Not yet implemented")
+    override fun getChangeRunModeExecutor(): ICameraRunMode
+    {
+        return (dummyOperation)
     }
 
-    override fun getConnectionInterface(): ICameraConnection {
-        TODO("Not yet implemented")
+    override fun getConnectionInterface(): ICameraConnection
+    {
+        return (cameraConnection)
     }
 
-    override fun getZoomLensHolder(): IZoomLensHolder {
-        TODO("Not yet implemented")
+    override fun getZoomLensHolder(): IZoomLensHolder
+    {
+        return (dummyOperation)
     }
 
-    override fun getLevelGauge(): ILevelGauge {
-        TODO("Not yet implemented")
+    override fun getLevelGauge(): ILevelGauge
+    {
+        return (dummyOperation)
     }
 
+    override fun onAfLockUpdate(isAfLocked: Boolean)
+    {
+        //TODO("Not yet implemented")
+    }
 
-}
\ No newline at end of file
+    override fun onShootingStatusUpdate(status: IIndicatorControl.shootingStatus?)
+    {
+        //TODO("Not yet implemented")
+    }
+}
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/ThetaSessionHolder.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/ThetaSessionHolder.kt
new file mode 100644 (file)
index 0000000..cf8964b
--- /dev/null
@@ -0,0 +1,24 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper
+
+class ThetaSessionHolder : IThetaSessionIdProvider, IThetaSessionIdNotifier
+{
+    private var sessionId : String = ""
+
+    override fun getSessionId(): String
+    {
+        return (sessionId)
+    }
+
+    override fun receivedSessionId(sessionId: String?)
+    {
+        if (sessionId != null)
+        {
+            this.sessionId = sessionId
+        }
+    }
+
+    fun isApiLevelV21() : Boolean
+    {
+        return (!(sessionId.isNotEmpty()))
+    }
+}
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnectSequence.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnectSequence.kt
new file mode 100644 (file)
index 0000000..cbf8c38
--- /dev/null
@@ -0,0 +1,189 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.connection
+
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import jp.sfjp.gokigen.a01c.R
+import jp.sfjp.gokigen.a01c.liveview.ICameraStatusReceiver
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.IThetaSessionIdNotifier
+import jp.sfjp.gokigen.a01c.utils.SimpleHttpClient
+import org.json.JSONObject
+
+class ThetaCameraConnectSequence(private val context: AppCompatActivity, private val cameraStatusReceiver: ICameraStatusReceiver, private val sessionIdNotifier: IThetaSessionIdNotifier) : Runnable
+{
+    private var useThetaV21 : Boolean = false
+    private val httpClient = SimpleHttpClient()
+
+    override fun run()
+    {
+        // 使用する API Levelを決める
+        useThetaV21 = decideApiLevel()
+        try
+        {
+            Log.v(TAG,"Theta API v2.1 : $useThetaV21")
+            if (useThetaV21)
+            {
+                // API Level V2.1を使用して通信する
+                connectApiV21()
+            }
+            else
+            {
+                // API Level V2 を使用して通信する
+                connectApiV2()
+            }
+        }
+        catch (e : Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    /**
+     *
+     */
+    private fun decideApiLevel() : Boolean
+    {
+        var apiLevelIsV21 = false
+        try
+        {
+            val oscInfoUrl = "http://192.168.1.1/osc/info"
+            val timeoutMs = 5000
+            val response: String = httpClient.httpGet(oscInfoUrl, timeoutMs)
+            Log.v(TAG, " $oscInfoUrl $response")
+            if (response.isNotEmpty())
+            {
+                val apiLevelArray = JSONObject(response).getJSONArray("apiLevel")
+                val size = apiLevelArray.length()
+                for (index in 0 until size)
+                {
+                    val api = apiLevelArray.getInt(index)
+                    if (api == 2)  //if (api == 2 && useThetaV21)
+                    {
+                        apiLevelIsV21 = true
+                    }
+                }
+            }
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+        return (apiLevelIsV21)
+    }
+
+    /**
+     *
+     */
+    private fun connectApiV2()
+    {
+        val commandsExecuteUrl = "http://192.168.1.1/osc/commands/execute"
+        val startSessionData = "{\"name\":\"camera.startSession\",\"parameters\":{\"timeout\":0}}"
+        val getStateUrl = "http://192.168.1.1/osc/state"
+        val timeoutMs = 5000
+        try
+        {
+            val response: String? = httpClient.httpPostWithHeader(commandsExecuteUrl, startSessionData, null, "application/json;charset=utf-8", timeoutMs)
+            Log.v(TAG, " $commandsExecuteUrl $startSessionData $response")
+
+            val response2: String? = httpClient.httpPostWithHeader(getStateUrl, "", null, "application/json;charset=utf-8", timeoutMs)
+            Log.v(TAG, " $getStateUrl $response2")
+            if ((response2 != null)&&(response2.isNotEmpty()))
+            {
+                try
+                {
+                    val jsonObject = JSONObject(response2)
+                    val sessionId = jsonObject.getJSONObject("state").getString("sessionId")
+                    sessionIdNotifier.receivedSessionId(sessionId)
+                    onConnectNotify()
+                    return
+                }
+                catch (e: Exception)
+                {
+                    e.printStackTrace()
+                }
+            }
+            // 応答なし、を応答する。
+            onConnectError(context.getString(R.string.theta_connect_response_ng))
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+            onConnectError(e.localizedMessage)
+        }
+    }
+
+    private fun connectApiV21() {
+        val commandsExecuteUrl = "http://192.168.1.1/osc/commands/execute"
+        val startSessionData = "{\"name\":\"camera.startSession\",\"parameters\":{\"timeout\":0}}"
+        val getStateUrl = "http://192.168.1.1/osc/state"
+        val timeoutMs = 5000
+        try {
+            val responseS: String? = httpClient.httpPostWithHeader(commandsExecuteUrl, startSessionData, null, "application/json;charset=utf-8", timeoutMs)
+            Log.v(TAG, " [ $httpClient ] $startSessionData ::: $responseS")
+            val response: String? = httpClient.httpPostWithHeader(getStateUrl, "", null, null, timeoutMs)
+            Log.v(TAG, " ($getStateUrl) $response")
+            if ((response != null)&&(response.isNotEmpty()))
+            {
+                var apiLevel = 1
+                var sessionId: String? = null
+                val `object` = JSONObject(response)
+                try {
+                    apiLevel = `object`.getJSONObject("state").getInt("_apiVersion")
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                }
+                try {
+                    sessionId = `object`.getJSONObject("state").getString("sessionId")
+                    sessionIdNotifier.receivedSessionId(sessionId)
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                }
+                if (apiLevel != 2) {
+                    val setApiLevelData = "{\"name\":\"camera.setOptions\",\"parameters\":{\"sessionId\" : \"$sessionId\", \"options\":{ \"clientVersion\":2}}}"
+                    val response3: String? = httpClient.httpPostWithHeader(commandsExecuteUrl, setApiLevelData, null, "application/json;charset=utf-8", timeoutMs)
+                    Log.v(TAG, " $commandsExecuteUrl $setApiLevelData $response3")
+                }
+                onConnectNotify()
+            } else {
+                onConnectError(context.getString(R.string.camera_not_found))
+            }
+        } catch (e: Exception)
+        {
+            e.printStackTrace()
+            onConnectError(e.localizedMessage)
+        }
+    }
+
+    private fun onConnectNotify()
+    {
+        try
+        {
+            val thread = Thread { // カメラとの接続確立を通知する
+                cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_connected))
+                cameraStatusReceiver.onCameraConnected()
+                Log.v(TAG, "onConnectNotify()")
+            }
+            thread.start()
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    private fun onConnectError(reason: String?)
+    {
+        if (reason != null)
+        {
+            cameraStatusReceiver.onCameraConnectError(reason)
+        }
+        else
+        {
+            cameraStatusReceiver.onCameraConnectError("")
+        }
+    }
+
+    companion object
+    {
+        private val TAG = ThetaCameraConnectSequence::class.java.simpleName
+    }
+}
\ No newline at end of file
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnection.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraConnection.kt
new file mode 100644 (file)
index 0000000..cc08ce7
--- /dev/null
@@ -0,0 +1,166 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.connection
+
+import android.content.*
+import android.net.ConnectivityManager
+import android.net.wifi.WifiManager
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import jp.sfjp.gokigen.a01c.ICameraConnection
+import jp.sfjp.gokigen.a01c.R
+import jp.sfjp.gokigen.a01c.liveview.ICameraStatusReceiver
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.IThetaSessionIdNotifier
+import java.util.concurrent.Executor
+import java.util.concurrent.Executors
+
+/**
+ *
+ */
+class ThetaCameraConnection(private val context: AppCompatActivity, private val statusReceiver: ICameraStatusReceiver, private val sessionIdNotifier: IThetaSessionIdNotifier) : ICameraConnection
+{
+    private val cameraExecutor: Executor = Executors.newFixedThreadPool(1)
+    private var connectionStatus: ICameraConnection.CameraConnectionStatus = ICameraConnection.CameraConnectionStatus.UNKNOWN
+    private var isNetworkStatusWatching : Boolean = false
+    private var connectionReceiver = object : BroadcastReceiver()
+    {
+        override fun onReceive(context: Context, intent: Intent)
+        {
+            onReceiveBroadcastOfConnection(context, intent)
+        }
+    }
+
+    /**
+     *
+     */
+    private fun onReceiveBroadcastOfConnection(context: Context, intent: Intent)
+    {
+        statusReceiver.onStatusNotify(context.getString(R.string.connect_check_wifi))
+        Log.v(TAG, context.getString(R.string.connect_check_wifi))
+        val action = intent.action
+        if (action == null)
+        {
+            Log.v(TAG, "intent.getAction() : null")
+            return
+        }
+        try
+        {
+            if (action == ConnectivityManager.CONNECTIVITY_ACTION)
+            {
+                Log.v(TAG, "onReceiveBroadcastOfConnection() : CONNECTIVITY_ACTION")
+                val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+                val info = wifiManager.connectionInfo
+                if ((wifiManager.isWifiEnabled)&&(info != null))
+                {
+                    connectToCamera()
+                }
+                else
+                {
+                    if (info == null)
+                    {
+                        Log.v(TAG, "NETWORK INFO IS NULL.")
+                    }
+                    else
+                    {
+                        Log.v(TAG, "isWifiEnabled : " + wifiManager.isWifiEnabled + " NetworkId : " + info.networkId)
+                    }
+                }
+            }
+        }
+        catch (e: Exception)
+        {
+            Log.w(TAG, "onReceiveBroadcastOfConnection() EXCEPTION" + e.message)
+            e.printStackTrace()
+        }
+    }
+
+    /**
+     *
+     */
+    override fun startWatchWifiStatus(context: Context)
+    {
+        Log.v(TAG, "startWatchWifiStatus()")
+        statusReceiver.onStatusNotify("prepare")
+        isNetworkStatusWatching = true
+        val filter = IntentFilter()
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION)
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
+        context.registerReceiver(connectionReceiver, filter)
+    }
+
+    /**
+     *
+     */
+    override fun stopWatchWifiStatus(context: Context)
+    {
+        Log.v(TAG, "stopWatchWifiStatus()")
+        isNetworkStatusWatching = false
+        context.unregisterReceiver(connectionReceiver)
+        disconnect(false)
+    }
+
+    /**
+     *
+     */
+    override fun isWatchWifiStatus(): Boolean
+    {
+        return (isNetworkStatusWatching)
+    }
+
+    /**
+     *
+     */
+    override fun disconnect(powerOff: Boolean)
+    {
+        Log.v(TAG, "disconnect()")
+        disconnectFromCamera(powerOff)
+        connectionStatus = ICameraConnection.CameraConnectionStatus.DISCONNECTED
+        statusReceiver.onCameraDisconnected()
+    }
+
+    /**
+     *
+     */
+    override fun connect()
+    {
+        Log.v(TAG, "connect()")
+        connectToCamera()
+    }
+
+    /**
+     * カメラとの切断処理
+     */
+    private fun disconnectFromCamera(powerOff: Boolean)
+    {
+        Log.v(TAG, "disconnectFromCamera() : $powerOff")
+        try
+        {
+            cameraExecutor.execute(ThetaCameraDisconnectSequence())
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    /**
+     * カメラとの接続処理
+     */
+    private fun connectToCamera()
+    {
+        Log.v(TAG, "connectToCamera()")
+        connectionStatus = ICameraConnection.CameraConnectionStatus.CONNECTING
+        try
+        {
+            cameraExecutor.execute(ThetaCameraConnectSequence(context, statusReceiver, sessionIdNotifier))
+        }
+        catch (e: Exception)
+        {
+            Log.v(TAG, "connectToCamera() EXCEPTION : " + e.message)
+            e.printStackTrace()
+        }
+    }
+
+    companion object
+    {
+        private val TAG = ThetaCameraConnection::class.java.simpleName
+    }
+}
\ No newline at end of file
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraDisconnectSequence.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/connection/ThetaCameraDisconnectSequence.kt
new file mode 100644 (file)
index 0000000..9938665
--- /dev/null
@@ -0,0 +1,12 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.connection
+
+import android.util.Log
+
+class ThetaCameraDisconnectSequence : Runnable
+{
+    override fun run()
+    {
+        // カメラをPowerOffして接続を切る
+        Log.v(ThetaCameraDisconnectSequence::class.java.simpleName, " Disconnect from THETA.")
+    }
+}
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/liveview/ThetaLiveViewControl.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/liveview/ThetaLiveViewControl.kt
new file mode 100644 (file)
index 0000000..b0648aa
--- /dev/null
@@ -0,0 +1,110 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.liveview
+
+import android.util.Log
+import jp.sfjp.gokigen.a01c.liveview.CameraLiveViewListenerImpl
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.IThetaSessionIdProvider
+import jp.sfjp.gokigen.a01c.utils.SimpleLiveviewSlicer
+
+class ThetaLiveViewControl(private val sessionIdProvider: IThetaSessionIdProvider, private val liveViewListener: CameraLiveViewListenerImpl)
+{
+    private var whileFetching = false
+
+    fun startLiveView()
+    {
+        Log.v(TAG, " startLiveView()")
+        try
+        {
+            val thread = Thread {
+                try
+                {
+
+                    start(!(sessionIdProvider.sessionId.isEmpty()))
+                }
+                catch (e: Exception)
+                {
+                    e.printStackTrace()
+                }
+            }
+            thread.start()
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    fun stopLiveView()
+    {
+        Log.v(TAG, " stopLiveView()")
+        whileFetching = false
+    }
+
+    private fun start(useOscV2 : Boolean)
+    {
+        if (whileFetching)
+        {
+            Log.v(TAG, "start() already starting.")
+            return
+        }
+        whileFetching = true
+
+        try
+        {
+            val thread = Thread {
+                Log.d(TAG, "Starting retrieving streaming data from server.")
+                val slicer = SimpleLiveviewSlicer()
+                var continuousNullDataReceived = 0
+                try
+                {
+                    val streamUrl = "http://192.168.1.1/osc/commands/execute"
+                    val paramData = if (useOscV2) "{\"name\":\"camera.getLivePreview\",\"parameters\":{\"timeout\":0}}" else "{\"name\":\"camera._getLivePreview\",\"parameters\":{\"sessionId\": \"" + sessionIdProvider.getSessionId().toString() + "\"}}"
+                    Log.v(TAG, " >>>>> START THETA PREVIEW : $streamUrl $paramData")
+
+                    // Create Slicer to open the stream and parse it.
+                    slicer.open(streamUrl, paramData, "application/json;charset=utf-8")
+                    while (whileFetching) {
+                        val payload: SimpleLiveviewSlicer.Payload? = slicer.nextPayloadForMotionJpeg()
+                        if (payload == null)
+                        {
+                            //Log.v(TAG, "Liveview Payload is null.");
+                            continuousNullDataReceived++
+                            if (continuousNullDataReceived > FETCH_ERROR_MAX)
+                            {
+                                Log.d(TAG, " FETCH ERROR MAX OVER ")
+                                break
+                            }
+                            continue
+                        }
+                        liveViewListener.setImageData(payload.jpegData, null)
+                        continuousNullDataReceived = 0
+                    }
+                }
+                catch (e: Exception)
+                {
+                    e.printStackTrace()
+                }
+                finally
+                {
+                    slicer.close()
+                    if (whileFetching && continuousNullDataReceived > FETCH_ERROR_MAX)
+                    {
+                        // 再度ライブビューのスタートをやってみる。
+                        whileFetching = false
+                        start(useOscV2)
+                    }
+                }
+            }
+            thread.start()
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    companion object
+    {
+        private val TAG = ThetaLiveViewControl::class.java.simpleName
+        private const val FETCH_ERROR_MAX = 30
+    }
+}
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaDummyOperation.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaDummyOperation.kt
new file mode 100644 (file)
index 0000000..d9d7a41
--- /dev/null
@@ -0,0 +1,182 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.operation
+
+import android.graphics.Color
+import jp.co.olympus.camerakit.OLYCamera
+import jp.sfjp.gokigen.a01c.olycamerawrapper.ICameraHardwareStatus
+import jp.sfjp.gokigen.a01c.olycamerawrapper.ICameraRunMode
+import jp.sfjp.gokigen.a01c.olycamerawrapper.ILevelGauge
+import jp.sfjp.gokigen.a01c.olycamerawrapper.IZoomLensHolder
+import jp.sfjp.gokigen.a01c.olycamerawrapper.property.ICameraPropertyLoadSaveOperations
+import jp.sfjp.gokigen.a01c.olycamerawrapper.property.ILoadSaveCameraProperties
+import jp.sfjp.gokigen.a01c.olycamerawrapper.property.IOlyCameraPropertyProvider
+
+class ThetaDummyOperation : ILevelGauge, IZoomLensHolder, ICameraRunMode, ILoadSaveCameraProperties, ICameraPropertyLoadSaveOperations, IOlyCameraPropertyProvider, ICameraHardwareStatus
+{
+    override fun getLevel(area: ILevelGauge.LevelArea?): Float {
+        // TODO("Not yet implemented")
+        return (1.0f)
+    }
+
+    override fun getLevelColor(value: Float): Int {
+        // TODO("Not yet implemented")
+        return (Color.WHITE)
+    }
+
+    override fun checkLevelGauge(camera: OLYCamera?) {
+        // TODO("Not yet implemented")
+    }
+
+    override fun updateLevelGaugeChecking(isWatch: Boolean) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun canZoom(): Boolean {
+        //TODO("Not yet implemented")
+        return (false)
+    }
+
+    override fun updateStatus() {
+        //TODO("Not yet implemented")
+    }
+
+    override fun getMaximumFocalLength(): Float {
+        // TODO("Not yet implemented")
+        return (16.0f)
+    }
+
+    override fun getActualFocalLength(): Float {
+        TODO("Not yet implemented")
+    }
+
+    override fun inquireHardwareInformation(): MutableMap<String, Any> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getLensMountStatus(): String {
+        TODO("Not yet implemented")
+    }
+
+    override fun getMediaMountStatus(): String {
+        TODO("Not yet implemented")
+    }
+
+    override fun getMinimumFocalLength(): Float {
+        //TODO("Not yet implemented")
+        return (16.0f)
+    }
+
+    override fun getCurrentFocalLength(): Float {
+        //TODO("Not yet implemented")
+        return (16.0f)
+    }
+
+    override fun driveZoomLens(targetLength: Float) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun driveZoomLens(direction: Int) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun isDrivingZoomLens(): Boolean {
+        //TODO("Not yet implemented")
+        return (false)
+    }
+
+    override fun getCurrentDigitalZoomScale(): Float {
+        //TODO("Not yet implemented")
+        return (1.0f)
+    }
+
+    override fun magnifyLiveView(scale: Int): Boolean {
+        //TODO("Not yet implemented")
+        return (false)
+    }
+
+    override fun changeDigitalZoomScale(scale: Float, isCyclic: Boolean) {
+       // TODO("Not yet implemented")
+    }
+
+    override fun changeRunMode(isRecording: Boolean) {
+      //TODO("Not yet implemented")
+    }
+
+    override fun isRecordingMode(): Boolean {
+        //TODO("Not yet implemented")
+        return (true)
+    }
+
+    override fun loadCameraSettings(id: String?) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun saveCameraSettings(id: String?, name: String?) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun saveProperties(idHeader: String?, dataName: String?) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun loadProperties(idHeader: String?, dataName: String?) {
+        //TODO("Not yet implemented")
+    }
+
+    override fun getCameraPropertyNames(): MutableSet<String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getCameraPropertyValue(name: String?): String {
+        //TODO("Not yet implemented")
+        return ("")
+    }
+
+    override fun getCameraPropertyValues(names: MutableSet<String>?): MutableMap<String, String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getCameraPropertyTitle(name: String?): String {
+        TODO("Not yet implemented")
+    }
+
+    override fun getCameraPropertyValueList(name: String?): MutableList<String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getCameraPropertyValueTitle(propertyValue: String?): String {
+        TODO("Not yet implemented")
+    }
+
+    override fun setCameraPropertyValue(name: String?, value: String?) {
+        TODO("Not yet implemented")
+    }
+
+    override fun setCameraPropertyValues(values: MutableMap<String, String>?) {
+        TODO("Not yet implemented")
+    }
+
+    override fun updateCameraPropertyUp(name: String?) {
+        TODO("Not yet implemented")
+    }
+
+    override fun updateCameraPropertyDown(name: String?) {
+        TODO("Not yet implemented")
+    }
+
+    override fun changeCameraProperty(name: String?, direction: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun canSetCameraProperty(name: String?): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun isConnected(): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun getHardwareStatus(): ICameraHardwareStatus {
+        TODO("Not yet implemented")
+    }
+
+}
\ No newline at end of file
diff --git a/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaSingleShotControl.kt b/wear/src/main/java/jp/sfjp/gokigen/a01c/thetacamerawrapper/operation/ThetaSingleShotControl.kt
new file mode 100644 (file)
index 0000000..8caa898
--- /dev/null
@@ -0,0 +1,141 @@
+package jp.sfjp.gokigen.a01c.thetacamerawrapper.operation
+
+import android.util.Log
+import jp.sfjp.gokigen.a01c.ICameraController
+import jp.sfjp.gokigen.a01c.olycamerawrapper.IIndicatorControl
+import jp.sfjp.gokigen.a01c.thetacamerawrapper.IThetaSessionIdProvider
+import jp.sfjp.gokigen.a01c.utils.SimpleHttpClient
+import org.json.JSONObject
+
+
+class ThetaSingleShotControl(private val sessionIdProvider: IThetaSessionIdProvider, private val indicator: IIndicatorControl, private val liveViewControl: ICameraController)
+{
+    private val httpClient = SimpleHttpClient()
+
+    /**
+     *
+     *
+     */
+    fun singleShot(useThetaV21 : Boolean)
+    {
+        Log.v(TAG, "singleShot()")
+        try
+        {
+            val thread = Thread {
+                try
+                {
+                    val shootUrl = "http://192.168.1.1/osc/commands/execute"
+                    val postData = if (useThetaV21) "{\"name\":\"camera.takePicture\",\"parameters\":{\"timeout\":0}}" else "{\"name\":\"camera.takePicture\",\"parameters\":{\"sessionId\": \"" + sessionIdProvider.sessionId + "\"}}"
+                    val result: String? = httpClient.httpPostWithHeader(shootUrl, postData, null, "application/json;charset=utf-8", timeoutMs)
+                    if ((result != null)&&(result.isNotEmpty()))
+                    {
+                        Log.v(TAG, " singleShot() : $result")
+                        indicator.onShootingStatusUpdate(IIndicatorControl.shootingStatus.Starting)
+
+                        // 画像処理が終わるまで待つ
+                        waitChangeStatus()
+
+                        // ライブビューのの再実行を指示する
+                        indicator.onShootingStatusUpdate(IIndicatorControl.shootingStatus.Stopping)
+                        liveViewControl.stopLiveView()
+                        waitMs(300) // ちょっと待つ...
+                        liveViewControl.startLiveView()
+                    }
+                    else
+                    {
+                        Log.v(TAG, "singleShot() reply is null.")
+                    }
+                }
+                catch (e: Exception)
+                {
+                    e.printStackTrace()
+                }
+            }
+            thread.start()
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    /**
+     * 撮影状態が変わるまで待つ。
+     * (ただし、タイムアウト時間を超えたらライブビューを再開させる)
+     */
+    private fun waitChangeStatus()
+    {
+        val getStateUrl = "http://192.168.1.1/osc/state"
+        val maxWaitTimeoutMs = 9000 // 最大待ち時間 (単位: ms)
+        var fingerprint = ""
+        try
+        {
+            val result: String? = httpClient.httpPost(getStateUrl, "", timeoutMs)
+            if ((result != null)&&(result.isNotEmpty()))
+            {
+                val jsonObject = JSONObject(result)
+                fingerprint = jsonObject.getString("fingerprint")
+
+                //  現在の状態(ログを出す)
+                Log.v(TAG, " $getStateUrl $result ($fingerprint)")
+            }
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+
+        try
+        {
+            val firstTime = System.currentTimeMillis()
+            var currentTime = firstTime
+            while (currentTime - firstTime < maxWaitTimeoutMs)
+            {
+                //  ... 状態を見て次に進める
+                val result: String? = httpClient.httpPost(getStateUrl, "", timeoutMs)
+                if ((result != null)&&(result.isNotEmpty()))
+                {
+                    val jsonObject = JSONObject(result)
+                    val currentFingerprint = jsonObject.getString("fingerprint")
+
+                    //  ログを出してみる
+                    // Log.v(TAG, " " + getStateUrl + " ( " + result + " ) " + "(" + fingerprint + " " + current_fingerprint + ")");
+                    if (fingerprint != currentFingerprint)
+                    {
+                        // fingerprintが更新された!
+                        break
+                    }
+                    Log.v(TAG, "  -----  NOW PROCESSING  ----- : $fingerprint")
+                }
+                waitMs(1000)
+                currentTime = System.currentTimeMillis()
+            }
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    private fun waitMs(waitMs: Int)
+    {
+        try
+        {
+            Thread.sleep(waitMs.toLong())
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+    }
+
+    companion object
+    {
+        private val TAG = ThetaSingleShotControl::class.java.simpleName
+        private const val timeoutMs = 6000
+    }
+}
index 3e81231..e43dc5f 100644 (file)
@@ -7,7 +7,7 @@ import java.io.*
 import java.net.HttpURLConnection
 import java.net.URL
 
-class SimpleHttpClient()
+class SimpleHttpClient
 {
     /**
      *
index e966102..727b8ee 100644 (file)
@@ -4,6 +4,7 @@ package jp.sfjp.gokigen.a01c.utils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
@@ -351,7 +352,7 @@ public class SimpleLiveviewSlicer
      *
      *
      */
-    public Payload nextPayloadForMotionJpeg()
+    public @Nullable Payload nextPayloadForMotionJpeg()
     {
         int searchIndex = 0;
         int[] endmarker = { 0xff, 0xd9 };
index 2264523..e7720ac 100644 (file)
@@ -74,4 +74,7 @@
     <string name="connection_method_opc">OPC</string>
     <string name="connection_method_theta">THETA</string>
 
+    <string name="theta_connect_response_ng">応答がありません。</string>
+    <string name="camera_not_found">カメラ未発見</string>
+
 </resources>
index 22bac36..86b39ba 100644 (file)
@@ -72,4 +72,7 @@
     <string name="connection_method_opc">OPC</string>
     <string name="connection_method_theta">THETA</string>
 
+    <string name="theta_connect_response_ng">Did not receive any response.</string>
+    <string name="camera_not_found">Not Found&#8230;</string>
+
 </resources>