OSDN Git Service

次バージョンのための拡張を開始。
authorMRSa <mrsa@myad.jp>
Wed, 16 Oct 2019 15:28:04 +0000 (00:28 +0900)
committerMRSa <mrsa@myad.jp>
Wed, 16 Oct 2019 15:28:04 +0000 (00:28 +0900)
29 files changed:
app/build.gradle
app/src/main/java/net/osdn/gokigen/pkremote/camera/CameraInterfaceProvider.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/interfaces/control/ICameraConnection.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/INikonInterfaceProvider.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/NikonInterfaceProvider.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonImageObjectReceiver.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonPlaybackControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/IOlympusPenInterfaceProvider.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/operation/OlympusPenCameraPowerOff.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenInterfaceProvider.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenRunMode.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraConnectSequence.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraDisconnectSequence.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenConnection.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenButtonControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenHardwareStatus.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/playback/OlympusPenPlaybackControl.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/PtpIpRunMode.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/playback/PtpIpFullImageReceiver.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/playback/PtpIpImageContentInfo.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/playback/PtpIpScreennailImageReceiver.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/playback/PtpIpSmallImageReceiver.java
app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/ptpip/wrapper/playback/PtpIpThumbnailImageReceiver.java
app/src/main/java/net/osdn/gokigen/pkremote/preference/nikon/NikonPreferenceFragment.java
app/src/main/java/net/osdn/gokigen/pkremote/preference/olympuspen/OlympusPenPreferenceFragment.java [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/pkremote/scene/CameraSceneUpdater.java
app/src/main/res/values-ja/arrays.xml
app/src/main/res/values/arrays.xml
app/src/main/res/xml/preferences_olympus.xml [new file with mode: 0644]

index ff6a19f..331e3b5 100644 (file)
@@ -6,8 +6,8 @@ android {
         applicationId "net.osdn.gokigen.pkremote"
         minSdkVersion 14
         targetSdkVersion 29
-        versionCode 10400
-        versionName "1.4.0"
+        versionCode 10500
+        versionName "1.5.0"
     }
     buildTypes {
         release {
index 97ad2df..fa04c76 100644 (file)
@@ -25,6 +25,7 @@ import net.osdn.gokigen.pkremote.camera.utils.CameraStatusListener;
 import net.osdn.gokigen.pkremote.camera.vendor.fujix.wrapper.FujiXInterfaceProvider;
 import net.osdn.gokigen.pkremote.camera.vendor.olympus.IOlympusInterfaceProvider;
 import net.osdn.gokigen.pkremote.camera.vendor.olympus.wrapper.OlympusInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.OlympusPenInterfaceProvider;
 import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.PanasonicCameraWrapper;
 import net.osdn.gokigen.pkremote.camera.vendor.ptpip.IPtpIpInterfaceProvider;
 import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.PtpIpInterfaceProvider;
@@ -49,6 +50,7 @@ public class CameraInterfaceProvider implements IInterfaceProvider
     private final FujiXInterfaceProvider fujiX;
     private final PanasonicCameraWrapper panasonic;
     private final PtpIpInterfaceProvider ptpip;
+    private final OlympusPenInterfaceProvider olympuspen;
     private final IInformationReceiver informationReceiver;
     private final CameraContentsRecognizer cameraContentsRecognizer;
     private final AppCompatActivity context;
@@ -74,6 +76,7 @@ public class CameraInterfaceProvider implements IInterfaceProvider
         sony = new SonyCameraWrapper(context, provider, statusListener, informationReceiver);
         ptpip = new PtpIpInterfaceProvider(context, provider, statusListener, informationReceiver);
         panasonic = new PanasonicCameraWrapper(context, provider, statusListener, informationReceiver);
+        olympuspen = new OlympusPenInterfaceProvider(context, provider);
         this.informationReceiver = informationReceiver;
         this.cameraContentsRecognizer = new CameraContentsRecognizer(context, this);
     }
@@ -130,6 +133,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getPtpIpCameraConnection());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getOlyCameraConnection());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getRicohGr2CameraConnection());
@@ -172,6 +179,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getButtonControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getButtonControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getButtonControl());
@@ -214,6 +225,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getDisplayInjector());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getDisplayInjector());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getDisplayInjector());
@@ -256,6 +271,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getLiveViewControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getLiveViewControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getLiveViewControl());
@@ -298,6 +317,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getLiveViewListener());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getLiveViewListener());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getLiveViewListener());
@@ -340,6 +363,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getFocusingControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getFocusingControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getFocusingControl());
@@ -382,6 +409,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getCameraInformation());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getCameraInformation());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getCameraInformation());
@@ -424,6 +455,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getZoomLensControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getZoomLensControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getZoomLensControl());
@@ -466,6 +501,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getCaptureControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getCaptureControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getCaptureControl());
@@ -508,6 +547,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getCameraStatusListHolder());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getCameraStatusListHolder());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getCameraStatusListHolder());
@@ -550,6 +593,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getCameraStatusWatcher());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getCameraStatusWatcher());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getCameraStatusWatcher());
@@ -592,6 +639,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getPlaybackControl());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getPlaybackControl());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getPlaybackControl());
@@ -634,6 +685,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getHardwareStatus());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getHardwareStatus());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getHardwareStatus());
@@ -676,6 +731,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 return (ptpip.getCameraRunMode());
             }
