OSDN Git Service

Theta拡張向けで、とりあえずビルドを通すところまで。
authorMRSa <mrsa@myad.jp>
Tue, 21 Jan 2020 15:22:43 +0000 (00:22 +0900)
committerMRSa <mrsa@myad.jp>
Tue, 21 Jan 2020 15:22:43 +0000 (00:22 +0900)
22 files changed:
app/src/main/java/net/osdn/gokigen/a01d/A01dMain.java
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/IThetaInterfaceProvider.java
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCameraInformation.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCaptureControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaFocusControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaInterfaceProvider.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaLiveViewControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaRunMode.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaZoomLensControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraConnectSequence.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraDisconnectSequence.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaConnection.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/hardware/ThetaHardwareStatus.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/status/ThetaCameraStatusWatcher.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/camera/utils/SimpleHttpClient.java
app/src/main/java/net/osdn/gokigen/a01d/camera/utils/SimpleHttpSendCommandDialog.java
app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java
app/src/main/res/layout-land/http_request_layout.xml
app/src/main/res/layout/http_request_layout.xml
app/src/main/res/values-ja/strings.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/preferences_theta.xml

index d07047d..52ce47b 100644 (file)
@@ -264,7 +264,6 @@ public class A01dMain extends AppCompatActivity implements ICameraStatusReceiver
                 {
                     // FUJI X Seriesの場合は、コマンド送信ダイアログを表示する
                     FujiXCameraCommandSendDialog.newInstance(interfaceProvider.getFujiXInterface()).show(getSupportFragmentManager(), "sendCommandDialog");
-
                 }
                 catch (Exception e)
                 {
index fb647f6..e7363b4 100644 (file)
@@ -14,7 +14,7 @@ import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
 
 public interface IThetaInterfaceProvider
 {
-    ICameraConnection getCanonCameraConnection();
+    ICameraConnection getCameraConnection();
     ILiveViewControl getLiveViewControl();
     ILiveViewListener getLiveViewListener();
     IFocusingControl getFocusingControl();
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCameraInformation.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCameraInformation.java
new file mode 100644 (file)
index 0000000..2068405
--- /dev/null
@@ -0,0 +1,79 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import net.osdn.gokigen.a01d.camera.ICameraInformation;
+import net.osdn.gokigen.a01d.camera.olympus.wrapper.property.IOlyCameraPropertyProvider;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ThetaCameraInformation implements ICameraInformation, IOlyCameraPropertyProvider
+{
+    ThetaCameraInformation()
+    {
+
+    }
+
+    @Override
+    public boolean isManualFocus()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isElectricZoomLens()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isExposureLocked()
+    {
+        return false;
+    }
+
+    @Override
+    public Set<String> getCameraPropertyNames() {
+        return null;
+    }
+
+    @Override
+    public String getCameraPropertyValue(String name) {
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getCameraPropertyValues(Set<String> names) {
+        return null;
+    }
+
+    @Override
+    public String getCameraPropertyTitle(String name) {
+        return null;
+    }
+
+    @Override
+    public List<String> getCameraPropertyValueList(String name) {
+        return null;
+    }
+
+    @Override
+    public String getCameraPropertyValueTitle(String propertyValue) {
+        return null;
+    }
+
+    @Override
+    public void setCameraPropertyValue(String name, String value) {
+
+    }
+
+    @Override
+    public void setCameraPropertyValues(Map<String, String> values) {
+
+    }
+
+    @Override
+    public boolean canSetCameraProperty(String name) {
+        return false;
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCaptureControl.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaCaptureControl.java
new file mode 100644 (file)
index 0000000..267ffde
--- /dev/null
@@ -0,0 +1,42 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ICaptureControl;
+import net.osdn.gokigen.a01d.camera.olympuspen.operation.OlympusPenSingleShotControl;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.PanasonicCameraCaptureControl;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.takepicture.SingleShotControl;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCamera;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+public class ThetaCaptureControl implements ICaptureControl
+{
+    private static final String TAG = PanasonicCameraCaptureControl.class.getSimpleName();
+    //private final OlympusPenSingleShotControl singleShotControl;
+
+    public ThetaCaptureControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+    {
+        //singleShotControl = new OlympusPenSingleShotControl(frameDisplayer, indicator);
+    }
+
+    /**
+     *   撮影する
+     *
+     */
+    @Override
+    public void doCapture(int kind)
+    {
+        Log.v(TAG, "doCapture() : " + kind);
+        try
+        {
+            //singleShotControl.singleShot();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaFocusControl.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaFocusControl.java
new file mode 100644 (file)
index 0000000..a8f67ed
--- /dev/null
@@ -0,0 +1,83 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.IFocusingControl;
+import net.osdn.gokigen.a01d.camera.olympuspen.operation.OlympusPenAutoFocusControl;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+public class ThetaFocusControl implements IFocusingControl
+{
+    private final String TAG = toString();
+    //private final OlympusPenAutoFocusControl afControl;
+    private final IAutoFocusFrameDisplay frameDisplay;
+
+    ThetaFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, @NonNull final IIndicatorControl indicator)
+    {
+        this.frameDisplay = frameDisplayer;
+        //afControl = new OlympusPenAutoFocusControl(frameDisplayer, indicator);
+    }
+
+    @Override
+    public boolean driveAutoFocus(final MotionEvent motionEvent)
+    {
+        Log.v(TAG, "driveAutoFocus()");
+        if (motionEvent.getAction() != MotionEvent.ACTION_DOWN)
+        {
+            return (false);
+        }
+        try
+        {
+            PointF point = frameDisplay.getPointWithEvent(motionEvent);
+            if (frameDisplay.isContainsPoint(point))
+            {
+               //afControl.lockAutoFocus(point);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return (false);
+    }
+
+    @Override
+    public void unlockAutoFocus()
+    {
+        Log.v(TAG, "unlockAutoFocus()");
+        try
+        {
+            //afControl.unlockAutoFocus();
+            frameDisplay.hideFocusFrame();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void halfPressShutter(boolean isPressed)
+    {
+        Log.v(TAG, "halfPressShutter() " + isPressed);
+        try
+        {
+            //afControl.halfPressShutter(isPressed);
+            if (!isPressed)
+            {
+                // フォーカスを外す
+                frameDisplay.hideFocusFrame();
+                //afControl.unlockAutoFocus();
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaInterfaceProvider.java
new file mode 100644 (file)
index 0000000..a512646
--- /dev/null
@@ -0,0 +1,164 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.CameraStatusListener;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraInformation;
+import net.osdn.gokigen.a01d.camera.ICameraStatus;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.ICameraStatusWatcher;
+import net.osdn.gokigen.a01d.camera.ICaptureControl;
+import net.osdn.gokigen.a01d.camera.IDisplayInjector;
+import net.osdn.gokigen.a01d.camera.IFocusingControl;
+import net.osdn.gokigen.a01d.camera.IFocusingModeNotify;
+import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+import net.osdn.gokigen.a01d.camera.IZoomLensControl;
+import net.osdn.gokigen.a01d.camera.theta.IThetaInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.theta.wrapper.connection.ThetaConnection;
+import net.osdn.gokigen.a01d.camera.theta.wrapper.hardware.ThetaHardwareStatus;
+import net.osdn.gokigen.a01d.camera.theta.wrapper.status.ThetaCameraStatusWatcher;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
+
+/**
+ *
+ *
+ */
+public class ThetaInterfaceProvider implements IThetaInterfaceProvider, IDisplayInjector
+{
+    private final String TAG = toString();
+    private final ThetaConnection thetaConnection;
+    private final ThetaHardwareStatus hardwareStatus;
+    private final ThetaRunMode runMode;
+    private final ThetaLiveViewControl liveViewControl;
+    private final ThetaZoomLensControl zoomLensControl;
+    private final ThetaCameraInformation cameraInformation;
+    private final ThetaCameraStatusWatcher statusWatcher;
+    private final CameraStatusListener statusListener;
+    private  ThetaFocusControl focusControl = null;
+    private  ThetaCaptureControl captureControl = null;
+
+    /**
+     *
+     *
+     */
+    public ThetaInterfaceProvider(@NonNull Activity context, @NonNull ICameraStatusReceiver provider, @NonNull CameraStatusListener statusListener)
+    {
+/*
+        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+        int communicationTimeoutMs = 10000;  // デフォルトは 10000ms とする
+        try
+        {
+            communicationTimeoutMs = Integer.parseInt(preferences.getString(IPreferencePropertyAccessor.RICOH_GET_PICS_LIST_TIMEOUT, IPreferencePropertyAccessor.RICOH_GET_PICS_LIST_TIMEOUT_DEFAULT_VALUE)) * 1000;
+            if (communicationTimeoutMs < 3000)
+            {
+                communicationTimeoutMs = 3000;  // 最小値は 3000msとする。
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+*/
+        //this.activity = context;
+        //this.provider = provider;
+        this.statusListener = statusListener;
+        thetaConnection = new ThetaConnection(context, provider);
+        hardwareStatus = new ThetaHardwareStatus();
+        statusWatcher = new ThetaCameraStatusWatcher();
+        runMode = new ThetaRunMode();
+        liveViewControl = new ThetaLiveViewControl(statusWatcher, statusListener);
+        zoomLensControl = new ThetaZoomLensControl(hardwareStatus);
+        cameraInformation = new ThetaCameraInformation();
+    }
+
+    public void prepare()
+    {
+        Log.v(TAG, "prepare()");
+    }
+
+    @Override
+    public void injectDisplay(IAutoFocusFrameDisplay frameDisplayer, IIndicatorControl indicator, IFocusingModeNotify focusingModeNotify)
+    {
+        Log.v(TAG, "injectDisplay()");
+        focusControl = new ThetaFocusControl(frameDisplayer, indicator);
+        captureControl = new ThetaCaptureControl(frameDisplayer, indicator);
+    }
+
+    @Override
+    public ICameraConnection getCameraConnection()
+    {
+        return (thetaConnection);
+    }
+
+    @Override
+    public ILiveViewControl getLiveViewControl()
+    {
+        return (liveViewControl);
+    }
+
+    @Override
+    public ILiveViewListener getLiveViewListener()
+    {
+        return (liveViewControl.getLiveViewListener());
+    }
+
+    @Override
+    public IFocusingControl getFocusingControl()
+    {
+        return (focusControl);
+    }
+
+    @Override
+    public ICameraInformation getCameraInformation()
+    {
+        return (cameraInformation);
+    }
+
+    @Override
+    public IZoomLensControl getZoomLensControl()
+    {
+        return (zoomLensControl);
+    }
+
+    @Override
+    public ICaptureControl getCaptureControl()
+    {
+        return (captureControl);
+    }
+
+    @Override
+    public IDisplayInjector getDisplayInjector() {
+        return (this);
+    }
+
+    @Override
+    public ICameraStatusWatcher getStatusWatcher()
+    {
+        return (statusWatcher);
+    }
+
+    @Override
+    public ICameraStatusUpdateNotify getStatusListener()
+    {
+        return (statusListener);
+    }
+
+    @Override
+    public ICameraStatus getCameraStatusListHolder()
+    {
+        return (statusWatcher);
+    }
+
+    @Override
+    public ICameraStatusWatcher getCameraStatusWatcher() {
+        return (statusWatcher);
+    }
+
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaLiveViewControl.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaLiveViewControl.java
new file mode 100644 (file)
index 0000000..da3dfc7
--- /dev/null
@@ -0,0 +1,63 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.CameraStatusListener;
+import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+import net.osdn.gokigen.a01d.camera.theta.wrapper.status.ThetaCameraStatusWatcher;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.IImageDataReceiver;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
+
+
+public class ThetaLiveViewControl implements ILiveViewControl, ILiveViewListener
+{
+    ThetaLiveViewControl(@NonNull ThetaCameraStatusWatcher statusHolder, @NonNull CameraStatusListener statusListener)
+    {
+
+    }
+
+    ILiveViewListener getLiveViewListener()
+    {
+        return (this);
+    }
+
+    @Override
+    public void changeLiveViewSize(String size) {
+
+    }
+
+    @Override
+    public void startLiveView() {
+
+    }
+
+    @Override
+    public void stopLiveView() {
+
+    }
+
+    @Override
+    public void updateDigitalZoom() {
+
+    }
+
+    @Override
+    public void updateMagnifyingLiveViewScale(boolean isChangeScale) {
+
+    }
+
+    @Override
+    public float getMagnifyingLiveViewScale() {
+        return 0;
+    }
+
+    @Override
+    public float getDigitalZoomScale() {
+        return 0;
+    }
+
+    @Override
+    public void setCameraLiveImageView(IImageDataReceiver target) {
+
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaRunMode.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaRunMode.java
new file mode 100644 (file)
index 0000000..8d1d481
--- /dev/null
@@ -0,0 +1,25 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import net.osdn.gokigen.a01d.camera.olympus.wrapper.ICameraRunMode;
+
+public class ThetaRunMode implements ICameraRunMode
+{
+    private boolean runMode = false;
+
+    ThetaRunMode()
+    {
+        //
+    }
+
+    @Override
+    public void changeRunMode(boolean isRecording)
+    {
+        this.runMode = isRecording;
+    }
+
+    @Override
+    public boolean isRecordingMode()
+    {
+        return (runMode);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaZoomLensControl.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/ThetaZoomLensControl.java
new file mode 100644 (file)
index 0000000..1f43940
--- /dev/null
@@ -0,0 +1,140 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.IZoomLensControl;
+import net.osdn.gokigen.a01d.camera.olympuspen.wrapper.hardware.OlympusPenHardwareStatus;
+import net.osdn.gokigen.a01d.camera.theta.wrapper.hardware.ThetaHardwareStatus;
+import net.osdn.gokigen.a01d.camera.utils.SimpleHttpClient;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ThetaZoomLensControl  implements IZoomLensControl
+{
+    private final String TAG = toString();
+    private boolean isZooming = false;
+    private final ThetaHardwareStatus hardwareStatus;
+    private static final int TIMEOUT_MS = 3000;
+    private final String COMMUNICATION_URL = "http://192.168.0.10/";
+    private Map<String, String> headerMap;
+
+
+    ThetaZoomLensControl(@NonNull ThetaHardwareStatus hardwareStatus)
+    {
+        Log.v(TAG, "OlympusPenZoomLensControl()");
+
+        headerMap = new HashMap<>();
+        headerMap.put("User-Agent", "OlympusCameraKit"); // "OI.Share"
+        headerMap.put("X-Protocol", "OlympusCameraKit"); // "OI.Share"
+
+        this.hardwareStatus = hardwareStatus;
+    }
+
+    @Override
+    public boolean canZoom()
+    {
+        Log.v(TAG, "canZoom()");
+        return (false);
+    }
+
+    @Override
+    public void updateStatus()
+    {
+        hardwareStatus.updateStatus();
+    }
+
+    @Override
+    public float getMaximumFocalLength()
+    {
+        return (hardwareStatus.getMaximumFocalLength());
+    }
+
+    @Override
+    public float getMinimumFocalLength()
+    {
+        return (hardwareStatus.getMinimumFocalLength());
+    }
+
+    @Override
+    public float getCurrentFocalLength()
+    {
+        return (hardwareStatus.getActualFocalLength());
+    }
+
+    @Override
+    public void driveZoomLens(float targetLength)
+    {
+        Log.v(TAG, "driveZoomLens() : " + targetLength);
+    }
+
+    @Override
+    public void moveInitialZoomPosition()
+    {
+        Log.v(TAG, "moveInitialZoomPosition()");
+    }
+
+    @Override
+    public boolean isDrivingZoomLens()
+    {
+        Log.v(TAG, "isDrivingZoomLens()");
+        return (isZooming);
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void driveZoomLens(final boolean isZoomIn)
+    {
+        Log.v(TAG, "driveZoomLens() : " + isZoomIn);
+        try
+        {
+            Thread thread = new Thread(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    try
+                    {
+                        String command;
+                        if (isZooming)
+                        {
+                            command = "exec_takemisc.cgi?com=ctrlzoom&move=off";
+                            //command = (isZoomIn) ? "exec_takemisc.cgi?com=ctrlzoom&move=teleterm" : "exec_takemisc.cgi?com=ctrlzoom&move=wideterm";
+                        }
+                        else
+                        {
+                            command = (isZoomIn) ? "exec_takemisc.cgi?com=ctrlzoom&move=telemove" : "exec_takemisc.cgi?com=ctrlzoom&move=widemove";
+                        }
+                        String reply =  SimpleHttpClient.httpGetWithHeader(COMMUNICATION_URL + command , headerMap, null, TIMEOUT_MS);
+                        isZooming = !isZooming;
+                        Log.v(TAG, "ZOOM : " + isZooming + " cmd : " + command + "  RET : " + reply);
+/*
+                        if (reply.contains("ok"))
+                        {
+                            isZooming = !isZooming;
+                        }
+                        else
+                        {
+                            Log.v(TAG, "driveZoomLens() reply is failure.");
+                        }
+*/
+                    }
+                    catch (Exception e)
+                    {
+                        e.printStackTrace();
+                    }
+                }
+            });
+            thread.start();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraConnectSequence.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraConnectSequence.java
new file mode 100644 (file)
index 0000000..d067505
--- /dev/null
@@ -0,0 +1,188 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper.connection;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ *   Thetaとの接続シーケンス
+ *
+ */
+public class ThetaCameraConnectSequence implements Runnable
+{
+    private final String TAG = this.toString();
+    private final Activity context;
+    private final ICameraConnection cameraConnection;
+    private final ICameraStatusReceiver cameraStatusReceiver;
+
+    ThetaCameraConnectSequence(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection)
+    {
+        Log.v(TAG, "ThetaCameraConnectSequence");
+        this.context = context;
+        this.cameraConnection = cameraConnection;
+        this.cameraStatusReceiver = statusReceiver;
+    }
+
+    @Override
+    public void run()
+    {
+        try
+        {
+            final String oscInfoUrl = "http://192.168.1.1/osc/info";
+            final int TIMEOUT_MS = 5000;
+
+            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+            boolean useThetaV21 = preferences.getBoolean(IPreferencePropertyAccessor.USE_OSC_THETA_V21, false);
+
+            String response = SimpleHttpClient.httpGet(oscInfoUrl, TIMEOUT_MS);
+            Log.v(TAG, " " + oscInfoUrl + " " + response);
+            if (response.length() > 0)
+            {
+                try
+                {
+                    JSONArray apiLevelArray = new JSONObject(response).getJSONArray("apiLevel");
+                    int size = apiLevelArray.length();
+                    for (int index = 0; index < size; index++)
+                    {
+                        int api = apiLevelArray.getInt(index);
+                        if ((api == 2)&&(useThetaV21))
+                        {
+                            // API Level V2.1を使用して通信する
+                            connectApiV21();
+                            return;
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            // onConnectError(e.getLocalizedMessage());
+        }
+
+        // API Level V2 を使用して通信する
+        connectApiV2();
+    }
+
+    /**
+     *
+     */
+    private void connectApiV2()
+    {
+        final String commandsExecuteUrl = "http://192.168.1.1/osc/commands/execute";
+        final String startSessionData = "{\"name\":\"camera.startSession\",\"parameters\":{\"timeout\":0}}";
+        final String getStateUrl = "http://192.168.1.1/osc/state";
+        final int TIMEOUT_MS = 2000;
+
+        try
+        {
+            String response = SimpleHttpClient.httpPost(commandsExecuteUrl, startSessionData, TIMEOUT_MS);
+            Log.v(TAG, " " + commandsExecuteUrl + " " + startSessionData + " " + response);
+
+            String response2 = SimpleHttpClient.httpPost(getStateUrl, "", TIMEOUT_MS);
+            Log.v(TAG, " " + getStateUrl + " " + response2);
+
+            onConnectNotify();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            onConnectError(e.getLocalizedMessage());
+        }
+    }
+
+    private void connectApiV21()
+    {
+        final String commandsExecuteUrl = "http://192.168.1.1/osc/commands/execute";
+        final String startSessionData = "{\"name\":\"camera.startSession\",\"parameters\":{\"timeout\":0}}";
+        final String getStateUrl = "http://192.168.1.1/osc/state";
+        final int TIMEOUT_MS = 5000;
+
+        try
+        {
+            String responseS = SimpleHttpClient.httpPost(commandsExecuteUrl, startSessionData, TIMEOUT_MS);
+            Log.v(TAG, " " + commandsExecuteUrl + " " + startSessionData + " " + responseS);
+
+            String response = SimpleHttpClient.httpPost(getStateUrl, "", TIMEOUT_MS);
+            Log.v(TAG, " " + getStateUrl + " " + response);
+            if (response.length() > 0)
+            {
+                int apiLevel = 1;
+               JSONObject object = new JSONObject(response);
+               try
+               {
+                   apiLevel = object.getJSONObject("state").getInt("_apiVersion");
+               }
+               catch (Exception e)
+               {
+                   e.printStackTrace();
+               }
+               if (apiLevel != 2)
+               {
+                   JSONObject jsonObject = object.getJSONObject("state");
+                   String sessionId = jsonObject.getString("sessionId");
+                   String setApiLevelData = "{\"name\":\"camera.setOptions\",\"parameters\":{" + "\"sessionId\" : \"" + sessionId + "\", \"options\":{ \"clientVersion\":2}}}";
+
+                   String response3 = SimpleHttpClient.httpPost(commandsExecuteUrl, setApiLevelData, TIMEOUT_MS);
+                   Log.v(TAG, " " + commandsExecuteUrl + " " + setApiLevelData + " " + response3);
+               }
+                onConnectNotify();
+            }
+            else
+            {
+                onConnectError(context.getString(R.string.camera_not_found));
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            onConnectError(e.getLocalizedMessage());
+        }
+    }
+
+    private void onConnectNotify()
+    {
+        try
+        {
+            final Thread thread = new Thread(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    // カメラとの接続確立を通知する
+                    cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_connected));
+                    cameraStatusReceiver.onCameraConnected();
+                    Log.v(TAG, "onConnectNotify()");
+                }
+            });
+            thread.start();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private void onConnectError(String reason)
+    {
+        cameraConnection.alertConnectingFailed(reason);
+    }
+
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraDisconnectSequence.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaCameraDisconnectSequence.java
new file mode 100644 (file)
index 0000000..ae556e8
--- /dev/null
@@ -0,0 +1,39 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper.connection;
+
+import android.app.Activity;
+
+public class ThetaCameraDisconnectSequence implements Runnable
+{
+    private final String TAG = this.toString();
+
+    ThetaCameraDisconnectSequence(Activity activity, boolean isOff)
+    {
+        //
+    }
+
+    @Override
+    public void run()
+    {
+        // カメラをPowerOffして接続を切る
+/*
+        try
+        {
+            Map<String, String> headerMap = new HashMap<>();
+            headerMap.put("User-Agent", "OlympusCameraKit"); // "OI.Share"
+            headerMap.put("X-Protocol", "OlympusCameraKit"); // "OI.Share"
+
+            if (powerOff)
+            {
+                final String cameraPowerOffUrl = "http://192.168.0.10/exec_pwoff.cgi";
+                final int TIMEOUT_MS = 5000;
+                String response = SimpleHttpClient.httpGetWithHeader(cameraPowerOffUrl, headerMap, null, TIMEOUT_MS);
+                Log.v(TAG, " " + cameraPowerOffUrl + " " + response);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+*/
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaConnection.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/connection/ThetaConnection.java
new file mode 100644 (file)
index 0000000..63a1e50
--- /dev/null
@@ -0,0 +1,270 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper.connection;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class ThetaConnection implements ICameraConnection
+{
+    private final String TAG = toString();
+    private final Activity context;
+    private final ICameraStatusReceiver statusReceiver;
+    private final BroadcastReceiver connectionReceiver;
+    //private final ConnectivityManager connectivityManager;
+    private final Executor cameraExecutor = Executors.newFixedThreadPool(1);
+    //private final Handler networkConnectionTimeoutHandler;
+    //private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
+    private CameraConnectionStatus connectionStatus = CameraConnectionStatus.UNKNOWN;
+
+
+    /**
+     *
+     *
+     */
+    public ThetaConnection(@NonNull final Activity context, @NonNull final ICameraStatusReceiver statusReceiver)
+    {
+        Log.v(TAG, "ThetaConnection()");
+        this.context = context;
+        this.statusReceiver = statusReceiver;
+        connectionReceiver = new BroadcastReceiver()
+        {
+            @Override
+            public void onReceive(Context context, Intent intent)
+            {
+                onReceiveBroadcastOfConnection(context, intent);
+            }
+        };
+    }
+
+    /**
+     *
+     *
+     */
+    private void onReceiveBroadcastOfConnection(Context context, Intent intent)
+    {
+        statusReceiver.onStatusNotify(context.getString(R.string.connect_check_wifi));
+        Log.v(TAG,context.getString(R.string.connect_check_wifi));
+
+        String action = intent.getAction();
+        if (action == null)
+        {
+            //
+            Log.v(TAG, "intent.getAction() : null");
+            return;
+        }
+
+        try
+        {
+            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
+            {
+                Log.v(TAG, "onReceiveBroadcastOfConnection() : CONNECTIVITY_ACTION");
+
+                WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+                if (wifiManager != null) {
+                    WifiInfo info = wifiManager.getConnectionInfo();
+                    if (wifiManager.isWifiEnabled() && info != null)
+                    {
+                        if (info.getNetworkId() != -1)
+                        {
+                            Log.v(TAG, "Network ID is -1, there is no currently connected network.");
+                        }
+                        // 自動接続が指示されていた場合は、カメラとの接続処理を行う
+                        connectToCamera();
+                    } else {
+                        if (info == null)
+                        {
+                            Log.v(TAG, "NETWORK INFO IS NULL.");
+                        } else {
+                            Log.v(TAG, "isWifiEnabled : " + wifiManager.isWifiEnabled() + " NetworkId : " + info.getNetworkId());
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            Log.w(TAG, "onReceiveBroadcastOfConnection() EXCEPTION" + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void startWatchWifiStatus(Context context)
+    {
+        Log.v(TAG, "startWatchWifiStatus()");
+        statusReceiver.onStatusNotify("prepare");
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        context.registerReceiver(connectionReceiver, filter);
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void stopWatchWifiStatus(Context context)
+    {
+        Log.v(TAG, "stopWatchWifiStatus()");
+        context.unregisterReceiver(connectionReceiver);
+        disconnect(false);
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void disconnect(boolean powerOff)
+    {
+        Log.v(TAG, "disconnect()");
+        disconnectFromCamera(powerOff);
+        connectionStatus = CameraConnectionStatus.DISCONNECTED;
+        statusReceiver.onCameraDisconnected();
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void connect()
+    {
+        Log.v(TAG, "connect()");
+        connectToCamera();
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void alertConnectingFailed(String message)
+    {
+        Log.v(TAG, "alertConnectingFailed() : " + message);
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+                .setTitle(context.getString(R.string.dialog_title_connect_failed_theta))
+                .setMessage(message)
+                .setPositiveButton(context.getString(R.string.dialog_title_button_retry), new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which)
+                    {
+                        connect();
+                    }
+                })
+                .setNeutralButton(R.string.dialog_title_button_network_settings, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which)
+                    {
+                        try
+                        {
+                            // Wifi 設定画面を表示する
+                            context.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
+                        }
+                        catch (android.content.ActivityNotFoundException ex)
+                        {
+                            // Activity が存在しなかった...設定画面が起動できなかった
+                            Log.v(TAG, "android.content.ActivityNotFoundException...");
+
+                            // この場合は、再試行と等価な動きとする
+                            connect();
+                        }
+                        catch (Exception e)
+                        {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+        context.runOnUiThread(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                try
+                {
+                    builder.show();
+                }
+                catch (Exception e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    @Override
+    public CameraConnectionStatus getConnectionStatus()
+    {
+        Log.v(TAG, "getConnectionStatus()");
+        return (connectionStatus);
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void forceUpdateConnectionStatus(CameraConnectionStatus status)
+    {
+        Log.v(TAG, "forceUpdateConnectionStatus()");
+        connectionStatus = status;
+    }
+
+    /**
+     * カメラとの切断処理
+     */
+    private void disconnectFromCamera(final boolean powerOff)
+    {
+        Log.v(TAG, "disconnectFromCamera()");
+        try
+        {
+            cameraExecutor.execute(new ThetaCameraDisconnectSequence(context, powerOff));
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * カメラとの接続処理
+     */
+    private void connectToCamera()
+    {
+        Log.v(TAG, "connectToCamera()");
+        connectionStatus = CameraConnectionStatus.CONNECTING;
+        try
+        {
+            cameraExecutor.execute(new ThetaCameraConnectSequence(context, statusReceiver, this));
+        }
+        catch (Exception e)
+        {
+            Log.v(TAG, "connectToCamera() EXCEPTION : " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/hardware/ThetaHardwareStatus.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/hardware/ThetaHardwareStatus.java
new file mode 100644 (file)
index 0000000..cbef7d8
--- /dev/null
@@ -0,0 +1,55 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper.hardware;
+
+import net.osdn.gokigen.a01d.camera.olympus.wrapper.ICameraHardwareStatus;
+
+import java.util.Map;
+
+public class ThetaHardwareStatus implements ICameraHardwareStatus
+{
+    public void updateStatus()
+    {
+        //
+    }
+
+    @Override
+    public boolean isAvailableHardwareStatus()
+    {
+        return (false);
+    }
+
+    @Override
+    public String getLensMountStatus()
+    {
+        return (null);
+    }
+
+    @Override
+    public String getMediaMountStatus()
+    {
+        return (null);
+    }
+
+    @Override
+    public float getMinimumFocalLength()
+    {
+        return (0);
+    }
+
+    @Override
+    public float getMaximumFocalLength()
+    {
+        return (0);
+    }
+
+    @Override
+    public float getActualFocalLength()
+    {
+        return (0);
+    }
+
+    @Override
+    public Map<String, Object> inquireHardwareInformation()
+    {
+        return (null);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/status/ThetaCameraStatusWatcher.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/theta/wrapper/status/ThetaCameraStatusWatcher.java
new file mode 100644 (file)
index 0000000..c69b91c
--- /dev/null
@@ -0,0 +1,43 @@
+package net.osdn.gokigen.a01d.camera.theta.wrapper.status;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ICameraStatus;
+import net.osdn.gokigen.a01d.camera.ICameraStatusWatcher;
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+
+import java.util.List;
+
+public class ThetaCameraStatusWatcher implements ICameraStatus, ICameraStatusWatcher
+{
+    public ThetaCameraStatusWatcher()
+    {
+
+    }
+
+
+    @Override
+    public List<String> getStatusList(String key) {
+        return null;
+    }
+
+    @Override
+    public String getStatus(String key) {
+        return null;
+    }
+
+    @Override
+    public void setStatus(String key, String value) {
+
+    }
+
+    @Override
+    public void startStatusWatch(@NonNull ICameraStatusUpdateNotify notifier) {
+
+    }
+
+    @Override
+    public void stopStatusWatch() {
+
+    }
+}
index aca52ad..15f6929 100644 (file)
@@ -16,6 +16,7 @@ import java.util.List;
 import java.util.Map;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 /**
  *
@@ -132,7 +133,24 @@ public class SimpleHttpClient
      */
     public static void httpGetBytes(String url, Map<String, String> setProperty, int timeoutMs, @NonNull IReceivedMessageCallback callback)
     {
+        httpCommandBytes(url, "GET", null, setProperty, null, timeoutMs, callback);
+    }
+
+    /**
+     *
+     *
+     *
+     */
+    public static void httpPostBytes(String url, String postData, Map<String, String> setProperty, int timeoutMs, @NonNull IReceivedMessageCallback callback)
+    {
+        httpCommandBytes(url, "POST", postData, setProperty, null, timeoutMs, callback);
+    }
+
+    private static void httpCommandBytes(@NonNull String url, @NonNull String requestMethod, @Nullable String postData, @Nullable Map<String, String> setProperty, @Nullable String contentType, int timeoutMs, @NonNull IReceivedMessageCallback callback)
+    {
         HttpURLConnection httpConn = null;
+        OutputStream outputStream = null;
+        OutputStreamWriter writer = null;
         InputStream inputStream = null;
         int timeout = timeoutMs;
         if (timeoutMs < 0)
@@ -140,12 +158,12 @@ public class SimpleHttpClient
             timeout = DEFAULT_TIMEOUT;
         }
 
-        //  HTTP GETメソッドで要求を投げる
+        //  HTTP メソッドで要求を送出
         try
         {
             final URL urlObj = new URL(url);
             httpConn = (HttpURLConnection) urlObj.openConnection();
-            httpConn.setRequestMethod("GET");
+            httpConn.setRequestMethod(requestMethod);
             if (setProperty != null)
             {
                 for (String key : setProperty.keySet())
@@ -154,9 +172,29 @@ public class SimpleHttpClient
                     httpConn.setRequestProperty(key, value);
                 }
             }
+            if (contentType != null)
+            {
+                httpConn.setRequestProperty("Content-Type", contentType);
+            }
             httpConn.setConnectTimeout(timeout);
             httpConn.setReadTimeout(timeout);
-            httpConn.connect();
+            if (postData == null)
+            {
+                httpConn.connect();
+            }
+            else
+            {
+                httpConn.setDoInput(true);
+                httpConn.setDoOutput(true);
+                outputStream = httpConn.getOutputStream();
+                writer = new OutputStreamWriter(outputStream, "UTF-8");
+                writer.write(postData);
+                writer.flush();
+                writer.close();
+                writer = null;
+                outputStream.close();
+                outputStream = null;
+            }
 
             int responseCode = httpConn.getResponseCode();
             if (responseCode == HttpURLConnection.HTTP_OK)
@@ -165,7 +203,7 @@ public class SimpleHttpClient
             }
             if (inputStream == null)
             {
-                Log.w(TAG, "httpGet: Response Code Error: " + responseCode + ": " + url);
+                Log.w(TAG, " http " + requestMethod + " Response Code Error: " + responseCode + ": " + url);
                 callback.onErrorOccurred(new NullPointerException());
                 callback.onCompleted();
                 return;
@@ -173,7 +211,7 @@ public class SimpleHttpClient
         }
         catch (Exception e)
         {
-            Log.w(TAG, "httpGet: " + url + "  " + e.getMessage());
+            Log.w(TAG, "http " + requestMethod + " " + url + "  " + e.getMessage());
             e.printStackTrace();
             if (httpConn != null)
             {
@@ -183,6 +221,31 @@ public class SimpleHttpClient
             callback.onCompleted();
             return;
         }
+        finally
+        {
+            try
+            {
+                if (writer != null)
+                {
+                    writer.close();
+                }
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+            }
+            try
+            {
+                if (outputStream != null)
+                {
+                    outputStream.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
 
         // 応答を確認する
         try
@@ -256,6 +319,7 @@ public class SimpleHttpClient
         callback.onCompleted();
     }
 
+
     public static String getValue(List<String> valueList)
     {
         // 応答ヘッダの値切り出し用...
@@ -276,15 +340,32 @@ public class SimpleHttpClient
         return (values.toString());
     }
 
+    public static Bitmap httpGetBitmap(String url, Map<String, String> setProperty, int timeoutMs)
+    {
+        return (httpCommandBitmap(url, "GET", null, setProperty, null, timeoutMs));
+    }
+
     /**
      *
      *
      *
      */
-    public static Bitmap httpGetBitmap(String url, Map<String, String> setProperty, int timeoutMs)
+    public static Bitmap httpPostBitmap(String url, String postData, int timeoutMs)
+    {
+        return (httpCommandBitmap(url, "POST", postData, null, null, timeoutMs));
+    }
+
+    /**
+     *
+     *
+     *
+     */
+    private static Bitmap httpCommandBitmap(@NonNull String url, @NonNull String requestMethod, @Nullable String postData, @Nullable Map<String, String> setProperty, @Nullable String contentType, int timeoutMs)
     {
         HttpURLConnection httpConn = null;
         InputStream inputStream = null;
+        OutputStream outputStream = null;
+        OutputStreamWriter writer = null;
         Bitmap bmp = null;
 
         int timeout = timeoutMs;
@@ -293,12 +374,12 @@ public class SimpleHttpClient
             timeout = DEFAULT_TIMEOUT;
         }
 
-        //  HTTP GETメソッドで要求を投げる
+        //  HTTP メソッドで要求を送出
         try
         {
             final URL urlObj = new URL(url);
             httpConn = (HttpURLConnection) urlObj.openConnection();
-            httpConn.setRequestMethod("GET");
+            httpConn.setRequestMethod(requestMethod);
             if (setProperty != null)
             {
                 for (String key : setProperty.keySet())
@@ -307,9 +388,30 @@ public class SimpleHttpClient
                     httpConn.setRequestProperty(key, value);
                 }
             }
+            if (contentType != null)
+            {
+                httpConn.setRequestProperty("Content-Type", contentType);
+            }
             httpConn.setConnectTimeout(timeout);
             httpConn.setReadTimeout(timeout);
-            httpConn.connect();
+
+            if (postData == null)
+            {
+                httpConn.connect();
+            }
+            else
+            {
+                httpConn.setDoInput(true);
+                httpConn.setDoOutput(true);
+                outputStream = httpConn.getOutputStream();
+                writer = new OutputStreamWriter(outputStream, "UTF-8");
+                writer.write(postData);
+                writer.flush();
+                writer.close();
+                writer = null;
+                outputStream.close();
+                outputStream = null;
+            }
 
             int responseCode = httpConn.getResponseCode();
             if (responseCode == HttpURLConnection.HTTP_OK)
@@ -322,14 +424,14 @@ public class SimpleHttpClient
             }
             if (inputStream == null)
             {
-                Log.w(TAG, "httpGet: Response Code Error: " + responseCode + ": " + url);
+                Log.w(TAG, "http: (" + requestMethod + ") Response Code Error: " + responseCode + ": " + url);
                 return (null);
             }
             inputStream.close();
         }
         catch (Exception e)
         {
-            Log.w(TAG, "httpGet: " + url + "  " + e.getMessage());
+            Log.w(TAG, "http: (" + requestMethod + ") " + url + "  " + e.getMessage());
             e.printStackTrace();
             if (httpConn != null)
             {
@@ -337,6 +439,31 @@ public class SimpleHttpClient
             }
             return (null);
         }
+        finally
+        {
+            try
+            {
+                if (writer != null)
+                {
+                    writer.close();
+                }
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+            }
+            try
+            {
+                if (outputStream != null)
+                {
+                    outputStream.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
         return (bmp);
     }
 
@@ -350,7 +477,6 @@ public class SimpleHttpClient
         return (httpCommand(url, "POST", postData, null, null, timeoutMs));
     }
 
-
     /**
      *
      *
@@ -381,7 +507,6 @@ public class SimpleHttpClient
         return (httpCommand(url, "PUT", putData, headerMap, contentType, timeoutMs));
     }
 
-
     /**
      *
      *
@@ -397,9 +522,9 @@ public class SimpleHttpClient
      *
      *
      */
-    public static String httpOptions(String url, String postData, int timeoutMs)
+    public static String httpOptions(String url, String optionsData, int timeoutMs)
     {
-        return (httpCommand(url, "OPTIONS", postData, null, null, timeoutMs));
+        return (httpCommand(url, "OPTIONS", optionsData, null, null, timeoutMs));
     }
 
     /**
@@ -466,6 +591,14 @@ public class SimpleHttpClient
             if (inputStream == null)
             {
                 Log.w(TAG, "http " + requestMethod + " : Response Code Error: " + responseCode + ": " + url);
+/*
+                inputStream = httpConn.getInputStream();
+                if (inputStream != null)
+                {
+                    // DUMP RESPONSE DETAIL
+                    Log.w(TAG, " RESP : " + readFromInputStream(inputStream));
+                }
+*/
                 return ("");
             }
         }
@@ -506,6 +639,8 @@ public class SimpleHttpClient
         }
 
         // 応答の読み出し
+        return (readFromInputStream(inputStream));
+/*
         BufferedReader reader = null;
         String replyString = "";
         try
@@ -539,8 +674,51 @@ public class SimpleHttpClient
             }
         }
         return (replyString);
+*/
     }
 
+    private static String readFromInputStream(InputStream inputStream)
+    {
+        BufferedReader reader = null;
+        String replyString = "";
+        if (inputStream == null)
+        {
+            return ("");
+        }
+        try
+        {
+            StringBuilder responseBuf = new StringBuilder();
+            reader = new BufferedReader(new InputStreamReader(inputStream));
+
+            int c;
+            while ((c = reader.read()) != -1)
+            {
+                responseBuf.append((char) c);
+            }
+            replyString = responseBuf.toString();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (reader != null)
+                {
+                    reader.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
+        return (replyString);
+    }
+
+
     public interface IReceivedMessageCallback
     {
         void onCompleted();
index a8e0dba..f3aab38 100644 (file)
@@ -1,5 +1,4 @@
 package net.osdn.gokigen.a01d.camera.utils;
-
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -18,6 +17,7 @@ import androidx.fragment.app.DialogFragment;
 
 import net.osdn.gokigen.a01d.R;
 import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+
 import java.util.Map;
 
 public class SimpleHttpSendCommandDialog extends DialogFragment implements View.OnClickListener
@@ -25,6 +25,7 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
     private final String TAG = toString();
     private ILiveViewControl liveViewControl = null;
     private Dialog myDialog = null;
+    private EditText http_header = null;
     private EditText method = null;
     private EditText service = null;
     private EditText parameter = null;
@@ -40,7 +41,7 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
      *
      *
      */
-    public static SimpleHttpSendCommandDialog newInstance(@Nullable String urlToSend, @NonNull ILiveViewControl liveViewControl,  @Nullable Map<String, String> headerMap)
+    public static SimpleHttpSendCommandDialog newInstance(@Nullable String urlToSend, @Nullable ILiveViewControl liveViewControl,  @Nullable Map<String, String> headerMap)
     {
         SimpleHttpSendCommandDialog instance = new SimpleHttpSendCommandDialog();
         instance.prepare(urlToSend, liveViewControl, headerMap);
@@ -58,7 +59,7 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
      *
      *
      */
-    private void prepare(@Nullable String urlToSend, @NonNull ILiveViewControl liveViewControl, @Nullable Map<String, String> headerMap)
+    private void prepare(@Nullable String urlToSend, @Nullable ILiveViewControl liveViewControl, @Nullable Map<String, String> headerMap)
     {
         if ((urlToSend == null)||(!urlToSend.contains("http://")))
         {
@@ -115,6 +116,7 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
 
         alertDialog.setIcon(R.drawable.ic_linked_camera_black_24dp);
         alertDialog.setTitle(activity.getString(R.string.dialog_http_command_title_command));
+        http_header = alertView.findViewById(R.id.edit_http_header);
         method = alertView.findViewById(R.id.edit_method);
         service = alertView.findViewById(R.id.edit_service);
         parameter = alertView.findViewById(R.id.edit_parameter);
@@ -124,8 +126,17 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
         final Button toRunningButton = alertView.findViewById(R.id.change_to_liveview);
         final Button toPlaybackButton = alertView.findViewById(R.id.change_to_playback);
 
-        toRunningButton.setOnClickListener(this);
-        toPlaybackButton.setOnClickListener(this);
+        if (liveViewControl != null)
+        {
+            toRunningButton.setOnClickListener(this);
+            toPlaybackButton.setOnClickListener(this);
+        }
+        else
+        {
+            // ライブビューのオン・オフ切り替えボタンを非表示にする
+            toRunningButton.setVisibility(View.GONE);
+            toPlaybackButton.setVisibility(View.GONE);
+        }
         sendButton.setOnClickListener(this);
         alertDialog.setCancelable(true);
         try
@@ -134,6 +145,10 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
             {
                 method.setText(activity.getText(R.string.http_method_string));
             }
+            if (http_header != null)
+            {
+                http_header.setText(urlToSend);
+            }
         }
         catch (Exception e)
         {
@@ -212,6 +227,20 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
             final Activity activity = getActivity();
             if (activity != null)
             {
+                if (http_header != null)
+                {
+                    String httpStr = http_header.getText().toString().toLowerCase();
+                    if (!httpStr.contains("http://"))
+                    {
+                        this.urlToSend = COMMUNICATE_URL_DEFAULT;
+                        http_header.setText(COMMUNICATE_URL_DEFAULT);
+                    }
+                    else
+                    {
+                        this.urlToSend = httpStr;
+                    }
+                }
+                
                 if (method != null)
                 {
                     methodStr = method.getText().toString().toLowerCase();
@@ -271,7 +300,7 @@ public class SimpleHttpSendCommandDialog extends DialogFragment implements View.
                             {
                                 reply = SimpleHttpClient.httpGetWithHeader(url, headerMap, null, TIMEOUT_MS);
                             }
-                            Log.v(TAG, "URL : " + url + " RESPONSE : " + reply);
+                            Log.v(TAG, "URL : " + url + " "+ param + " RESP : " + reply);
                             final String response = reply;
                             activity.runOnUiThread(new Runnable() {
                                 @Override
index a82b0a8..d2c4566 100644 (file)
@@ -65,6 +65,8 @@ public interface IPreferencePropertyAccessor
 
     String FUJIX_CONNECTION_FOR_READ = "fujix_connection_for_read";
 
+    String USE_OSC_THETA_V21 = "use_osc_theta_v21";
+
     /*
     int CHOICE_SPLASH_SCREEN = 10;
 
index 637a59f..4cbeb36 100644 (file)
                 android:layout_gravity="start">
             </TextView>
 
+            <EditText android:id="@+id/edit_http_header"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:autoLink="all"
+                android:linksClickable="true"
+                android:inputType="text"
+                android:hint="@string/http_dialog_http_url_hint"
+                />
+
             <EditText android:id="@+id/edit_method"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
index 637a59f..4cbeb36 100644 (file)
                 android:layout_gravity="start">
             </TextView>
 
+            <EditText android:id="@+id/edit_http_header"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:autoLink="all"
+                android:linksClickable="true"
+                android:inputType="text"
+                android:hint="@string/http_dialog_http_url_hint"
+                />
+
             <EditText android:id="@+id/edit_method"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
index 3f47db4..6f8e03f 100644 (file)
     <string name="dialog_title_connect_failed_panasonic">接続失敗(PANASONIC)</string>
     <string name="dialog_title_connect_failed_sony">接続失敗(SONY)</string>
     <string name="dialog_title_connect_failed_fuji">接続失敗(FUJI)</string>
+    <string name="dialog_title_connect_failed_theta">接続失敗(THETA)</string>
     <string name="fatal_cannot_use_camera">Olympus Camera Kitが動作しないモードのため、カメラのリセットが必要です。電源ボタンを8秒以上長押しして、カメラをリセットしてください。</string>
     <string name="network_connection_timeout">接続タイムアウト</string>
     <string name="restored_my_props">設定を展開しました。 : </string>
     <string name="dialog_button_playback">画像参照</string>
     <string name="dialog_command_hint">(command)</string>
     <string name="dialog_service_hint">(service)</string>
+    <string name="http_dialog_http_url_hint">http://192.168.1.1/</string>
     <string name="panasonic_service_string">cam.cgi</string>
     <string name="http_dialog_service_hint">(service)</string>
     <string name="http_dialog_method_hint">GET/POST/PUT</string>
     <string name="connect_error_message_olympus">接続失敗 (OLYMPUS)</string>
     <string name="connect_error_message_fuji">接続失敗 (FUJI)</string>
 
+    <string name="pref_use_osc_theta_v21">THETA Web API v2.1の使用</string>
+    <string name="pref_summary_use_osc_theta_v21"> </string>
+
 </resources>
index d04afdb..796534c 100644 (file)
@@ -88,6 +88,7 @@
     <string name="dialog_title_connect_failed_panasonic">Connect failed (PANASONIC)</string>
     <string name="dialog_title_connect_failed_sony">Connect failed (SONY)</string>
     <string name="dialog_title_connect_failed_fuji">Connect failed (FUJI)</string>
+    <string name="dialog_title_connect_failed_theta">Connect failed (THETA)</string>
     <string name="dialog_title_button_retry">Retry</string>
     <string name="dialog_title_button_network_settings">WiFi Settings</string>
 
     <string name="dialog_button_playback">to Playback</string>
     <string name="dialog_command_hint">(command)</string>
     <string name="dialog_service_hint">(service)</string>
+    <string name="http_dialog_http_url_hint">http://192.168.1.1/</string>
     <string name="panasonic_service_string">cam.cgi</string>
     <string name="http_dialog_service_hint">(service)</string>
     <string name="http_dialog_method_hint">GET/POST/PUT</string>
     <string name="connect_error_message_olympus">CONNECTION ERROR (OLYMPUS)</string>
     <string name="connect_error_message_fuji">CONNECTION ERROR (FUJI)</string>
 
+    <string name="pref_use_osc_theta_v21">Use THETA Web API v2.1</string>
+    <string name="pref_summary_use_osc_theta_v21"> </string>
+
 </resources>
index 0b9c86e..0f776e5 100644 (file)
         android:title="@string/pref_cat_camera">
 
         <CheckBoxPreference
+            android:key="use_osc_theta_v21"
+            android:title="@string/pref_use_osc_theta_v21"
+            android:summary="@string/pref_summary_use_osc_theta_v21"/>
+
+        <CheckBoxPreference
             android:key="capture_both_camera_and_live_view"
             android:title="@string/pref_capture_both_camera_and_live_view" />