applicationId "net.osdn.gokigen.pkremote"
minSdkVersion 14
targetSdkVersion 29
- versionCode 10400
- versionName "1.4.0"
+ versionCode 10500
+ versionName "1.5.0"
}
buildTypes {
release {
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;
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;
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);
}
{
return (ptpip.getPtpIpCameraConnection());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getOlyCameraConnection());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getRicohGr2CameraConnection());
{
return (ptpip.getButtonControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getButtonControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getButtonControl());
{
return (ptpip.getDisplayInjector());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getDisplayInjector());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getDisplayInjector());
{
return (ptpip.getLiveViewControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getLiveViewControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getLiveViewControl());
{
return (ptpip.getLiveViewListener());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getLiveViewListener());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getLiveViewListener());
{
return (ptpip.getFocusingControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getFocusingControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getFocusingControl());
{
return (ptpip.getCameraInformation());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getCameraInformation());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getCameraInformation());
{
return (ptpip.getZoomLensControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getZoomLensControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getZoomLensControl());
{
return (ptpip.getCaptureControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getCaptureControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getCaptureControl());
{
return (ptpip.getCameraStatusListHolder());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getCameraStatusListHolder());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getCameraStatusListHolder());
{
return (ptpip.getCameraStatusWatcher());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getCameraStatusWatcher());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getCameraStatusWatcher());
{
return (ptpip.getPlaybackControl());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getPlaybackControl());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getPlaybackControl());
{
return (ptpip.getHardwareStatus());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getHardwareStatus());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getHardwareStatus());
{
return (ptpip.getCameraRunMode());
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.OLYMPUS)
+ {
+ return (olympuspen.getCameraRunMode());
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.RICOH)
{
return (ricohGr2.getCameraRunMode());
{
ret = ICameraConnection.CameraConnectionMethod.NIKON;
}
+ else if (connectionMethod.contains("OLYMPUS"))
+ {
+ ret = ICameraConnection.CameraConnectionMethod.OLYMPUS;
+ }
else // if (connectionMethod.contains("OPC"))
{
ret = ICameraConnection.CameraConnectionMethod.OPC;
PANASONIC,
CANON,
NIKON,
+ OLYMPUS,
}
enum CameraConnectionStatus
--- /dev/null
+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);
+}
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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();
+ }
+ }
+
+}
--- /dev/null
+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();
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+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);
+ }
+}
private boolean isChanging = false;
private boolean isRecordingMode = false;
- PtpIpRunMode()
+ public PtpIpRunMode()
{
//
}
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)
{
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;
return (indexNumber);
}
- int getOriginalSize()
+ public int getOriginalSize()
{
try
{
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;
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)
{
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;
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) {
try
{
ListPreference pref;
- pref = (ListPreference) findPreference(pref_key);
+ pref = findPreference(pref_key);
String value = preferences.getString(key, defaultValue);
if (pref != null)
{
{
try
{
- CheckBoxPreference pref = (CheckBoxPreference) findPreference(pref_key);
+ CheckBoxPreference pref = findPreference(pref_key);
if (pref != null) {
boolean value = preferences.getBoolean(key, defaultValue);
pref.setChecked(value);
--- /dev/null
+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();
+ }
+ }
+ });
+ }
+ }
+
+}
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;
{
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);
<item>Panasonic</item>
<item>Sony</item>
<item>Canon</item>
+ <item>Olympus(OM-D/PEN)</item>
<!--
<item>Nikon</item>
-->
<item>PANASONIC</item>
<item>SONY</item>
<item>CANON</item>
+ <item>OLYMPUS</item>
<!--
<item>NIKON</item>
-->
<item>Panasonic</item>
<item>Sony</item>
<item>Canon</item>
+ <item>Olympus(OM-D/PEN)</item>
<!--
<item>Nikon</item>
-->
<item>PANASONIC</item>
<item>SONY</item>
<item>CANON</item>
+ <item>OLYMPUS</item>
<!--
<item>NIKON</item>
-->
--- /dev/null
+<?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>