+            else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+            {
+                return (olympuspen.getCameraRunMode());
+            }
             else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
             {
                 return (ricohGr2.getCameraRunMode());
@@ -763,6 +822,10 @@ public class CameraInterfaceProvider implements IInterfaceProvider
             {
                 ret = ICameraConnection.CameraConnectionMethod.NIKON;
             }
+            else if (connectionMethod.contains("OLYMPUS"))
+            {
+                ret = ICameraConnection.CameraConnectionMethod.OLYMPUS;
+            }
             else // if (connectionMethod.contains("OPC"))
             {
                 ret = ICameraConnection.CameraConnectionMethod.OPC;
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/INikonInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/INikonInterfaceProvider.java
new file mode 100644 (file)
index 0000000..8380910
--- /dev/null
@@ -0,0 +1,57 @@
+package net.osdn.gokigen.pkremote.camera.vendor.nikon;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.IInformationReceiver;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraButtonControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraRunMode;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ICameraStatusUpdateNotify;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IDisplayInjector;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusWatcher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommunication;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.IPtpIpRunModeHolder;
+
+public interface INikonInterfaceProvider
+{
+    ICameraConnection getPtpIpCameraConnection();
+    ILiveViewControl getLiveViewControl();
+    ILiveViewListener getLiveViewListener();
+    IFocusingControl getFocusingControl();
+    ICameraInformation getCameraInformation();
+    IZoomLensControl getZoomLensControl();
+    ICaptureControl getCaptureControl();
+    IDisplayInjector getDisplayInjector();
+
+    IPtpIpRunModeHolder getRunModeHolder();
+    IPtpIpCommandCallback getStatusHolder();
+    IPtpIpCommandPublisher getCommandPublisher();
+    IPtpIpCommunication getLiveviewCommunication();
+    IPtpIpCommunication getAsyncEventCommunication();
+    IPtpIpCommunication getCommandCommunication();
+
+    ICameraStatusUpdateNotify getStatusListener();
+
+    ICameraStatusWatcher getCameraStatusWatcher();
+    ICameraStatus getCameraStatusListHolder();
+
+    ICameraButtonControl getButtonControl();
+    IPlaybackControl getPlaybackControl();
+    ICameraHardwareStatus getHardwareStatus();
+    ICameraRunMode getCameraRunMode();
+
+    IInformationReceiver getInformationReceiver();
+
+    void setAsyncEventReceiver(@NonNull IPtpIpCommandCallback receiver);
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/NikonInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/NikonInterfaceProvider.java
new file mode 100644 (file)
index 0000000..764251d
--- /dev/null
@@ -0,0 +1,233 @@
+package net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.IInformationReceiver;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraButtonControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraRunMode;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingModeNotify;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ICameraStatusUpdateNotify;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IDisplayInjector;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusWatcher;
+import net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper.playback.NikonPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.IPtpIpInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.operation.PtpIpZoomControl;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.PtpIpButtonControl;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.PtpIpHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.PtpIpRunMode;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommunication;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpAsyncResponseReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.connection.CanonConnection;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.liveview.PtpIpLiveViewControl;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.IPtpIpRunModeHolder;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.PtpIpStatusChecker;
+
+public class NikonInterfaceProvider implements IPtpIpInterfaceProvider, IDisplayInjector
+{
+    private final String TAG = toString();
+
+    private static final int STREAM_PORT = 15742;   // ??
+    private static final int ASYNC_RESPONSE_PORT = 15741;  // ??
+    private static final int CONTROL_PORT = 15740;
+    private static final int EVENT_PORT = 15740;
+    private static final String CAMERA_IP = "192.168.0.1";
+
+    private final Activity activity;
+    private final PtpIpRunMode runmode;
+    private final PtpIpHardwareStatus hardwareStatus;
+    private PtpIpButtonControl ptpIpButtonControl;
+    private CanonConnection canonConnection;
+    private PtpIpCommandPublisher commandPublisher;
+    private PtpIpLiveViewControl liveViewControl;
+    private PtpIpAsyncResponseReceiver asyncReceiver;
+    private PtpIpZoomControl zoomControl;
+    //private PtpIpCaptureControl captureControl;
+    //private PtpIpFocusingControl focusingControl;
+    private PtpIpStatusChecker statusChecker;
+    private ICameraStatusUpdateNotify statusListener;
+    private NikonPlaybackControl playbackControl;
+    private IInformationReceiver informationReceiver;
+
+    public NikonInterfaceProvider(@NonNull Activity context, @NonNull ICameraStatusReceiver provider, @NonNull ICameraStatusUpdateNotify statusListener, @NonNull IInformationReceiver informationReceiver)
+    {
+        this.activity = context;
+        commandPublisher = new PtpIpCommandPublisher(CAMERA_IP, CONTROL_PORT);
+        liveViewControl = new PtpIpLiveViewControl(context, CAMERA_IP, STREAM_PORT);
+        asyncReceiver = new PtpIpAsyncResponseReceiver(CAMERA_IP, ASYNC_RESPONSE_PORT);
+        statusChecker = new PtpIpStatusChecker(activity, commandPublisher, CAMERA_IP, EVENT_PORT);
+        canonConnection = new CanonConnection(context, provider, this, statusChecker);
+        zoomControl = new PtpIpZoomControl();
+        this.statusListener = statusListener;
+        this.runmode = new PtpIpRunMode();
+        this.hardwareStatus = new PtpIpHardwareStatus();
+        this.ptpIpButtonControl = new PtpIpButtonControl();
+        this.playbackControl = new NikonPlaybackControl(activity, this);
+        this.informationReceiver = informationReceiver;
+    }
+
+    @Override
+    public void injectDisplay(IAutoFocusFrameDisplay frameDisplayer, IIndicatorControl indicator, IFocusingModeNotify focusingModeNotify)
+    {
+        Log.v(TAG, "injectDisplay()");
+        //captureControl = new FujiXCaptureControl(commandPublisher, frameDisplayer);
+        //focusingControl = new FujiXFocusingControl(activity, commandPublisher, frameDisplayer, indicator);
+    }
+
+    @Override
+    public ICameraConnection getPtpIpCameraConnection()
+    {
+        return (canonConnection);
+    }
+
+    @Override
+    public ILiveViewControl getLiveViewControl()
+    {
+        return (liveViewControl);
+    }
+
+    @Override
+    public ILiveViewListener getLiveViewListener()
+    {
+        return (liveViewControl.getLiveViewListener());
+    }
+
+    @Override
+    public IFocusingControl getFocusingControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public ICameraInformation getCameraInformation()
+    {
+        return null;
+    }
+
+    @Override
+    public IZoomLensControl getZoomLensControl()
+    {
+        return (zoomControl);
+    }
+
+    @Override
+    public ICaptureControl getCaptureControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public IDisplayInjector getDisplayInjector()
+    {
+        return (this);
+    }
+
+    @Override
+    public IPtpIpRunModeHolder getRunModeHolder()
+    {
+        return (runmode);
+    }
+
+    @Override
+    public IPtpIpCommandCallback getStatusHolder() {
+        return (statusChecker);
+    }
+
+    @Override
+    public IPtpIpCommandPublisher getCommandPublisher()
+    {
+        return (commandPublisher);
+    }
+
+    @Override
+    public IPtpIpCommunication getLiveviewCommunication()
+    {
+        return (liveViewControl);
+    }
+
+    @Override
+    public IPtpIpCommunication getAsyncEventCommunication()
+    {
+        return (asyncReceiver);
+    }
+
+    @Override
+    public IPtpIpCommunication getCommandCommunication()
+    {
+        return (commandPublisher);
+    }
+
+    @Override
+    public ICameraStatusWatcher getCameraStatusWatcher()
+    {
+        return (statusChecker);
+    }
+
+    @Override
+    public ICameraStatusUpdateNotify getStatusListener()
+    {
+        return (statusListener);
+    }
+
+    @Override
+    public ICameraStatus getCameraStatusListHolder()
+    {
+        return (statusChecker);
+    }
+
+    @Override
+    public ICameraButtonControl getButtonControl()
+    {
+        return (ptpIpButtonControl);
+    }
+
+    @Override
+    public IPlaybackControl getPlaybackControl()
+    {
+        return (playbackControl);
+    }
+
+    @Override
+    public ICameraHardwareStatus getHardwareStatus()
+    {
+        return (hardwareStatus);
+    }
+
+    @Override
+    public ICameraRunMode getCameraRunMode()
+    {
+        return (runmode);
+    }
+
+    @Override
+    public IInformationReceiver getInformationReceiver()
+    {
+        // ちょっとこの引き回しは気持ちがよくない...
+        return (informationReceiver);
+    }
+
+    @Override
+    public void setAsyncEventReceiver(@NonNull IPtpIpCommandCallback receiver)
+    {
+        asyncReceiver.setEventSubscriber(receiver);
+    }
+
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonImageObjectReceiver.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonImageObjectReceiver.java
new file mode 100644 (file)
index 0000000..30acdda
--- /dev/null
@@ -0,0 +1,215 @@
+package net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper.playback;
+
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContent;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContentListCallback;
+import net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper.NikonInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.PtpIpCommandGeneric;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpImageContentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages.GET_OBJECT_INFO_EX_2;
+import static net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages.GET_OBJECT_INFO_EX_3;
+import static net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages.GET_STORAGE_ID;
+import static net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages.GET_STORAGE_INFO;
+import static net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages.GET_OBJECT_INFO_EX;
+
+public class NikonImageObjectReceiver implements IPtpIpCommandCallback
+{
+    private final String TAG = toString();
+    private final NikonInterfaceProvider provider;
+    private boolean isDumpLog = false;
+    private List<ICameraContent> imageObjectList;
+    private List<PtpIpImageContentInfo> ptpIpImageObjectList;
+    private ICameraContentListCallback callback = null;
+    private int subDirectoriesCount = -1;
+    private int receivedSubDirectoriesCount = -1;
+
+    NikonImageObjectReceiver(NikonInterfaceProvider provider)
+    {
+        this.provider = provider;
+        this.imageObjectList = new ArrayList<>();
+        this.ptpIpImageObjectList = new ArrayList<>();
+    }
+
+    @Override
+    public void receivedMessage(int id, byte[] rx_body)
+    {
+        try
+        {
+            IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+            //SimpleLogDumper.dump_bytes(" [RX] ", rx_body);
+            switch (id)
+            {
+                case GET_STORAGE_ID:
+                    // TODO: ストレージのIDを 0x00100010 で固定にしている。複数スロットある場合もあるので、このタイミングでちゃんと応答を parse してループさせる必要がある
+                    publisher.enqueueCommand(new PtpIpCommandGeneric(this, GET_STORAGE_INFO, isDumpLog,  0, 0x9102, 4, 0x00010001));
+                    subDirectoriesCount = -1;  // ここから画像取得シーケンスに入るので、、、
+                    break;
+
+                case GET_STORAGE_INFO:
+                    // TODO: (要検討) ストレージの情報を取得しているが、本当に使わなくてもよい?
+                    publisher.enqueueCommand(new PtpIpCommandGeneric(this, GET_OBJECT_INFO_EX, isDumpLog, 0, 0x9109, 12, 0x00010001, 0xffffffff, 0x00200000));
+                    break;
+
+                case GET_OBJECT_INFO_EX:
+                    List<PtpIpImageContentInfo> directries =  parseContentSubdirectories(rx_body, 32);
+                    {
+                        // サブディレクトリの情報を拾う
+                        for (PtpIpImageContentInfo contentInfo : directries)
+                        {
+                            publisher.enqueueCommand(new PtpIpCommandGeneric(this, GET_OBJECT_INFO_EX_2, isDumpLog, 0, 0x9109, 12, 0x00010001, contentInfo.getId(), 0x00200000));
+                        }
+                    }
+                    break;
+
+                case GET_OBJECT_INFO_EX_2:
+                    List<PtpIpImageContentInfo> subDirectries =  parseContentSubdirectories(rx_body, 32);
+                    {
+                        // 画像の情報を拾う
+                        for (PtpIpImageContentInfo contentInfo : subDirectries)
+                        {
+                            publisher.enqueueCommand(new PtpIpCommandGeneric(this, GET_OBJECT_INFO_EX_3, isDumpLog, 0, 0x9109, 12, 0x00010001, contentInfo.getId(), 0x00200000));
+                        }
+                        subDirectoriesCount = subDirectries.size();
+                        receivedSubDirectoriesCount = 0;
+                        if (subDirectoriesCount <= 0)
+                        {
+                            // カメラの画像コンテンツが見つからなかった(サブディレクトリがなかった)...ここで画像解析終了の報告をする
+                            callback.onCompleted(imageObjectList);
+                        }
+                    }
+                    break;
+
+                case GET_OBJECT_INFO_EX_3:
+                    if (isDumpLog)
+                    {
+                        Log.v(TAG, " --- CONTENT ---");
+                    }
+                    List<PtpIpImageContentInfo> objects =  parseContentSubdirectories(rx_body, 32);
+                    if (objects.size() > 0)
+                    {
+                        imageObjectList.addAll(objects);
+                        ptpIpImageObjectList.addAll(objects);
+                    }
+                    receivedSubDirectoriesCount++;
+                    if (receivedSubDirectoriesCount >= subDirectoriesCount)
+                    {
+                        // 全コンテンツの受信成功
+                        if(this.callback != null)
+                        {
+                            callback.onCompleted(imageObjectList);
+                        }
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private List<PtpIpImageContentInfo> parseContentSubdirectories(byte[] rx_body, int offset)
+    {
+        List<PtpIpImageContentInfo> result = new ArrayList<>();
+        try
+        {
+            int nofObjects = (rx_body[offset] & 0xff);
+            nofObjects = nofObjects + ((rx_body[offset + 1]  & 0xff) << 8);
+            nofObjects = nofObjects + ((rx_body[offset + 2] & 0xff) << 16);
+            nofObjects = nofObjects + ((rx_body[offset + 3] & 0xff) << 24);
+
+            int dataIndex = offset + 4;
+            while (rx_body.length > dataIndex)
+            {
+                int objectSize = (rx_body[dataIndex++] & 0xff);
+                objectSize = objectSize + ((rx_body[dataIndex++]  & 0xff) << 8);
+                objectSize = objectSize + ((rx_body[dataIndex++] & 0xff) << 16);
+                objectSize = objectSize + ((rx_body[dataIndex++] & 0xff) << 24);
+                objectSize = objectSize - 4;  // 抽出したレングス長分減らず
+
+                int id = (rx_body[dataIndex] & 0xff);
+                id = id + ((rx_body[dataIndex + 1]  & 0xff) << 8);
+                id = id + ((rx_body[dataIndex + 2] & 0xff) << 16);
+                id = id + ((rx_body[dataIndex + 3] & 0xff) << 24);
+
+                PtpIpImageContentInfo content = new PtpIpImageContentInfo(id, "", rx_body, dataIndex, objectSize);
+                result.add(content);
+                dataIndex = dataIndex + objectSize;
+                if (result.size() >= nofObjects)
+                {
+                    // オブジェクトを全部切り出した
+                    break;
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return (result);
+    }
+
+    @Override
+    public void onReceiveProgress(int currentBytes, int totalBytes, byte[] rx_body)
+    {
+        Log.v(TAG, "onReceiveProgress(" + currentBytes + "/" + totalBytes + ")");
+    }
+
+    @Override
+    public boolean isReceiveMulti()
+    {
+        return (false);
+    }
+
+    PtpIpImageContentInfo getContentObject(String fileName)
+    {
+        for (PtpIpImageContentInfo contentInfo : ptpIpImageObjectList)
+        {
+
+            if (fileName.matches(contentInfo.getContentName()))
+            {
+                return (contentInfo);
+            }
+        }
+        return (null);
+    }
+
+    public void getCameraContents(ICameraContentListCallback callback)
+    {
+        this.callback = null;
+        try
+        {
+            ICameraConnection connection = provider.getPtpIpCameraConnection();
+            if (connection.getConnectionStatus() != ICameraConnection.CameraConnectionStatus.CONNECTED)
+            {
+                Log.v(TAG, "DOES NOT CONNECT TO CAMERA.");
+                return;
+            }
+
+            IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+            if (publisher != null)
+            {
+                // オブジェクト一覧をクリアする
+                this.imageObjectList.clear();
+                this.ptpIpImageObjectList.clear();
+                publisher.enqueueCommand(new PtpIpCommandGeneric(this, GET_STORAGE_ID, isDumpLog, 0, 0x9101));
+                this.callback = callback;
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonPlaybackControl.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/nikon/wrapper/playback/NikonPlaybackControl.java
new file mode 100644 (file)
index 0000000..823d925
--- /dev/null
@@ -0,0 +1,257 @@
+package net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper.playback;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.util.Log;
+
+import androidx.preference.PreferenceManager;
+
+import net.osdn.gokigen.pkremote.IInformationReceiver;
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContentListCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraFileInfo;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IContentInfoCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentListCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadThumbnailImageCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.vendor.nikon.wrapper.NikonInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.PtpIpCommandGeneric;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonRequestInnerDevelopStart;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpFullImageReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpImageContentInfo;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpScreennailImageReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpSmallImageReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.playback.PtpIpThumbnailImageReceiver;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+
+/**
+ *
+ *
+ */
+public class NikonPlaybackControl implements IPlaybackControl
+{
+    private final String TAG = toString();
+    private final Activity activity;
+    private final NikonInterfaceProvider provider;
+    private final PtpIpFullImageReceiver fullImageReceiver;
+    private final PtpIpSmallImageReceiver smallImageReciever;
+    private String raw_suffix = "CR2";
+    private boolean use_screennail_image = false;
+    private NikonImageObjectReceiver canonImageObjectReceiver;
+
+    public NikonPlaybackControl(Activity activity, NikonInterfaceProvider provider)
+    {
+        this.activity = activity;
+        this.provider = provider;
+        this.fullImageReceiver = new PtpIpFullImageReceiver(activity, provider.getCommandPublisher());
+        this.smallImageReciever = new PtpIpSmallImageReceiver(activity, provider.getCommandPublisher());
+        canonImageObjectReceiver = new NikonImageObjectReceiver(provider);
+
+        try
+        {
+            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
+            raw_suffix = preferences.getString(IPreferencePropertyAccessor.CANON_RAW_SUFFIX, IPreferencePropertyAccessor.CANON_RAW_SUFFIX_DEFAULT_VALUE);
+            use_screennail_image = preferences.getBoolean(IPreferencePropertyAccessor.CANON_USE_SCREENNAIL_AS_SMALL, false);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public String getRawFileSuffix()
+    {
+        return (raw_suffix);
+    }
+
+    @Override
+    public void downloadContentList(IDownloadContentListCallback callback)
+    {
+        // なにもしない。(未使用)
+    }
+
+    @Override
+    public void getContentInfo(String path, String name, IContentInfoCallback callback)
+    {
+        // showFileInformation
+
+    }
+
+    @Override
+    public void updateCameraFileInfo(ICameraFileInfo info)
+    {
+        //  なにもしない
+    }
+
+    @Override
+    public void downloadContentScreennail(String path, IDownloadThumbnailImageCallback callback)
+    {
+        Log.v(TAG, " downloadContentScreennail() " + path);
+
+        if (!use_screennail_image)
+        {
+            // Thumbnail と同じ画像を表示する
+            downloadContentThumbnail(path, callback);
+            return;
+        }
+
+        try
+        {
+            int start = 0;
+            if (path.indexOf("/") == 0)
+            {
+                start = 1;
+            }
+            final String indexStr = path.substring(start);
+            PtpIpImageContentInfo content = canonImageObjectReceiver.getContentObject(indexStr);
+            if (content != null)
+            {
+                IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+                //int storageId = content.getStorageId();
+                int objectId = content.getId();
+
+                // 画像表示中...のメッセージを表示する
+                IInformationReceiver display = provider.getInformationReceiver();
+                if (display != null)
+                {
+                    String message = activity.getString(R.string.canon_get_image_screennail);
+                    display.updateMessage(message, false, true, Color.LTGRAY);
+                }
+
+                // 画像を取得する
+                PtpIpScreennailImageReceiver receiver = new PtpIpScreennailImageReceiver(activity, objectId, publisher, callback);
+                publisher.enqueueCommand(new CanonRequestInnerDevelopStart(receiver, objectId, true, objectId, objectId));   // 0x9141 : RequestInnerDevelopStart
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void downloadContentThumbnail(String path, final IDownloadThumbnailImageCallback callback)
+    {
+        try
+        {
+            int start = 0;
+            if (path.indexOf("/") == 0)
+            {
+                start = 1;
+            }
+            //String indexStr = path.substring(start, path.indexOf("."));
+            final String indexStr = path.substring(start);
+            //Log.v(TAG, "downloadContentThumbnail() : [" + path + "] " + indexStr);
+
+            PtpIpImageContentInfo content = canonImageObjectReceiver.getContentObject(indexStr);
+            if (content != null)
+            {
+                IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+                //int storageId = content.getStorageId();
+                int objectId = content.getId();
+                // Log.v(TAG, "downloadContentThumbnail() " + indexStr + " [" + objectId + "] (" + storageId + ")");
+                publisher.enqueueCommand(new PtpIpCommandGeneric(new PtpIpThumbnailImageReceiver(activity, callback), objectId, false, 0, 0x910a, 8, objectId, 0x00032000));
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void downloadContent(String path, boolean isSmallSize, IDownloadContentCallback callback)
+    {
+        try
+        {
+            int start = 0;
+            if (path.indexOf("/") == 0)
+            {
+                start = 1;
+            }
+            final String indexStr = path.substring(start);
+            PtpIpImageContentInfo content = canonImageObjectReceiver.getContentObject(indexStr);
+            if (content != null)
+            {
+                if (isSmallSize)
+                {
+                    // スモールサイズの画像取得コマンド(シーケンス)を発行する
+                    smallImageReciever.issueCommand(content.getId(), callback);
+                }
+                else
+                {
+                    // オリジナル画像の取得コマンド(シーケンス)を発行する
+                    fullImageReceiver.issueCommand(content.getId(), content.getOriginalSize(), callback);
+                }
+            }
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void getCameraContentList(final ICameraContentListCallback callback)
+    {
+        if (callback == null)
+        {
+            return;
+        }
+
+        try
+        {
+            Thread thread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    canonImageObjectReceiver.getCameraContents(callback);
+                }
+            });
+            thread.start();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            callback.onErrorOccurred(e);
+        }
+    }
+
+    @Override
+    public void showPictureStarted()
+    {
+        try
+        {
+            Log.v(TAG, "   showPictureStarted() ");
+
+            IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+            publisher.flushHoldQueue();
+            System.gc();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void showPictureFinished()
+    {
+        try
+        {
+            Log.v(TAG, "   showPictureFinished() ");
+
+            IPtpIpCommandPublisher publisher = provider.getCommandPublisher();
+            publisher.flushHoldQueue();
+            System.gc();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/IOlympusPenInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/IOlympusPenInterfaceProvider.java
new file mode 100644 (file)
index 0000000..23639f9
--- /dev/null
@@ -0,0 +1,39 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraButtonControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraRunMode;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IDisplayInjector;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusWatcher;
+
+/**
+ *
+ */
+public interface IOlympusPenInterfaceProvider
+{
+    ICameraConnection getOlyCameraConnection();
+    ILiveViewControl getLiveViewControl();
+    ILiveViewListener getLiveViewListener();
+    IFocusingControl getFocusingControl();
+    ICameraInformation getCameraInformation();
+    IZoomLensControl getZoomLensControl();
+    ICaptureControl getCaptureControl();
+    ICameraButtonControl getButtonControl();
+    IDisplayInjector getDisplayInjector();
+
+    ICameraStatus getCameraStatusListHolder();
+    ICameraStatusWatcher getCameraStatusWatcher();
+    IPlaybackControl getPlaybackControl();
+
+    ICameraHardwareStatus getHardwareStatus();
+    ICameraRunMode getCameraRunMode();
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/operation/OlympusPenCameraPowerOff.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/operation/OlympusPenCameraPowerOff.java
new file mode 100644 (file)
index 0000000..f807c09
--- /dev/null
@@ -0,0 +1,81 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.operation;
+
+
+import android.content.Context;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+import net.osdn.gokigen.pkremote.scene.ConfirmationDialog;
+import net.osdn.gokigen.pkremote.scene.IChangeScene;
+
+import androidx.preference.Preference;
+
+/**
+ *  Preferenceがクリックされた時に処理するクラス
+ *
+ */
+public class OlympusPenCameraPowerOff implements Preference.OnPreferenceClickListener, ConfirmationDialog.Callback
+{
+    private final Context context;
+    private final IChangeScene changeScene;
+    private String preferenceKey = null;
+
+    /**
+     *   コンストラクタ
+     *
+     */
+    public OlympusPenCameraPowerOff(Context context, IChangeScene changeScene)
+    {
+        this.context = context;
+        this.changeScene = changeScene;
+    }
+
+    /**
+     *   クラスの準備
+     *
+     */
+    public void prepare()
+    {
+        // 何もしない
+    }
+
+    /**
+     *
+     *
+     * @param preference クリックしたpreference
+     * @return false : ハンドルしない / true : ハンドルした
+     */
+    @Override
+    public boolean onPreferenceClick(Preference preference)
+    {
+        if (!preference.hasKey())
+        {
+            return (false);
+        }
+
+        preferenceKey = preference.getKey();
+        if (preferenceKey.contains(IPreferencePropertyAccessor.EXIT_APPLICATION))
+        {
+
+            // 確認ダイアログの生成と表示
+            ConfirmationDialog dialog = ConfirmationDialog.newInstance(context);
+            dialog.show(R.string.dialog_title_confirmation, R.string.dialog_message_power_off, this);
+            return (true);
+        }
+        return (false);
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void confirm()
+    {
+        if (preferenceKey.contains(IPreferencePropertyAccessor.EXIT_APPLICATION))
+        {
+            // カメラの電源をOFFにしたうえで、アプリケーションを終了する。
+            changeScene.exitApplication();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenInterfaceProvider.java
new file mode 100644 (file)
index 0000000..8c04a20
--- /dev/null
@@ -0,0 +1,193 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraButtonControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraRunMode;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingModeNotify;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IDisplayInjector;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatus;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusWatcher;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.IOlympusPenInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.connection.OlympusPenConnection;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.hardware.OlympusPenButtonControl;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.hardware.OlympusPenHardwareStatus;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.playback.OlympusPenPlaybackControl;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+/**
+ *
+ *
+ */
+public class OlympusPenInterfaceProvider implements IOlympusPenInterfaceProvider, IDisplayInjector
+{
+    private final String TAG = toString();
+    //private final Activity activity;
+    //private final ICameraStatusReceiver provider;
+    private final OlympusPenConnection olympusPenConnection;
+    private final OlympusPenButtonControl buttonControl;
+    private final OlympusPenPlaybackControl playbackControl;
+    private final OlympusPenHardwareStatus hardwareStatus;
+    private final OlympusPenRunMode runMode;
+
+    /**
+     *
+     *
+     */
+    public OlympusPenInterfaceProvider(@NonNull Activity context, @NonNull ICameraStatusReceiver provider)
+    {
+        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+        //useGrCommand = preferences.getBoolean(IPreferencePropertyAccessor.USE_GR2_SPECIAL_COMMAND, true);
+        //pentaxCaptureAfterAf = preferences.getBoolean(IPreferencePropertyAccessor.PENTAX_CAPTURE_AFTER_AF, false);
+        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();
+        }
+        int maxCount = 3000;  // デフォルトは 3000枚 とする
+        try
+        {
+            maxCount = Integer.parseInt(preferences.getString(IPreferencePropertyAccessor.RICOH_GET_PICS_LIST_MAX_COUNT, IPreferencePropertyAccessor.RICOH_GET_PICS_LIST_MAX_COUNT_DEFAULT_VALUE));
+            if (maxCount < 300)
+            {
+                maxCount = 300;  // 最小値は 300枚とする。
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+        //this.activity = context;
+        //this.provider = provider;
+        olympusPenConnection = new OlympusPenConnection(context, provider);
+        //liveViewControl = new RicohGr2LiveViewControl(useGrCommand);
+        //zoomControl = new RicohGr2CameraZoomLensControl();
+        buttonControl = new OlympusPenButtonControl();
+        //statusChecker = new RicohGr2StatusChecker(500, useGrCommand);
+        playbackControl = new OlympusPenPlaybackControl(communicationTimeoutMs);
+        hardwareStatus = new OlympusPenHardwareStatus();
+        runMode = new OlympusPenRunMode();
+    }
+
+    public void prepare()
+    {
+        Log.v(TAG, "prepare()");
+    }
+
+    @Override
+    public void injectDisplay(IAutoFocusFrameDisplay frameDisplayer, IIndicatorControl indicator, IFocusingModeNotify focusingModeNotify)
+    {
+        Log.v(TAG, "injectDisplay()");
+        //focusControl = new RicohGr2CameraFocusControl(useGrCommand, frameDisplayer, indicator);
+        //captureControl = new RicohGr2CameraCaptureControl(useGrCommand, pentaxCaptureAfterAf, frameDisplayer, statusChecker);
+    }
+
+    @Override
+    public ICameraConnection getOlyCameraConnection()
+    {
+        return (olympusPenConnection);
+    }
+
+    @Override
+    public ILiveViewControl getLiveViewControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public ILiveViewListener getLiveViewListener()
+    {
+        return (null);
+    }
+
+    @Override
+    public IFocusingControl getFocusingControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public ICameraInformation getCameraInformation()
+    {
+        return (null);
+    }
+
+    @Override
+    public IZoomLensControl getZoomLensControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public ICaptureControl getCaptureControl()
+    {
+        return (null);
+    }
+
+    @Override
+    public IDisplayInjector getDisplayInjector() {
+        return (this);
+    }
+
+    @Override
+    public ICameraStatus getCameraStatusListHolder()
+    {
+        return (null);
+    }
+
+    @Override
+    public ICameraButtonControl getButtonControl()
+    {
+        return (buttonControl);
+    }
+
+    @Override
+    public ICameraStatusWatcher getCameraStatusWatcher() {
+        return (null);
+    }
+
+    @Override
+    public IPlaybackControl getPlaybackControl()
+    {
+        return (playbackControl);
+    }
+
+    @Override
+    public ICameraHardwareStatus getHardwareStatus()
+    {
+        return (hardwareStatus);
+    }
+
+    @Override
+    public ICameraRunMode getCameraRunMode()
+    {
+        return (runMode);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenRunMode.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/OlympusPenRunMode.java
new file mode 100644 (file)
index 0000000..395385e
--- /dev/null
@@ -0,0 +1,20 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraRunMode;
+
+public class OlympusPenRunMode implements ICameraRunMode
+{
+    @Override
+    public void changeRunMode(boolean isRecording)
+    {
+
+
+
+    }
+
+    @Override
+    public boolean isRecordingMode()
+    {
+        return (true);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraConnectSequence.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraConnectSequence.java
new file mode 100644 (file)
index 0000000..4a8182a
--- /dev/null
@@ -0,0 +1,115 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.connection;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+
+import androidx.annotation.NonNull;
+
+class OlympusPenCameraConnectSequence implements Runnable
+{
+    private final String TAG = this.toString();
+    private final Activity context;
+    private final ICameraConnection cameraConnection;
+    private final ICameraStatusReceiver cameraStatusReceiver;
+
+    OlympusPenCameraConnectSequence(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection)
+    {
+        Log.v(TAG, "OlympusPenCameraConnectSequence");
+        this.context = context;
+        this.cameraConnection = cameraConnection;
+        this.cameraStatusReceiver = statusReceiver;
+    }
+
+    @Override
+    public void run()
+    {
+        final String areYouThereUrl = "http://192.168.0.1/v1/ping";
+        final String grCommandUrl = "http://192.168.0.1/_gr";
+        final int TIMEOUT_MS = 5000;
+        try
+        {
+            String response = SimpleHttpClient.httpGet(areYouThereUrl, TIMEOUT_MS);
+            Log.v(TAG, areYouThereUrl + " " + response);
+            if (response.length() > 0)
+            {
+                SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+                // 接続時、レンズロックOFF
+                {
+                    final String postData = "cmd=acclock off";
+                    String response0 = SimpleHttpClient.httpPost(grCommandUrl, postData, TIMEOUT_MS);
+                    Log.v(TAG, grCommandUrl + " " + response0);
+                }
+
+                // 接続時、カメラの画面を消す
+                if (preferences.getBoolean(IPreferencePropertyAccessor.GR2_LCD_SLEEP, false))
+                {
+                    final String postData = "cmd=lcd sleep on";
+                    String response0 = SimpleHttpClient.httpPost(grCommandUrl, postData, TIMEOUT_MS);
+                    Log.v(TAG, grCommandUrl + " " + response0);
+                }
+                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 waitForAMoment(long mills)
+    {
+        if (mills > 0)
+        {
+            try {
+                Log.v(TAG, " WAIT " + mills + "ms");
+                Thread.sleep(mills);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+*/
+
+    private void onConnectError(String reason)
+    {
+        cameraConnection.alertConnectingFailed(reason);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraDisconnectSequence.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenCameraDisconnectSequence.java
new file mode 100644 (file)
index 0000000..3402c11
--- /dev/null
@@ -0,0 +1,53 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.connection;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+
+public class OlympusPenCameraDisconnectSequence  implements Runnable
+{
+    private final String TAG = this.toString();
+    private final Activity activity;
+    private final boolean powerOff;
+
+    OlympusPenCameraDisconnectSequence(Activity activity, boolean isOff)
+    {
+        this.activity = activity;
+        this.powerOff = isOff;
+    }
+
+    @Override
+    public void run()
+    {
+        // カメラをPowerOffして接続を切る
+        try
+        {
+            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
+            if (preferences.getBoolean(IPreferencePropertyAccessor.GR2_LCD_SLEEP, false))
+            {
+                final String screenOnUrl = "http://192.168.0.1/_gr";
+                final String postData = "lcd sleep off";
+                final int TIMEOUT_MS = 5000;
+                String response = SimpleHttpClient.httpPost(screenOnUrl, postData, TIMEOUT_MS);
+                Log.v(TAG, screenOnUrl + " " + response);
+            }
+
+            if (powerOff)
+            {
+                final String cameraPowerOffUrl = "http://192.168.0.1/v1/device/finish";
+                final String postData = "";
+                final int TIMEOUT_MS = 5000;
+                String response = SimpleHttpClient.httpPost(cameraPowerOffUrl, postData, TIMEOUT_MS);
+                Log.v(TAG, cameraPowerOffUrl + " " + response);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenConnection.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/connection/OlympusPenConnection.java
new file mode 100644 (file)
index 0000000..03b25b3
--- /dev/null
@@ -0,0 +1,278 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.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 net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+
+/**
+ *
+ *
+ */
+public class OlympusPenConnection 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 OlympusPenConnection(@NonNull final Activity context, @NonNull final ICameraStatusReceiver statusReceiver)
+    {
+        Log.v(TAG, "OlympusPenConnection()");
+        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_ricoh))
+                .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 OlympusPenCameraDisconnectSequence(context, powerOff));
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * カメラとの接続処理
+     */
+    private void connectToCamera()
+    {
+        Log.v(TAG, "connectToCamera()");
+        connectionStatus = CameraConnectionStatus.CONNECTING;
+        try
+        {
+            cameraExecutor.execute(new OlympusPenCameraConnectSequence(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/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenButtonControl.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenButtonControl.java
new file mode 100644 (file)
index 0000000..ede6f6d
--- /dev/null
@@ -0,0 +1,13 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.hardware;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraButtonControl;
+
+public class OlympusPenButtonControl implements ICameraButtonControl
+{
+
+    @Override
+    public boolean pushedButton(String code, boolean isLongPress)
+    {
+        return (false);
+    }
+}
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenHardwareStatus.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/hardware/OlympusPenHardwareStatus.java
new file mode 100644 (file)
index 0000000..8e2ffe1
--- /dev/null
@@ -0,0 +1,51 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.hardware;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraHardwareStatus;
+
+import java.util.Map;
+
+public class OlympusPenHardwareStatus implements ICameraHardwareStatus
+{
+    @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/pkremote/camera/vendor/olympuspen/wrapper/playback/OlympusPenPlaybackControl.java b/app/src/main/java/net/osdn/gokigen/pkremote/camera/vendor/olympuspen/wrapper/playback/OlympusPenPlaybackControl.java
new file mode 100644 (file)
index 0000000..e6e77b5
--- /dev/null
@@ -0,0 +1,464 @@
+package net.osdn.gokigen.pkremote.camera.vendor.olympuspen.wrapper.playback;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContent;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContentListCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraFileInfo;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IContentInfoCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentListCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadThumbnailImageCallback;
+import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
+import net.osdn.gokigen.pkremote.camera.playback.CameraContentInfo;
+import net.osdn.gokigen.pkremote.camera.playback.CameraFileInfo;
+import net.osdn.gokigen.pkremote.camera.playback.ProgressEvent;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+import androidx.annotation.NonNull;
+
+/**
+ *
+ *
+ */
+public class OlympusPenPlaybackControl implements IPlaybackControl
+{
+    private final String TAG = toString();
+    private final String getPhotoUrl = "http://192.168.0.1/v1/photos/";
+    private static final int DEFAULT_TIMEOUT = 3000;
+    private final int timeoutValue;
+
+    public OlympusPenPlaybackControl(int timeoutMs)
+    {
+        this.timeoutValue  = (timeoutMs < DEFAULT_TIMEOUT) ? DEFAULT_TIMEOUT : timeoutMs;
+    }
+
+    @Override
+    public String getRawFileSuffix()
+    {
+        return (".ORF");
+    }
+
+    @Override
+    public void downloadContentList(@NonNull IDownloadContentListCallback callback)
+    {
+        List<ICameraFileInfo> fileList = new ArrayList<>();
+        String imageListurl = "http://192.168.0.1/v1/photos?";// + maxCount;
+        String contentList;
+        try
+        {
+            contentList = SimpleHttpClient.httpGet(imageListurl, timeoutValue);
+            if (contentList == null)
+            {
+                // ぬるぽ発行
+                callback.onErrorOccurred(new NullPointerException());
+                return;
+            }
+        }
+        catch (Exception e)
+        {
+            // 例外をそのまま転送
+            callback.onErrorOccurred(e);
+            return;
+        }
+        try
+        {
+            JSONArray dirsArray = new JSONObject(contentList).getJSONArray("dirs");
+            if (dirsArray != null)
+            {
+                int size = dirsArray.length();
+                for (int index = 0; index < size; index++)
+                {
+                    JSONObject object = dirsArray.getJSONObject(index);
+                    String dirName = object.getString("name");
+                    JSONArray filesArray = object.getJSONArray("files");
+                    int nofFiles = filesArray.length();
+                    for (int fileIndex = 0; fileIndex < nofFiles; fileIndex++)
+                    {
+                        String fileName = filesArray.getString(fileIndex);
+                        fileList.add(new CameraFileInfo(dirName, fileName));
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            callback.onErrorOccurred(e);
+            return;
+        }
+        callback.onCompleted(fileList);
+    }
+
+    @Override
+    public void updateCameraFileInfo(ICameraFileInfo info)
+    {
+        String url = getPhotoUrl + info.getDirectoryPath() + "/" + info.getFilename() + "/info";
+        Log.v(TAG, "updateCameraFileInfo() GET URL : " + url);
+        try
+        {
+            String response = SimpleHttpClient.httpGet(url, timeoutValue);
+            if ((response == null)||(response.length() < 1))
+            {
+                return;
+            }
+            JSONObject object = new JSONObject(response);
+
+            // データを突っ込む
+            boolean captured = object.getBoolean("captured");
+            String av = getJSONString(object, "av");
+            String tv = getJSONString(object, "tv");
+            String sv = getJSONString(object,"sv");
+            String xv = getJSONString(object,"xv");
+            int orientation = object.getInt("orientation");
+            String aspectRatio = getJSONString(object,"aspectRatio");
+            String cameraModel = getJSONString(object,"cameraModel");
+            String latLng = getJSONString(object,"latlng");
+            String dateTime = object.getString("datetime");
+            info.updateValues(dateTime, av, tv, sv, xv, orientation, aspectRatio, cameraModel, latLng, captured);
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private String getJSONString(JSONObject object, String key)
+    {
+        String value = "";
+        try
+        {
+            value = object.getString(key);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return (value);
+    }
+
+    @Override
+    public void getContentInfo(@NonNull String path, @NonNull String name, @NonNull IContentInfoCallback callback)
+    {
+        String url = getPhotoUrl + path + "/" + name + "/info";
+        Log.v(TAG, "getContentInfo() GET URL : " + url);
+        try
+        {
+            String response = SimpleHttpClient.httpGet(url, timeoutValue);
+            if ((response == null)||(response.length() < 1))
+            {
+                callback.onErrorOccurred(new NullPointerException());
+            }
+            CameraFileInfo fileInfo = new CameraFileInfo(path, name);
+
+            JSONObject object = new JSONObject(response);
+
+            boolean captured = object.getBoolean("captured");
+            String av = getJSONString(object, "av");
+            String tv = getJSONString(object, "tv");
+            String sv = getJSONString(object,"sv");
+            String xv = getJSONString(object,"xv");
+            int orientation = object.getInt("orientation");
+            String aspectRatio = getJSONString(object,"aspectRatio");
+            String cameraModel = getJSONString(object,"cameraModel");
+            String latLng = getJSONString(object,"latlng");
+            String dateTime = object.getString("datetime");
+            fileInfo.updateValues(dateTime, av, tv, sv, xv, orientation, aspectRatio, cameraModel, latLng, captured);
+
+            callback.onCompleted(fileInfo);
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void downloadContentScreennail(@NonNull String path, @NonNull IDownloadThumbnailImageCallback callback)
+    {
+        //Log.v(TAG, "downloadContentScreennail() : " + path);
+        String suffix = "?size=view";
+        String url = getPhotoUrl + path + suffix;
+        Log.v(TAG, "downloadContentScreennail() GET URL : " + url);
+        try
+        {
+            Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutValue);
+            HashMap<String, Object> map = new HashMap<>();
+            map.put("Orientation", 0);
+            callback.onCompleted(bmp, map);
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void downloadContentThumbnail(@NonNull String path, @NonNull IDownloadThumbnailImageCallback callback)
+    {
+        //Log.v(TAG, "downloadContentThumbnail() : " + path);
+        String suffix = "?size=view";
+        if (path.contains(".JPG"))
+        {
+            suffix = "?size=thumb";
+        }
+        String url = getPhotoUrl + path + suffix;
+        Log.v(TAG, "downloadContentThumbnail() GET URL : " + url);
+        try
+        {
+            Bitmap bmp = SimpleHttpClient.httpGetBitmap(url, timeoutValue);
+            HashMap<String, Object> map = new HashMap<>();
+            map.put("Orientation", 0);
+            callback.onCompleted(bmp, map);
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+            callback.onErrorOccurred(new NullPointerException());
+        }
+   }
+
+    @Override
+    public void downloadContent(@NonNull String  path, boolean isSmallSize, @NonNull final IDownloadContentCallback callback)
+    {
+        Log.v(TAG, "downloadContent() : " + path);
+        String suffix = "?size=full";
+        if (isSmallSize)
+        {
+            suffix = "?size=view";
+        }
+        String url = getPhotoUrl + path + suffix;
+        Log.v(TAG, "downloadContent() GET URL : " + url);
+        try
+        {
+            SimpleHttpClient.httpGetBytes(url, timeoutValue, new SimpleHttpClient.IReceivedMessageCallback() {
+                @Override
+                public void onCompleted() {
+                    callback.onCompleted();
+                }
+
+                @Override
+                public void onErrorOccurred(Exception e) {
+                    callback.onErrorOccurred(e);
+                }
+
+                @Override
+                public void onReceive(int readBytes, int length, int size, byte[] data) {
+                    float percent = (length == 0) ? 0.0f : ((float) readBytes / (float) length);
+                    ProgressEvent event = new ProgressEvent(percent, null);
+                    callback.onProgress(data, size, event);
+                }
+            });
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *   撮影時刻は(個別に)取れるが、非常に遅い...
+     *
+     */
+    private Date getCameraContentDate(@NonNull ICameraContent cameraContent)
+    {
+        // 各ファイルを個別に撮影時刻をとると、反応が悪すぎるので処理を抑止。
+/*
+        String fileInfo;
+        try
+        {
+            String imageInfoUrl = "http://192.168.0.1/v1/photos/" + cameraContent.getContentPath() + "/" + cameraContent.getContentName() + "/info?storage=" + cameraContent.getCardId();
+            //Log.v(TAG, "getCameraContentDate() : " + imageInfoUrl);
+            fileInfo = SimpleHttpClient.httpGet(imageInfoUrl, DEFAULT_TIMEOUT);
+            if (fileInfo != null)
+            {
+                String datetime = new JSONObject(fileInfo).getString("datetime");
+                SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); // "yyyy-MM-dd'T'HH:mm:ssZ"
+                dateFormatter.setCalendar(new GregorianCalendar());
+                return (dateFormatter.parse(datetime));
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return (cameraContent.getCapturedDate());
+*/
+        return (null);
+    }
+
+
+    /**
+     *   カメラ内画像ファイルの取得処理... GRコマンドが失敗したらPENTAXコマンドを使う。
+     *
+     */
+    @Override
+    public void getCameraContentList(ICameraContentListCallback callback)
+    {
+        try
+        {
+/*
+            if (useGrCommand)
+            {
+                getGrCameraContentListImpl(callback);
+                return;
+            }
+*/
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        getCameraContentListImpl(callback);
+    }
+
+    @Override
+    public void showPictureStarted()
+    {
+
+    }
+
+    @Override
+    public void showPictureFinished()
+    {
+
+    }
+
+    /**
+     *   RICOH GR2用のカメラ内画像ファイル一覧取得処理
+     *   (エラー発生時には、通常のPENTAX用のカメラ内画像ファイル一覧取得処理を使う)
+     *
+     */
+    private void getGrCameraContentListImpl(ICameraContentListCallback callback)
+    {
+        List<ICameraContent> fileList = new ArrayList<>();
+        String imageListurl = "http://192.168.0.1/_gr/objs";
+        String contentList;
+
+        // try ~ catch でくくらない ... だめだったら PENTAXのシーケンスに入るようにしたいので
+        contentList = SimpleHttpClient.httpGet(imageListurl, timeoutValue);
+        if (contentList == null)
+        {
+            // ぬるぽ発行
+            throw (new NullPointerException());
+        }
+
+        try
+        {
+            String cameraId = ""; //statusChecker.getCameraId();
+            JSONArray dirsArray = new JSONObject(contentList).getJSONArray("dirs");
+            if (dirsArray != null)
+            {
+                int size = dirsArray.length();
+                for (int index = 0; index < size; index++)
+                {
+                    JSONObject object = dirsArray.getJSONObject(index);
+                    String dirName = object.getString("name");
+                    JSONArray filesArray = object.getJSONArray("files");
+                    int nofFiles = filesArray.length();
+                    for (int fileIndex = 0; fileIndex < nofFiles; fileIndex++)
+                    {
+                        JSONObject fileObject = filesArray.getJSONObject(fileIndex);
+                        String fileName = fileObject.getString("n");
+                        String dateString = fileObject.getString("d");
+                        Date capturedDate = new Date(2001, 1, 1);
+                        if (dateString != null)
+                        {
+                            SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); // "yyyy-MM-dd'T'HH:mm:ssZ"
+                            dateFormatter.setCalendar(new GregorianCalendar());
+                            capturedDate = dateFormatter.parse(dateString);
+                        }
+                        ICameraContent cameraContent = new CameraContentInfo(cameraId, "sd1", dirName, fileName, capturedDate);
+                        fileList.add(cameraContent);
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            // ぬるぽ発行
+           throw  (new NullPointerException());
+        }
+        callback.onCompleted(fileList);
+    }
+
+    private void getCameraContentListImpl(ICameraContentListCallback callback)
+    {
+        List<ICameraContent> fileList = new ArrayList<>();
+        String imageListurl = "http://192.168.0.1/v1/photos?limit=";// + maxCount;
+        String contentList;
+        try
+        {
+            contentList = SimpleHttpClient.httpGet(imageListurl, timeoutValue);
+            if (contentList == null)
+            {
+                // ぬるぽ発行
+                callback.onErrorOccurred(new NullPointerException());
+                return;
+            }
+        }
+        catch (Exception e)
+        {
+            // 例外をそのまま転送
+            callback.onErrorOccurred(e);
+            return;
+        }
+        try
+        {
+            Log.v(TAG, "PHOTO LIST RECV: [" + contentList.length() + "]");
+            String cameraId = "";//statusChecker.getCameraId();
+            JSONArray dirsArray = new JSONObject(contentList).getJSONArray("dirs");
+            if (dirsArray != null)
+            {
+                int size = dirsArray.length();
+                Log.v(TAG, "DIRECTORIES : " + size);
+                for (int index = 0; index < size; index++)
+                {
+                    JSONObject object = dirsArray.getJSONObject(index);
+                    String dirName = object.getString("name");
+                    JSONArray filesArray = object.getJSONArray("files");
+                    int nofFiles = filesArray.length();
+                    Log.v(TAG, "FILES : [" + dirName + "] " + nofFiles);
+                    for (int fileIndex = 0; fileIndex < nofFiles; fileIndex++)
+                    {
+                        String fileName = filesArray.getString(fileIndex);
+                        //Log.v(TAG, "FILE : " + fileName);
+                        ICameraContent cameraContent = new CameraContentInfo(cameraId, "sd1", dirName, fileName, null);
+                        Date capturedDate = getCameraContentDate(cameraContent);
+                        if (capturedDate != null)
+                        {
+                            cameraContent.setCapturedDate(capturedDate);
+                        }
+                        fileList.add(cameraContent);
+                    }
+                }
+            }
+            else
+            {
+                Log.v(TAG, "NOT FOUND dirs array.");
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            try {
+                fileList.clear();
+            }
+            catch (Exception ee)
+            {
+                ee.printStackTrace();
+            }
+        }
+        callback.onCompleted(fileList);
+    }
+}
index 903dead..06a01d3 100644 (file)
@@ -11,7 +11,7 @@ public class PtpIpRunMode implements ICameraRunMode, IPtpIpRunModeHolder
     private boolean isChanging = false;
     private boolean isRecordingMode = false;
 
-    PtpIpRunMode()
+    public PtpIpRunMode()
     {
         //
     }
index bfa7ca2..cc8d5e0 100644 (file)
@@ -31,13 +31,13 @@ public class PtpIpFullImageReceiver implements IPtpIpCommandCallback
     private int target_image_size = 0;
     private boolean receivedFirstData = false;
 
-    PtpIpFullImageReceiver(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher publisher)
+    public PtpIpFullImageReceiver(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher publisher)
     {
         this.activity = activity;
         this.publisher = publisher;
     }
 
-    void issueCommand(int objectId, int imageSize, IDownloadContentCallback callback)
+    public void issueCommand(int objectId, int imageSize, IDownloadContentCallback callback)
     {
         if (this.objectId != 0)
         {
index ced1e30..923b16c 100644 (file)
@@ -17,7 +17,7 @@ public class PtpIpImageContentInfo implements ICameraContent
     private Date date;
     private final byte[] rx_body;
 
-    PtpIpImageContentInfo(int indexNumber, String contentPath, byte[] binaryData, int offset, int length)
+    public PtpIpImageContentInfo(int indexNumber, String contentPath, byte[] binaryData, int offset, int length)
     {
         this.indexNumber = indexNumber;
         this.contentPath = contentPath;
@@ -111,7 +111,7 @@ public class PtpIpImageContentInfo implements ICameraContent
         return (indexNumber);
     }
 
-    int getOriginalSize()
+    public int getOriginalSize()
     {
         try
         {
index fb9634c..ef5187b 100644 (file)
@@ -25,7 +25,7 @@ public class PtpIpScreennailImageReceiver implements IPtpIpCommandCallback
     private final IPtpIpCommandPublisher publisher;
     private final int objectId;
 
-    PtpIpScreennailImageReceiver(Activity activity, int objectId, IPtpIpCommandPublisher publisher, IDownloadThumbnailImageCallback callback)
+    public PtpIpScreennailImageReceiver(Activity activity, int objectId, IPtpIpCommandPublisher publisher, IDownloadThumbnailImageCallback callback)
     {
         this.activity = activity;
         this.callback = callback;
index fd97087..dda5345 100644 (file)
@@ -33,14 +33,14 @@ public class PtpIpSmallImageReceiver implements IPtpIpCommandCallback
     private int received_total_bytes = 0;
     private int received_remain_bytes = 0;
 
-    PtpIpSmallImageReceiver(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher publisher)
+    public PtpIpSmallImageReceiver(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher publisher)
     {
         this.activity = activity;
         this.publisher = publisher;
         this.mine = this;
     }
 
-    void issueCommand(final int objectId, IDownloadContentCallback callback)
+    public void issueCommand(final int objectId, IDownloadContentCallback callback)
     {
         if (this.objectId != 0)
         {
index 850d1ac..4b76c22 100644 (file)
@@ -23,7 +23,7 @@ public class PtpIpThumbnailImageReceiver implements IPtpIpCommandCallback
     private final Activity context;
     private final IDownloadThumbnailImageCallback callback;
 
-    PtpIpThumbnailImageReceiver(@NonNull Activity context, @NonNull IDownloadThumbnailImageCallback callback)
+    public PtpIpThumbnailImageReceiver(@NonNull Activity context, @NonNull IDownloadThumbnailImageCallback callback)
     {
         this.context = context;
         this.callback = callback;
index 88833c7..6037070 100644 (file)
@@ -167,9 +167,9 @@ public class NikonPreferenceFragment  extends PreferenceFragmentCompat implement
         try
         {
             //super.onCreate(savedInstanceState);
-            addPreferencesFromResource(R.xml.preferences_fuji_x);
+            addPreferencesFromResource(R.xml.preferences_nikon);
 
-            ListPreference connectionMethod = (ListPreference) findPreference(IPreferencePropertyAccessor.CONNECTION_METHOD);
+            ListPreference connectionMethod =findPreference(IPreferencePropertyAccessor.CONNECTION_METHOD);
             connectionMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -246,7 +246,7 @@ public class NikonPreferenceFragment  extends PreferenceFragmentCompat implement
         try
         {
             ListPreference pref;
-            pref = (ListPreference) findPreference(pref_key);
+            pref = findPreference(pref_key);
             String value = preferences.getString(key, defaultValue);
             if (pref != null)
             {
@@ -271,7 +271,7 @@ public class NikonPreferenceFragment  extends PreferenceFragmentCompat implement
     {
         try
         {
-            CheckBoxPreference pref = (CheckBoxPreference) findPreference(pref_key);
+            CheckBoxPreference pref = findPreference(pref_key);
             if (pref != null) {
                 boolean value = preferences.getBoolean(key, defaultValue);
                 pref.setChecked(value);
diff --git a/app/src/main/java/net/osdn/gokigen/pkremote/preference/olympuspen/OlympusPenPreferenceFragment.java b/app/src/main/java/net/osdn/gokigen/pkremote/preference/olympuspen/OlympusPenPreferenceFragment.java
new file mode 100644 (file)
index 0000000..39450e6
--- /dev/null
@@ -0,0 +1,313 @@
+package net.osdn.gokigen.pkremote.preference.olympuspen;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Map;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceManager;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.vendor.olympuspen.operation.OlympusPenCameraPowerOff;
+import net.osdn.gokigen.pkremote.logcat.LogCatViewer;
+import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+import net.osdn.gokigen.pkremote.scene.IChangeScene;
+
+/**
+ *
+ *
+ */
+public class OlympusPenPreferenceFragment  extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener
+{
+    private final String TAG = toString();
+    private SharedPreferences preferences = null;
+    private OlympusPenCameraPowerOff powerOffController = null;
+    private LogCatViewer logCatViewer = null;
+
+    /**
+     *
+     *
+     */
+    public static OlympusPenPreferenceFragment newInstance(@NonNull AppCompatActivity context, @NonNull IChangeScene changeScene)
+    {
+        OlympusPenPreferenceFragment instance = new OlympusPenPreferenceFragment();
+        instance.prepare(context, changeScene);
+
+        // パラメータはBundleにまとめておく
+        Bundle arguments = new Bundle();
+        //arguments.putString("title", title);
+        //arguments.putString("message", message);
+        instance.setArguments(arguments);
+
+        return (instance);
+    }
+
+    /**
+     *
+     *
+     */
+    private void prepare(@NonNull AppCompatActivity context, @NonNull IChangeScene changeScene)
+    {
+        try
+        {
+            powerOffController = new OlympusPenCameraPowerOff(context, changeScene);
+            powerOffController.prepare();
+
+            logCatViewer = new LogCatViewer(changeScene);
+            logCatViewer.prepare();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void onAttach(Context activity)
+    {
+        super.onAttach(activity);
+        Log.v(TAG, "onAttach()");
+
+        try
+        {
+            // Preference をつかまえる
+            preferences = PreferenceManager.getDefaultSharedPreferences(activity);
+
+            // Preference を初期設定する
+            initializePreferences();
+
+            preferences.registerOnSharedPreferenceChangeListener(this);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Preferenceの初期化...
+     *
+     */
+    private void initializePreferences()
+    {
+        try
+        {
+            Map<String, ?> items = preferences.getAll();
+            SharedPreferences.Editor editor = preferences.edit();
+
+            if (!items.containsKey(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA)) {
+                editor.putBoolean(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, true);
+            }
+            if (!items.containsKey(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW)) {
+                editor.putBoolean(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, true);
+            }
+            if (!items.containsKey(IPreferencePropertyAccessor.CONNECTION_METHOD)) {
+                editor.putString(IPreferencePropertyAccessor.CONNECTION_METHOD, IPreferencePropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE);
+            }
+            editor.apply();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
+    {
+        Log.v(TAG, "onSharedPreferenceChanged() : " + key);
+        boolean value;
+        if (key != null)
+        {
+            switch (key)
+            {
+                case IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA:
+                    value = preferences.getBoolean(key, true);
+                    Log.v(TAG, " " + key + " , " + value);
+                    break;
+
+                case IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW:
+                    value = preferences.getBoolean(key, true);
+                    Log.v(TAG, " " + key + " , " + value);
+                    break;
+
+                default:
+                    String strValue = preferences.getString(key, "");
+                    setListPreference(key, key, strValue);
+                    break;
+            }
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
+    {
+        Log.v(TAG, "onCreatePreferences()");
+        try
+        {
+            //super.onCreate(savedInstanceState);
+            addPreferencesFromResource(R.xml.preferences_olympus);
+
+            ListPreference connectionMethod = findPreference(IPreferencePropertyAccessor.CONNECTION_METHOD);
+            connectionMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+                @Override
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    preference.setSummary(newValue + " ");
+                    return (true);
+                }
+            });
+            connectionMethod.setSummary(connectionMethod.getValue() + " ");
+
+            findPreference("exit_application").setOnPreferenceClickListener(powerOffController);
+            findPreference("debug_info").setOnPreferenceClickListener(logCatViewer);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void onResume()
+    {
+        super.onResume();
+        Log.v(TAG, "onResume() Start");
+
+        try
+        {
+            synchronizedProperty();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+        Log.v(TAG, "onResume() End");
+
+    }
+
+    /**
+     *
+     *
+     */
+    @Override
+    public void onPause()
+    {
+        super.onPause();
+        Log.v(TAG, "onPause() Start");
+
+        try
+        {
+            // Preference変更のリスナを解除
+            preferences.unregisterOnSharedPreferenceChangeListener(this);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+        Log.v(TAG, "onPause() End");
+    }
+
+    /**
+     * ListPreference の表示データを設定
+     *
+     * @param pref_key     Preference(表示)のキー
+     * @param key          Preference(データ)のキー
+     * @param defaultValue Preferenceのデフォルト値
+     */
+    private void setListPreference(String pref_key, String key, String defaultValue)
+    {
+        try
+        {
+            ListPreference pref;
+            pref = findPreference(pref_key);
+            String value = preferences.getString(key, defaultValue);
+            if (pref != null)
+            {
+                pref.setValue(value);
+                pref.setSummary(value);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * BooleanPreference の表示データを設定
+     *
+     * @param pref_key     Preference(表示)のキー
+     * @param key          Preference(データ)のキー
+     * @param defaultValue Preferenceのデフォルト値
+     */
+    private void setBooleanPreference(String pref_key, String key, boolean defaultValue)
+    {
+        try
+        {
+            CheckBoxPreference pref = findPreference(pref_key);
+            if (pref != null) {
+                boolean value = preferences.getBoolean(key, defaultValue);
+                pref.setChecked(value);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *
+     *
+     */
+    private void synchronizedProperty()
+    {
+        final FragmentActivity activity = getActivity();
+        if (activity != null)
+        {
+            activity.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    try
+                    {
+                        // Preferenceの画面に反映させる
+                        setBooleanPreference(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, true);
+                        setBooleanPreference(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, true);
+                    }
+                    catch (Exception e)
+                    {
+                        e.printStackTrace();
+                    }
+                }
+            });
+        }
+    }
+
+}
index e1b79cc..a684bfa 100644 (file)
@@ -19,6 +19,7 @@ import net.osdn.gokigen.pkremote.preference.canon.CanonPreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.fujix.FujiXPreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.nikon.NikonPreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.olympus.OpcPreferenceFragment;
+import net.osdn.gokigen.pkremote.preference.olympuspen.OlympusPenPreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.panasonic.PanasonicPreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.ricohgr2.RicohGr2PreferenceFragment;
 import net.osdn.gokigen.pkremote.preference.sony.SonyPreferenceFragment;
@@ -330,6 +331,10 @@ public class CameraSceneUpdater implements ICameraStatusReceiver, IChangeScene,
                     {
                         preferenceFragment = NikonPreferenceFragment.newInstance(activity, this);
                     }
+                    else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+                    {
+                        preferenceFragment = OlympusPenPreferenceFragment.newInstance(activity, this);
+                    }
                     else //  if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
                     {
                         preferenceFragment = OpcPreferenceFragment.newInstance(activity, interfaceProvider, this);
index e8f1813..486eae7 100644 (file)
@@ -7,6 +7,7 @@
         <item>Panasonic</item>
         <item>Sony</item>
         <item>Canon</item>
+        <item>Olympus(OM-D/PEN)</item>
 <!--
         <item>Nikon</item>
 -->
@@ -19,6 +20,7 @@
         <item>PANASONIC</item>
         <item>SONY</item>
         <item>CANON</item>
+        <item>OLYMPUS</item>
 <!--
         <item>NIKON</item>
 -->
index 620e29e..3a58604 100644 (file)
@@ -7,6 +7,7 @@
         <item>Panasonic</item>
         <item>Sony</item>
         <item>Canon</item>
+        <item>Olympus(OM-D/PEN)</item>
 <!--
         <item>Nikon</item>
 -->
@@ -19,6 +20,7 @@
         <item>PANASONIC</item>
         <item>SONY</item>
         <item>CANON</item>
+        <item>OLYMPUS</item>
 <!--
         <item>NIKON</item>
 -->
diff --git a/app/src/main/res/xml/preferences_olympus.xml b/app/src/main/res/xml/preferences_olympus.xml
new file mode 100644 (file)
index 0000000..58394c3
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
+    <PreferenceCategory
+        android:title="@string/pref_cat_application_control">
+
+        <PreferenceScreen
+            android:key="exit_application"
+            android:icon="@drawable/ic_power_settings_new_black_24dp"
+            android:title="@string/pref_exit_power_off_sony" />
+
+        <ListPreference
+            android:title="@string/pref_connection_method"
+            android:entryValues="@array/connection_method_value"
+            android:entries="@array/connection_method"
+            android:key="connection_method"
+            android:defaultValue="OPC"/>
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:title="@string/pref_cat_camera">
+
+        <!--
+
+        <PreferenceScreen
+            android:key="sony_api_list"
+            android:title="@string/pref_sony_api_list"
+            android:summary="@string/pref_summary_sony_api_list" />
+
+        <CheckBoxPreference
+            android:key="use_smartphone_transfer_mode"
+            android:title="@string/pref_sony_use_smartphone_transfer"
+            android:summary="@string/pref_summary_sony_use_smartphone_transfer" />
+
+        <CheckBoxPreference
+            android:key="get_small_picture_as_vga"
+            android:title="@string/pref_get_small_picture_as_vga"
+            android:summary="@string/pref_summary_get_small_picture_as_vga" />
+
+                <CheckBoxPreference
+                    android:key="capture_both_camera_and_live_view"
+                    android:title="@string/pref_capture_both_camera_and_live_view" />
+        -->
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:title="@string/pref_cat_initialize">
+
+        <CheckBoxPreference
+        android:key="auto_connect_to_camera"
+        android:title="@string/pref_auto_connect_camera"
+        android:summary="@string/pref_summary_auto_connect_camera" />
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:title="@string/pref_cat_gokigen">
+
+        <Preference
+            android:key="instruction_link"
+            android:title="@string/pref_instruction_manual"
+            android:summary="https://osdn.net/projects/gokigen/wiki/A01d"
+            android:selectable="true">
+            <intent android:action="android.intent.action.VIEW"
+                android:data="https://osdn.net/projects/gokigen/wiki/A01d" />
+        </Preference>
+
+        <Preference
+            android:key="privacy_policy"
+            android:title="@string/pref_privacy_policy"
+            android:summary="https://osdn.net/projects/gokigen/wiki/PrivacyPolicy"
+            android:selectable="true">
+            <intent android:action="android.intent.action.VIEW"
+                android:data="https://osdn.net/projects/gokigen/wiki/PrivacyPolicy" />
+        </Preference>
+
+        <PreferenceScreen
+            android:key="debug_info"
+            android:title="@string/pref_degug_info"
+            android:summary="@string/pref_summary_debug_info" />
+
+    </PreferenceCategory>
+</PreferenceScreen>