applicationId "net.osdn.gokigen.pkremote"
minSdkVersion 14
targetSdkVersion 29
- versionCode 10201
- versionName "1.2.1"
+ versionCode 10300
+ versionName "1.3.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.panasonic.wrapper.PanasonicCameraWrapper;
import net.osdn.gokigen.pkremote.camera.vendor.ricoh.wrapper.RicohGr2InterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.ISonyInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.SonyCameraWrapper;
import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
import androidx.annotation.NonNull;
*/
public class CameraInterfaceProvider implements IInterfaceProvider
{
- //private final SonyCameraWrapper sony;
+ private final SonyCameraWrapper sony;
private final OlympusInterfaceProvider olympus;
private final RicohGr2InterfaceProvider ricohGr2;
private final FujiXInterfaceProvider fujiX;
+ private final PanasonicCameraWrapper panasonic;
private final IInformationReceiver informationReceiver;
private final CameraContentsRecognizer cameraContentsRecognizer;
private final AppCompatActivity context;
olympus = new OlympusInterfaceProvider(context, provider);
ricohGr2 = new RicohGr2InterfaceProvider(context, provider);
fujiX = new FujiXInterfaceProvider(context, provider, statusListener, informationReceiver);
- //sony = new SonyCameraWrapper(context, provider);
+ sony = new SonyCameraWrapper(context, provider, statusListener);
+ panasonic = new PanasonicCameraWrapper(context, provider, statusListener);
this.informationReceiver = informationReceiver;
this.cameraContentsRecognizer = new CameraContentsRecognizer(context, this);
}
return (olympus);
}
+ @Override
+ public ISonyInterfaceProvider getSonyInterface()
+ {
+ return (sony);
+ }
+
/**
*
*
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.olympus.IOlympusInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.ISonyInterfaceProvider;
/**
*
ICameraRunMode getCameraRunMode();
IOlympusInterfaceProvider getOlympusInterfaceProvider();
+ ISonyInterfaceProvider getSonyInterface();
ICameraConnection.CameraConnectionMethod getCammeraConnectionMethod();
void resetCameraConnectionMethod();
{
boolean driveAutoFocus(MotionEvent motionEvent);
void unlockAutoFocus();
+ void halfPressShutter(boolean isPressed);
}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.interfaces.status;
+
+import java.util.List;
+
+/**
+ *
+ *
+ */
+public interface ICameraChangeListener
+{
+ void onApiListModified(List<String> apis);
+ void onCameraStatusChanged(String status);
+ void onLiveviewStatusChanged(boolean status);
+ void onShootModeChanged(String shootMode);
+ void onZoomPositionChanged(int zoomPosition);
+ void onStorageIdChanged(String storageId);
+ void onFocusStatusChanged(String focusStatus);
+ void onResponseError();
+}
import androidx.annotation.NonNull;
import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ICameraStatusUpdateNotify;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
-public class CameraStatusListener implements ICameraStatusUpdateNotify
+import java.util.List;
+
+public class CameraStatusListener implements ICameraStatusUpdateNotify, ICameraChangeListener
{
private final String TAG = toString();
private ICameraStatusUpdateNotify updateReceiver = null;
{
Log.v(TAG, "updateStorageStatus() : " + status);
}
+
+ @Override
+ public void onApiListModified(List<String> apis)
+ {
+ Log.v(TAG, "onApiListModified() : ");
+ }
+
+ @Override
+ public void onCameraStatusChanged(String status)
+ {
+ Log.v(TAG, "onCameraStatusChanged() : " + status);
+ }
+
+ @Override
+ public void onLiveviewStatusChanged(boolean status)
+ {
+ Log.v(TAG, "onLiveviewStatusChanged() : " + status);
+ }
+
+ @Override
+ public void onShootModeChanged(String shootMode)
+ {
+ Log.v(TAG, "onShootModeChanged() : " + shootMode);
+ }
+
+ @Override
+ public void onZoomPositionChanged(int zoomPosition)
+ {
+ Log.v(TAG, "onZoomPositionChanged() : " + zoomPosition);
+ }
+
+ @Override
+ public void onStorageIdChanged(String storageId)
+ {
+ Log.v(TAG, "onStorageIdChanged() : " + storageId);
+ }
+
+ @Override
+ public void onFocusStatusChanged(String focusStatus)
+ {
+ Log.v(TAG, "onFocusStatusChanged() : " + focusStatus);
+ }
+
+ @Override
+ public void onResponseError()
+ {
+ Log.v(TAG, "onResponseError() : ");
+ }
}
}
}
+ @Override
+ public void halfPressShutter(boolean isPressed)
+ {
+
+ }
+
}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+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.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public interface IPanasonicInterfaceProvider
+{
+ ICameraConnection getPanasonicCameraConnection();
+ ILiveViewControl getPanasonicLiveViewControl();
+ ILiveViewListener getLiveViewListener();
+ IFocusingControl getFocusingControl();
+ ICameraInformation getCameraInformation();
+ IZoomLensControl getZoomLensControl();
+ ICaptureControl getCaptureControl();
+ IDisplayInjector getDisplayInjector();
+
+ IPanasonicCamera getPanasonicCamera();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+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;
+
+/**
+ * Preferenceがクリックされた時に処理するクラス
+ *
+ */
+public class CameraPowerOffPanasonic implements Preference.OnPreferenceClickListener, ConfirmationDialog.Callback
+{
+
+ private final Context context;
+ private final IChangeScene changeScene;
+ private String preferenceKey = null;
+
+ /**
+ * コンストラクタ
+ *
+ */
+ public CameraPowerOffPanasonic(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_exit_application, 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.panasonic.operation;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.takepicture.SingleShotControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public class PanasonicCameraCaptureControl implements ICaptureControl
+{
+ private static final String TAG = PanasonicCameraCaptureControl.class.getSimpleName();
+ private final SingleShotControl singleShotControl;
+
+ public PanasonicCameraCaptureControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+ {
+ singleShotControl = new SingleShotControl(frameDisplayer, indicator);
+ }
+
+ public void setCamera(@NonNull IPanasonicCamera panasonicCamera)
+ {
+ singleShotControl.setCamera(panasonicCamera);
+ }
+
+ /**
+ * 撮影する
+ *
+ */
+ @Override
+ public void doCapture(int kind)
+ {
+ Log.v(TAG, "doCapture() : " + kind);
+ try
+ {
+ singleShotControl.singleShot();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.takepicture.PanasonicAutoFocusControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public class PanasonicCameraFocusControl implements IFocusingControl
+{
+ private final String TAG = toString();
+ private final PanasonicAutoFocusControl afControl;
+ private final IAutoFocusFrameDisplay frameDisplay;
+
+ public PanasonicCameraFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, @NonNull final IIndicatorControl indicator)
+ {
+ this.frameDisplay = frameDisplayer;
+ afControl = new PanasonicAutoFocusControl(frameDisplayer, indicator);
+ }
+
+ public void setCamera(@NonNull IPanasonicCamera panasonicCamera)
+ {
+ afControl.setCamera(panasonicCamera);
+ }
+
+ @Override
+ public boolean driveAutoFocus(final MotionEvent motionEvent)
+ {
+ Log.v(TAG, "driveAutoFocus()");
+ if (motionEvent.getAction() != MotionEvent.ACTION_DOWN)
+ {
+ return (false);
+ }
+ try
+ {
+ PointF point = frameDisplay.getPointWithEvent(motionEvent);
+ if (frameDisplay.isContainsPoint(point))
+ {
+ afControl.lockAutoFocus(point);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (false);
+ }
+
+ @Override
+ public void unlockAutoFocus()
+ {
+ Log.v(TAG, "unlockAutoFocus()");
+ try
+ {
+ afControl.unlockAutoFocus();
+ frameDisplay.hideFocusFrame();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void halfPressShutter(boolean isPressed)
+ {
+ Log.v(TAG, "halfPressShutter() " + isPressed);
+ try
+ {
+ afControl.halfPressShutter(isPressed);
+ if (!isPressed)
+ {
+ // フォーカスを外す
+ frameDisplay.hideFocusFrame();
+ afControl.unlockAutoFocus();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public class PanasonicCameraZoomLensControl implements IZoomLensControl
+{
+ private final String TAG = toString();
+ private IPanasonicCamera camera = null;
+ private boolean isZooming = false;
+ private static final int TIMEOUT_MS = 3000;
+
+ public PanasonicCameraZoomLensControl()
+ {
+ Log.v(TAG, "PanasonicCameraZoomLensControl()");
+ }
+
+ public void setCamera(@NonNull IPanasonicCamera panasonicCamera)
+ {
+ camera = panasonicCamera;
+ }
+
+ @Override
+ public boolean canZoom() {
+ Log.v(TAG, "canZoom()");
+ return (true);
+ }
+
+ @Override
+ public void updateStatus()
+ {
+ Log.v(TAG, "updateStatus()");
+ }
+
+ @Override
+ public float getMaximumFocalLength()
+ {
+ Log.v(TAG, "getMaximumFocalLength()");
+ return (0);
+ }
+
+ @Override
+ public float getMinimumFocalLength()
+ {
+ Log.v(TAG, "getMinimumFocalLength()");
+ return (0);
+ }
+
+ @Override
+ public float getCurrentFocalLength()
+ {
+ Log.v(TAG, "getCurrentFocalLength()");
+ return (0);
+ }
+
+ @Override
+ public void driveZoomLens(float targetLength)
+ {
+ Log.v(TAG, "driveZoomLens() : " + targetLength);
+ }
+
+ @Override
+ public void moveInitialZoomPosition()
+ {
+ Log.v(TAG, "moveInitialZoomPosition()");
+ }
+
+ @Override
+ public boolean isDrivingZoomLens()
+ {
+ Log.v(TAG, "isDrivingZoomLens()");
+ return (isZooming);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void driveZoomLens(boolean isZoomIn)
+ {
+ Log.v(TAG, "driveZoomLens() : " + isZoomIn);
+ if (camera == null)
+ {
+ Log.v(TAG, "IPanasonicCameraApi is null...");
+ return;
+ }
+ try
+ {
+ String command;
+ if (isZooming)
+ {
+ command = "cam.cgi?mode=camcmd&value=zoomstop";
+ }
+ else
+ {
+ command = (isZoomIn) ? "cam.cgi?mode=camcmd&value=tele-normal" : "cam.cgi?mode=camcmd&value=wide-normal";
+ }
+ final String direction = command;
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + direction, TIMEOUT_MS);
+ if (reply.contains("ok"))
+ {
+ isZooming = !isZooming;
+ }
+ else
+ {
+ Log.v(TAG, "driveZoomLens() reply is failure.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.IPanasonicInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public class PanasonicSendCommandDialog extends DialogFragment implements View.OnClickListener
+{
+ private final String TAG = toString();
+ private IPanasonicInterfaceProvider interfaceProvider = null;
+ private IPanasonicCamera camera = null;
+ private Dialog myDialog = null;
+ private EditText service = null;
+ private EditText parameter = null;
+ private EditText command = null;
+ private TextView responseArea = null;
+ private static final int TIMEOUT_MS = 2000;
+
+ /**
+ *
+ *
+ */
+ public static PanasonicSendCommandDialog newInstance(@NonNull IPanasonicInterfaceProvider interfaceProvider)
+ {
+ PanasonicSendCommandDialog instance = new PanasonicSendCommandDialog();
+ instance.prepare(interfaceProvider);
+
+ // パラメータはBundleにまとめておく
+ Bundle arguments = new Bundle();
+ //arguments.putString("method", method);
+ //arguments.putString("message", message);
+ instance.setArguments(arguments);
+
+ return (instance);
+ }
+
+ /**
+ *
+ *
+ */
+ private void prepare(@NonNull IPanasonicInterfaceProvider interfaceProvider)
+ {
+ //
+ this.interfaceProvider = interfaceProvider;
+ this.camera = interfaceProvider.getPanasonicCamera();
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ Log.v(TAG, "AlertDialog::onPause()");
+ try
+ {
+ if (myDialog != null)
+ {
+ myDialog.cancel();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public @NonNull Dialog onCreateDialog(Bundle savedInstanceState)
+ {
+ final Activity activity = getActivity();
+
+ // コマンド送信ダイアログの生成
+ final AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
+
+ // Get the layout inflater
+ LayoutInflater inflater = activity.getLayoutInflater();
+ final View alertView = inflater.inflate(R.layout.panasonic_request_layout, null, false);
+ alertDialog.setView(alertView);
+
+ alertDialog.setIcon(R.drawable.ic_linked_camera_black_24dp);
+ alertDialog.setTitle(activity.getString(R.string.dialog_panasonic_command_title_command));
+ service = alertView.findViewById(R.id.edit_service);
+ parameter = alertView.findViewById(R.id.edit_parameter);
+ command = alertView.findViewById(R.id.edit_command);
+ responseArea = alertView.findViewById(R.id.panasonic_command_response_value);
+ final Button sendButton = alertView.findViewById(R.id.send_message_button);
+ final Button toRunningButton = alertView.findViewById(R.id.change_to_liveview);
+ final Button toPlaybackButton = alertView.findViewById(R.id.change_to_playback);
+
+ toRunningButton.setOnClickListener(this);
+ toPlaybackButton.setOnClickListener(this);
+ sendButton.setOnClickListener(this);
+ alertDialog.setCancelable(true);
+ try
+ {
+ if (service != null)
+ {
+ service.setText(activity.getText(R.string.panasonic_service_string));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ // ボタンを設定する(実行ボタン)
+ alertDialog.setPositiveButton(activity.getString(R.string.dialog_positive_execute),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which)
+ {
+ dialog.dismiss();
+ }
+ });
+
+ // ボタンを設定する (キャンセルボタン)
+ alertDialog.setNegativeButton(activity.getString(R.string.dialog_negative_cancel),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ // 確認ダイアログを応答する
+ myDialog = alertDialog.create();
+ return (myDialog);
+ }
+
+ private void changeRunMode(boolean isStartLiveView)
+ {
+ // ライブビューの停止と開始
+ Log.v(TAG, "changeRunMode() : " + isStartLiveView);
+ ILiveViewControl liveViewControl = interfaceProvider.getPanasonicLiveViewControl();
+ try
+ {
+ if (isStartLiveView)
+ {
+ liveViewControl.startLiveView(false);
+ }
+ else
+ {
+ liveViewControl.stopLiveView();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onClick(View view)
+ {
+ if (view.getId() == R.id.change_to_liveview)
+ {
+ changeRunMode(true);
+ return;
+ }
+ if (view.getId() == R.id.change_to_playback)
+ {
+ changeRunMode(false);
+ return;
+ }
+
+
+ try
+ {
+ String serviceStr = "";
+ String commandStr = "";
+ String parameterStr = "";
+ final Activity activity = getActivity();
+ if (activity != null)
+ {
+ if (service != null)
+ {
+ serviceStr = service.getText().toString();
+ }
+ if (command != null)
+ {
+ commandStr = command.getText().toString();
+ }
+ final boolean isPost = (serviceStr.contains("post"));
+ if (parameter != null)
+ {
+ parameterStr = parameter.getText().toString();
+ if ((!isPost)&&(parameterStr.length() > 0))
+ {
+ commandStr = commandStr + "&" + parameterStr;
+ }
+ }
+ if (serviceStr.contains("pic"))
+ {
+ serviceStr = camera.getPictureUrl() + commandStr;
+ }
+ else if (serviceStr.contains("obj"))
+ {
+ serviceStr = camera.getObjUrl() + commandStr;
+ }
+ else
+ {
+ serviceStr = camera.getCmdUrl() + serviceStr + "?" + commandStr;
+ }
+ final String url = serviceStr;
+ final String param = parameterStr;
+
+ Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String reply;
+ if (isPost)
+ {
+ reply = SimpleHttpClient.httpPost(url, param, TIMEOUT_MS);
+ }
+ else
+ {
+ reply = SimpleHttpClient.httpGet(url, TIMEOUT_MS);
+ }
+ Log.v(TAG, "URL : " + url + " RESPONSE : " + reply);
+ final String response = reply;
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (responseArea != null)
+ {
+ responseArea.setText(response);
+ }
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ else
+ {
+ Log.v(TAG, "getActivity() Fail...");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.takepicture;
+
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ *
+ *
+ */
+public class PanasonicAutoFocusControl
+{
+ private static final String TAG = PanasonicAutoFocusControl.class.getSimpleName();
+ private static final int TIMEOUT_MS = 3000;
+ private final IIndicatorControl indicator;
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private IPanasonicCamera camera = null;
+
+ /**
+ *
+ *
+ */
+ public PanasonicAutoFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, final IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCamera(@NonNull IPanasonicCamera panasonicCamera)
+ {
+ this.camera = panasonicCamera;
+ }
+
+ /**
+ *
+ *
+ */
+ public void lockAutoFocus(@NonNull final PointF point)
+ {
+ Log.v(TAG, "lockAutoFocus() : [" + point.x + ", " + point.y + "]");
+ if (camera == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ RectF preFocusFrameRect = getPreFocusFrameRect(point);
+ try
+ {
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Running, 0.0);
+
+ int posX = (int) (Math.floor(point.x * 1000.0));
+ int posY = (int) (Math.floor(point.y * 1000.0));
+ Log.v(TAG, "AF (" + posX + ", " + posY + ")");
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + "cam.cgi?mode=camctrl&type=touch&value=" + posX + "/" + posY + "&value2=on", TIMEOUT_MS);
+
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "setTouchAFPosition() reply is null.");
+ }
+/*
+ if (findTouchAFPositionResult(resultsObj))
+ {
+ // AF FOCUSED
+ Log.v(TAG, "lockAutoFocus() : FOCUSED");
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Focused, 0.0);
+ }
+ else
+ {
+ // AF ERROR
+ Log.v(TAG, "lockAutoFocus() : ERROR");
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Failed, 1.0);
+ }
+*/
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Errored, 1.0);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ try
+ {
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Errored, 1.0);
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * シャッター半押し処理
+ *
+ */
+ public void halfPressShutter(final boolean isPressed)
+ {
+ Log.v(TAG, "halfPressShutter() : " + isPressed);
+ if (camera == null)
+ {
+ Log.v(TAG, "IPanasonicCamera is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String status = (isPressed) ? "on" : "off";
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + "cam.cgi?mode=camctrl&type=touch&value=500/500&value2=" + status, TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "CENTER FOCUS (" + status + ") FAIL...");
+ }
+ else
+ {
+ indicator.onAfLockUpdate(isPressed);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ public void unlockAutoFocus()
+ {
+ Log.v(TAG, "unlockAutoFocus()");
+ if (camera == null)
+ {
+ Log.v(TAG, "IPanasonicCamera is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + "cam.cgi?mode=camctrl&type=touch&value=500/500&value2=off", TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "CENTER FOCUS (UNLOCK) FAIL...");
+ }
+ hideFocusFrame();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ private void showFocusFrame(RectF rect, IAutoFocusFrameDisplay.FocusFrameStatus status, double duration)
+ {
+ frameDisplayer.showFocusFrame(rect, status, duration);
+ indicator.onAfLockUpdate(IAutoFocusFrameDisplay.FocusFrameStatus.Focused == status);
+ }
+
+ /**
+ *
+ *
+ */
+ private void hideFocusFrame()
+ {
+ frameDisplayer.hideFocusFrame();
+ indicator.onAfLockUpdate(false);
+ }
+
+ /**
+ *
+ *
+ */
+ private RectF getPreFocusFrameRect(@NonNull PointF point)
+ {
+ float imageWidth = frameDisplayer.getContentSizeWidth();
+ float imageHeight = frameDisplayer.getContentSizeHeight();
+
+ // Display a provisional focus frame at the touched point.
+ float focusWidth = 0.125f; // 0.125 is rough estimate.
+ float focusHeight = 0.125f;
+ if (imageWidth > imageHeight)
+ {
+ focusHeight *= (imageWidth / imageHeight);
+ }
+ else
+ {
+ focusHeight *= (imageHeight / imageWidth);
+ }
+ return (new RectF(point.x - focusWidth / 2.0f, point.y - focusHeight / 2.0f,
+ point.x + focusWidth / 2.0f, point.y + focusHeight / 2.0f));
+ }
+
+ /**
+ *
+ *
+ */
+ private static boolean findTouchAFPositionResult(JSONObject replyJson)
+ {
+ boolean afResult = false;
+ try
+ {
+ int indexOfTouchAFPositionResult = 1;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfTouchAFPositionResult))
+ {
+ JSONObject touchAFPositionResultObj = resultsObj.getJSONObject(indexOfTouchAFPositionResult);
+ afResult = touchAFPositionResultObj.getBoolean("AFResult");
+ Log.v(TAG, "AF Result : " + afResult);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (afResult);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.takepicture;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+public class SingleShotControl
+{
+ private static final String TAG = SingleShotControl.class.getSimpleName();
+ private static final int TIMEOUT_MS = 3000;
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private final IIndicatorControl indicator;
+ private IPanasonicCamera camera = null;
+
+ /**
+ *
+ *
+ */
+ public SingleShotControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCamera(@NonNull IPanasonicCamera panasonicCamera)
+ {
+ this.camera = panasonicCamera;
+ }
+
+ /**
+ *
+ *
+ */
+ public void singleShot()
+ {
+ Log.v(TAG, "singleShot()");
+ if (camera == null)
+ {
+ Log.v(TAG, "IPanasonicCamera is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + "cam.cgi?mode=camcmd&value=capture", TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "Capture Failure... : " + reply);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ frameDisplayer.hideFocusFrame();
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+public interface IPanasonicApiService
+{
+ String getName();
+ String getActionUrl();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+import java.util.List;
+
+public interface IPanasonicCamera
+{
+ boolean hasApiService(String serviceName);
+ List<IPanasonicApiService> getApiServices();
+
+ String getFriendlyName();
+ String getModelName();
+ String getddUrl();
+ String getCmdUrl();
+ String getObjUrl();
+ String getPictureUrl();
+
+ String getClientDeviceUuId();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+public interface IPanasonicCameraHolder
+{
+ void detectedCamera(IPanasonicCamera camera);
+ void prepare();
+ void startRecMode();
+ void startEventWatch(@Nullable ICameraChangeListener listener);
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.utils.XmlElement;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ *
+ *
+ */
+public class PanasonicCameraDeviceProvider implements IPanasonicCamera
+{
+ private static final String TAG = PanasonicCameraDeviceProvider.class.getSimpleName();
+ private final List<IPanasonicApiService> apiServices;
+ private final String ddUrl;
+ private final String udn;
+ private final String friendlyName;
+ private final String modelName;
+ private final String iconUrl;
+ private final String uniqueID = UUID.randomUUID().toString();
+
+ /**
+ * コンストラクタ: staticメソッド searchPanasonicCameraDevice() で生成する
+ *
+ */
+ private PanasonicCameraDeviceProvider(String ddUrl, String friendlyName, String modelName, String udn, String iconUrl)
+ {
+ this.ddUrl = ddUrl;
+ this.friendlyName = friendlyName;
+ this.modelName = modelName;
+ this.udn = udn;
+ this.iconUrl = iconUrl;
+ Log.v(TAG, "Panasonic Device : " + this.friendlyName + "(" + this.modelName + ") " + this.ddUrl + " " + this.udn + " [" + this.iconUrl + "]");
+ Log.v(TAG, "ANDROID DEVICE : " + uniqueID);
+ apiServices = new ArrayList<>();
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public boolean hasApiService(@NonNull String serviceName)
+ {
+ try
+ {
+ for (IPanasonicApiService apiService : apiServices)
+ {
+ if (serviceName.equals(apiService.getName()))
+ {
+ return (true);
+ }
+ }
+ Log.v(TAG, "no API Service : " + serviceName + "[" + apiServices.size() + "]");
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (false);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public List<IPanasonicApiService> getApiServices()
+ {
+ return (apiServices);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getFriendlyName()
+ {
+ return (friendlyName);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getModelName()
+ {
+ return (modelName);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getddUrl()
+ {
+ return (ddUrl);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getCmdUrl()
+ {
+ // コマンド送信先を応答する
+ return (ddUrl.substring(0, ddUrl.indexOf(":", 7)) + "/");
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getObjUrl()
+ {
+ // オブジェクト取得用の送信先を応答する
+ return (ddUrl.substring(0, ddUrl.indexOf("/", 7)) + "/");
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getPictureUrl()
+ {
+ // 画像取得先を応答する
+ return (ddUrl.substring(0, ddUrl.indexOf(":", 7)) + ":50001/");
+ }
+
+ @Override
+ public String getClientDeviceUuId()
+ {
+ return (uniqueID);
+ }
+
+/*
+ private void addApiService(String name, String actionUrl)
+ {
+ Log.v(TAG, "API : " + name + " : " + actionUrl);
+ PanasonicApiService service = new PanasonicApiService(name, actionUrl);
+ apiServices.add(service);
+ }
+*/
+
+ /**
+ *
+ *
+ */
+ public static IPanasonicCamera searchPanasonicCameraDevice(@NonNull String ddUrl)
+ {
+ PanasonicCameraDeviceProvider device = null;
+ String ddXml;
+ try
+ {
+ ddXml = SimpleHttpClient.httpGet(ddUrl, -1);
+ Log.d(TAG, "fetch () httpGet done. : " + ddXml.length());
+ if (ddXml.length() < 2)
+ {
+ // 内容がないときは...終了する
+ Log.v(TAG, "NO BODY");
+ return (null);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return (null);
+ }
+ try
+ {
+ //Log.v(TAG, "ddXml : " + ddXml);
+ XmlElement rootElement = XmlElement.parse(ddXml);
+
+ // "root"
+ if ("root".equals(rootElement.getTagName()))
+ {
+ // "device"
+ XmlElement deviceElement = rootElement.findChild("device");
+ String friendlyName = deviceElement.findChild("friendlyName").getValue();
+ String modelName = deviceElement.findChild("modelName").getValue();
+ String udn = deviceElement.findChild("UDN").getValue();
+
+ // "iconList"
+ String iconUrl = "";
+ XmlElement iconListElement = deviceElement.findChild("iconList");
+ List<XmlElement> iconElements = iconListElement.findChildren("icon");
+ for (XmlElement iconElement : iconElements)
+ {
+ // Choose png icon to show Android UI.
+ if ("image/png".equals(iconElement.findChild("mimetype").getValue()))
+ {
+ String uri = iconElement.findChild("url").getValue();
+ String hostUrl = toSchemeAndHost(ddUrl);
+ iconUrl = hostUrl + uri;
+ }
+ }
+ device = new PanasonicCameraDeviceProvider(ddUrl, friendlyName, modelName, udn, iconUrl);
+/*
+ // SONY用のAPIサービス検索部分 (なので処理を止めておく)
+ // "av:X_ScalarWebAPI_DeviceInfo"
+ XmlElement wApiElement = deviceElement.findChild("X_ScalarWebAPI_DeviceInfo");
+ XmlElement wApiServiceListElement = wApiElement.findChild("X_ScalarWebAPI_ServiceList");
+ List<XmlElement> wApiServiceElements = wApiServiceListElement.findChildren("X_ScalarWebAPI_Service");
+ for (XmlElement wApiServiceElement : wApiServiceElements)
+ {
+ String serviceName = wApiServiceElement.findChild("X_ScalarWebAPI_ServiceType").getValue();
+ String actionUrl = wApiServiceElement.findChild("X_ScalarWebAPI_ActionList_URL").getValue();
+ device.addApiService(serviceName, actionUrl);
+ }
+*/
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Log.d(TAG, "fetch () parsing XML done.");
+ if (device == null)
+ {
+ Log.v(TAG, "device is null.");
+ }
+ return (device);
+ }
+
+ private static String toSchemeAndHost(String url)
+ {
+ int i = url.indexOf("://"); // http:// or https://
+ if (i == -1) {
+ return ("");
+ }
+
+ int j = url.indexOf("/", i + 3);
+ if (j == -1) {
+ return ("");
+ }
+
+ return (url.substring(0, j));
+ }
+
+ private static String toHost(String url)
+ {
+ int i = url.indexOf("://"); // http:// or https://
+ if (i == -1) {
+ return ("");
+ }
+
+ int j = url.indexOf(":", i + 3);
+ if (j == -1) {
+ return ("");
+ }
+ return (url.substring(i + 3, j));
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+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.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.IPanasonicInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.PanasonicCameraCaptureControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.PanasonicCameraFocusControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.operation.PanasonicCameraZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.connection.PanasonicCameraConnection;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener.CameraEventObserver;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener.ICameraEventObserver;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener.ICameraStatusHolder;
+
+public class PanasonicCameraWrapper implements IPanasonicCameraHolder, IPanasonicInterfaceProvider, IDisplayInjector
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private static final int TIMEOUT_MS = 3000;
+ private final ICameraStatusReceiver provider;
+ private final ICameraChangeListener listener;
+ private IPanasonicCamera panasonicCamera = null;
+ //private IPanasonicCameraApi panasonicCameraApi = null;
+ private ICameraEventObserver eventObserver = null;
+ private PanasonicLiveViewControl liveViewControl = null;
+ private PanasonicCameraFocusControl focusControl = null;
+ private PanasonicCameraCaptureControl captureControl = null;
+ private PanasonicCameraZoomLensControl zoomControl = null;
+ private PanasonicCameraConnection cameraConnection = null;
+
+ public PanasonicCameraWrapper(final Activity context, final ICameraStatusReceiver statusReceiver , final @NonNull ICameraChangeListener listener)
+ {
+ this.context = context;
+ this.provider = statusReceiver;
+ this.listener = listener;
+ }
+
+ @Override
+ public void prepare()
+ {
+ Log.v(TAG, " prepare : " + panasonicCamera.getFriendlyName() + " " + panasonicCamera.getModelName());
+ try
+ {
+ //this.panasonicCameraApi = PanasonicCameraApi.newInstance(panasonicCamera);
+ if (eventObserver == null)
+ {
+ eventObserver = CameraEventObserver.newInstance(context, panasonicCamera);
+ }
+ if (liveViewControl == null)
+ {
+ liveViewControl = new PanasonicLiveViewControl(panasonicCamera);
+ }
+ focusControl.setCamera(panasonicCamera);
+ captureControl.setCamera(panasonicCamera);
+ zoomControl.setCamera(panasonicCamera);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startRecMode()
+ {
+ try
+ {
+ // 撮影モード(RecMode)に切り替え
+ String reply = SimpleHttpClient.httpGet(this.panasonicCamera.getCmdUrl() + "cam.cgi?mode=camcmd&value=recmode", TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "CAMERA REPLIED ERROR : CHANGE RECMODE.");
+ }
+
+ // フォーカスに関しては、1点に切り替える(仮)
+ reply = SimpleHttpClient.httpGet(this.panasonicCamera.getCmdUrl() + "cam.cgi?mode=setsetting&type=afmode&value=1area", TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "CAMERA REPLIED ERROR : CHANGE AF MODE 1area.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startEventWatch(@Nullable ICameraChangeListener listener)
+ {
+ try
+ {
+ if (eventObserver != null)
+ {
+ if (listener != null)
+ {
+ eventObserver.setEventListener(listener);
+ }
+ eventObserver.activate();
+ eventObserver.start();
+ ICameraStatusHolder holder = eventObserver.getCameraStatusHolder();
+ if (holder != null)
+ {
+ holder.getLiveviewStatus();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void detectedCamera(@NonNull IPanasonicCamera camera)
+ {
+ Log.v(TAG, "detectedCamera()");
+ panasonicCamera = camera;
+ }
+
+ @Override
+ public ICameraConnection getPanasonicCameraConnection()
+ {
+ // PanasonicCameraConnectionは複数生成しない。
+ if (cameraConnection == null)
+ {
+ cameraConnection = new PanasonicCameraConnection(context, provider, this, listener);
+ }
+ return (cameraConnection);
+ }
+
+ @Override
+ public ILiveViewControl getPanasonicLiveViewControl()
+ {
+ return (liveViewControl);
+ }
+
+ @Override
+ public ILiveViewListener getLiveViewListener()
+ {
+ return (liveViewControl.getLiveViewListener());
+ }
+
+ @Override
+ public IFocusingControl getFocusingControl()
+ {
+ return (focusControl);
+ }
+
+ @Override
+ public ICameraInformation getCameraInformation()
+ {
+ return null;
+ }
+
+ @Override
+ public IZoomLensControl getZoomLensControl()
+ {
+ return (zoomControl);
+ }
+
+ @Override
+ public ICaptureControl getCaptureControl()
+ {
+ return (captureControl);
+ }
+
+ @Override
+ public IDisplayInjector getDisplayInjector()
+ {
+ return (this);
+ }
+
+ @Override
+ public IPanasonicCamera getPanasonicCamera()
+ {
+ return (panasonicCamera);
+ }
+
+ @Override
+ public void injectDisplay(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator, @NonNull IFocusingModeNotify focusingModeNotify)
+ {
+ Log.v(TAG, "injectDisplay()");
+
+ focusControl = new PanasonicCameraFocusControl(frameDisplayer, indicator);
+ captureControl = new PanasonicCameraCaptureControl(frameDisplayer, indicator);
+ zoomControl = new PanasonicCameraZoomLensControl();
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.liveview.CameraLiveViewListenerImpl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.util.Arrays;
+
+public class PanasonicLiveViewControl implements ILiveViewControl
+{
+ private final String TAG = toString();
+ private final IPanasonicCamera camera;
+ //private final BlockingQueue<byte[]> mJpegQueue = new ArrayBlockingQueue<>(2);
+ private final CameraLiveViewListenerImpl liveViewListener;
+ private DatagramSocket receiveSocket = null;
+ private boolean whileStreamReceive = false;
+ private int errorOccur = 0;
+ private static final int TIMEOUT_MAX = 3;
+ private static final int ERROR_MAX = 30;
+ private static final int RECEIVE_BUFFER_SIZE = 1024 * 1024 * 4;
+ private static final int TIMEOUT_MS = 1500;
+ private static final int LIVEVIEW_PORT = 49152;
+ private final String LIVEVIEW_START_REQUEST = "cam.cgi?mode=startstream&value=49152";
+ private final String LIVEVIEW_STOP_REQUEST = "cam.cgi?mode=stopstream";
+
+ PanasonicLiveViewControl(@NonNull IPanasonicCamera camera)
+ {
+ this.camera = camera;
+ liveViewListener = new CameraLiveViewListenerImpl();
+ }
+
+ @Override
+ public void changeLiveViewSize(String size)
+ {
+
+ }
+
+ @Override
+ public void startLiveView(final boolean isCameraScreen)
+ {
+ Log.v(TAG, "startLiveView() : " + isCameraScreen);
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ startReceiveStream();
+ if (!whileStreamReceive)
+ {
+ Log.v(TAG, "CANNOT OPEN : UDP RECEIVE SOCKET");
+ return;
+ }
+ String requestUrl = camera.getCmdUrl() + LIVEVIEW_START_REQUEST;
+ String reply = SimpleHttpClient.httpGet(requestUrl, TIMEOUT_MS);
+ if (!reply.contains("<result>ok</result>"))
+ {
+ try
+ {
+ // エラー回数のカウントアップ
+ errorOccur++;
+
+ // 少し待つ...
+ Thread.sleep(TIMEOUT_MS);
+
+ if (errorOccur < ERROR_MAX)
+ {
+ Log.v(TAG, "RETRY START LIVEVIEW... : " + errorOccur);
+ startLiveView(isCameraScreen);
+ }
+ else
+ {
+ Log.v(TAG, "RETRY OVER : START LIVEVIEW");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ else
+ {
+ Log.v(TAG, " ----- START LIVEVIEW ----- : " + requestUrl);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stopLiveView()
+ {
+ Log.v(TAG, "stopLiveView()");
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + LIVEVIEW_STOP_REQUEST, TIMEOUT_MS);
+ if (!reply.contains("<result>ok</result>"))
+ {
+ Log.v(TAG, "stopLiveview() reply is fail... " + reply);
+ }
+ else
+ {
+ Log.v(TAG, "stopLiveview() is issued.");
+ }
+ // ライブビューウォッチャーを止める
+ whileStreamReceive = false;
+ closeReceiveSocket();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void updateDigitalZoom()
+ {
+
+ }
+
+ @Override
+ public void updateMagnifyingLiveViewScale(boolean isChangeScale)
+ {
+
+ }
+
+ @Override
+ public float getMagnifyingLiveViewScale()
+ {
+ return (1.0f);
+ }
+
+ @Override
+ public float getDigitalZoomScale()
+ {
+ return (1.0f);
+ }
+
+ private void startReceiveStream()
+ {
+ if (whileStreamReceive)
+ {
+ Log.v(TAG, "startReceiveStream() : already starting.");
+ return;
+ }
+
+ // ソケットをあける (UDP)
+ try
+ {
+ receiveSocket = new DatagramSocket(LIVEVIEW_PORT);
+ whileStreamReceive = true;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ whileStreamReceive = false;
+ receiveSocket = null;
+ }
+
+ // 受信スレッドを動かす
+ Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ receiverThread();
+ }
+ });
+ try
+ {
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkReceiveImage(@NonNull DatagramPacket packet)
+ {
+ int dataLength = packet.getLength();
+ int searchIndex = 0;
+ int startPosition = 0;
+ int[] startmarker = { 0xff, 0xd8 };
+ byte[] receivedData = packet.getData();
+ if (receivedData == null)
+ {
+ // 受信データが取れなかったので終了する
+ Log.v(TAG, "RECEIVED DATA IS NULL...");
+ return;
+ }
+ //Log.v(TAG, "RECEIVED PACKET : " + dataLength);
+ while (startPosition < dataLength)
+ {
+ // 先頭のjpegマーカーが出てくるまで読み飛ばす
+ try
+ {
+ if (receivedData[startPosition++] == (byte) startmarker[searchIndex])
+ {
+ searchIndex++;
+ if (searchIndex >= startmarker.length)
+ {
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return;
+ }
+ }
+ int offset = startPosition - startmarker.length;
+ //liveViewListener.onUpdateLiveView(Arrays.copyOfRange(receivedData, offset, dataLength - offset), null);
+ liveViewListener.onUpdateLiveView(Arrays.copyOfRange(receivedData, offset, dataLength), null);
+ }
+
+ private void receiverThread()
+ {
+ int exceptionCount = 0;
+ byte[] buffer = new byte[RECEIVE_BUFFER_SIZE];
+ while (whileStreamReceive)
+ {
+ try
+ {
+ DatagramPacket receive_packet = new DatagramPacket(buffer, buffer.length);
+ if (receiveSocket != null)
+ {
+ receiveSocket.setSoTimeout(TIMEOUT_MS);
+ receiveSocket.receive(receive_packet);
+ checkReceiveImage(receive_packet);
+ exceptionCount = 0;
+ }
+ else
+ {
+ Log.v(TAG, "receiveSocket is NULL...");
+ }
+ }
+ catch (Exception e)
+ {
+ exceptionCount++;
+ e.printStackTrace();
+ if (exceptionCount > TIMEOUT_MAX)
+ {
+ try
+ {
+ Log.v(TAG, "LV : RETRY REQUEST");
+
+ exceptionCount = 0;
+ String reply = SimpleHttpClient.httpGet(camera.getCmdUrl() + LIVEVIEW_START_REQUEST, TIMEOUT_MS);
+ if (!reply.contains("ok"))
+ {
+ Log.v(TAG, "LV : RETRY COMMAND FAIL...");
+ }
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ }
+ }
+ closeReceiveSocket();
+ Log.v(TAG, " ----- startReceiveStream() : Finished.");
+ System.gc();
+ }
+
+ public ILiveViewListener getLiveViewListener()
+ {
+ return (liveViewListener);
+ }
+
+ private void closeReceiveSocket()
+ {
+ Log.v(TAG, "closeReceiveSocket()");
+ try
+ {
+ if (receiveSocket != null)
+ {
+ Log.v(TAG, " ----- SOCKET CLOSE ----- ");
+ receiveSocket.close();
+ receiveSocket = null;
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.connection;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCameraHolder;
+
+/**
+ * Panasonicカメラとの接続処理
+ *
+ */
+public class PanasonicCameraConnectSequence implements Runnable, PanasonicSsdpClient.ISearchResultCallback
+{
+ private final String TAG = this.toString();
+ private final Activity context;
+ private final ICameraConnection cameraConnection;
+ private final IPanasonicCameraHolder cameraHolder;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final ICameraChangeListener listener;
+ private final PanasonicSsdpClient client;
+
+ PanasonicCameraConnectSequence(Activity context, ICameraStatusReceiver statusReceiver, final ICameraConnection cameraConnection, final @NonNull IPanasonicCameraHolder cameraHolder, final @NonNull ICameraChangeListener listener)
+ {
+ Log.v(TAG, "PanasonicCameraConnectSequence");
+ this.context = context;
+ this.cameraConnection = cameraConnection;
+ this.cameraStatusReceiver = statusReceiver;
+ this.cameraHolder = cameraHolder;
+ this.listener = listener;
+ client = new PanasonicSsdpClient(context, this, statusReceiver, 1);
+ }
+
+ @Override
+ public void run()
+ {
+ Log.v(TAG, "search()");
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start));
+ client.search();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onDeviceFound(IPanasonicCamera cameraDevice)
+ {
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_detected) + " " + cameraDevice.getFriendlyName());
+ cameraHolder.detectedCamera(cameraDevice);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onFinished()
+ {
+ Log.v(TAG, "PanasonicCameraConnectSequence.onFinished()");
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ cameraHolder.prepare();
+ cameraHolder.startRecMode();
+ cameraHolder.startEventWatch(listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Log.v(TAG, "CameraConnectSequence:: connected.");
+ onConnectNotify();
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ 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();
+ }
+ }
+ }
+*/
+
+ @Override
+ public void onErrorFinished(String reason)
+ {
+ cameraConnection.alertConnectingFailed(reason);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.connection;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCameraHolder;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ *
+ *
+ */
+public class PanasonicCameraConnection implements ICameraConnection
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private final ICameraStatusReceiver statusReceiver;
+ private final BroadcastReceiver connectionReceiver;
+ private final IPanasonicCameraHolder cameraHolder;
+ //private final ConnectivityManager connectivityManager;
+ private final Executor cameraExecutor = Executors.newFixedThreadPool(1);
+ private final ICameraChangeListener listener;
+ //private final Handler networkConnectionTimeoutHandler;
+ //private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
+ private ICameraConnection.CameraConnectionStatus connectionStatus = CameraConnectionStatus.UNKNOWN;
+
+ public PanasonicCameraConnection(final Activity context, final ICameraStatusReceiver statusReceiver, @NonNull IPanasonicCameraHolder cameraHolder, final @NonNull ICameraChangeListener listener)
+ {
+ Log.v(TAG, "PanasonicCameraConnection()");
+ this.context = context;
+ this.statusReceiver = statusReceiver;
+ this.cameraHolder = cameraHolder;
+ this.listener = listener;
+/*
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ networkConnectionTimeoutHandler = new Handler()
+ {
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch (msg.what)
+ {
+ case MESSAGE_CONNECTIVITY_TIMEOUT:
+ Log.d(TAG, "Network connection timeout");
+ alertConnectingFailed(context.getString(R.string.network_connection_timeout));
+ connectionStatus = CameraConnectionStatus.DISCONNECTED;
+ break;
+ }
+ }
+ };
+*/
+ 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();
+ }
+ }
+
+
+ /**
+ * Wifi接続状態の監視
+ * (接続の実処理は onReceiveBroadcastOfConnection() で実施)
+ */
+ @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);
+ }
+
+ /**
+ * Wifi接続状態の監視終了
+ */
+ @Override
+ public void stopWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "stopWatchWifiStatus()");
+ context.unregisterReceiver(connectionReceiver);
+ disconnect(false);
+ }
+
+ /**
+ * カメラとの接続を解除する
+ *
+ * @param powerOff 真ならカメラの電源オフを伴う
+ */
+ @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();
+ }
+
+ /**
+ * 接続リトライのダイアログを出す
+ *
+ * @param message 表示用のメッセージ
+ */
+ @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))
+ .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()
+ {
+ builder.show();
+ }
+ });
+ }
+
+ @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 PanasonicCameraDisconnectSequence(powerOff));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラとの接続処理
+ */
+ private void connectToCamera()
+ {
+ Log.v(TAG, "connectToCamera()");
+ connectionStatus = CameraConnectionStatus.CONNECTING;
+ try
+ {
+ cameraExecutor.execute(new PanasonicCameraConnectSequence(context,statusReceiver, this, cameraHolder, listener));
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, "connectToCamera() EXCEPTION : " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.connection;
+
+
+public class PanasonicCameraDisconnectSequence implements Runnable
+{
+ //private final String TAG = this.toString();
+ //private final boolean powerOff;
+
+ PanasonicCameraDisconnectSequence(boolean isOff)
+ {
+ //this.powerOff = isOff;
+ }
+
+ @Override
+ public void run()
+ {
+ // カメラをPowerOffして接続を切る
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.connection;
+
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.PanasonicCameraDeviceProvider;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Panasonic SSDP Client : SonyのCameraRemoteSampleApp にある SimpleSsdpClient を参考にインプリメントした
+ * (API Level 14を minSdkVersion に設定したので... NsdManager.DiscoveryListener を使わなかった)
+ *
+ * SSDP : Simple Service Discovery Protocol
+ *
+ */
+class PanasonicSsdpClient
+{
+ private final String TAG = toString();
+ private static final int SEND_TIMES_DEFAULT = 3;
+ private static final int SEND_WAIT_DURATION_MS = 100;
+ private static final int SSDP_RECEIVE_TIMEOUT = 4 * 1000; // msec
+ private static final int PACKET_BUFFER_SIZE = 2048;
+ private static final int SSDP_PORT = 1900;
+ private static final int SSDP_MX = 2;
+ private static final String SSDP_ADDR = "239.255.255.250";
+ private static final String SSDP_ST = "urn:schemas-upnp-org:device:MediaServer:1";
+ private final Context context;
+ private final ISearchResultCallback callback;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final String ssdpRequest;
+ private final int sendRepeatCount;
+
+ PanasonicSsdpClient(@NonNull Context context, @NonNull ISearchResultCallback callback, @NonNull ICameraStatusReceiver statusReceiver, int sendRepeatCount)
+ {
+ this.context = context;
+ this.callback = callback;
+ this.cameraStatusReceiver = statusReceiver;
+ this.sendRepeatCount = (sendRepeatCount >= 0) ? sendRepeatCount : SEND_TIMES_DEFAULT;
+ ssdpRequest = "M-SEARCH * HTTP/1.1\r\n"
+ + String.format(Locale.US, "HOST: %s:%d\r\n", SSDP_ADDR, SSDP_PORT)
+ + "MAN: \"ssdp:discover\"\r\n"
+ + String.format(Locale.US, "MX: %d\r\n", SSDP_MX)
+ + String.format("ST: %s\r\n", SSDP_ST) + "\r\n";
+ }
+
+ void search()
+ {
+ final byte[] sendData = ssdpRequest.getBytes();
+ String detailString = "";
+ DatagramSocket socket = null;
+ DatagramPacket receivePacket;
+ DatagramPacket packet;
+
+ // 要求の送信
+ try
+ {
+ socket = new DatagramSocket();
+ socket.setReuseAddress(true);
+ InetSocketAddress iAddress = new InetSocketAddress(SSDP_ADDR, SSDP_PORT);
+ packet = new DatagramPacket(sendData, sendData.length, iAddress);
+
+ // 要求を繰り返し送信する
+ for (int loop = 1; loop <= sendRepeatCount; loop++)
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_search_request) + " " + loop);
+ socket.send(packet);
+ Thread.sleep(SEND_WAIT_DURATION_MS);
+ }
+ }
+ catch (Exception e)
+ {
+ if ((socket != null) && (!socket.isClosed()))
+ {
+ socket.close();
+ }
+ e.printStackTrace();
+
+ // エラー応答する
+ callback.onErrorFinished(detailString + " : " + e.getLocalizedMessage());
+ return;
+ }
+
+ // 応答の受信
+ long startTime = System.currentTimeMillis();
+ long currentTime = System.currentTimeMillis();
+ List<String> foundDevices = new ArrayList<>();
+ byte[] array = new byte[PACKET_BUFFER_SIZE];
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_wait_reply));
+ while (currentTime - startTime < SSDP_RECEIVE_TIMEOUT)
+ {
+ receivePacket = new DatagramPacket(array, array.length);
+ socket.setSoTimeout(SSDP_RECEIVE_TIMEOUT);
+ socket.receive(receivePacket);
+ String ssdpReplyMessage = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
+ String ddUsn;
+ if (ssdpReplyMessage.contains("HTTP/1.1 200"))
+ {
+ ddUsn = findParameterValue(ssdpReplyMessage, "USN");
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_received_reply));
+ if (!foundDevices.contains(ddUsn))
+ {
+ String ddLocation = findParameterValue(ssdpReplyMessage, "LOCATION");
+ foundDevices.add(ddUsn);
+
+ //// Fetch Device Description XML and parse it.
+ if (ddLocation != null)
+ {
+ cameraStatusReceiver.onStatusNotify("LOCATION : " + ddLocation);
+ IPanasonicCamera device = PanasonicCameraDeviceProvider.searchPanasonicCameraDevice(ddLocation);
+ //if ((device != null) && (device.hasApiService("camera")))
+ if (device != null)
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_found) + " " + device.getFriendlyName());
+
+ ///// カメラへの登録要求... /////
+ String registUrl = device.getCmdUrl() + "cam.cgi?mode=accctrl&type=req_acc&value=" + device.getClientDeviceUuId() + "&value2=GOKIGEN_a01Series";
+ String reply = SimpleHttpClient.httpGet(registUrl, SSDP_RECEIVE_TIMEOUT);
+ if (reply.contains("ok"))
+ {
+ callback.onDeviceFound(device);
+ // カメラと接続できた場合は breakする
+ break;
+ }
+ // 接続(デバイス登録)エラー...
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_rejected));
+ }
+ else
+ {
+ // カメラが見つからない...
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_not_found));
+ }
+ }
+ }
+ else
+ {
+ Log.v(TAG, "Already received. : " + ddUsn);
+ }
+ }
+ currentTime = System.currentTimeMillis();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+
+ // エラー応答する
+ callback.onErrorFinished(detailString + " : " + e.getLocalizedMessage());
+ return;
+ }
+ finally
+ {
+ try
+ {
+ if (!socket.isClosed())
+ {
+ socket.close();
+ }
+ } catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ callback.onFinished();
+ }
+
+ private static String findParameterValue(@NonNull String ssdpMessage, @NonNull String paramName)
+ {
+ String name = paramName;
+ if (!name.endsWith(":"))
+ {
+ name = name + ":";
+ }
+ int start = ssdpMessage.indexOf(name);
+ int end = ssdpMessage.indexOf("\r\n", start);
+ if ((start != -1)&&(end != -1))
+ {
+ start += name.length();
+ try
+ {
+ return ((ssdpMessage.substring(start, end)).trim());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ return (null);
+ }
+
+ /**
+ * 検索結果のコールバック
+ *
+ */
+ public interface ISearchResultCallback
+ {
+ void onDeviceFound(IPanasonicCamera cameraDevice); // デバイスが見つかった!
+ void onFinished(); // 通常の終了をしたとき
+ void onErrorFinished(String reason); // エラーが発生して応答したとき
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ *
+ *
+ */
+public class CameraEventObserver implements ICameraEventObserver
+{
+ private static final String TAG = CameraEventObserver.class.getSimpleName();
+ private boolean isEventMonitoring;
+ private boolean isActive;
+
+ private final IPanasonicCamera remote;
+ // private final ReplyJsonParser replyParser;
+ private String eventVersion = "1.1"; // 初期値を "1.0" から "1.1" に更新
+
+ public static ICameraEventObserver newInstance(@NonNull Context context, @NonNull IPanasonicCamera apiClient)
+ {
+ return (new CameraEventObserver(context, apiClient));
+ }
+
+ private CameraEventObserver(@NonNull Context context, @NonNull IPanasonicCamera apiClient)
+ {
+ super();
+ remote = apiClient;
+ //replyParser = new ReplyJsonParser(new Handler(context.getMainLooper()));
+ isEventMonitoring = false;
+ isActive = false;
+ }
+
+ @Override
+ public boolean start()
+ {
+ if (!isActive)
+ {
+ Log.w(TAG, "start() observer is not active.");
+ return (false);
+ }
+
+ if (isEventMonitoring)
+ {
+ Log.w(TAG, "start() already starting.");
+ return (false);
+ }
+
+ isEventMonitoring = false;
+ try
+ {
+ Thread thread = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ Log.d(TAG, "start() exec.");
+ boolean firstCall = true;
+ MONITORLOOP: while (isEventMonitoring)
+ {
+ // At first, call as non-Long Polling.
+ boolean longPolling = !firstCall;
+ try
+ {
+/*
+ // Call getEvent API.
+ JSONObject replyJson = remoteApi.getEvent(eventVersion, longPolling);
+
+ // Check error code at first.
+ int errorCode = findErrorCode(replyJson);
+ Log.d(TAG, "getEvent errorCode: " + errorCode);
+ switch (errorCode) {
+ case 0: // no error
+ // Pass through.
+ break;
+ case 1: // "Any" error
+ case 12: // "No such method" error
+ if (eventVersion.equals("1.1"))
+ {
+ // "1.1" でエラーが発生した時には "1.0" にダウングレードして再実行
+ eventVersion = "1.0";
+ continue MONITORLOOP;
+ }
+ replyParser.fireResponseErrorListener();
+ break MONITORLOOP; // end monitoring.
+
+ case 2: // "Timeout" error
+ // Re-call immediately.
+ continue MONITORLOOP;
+
+ case 40402: // "Already polling" error
+ // Retry after 5 sec.
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ // do nothing.
+ }
+ continue MONITORLOOP;
+
+ default:
+ Log.w(TAG, "SimpleCameraEventObserver: Unexpected error: " + errorCode);
+ replyParser.fireResponseErrorListener();
+ break MONITORLOOP; // end monitoring.
+ }
+
+ // parse
+ replyParser.parse(replyJson);
+*/
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ firstCall = false;
+ } // MONITORLOOP end.
+ isEventMonitoring = false;
+ }
+ };
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (true);
+ }
+
+ @Override
+ public void stop()
+ {
+ isEventMonitoring = false;
+ }
+
+ @Override
+ public void release()
+ {
+ isEventMonitoring = false;
+ isActive = false;
+ }
+
+ @Override
+ public void setEventListener(@NonNull ICameraChangeListener listener)
+ {
+ try
+ {
+ //replyParser.setEventChangeListener(listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearEventListener()
+ {
+ try
+ {
+ //replyParser.clearEventChangeListener();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public ICameraStatusHolder getCameraStatusHolder()
+ {
+ return (null);
+ //return (replyParser);
+ }
+
+ @Override
+ public void activate()
+ {
+ isActive = true;
+ }
+
+ private static int findErrorCode(JSONObject replyJson)
+ {
+ int code = 0; // 0 means no error.
+ try
+ {
+ if (replyJson.has("error"))
+ {
+ JSONArray errorObj = replyJson.getJSONArray("error");
+ code = errorObj.getInt(0);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ code = -1;
+ }
+ return (code);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener;
+
+import java.util.List;
+
+public class CameraStatusHolder implements ICameraStatusHolder
+{
+ @Override
+ public String getCameraStatus()
+ {
+ return (null);
+ }
+
+ @Override
+ public boolean getLiveviewStatus()
+ {
+ return (false);
+ }
+
+ @Override
+ public String getShootMode()
+ {
+ return (null);
+ }
+
+ @Override
+ public List<String> getAvailableShootModes()
+ {
+ return (null);
+ }
+
+ @Override
+ public int getZoomPosition()
+ {
+ return (0);
+ }
+
+ @Override
+ public String getStorageId()
+ {
+ return (null);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+public interface ICameraEventObserver
+{
+ void activate();
+ boolean start();
+ void stop();
+ void release();
+
+ void setEventListener(@NonNull ICameraChangeListener listener);
+ void clearEventListener();
+
+ ICameraStatusHolder getCameraStatusHolder();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.eventlistener;
+
+import java.util.List;
+
+public interface ICameraStatusHolder
+{
+ String getCameraStatus();
+ boolean getLiveviewStatus();
+ String getShootMode();
+ List<String> getAvailableShootModes();
+ int getZoomPosition();
+ String getStorageId();
+
+}
{
afControl.unlockAutoFocus();
}
+
+ @Override
+ public void halfPressShutter(boolean isPressed)
+ {
+
+ }
}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+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.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+import java.util.List;
+
+public interface ISonyInterfaceProvider
+{
+ ICameraConnection getSonyCameraConnection();
+ ILiveViewControl getSonyLiveViewControl();
+ ILiveViewListener getLiveViewListener();
+ IFocusingControl getFocusingControl();
+ ICameraInformation getCameraInformation();
+ IZoomLensControl getZoomLensControl();
+ ICaptureControl getCaptureControl();
+ IDisplayInjector getDisplayInjector();
+ List<String> getApiCommands();
+ ISonyCameraApi getCameraApi();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.cameraproperty;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+/**
+ *
+ *
+ */
+public class SendRequestDialog extends DialogFragment
+{
+ private final String TAG = toString();
+ private ISonyCameraApi cameraApi;
+ private String method = "";
+ private int selectedPosition = 0;
+ private SendRequestDialog.Callback callback = null;
+ Dialog myDialog = null;
+
+ /**
+ *
+ *
+ */
+ public static SendRequestDialog newInstance(@NonNull ISonyCameraApi cameraApi, @NonNull String method, @Nullable SendRequestDialog.Callback callback)
+ {
+ SendRequestDialog instance = new SendRequestDialog();
+ instance.prepare(cameraApi, method, callback);
+
+ // パラメータはBundleにまとめておく
+ Bundle arguments = new Bundle();
+ arguments.putString("method", method);
+ //arguments.putString("message", message);
+ instance.setArguments(arguments);
+
+ return (instance);
+ }
+
+ /**
+ *
+ *
+ */
+ private void prepare(@NonNull ISonyCameraApi cameraApi,@NonNull String method, @Nullable SendRequestDialog.Callback callback)
+ {
+ this.cameraApi = cameraApi;
+ this.method = method;
+ this.callback = callback;
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public @NonNull Dialog onCreateDialog(Bundle savedInstanceState)
+ {
+ final Activity activity = getActivity();
+
+ // 確認ダイアログの生成
+ //final AlertDialog.Builder alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.wear2_dialog_theme));
+ final AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
+
+ // Get the layout inflater
+ LayoutInflater inflater = activity.getLayoutInflater();
+ final View alertView = inflater.inflate(R.layout.request_edit_layout, null, false);
+ alertDialog.setView(alertView);
+
+ alertDialog.setIcon(R.drawable.ic_linked_camera_black_24dp);
+ alertDialog.setTitle("API : " + method);
+ final Spinner spinner = alertView.findViewById(R.id.spinner_selection_service);
+ final TextView methodName = alertView.findViewById(R.id.method_name);
+ final EditText parameter = alertView.findViewById(R.id.edit_parameter);
+ final EditText version = alertView.findViewById(R.id.edit_version);
+ try {
+ methodName.setText("");
+ version.setText(activity.getString(R.string.dialog_version_hint));
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(activity, android.R.layout.simple_spinner_item);
+ adapter.addAll(cameraApi.getSonyApiServiceList());
+
+ int defaultSelection;
+ for (defaultSelection = (adapter.getCount() - 1); defaultSelection >= 0; defaultSelection--)
+ {
+ String item = adapter.getItem(defaultSelection);
+ if ((item != null) && (item.equals("camera")))
+ {
+ break;
+ }
+ }
+ if ((defaultSelection < 0) || (defaultSelection >= adapter.getCount()))
+ {
+ defaultSelection = 0;
+ }
+ spinner.setAdapter(adapter);
+ spinner.setSelection(defaultSelection);
+ spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
+ {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
+ {
+ Log.v(TAG, "onItemSelected : " + position + " (" + id + ")");
+ selectedPosition = position;
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent)
+ {
+ Log.v(TAG, "onNothingSelected");
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ alertDialog.setCancelable(true);
+
+ // ボタンを設定する(実行ボタン)
+ alertDialog.setPositiveButton(activity.getString(R.string.dialog_positive_execute),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which)
+ {
+ try
+ {
+ Activity activity = getActivity();
+ if (activity != null)
+ {
+ if (callback != null)
+ {
+ callback.sendRequest((String) spinner.getAdapter().getItem(selectedPosition), method, parameter.getText().toString(), version.getText().toString());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ if (callback != null)
+ {
+ callback.cancelled();
+ }
+ }
+ dialog.dismiss();
+ }
+ });
+
+ // ボタンを設定する (キャンセルボタン)
+ alertDialog.setNegativeButton(activity.getString(R.string.dialog_negative_cancel),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (callback != null)
+ {
+ callback.cancelled();
+ }
+ dialog.cancel();
+ }
+ });
+
+ // 確認ダイアログを応答する
+ myDialog = alertDialog.create();
+ return (myDialog);
+ }
+
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ Log.v(TAG, "AlertDialog::onPause()");
+ if (myDialog != null)
+ {
+ myDialog.cancel();
+ }
+ }
+
+ /**
+ * コールバックインタフェース
+ *
+ */
+ public interface Callback
+ {
+ void sendRequest(String service, String apiName, String parameter, String version); // OKを選択したとき
+ void cancelled(); // キャンセルしたとき
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.cameraproperty;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.ListFragment;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.IInterfaceProvider;
+import net.osdn.gokigen.pkremote.scene.ConfirmationDialog;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SonyCameraApiListFragment extends ListFragment implements SendRequestDialog.Callback
+{
+ private final String TAG = toString();
+ private ArrayAdapter<String> adapter;
+ private List<String> dataItems = new ArrayList<>();
+ private IInterfaceProvider interfaceProvider = null;
+
+
+ /**
+ * カメラプロパティをやり取りするインタフェースを生成する
+ *
+ */
+ public static SonyCameraApiListFragment newInstance(@NonNull IInterfaceProvider interfaceProvider)
+ {
+ SonyCameraApiListFragment instance = new SonyCameraApiListFragment();
+ instance.prepare(interfaceProvider);
+
+ // パラメータはBundleにまとめておく
+ Bundle arguments = new Bundle();
+ //arguments.putString("title", title);
+ //arguments.putString("message", message);
+ instance.setArguments(arguments);
+
+ return (instance);
+ }
+
+ /**
+ *
+ *
+ */
+ private void prepare(@NonNull IInterfaceProvider interfaceProvider)
+ {
+ Log.v(TAG, "prepare()");
+ this.interfaceProvider = interfaceProvider;
+ }
+
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
+ {
+ inflater.inflate(R.menu.api_view, menu);
+ String title = getString(R.string.app_name) + " " + getString(R.string.pref_sony_api_list);
+ try {
+ AppCompatActivity activity = (AppCompatActivity) getActivity();
+ if (activity != null)
+ {
+ ActionBar bar = activity.getSupportActionBar();
+ if (bar != null)
+ {
+ bar.setTitle(title);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ if (item.getItemId() == R.id.action_refresh)
+ {
+ update();
+ return (true);
+ }
+ if (item.getItemId() == R.id.action_share)
+ {
+ share();
+ return (true);
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * API一覧の他アプリへ共有
+ *
+ */
+ private void share()
+ {
+ if ((dataItems != null)&&(dataItems.size() > 0))
+ {
+ try
+ {
+ StringBuilder shareData = new StringBuilder();
+ for (String item : dataItems)
+ {
+ shareData.append(item);
+ shareData.append("\r\n");
+ }
+ String title = "; " + getString(R.string.pref_sony_api_list);
+ Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_SUBJECT, title);
+ sendIntent.setType("text/plain");
+ sendIntent.putExtra(Intent.EXTRA_TEXT, new String(shareData));
+ FragmentActivity activity = getActivity();
+ if (activity != null)
+ {
+ // Intent発行(ACTION_SEND)
+ startActivity(sendIntent);
+ Log.v(TAG, "<<< SEND INTENT >>> : " + title);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * 表示データの更新
+ *
+ */
+ private void update()
+ {
+ try
+ {
+ if (dataItems != null)
+ {
+ dataItems.clear();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ Log.v(TAG, "START GET API LIST");
+ dataItems = interfaceProvider.getSonyInterface().getApiCommands();
+ Log.v(TAG, "FINISH GET API LIST");
+ try
+ {
+ final FragmentActivity activity = getActivity();
+ if (activity != null)
+ {
+ activity.runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ // 中身があったらクリアする
+ if (adapter.getCount() > 0)
+ {
+ adapter.clear();
+ }
+
+ // リストの内容を更新する
+ adapter.addAll(dataItems);
+
+ // 最下部にカーソルを移したい
+ ListView view = activity.findViewById(android.R.id.list);
+ view.setSelection(dataItems.size());
+
+ // 更新終了通知
+ Toast.makeText(getActivity(), getString(R.string.finish_refresh), Toast.LENGTH_SHORT).show();
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ try
+ {
+ // 本当は、ここでダイアログを出したい
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ Log.v(TAG, "onResume()");
+
+ update();
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ Log.v(TAG, "onPause()");
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ Log.v(TAG, "SonyCameraApiListFragment::onCreate()");
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState)
+ {
+ super.onActivityCreated(savedInstanceState);
+ Log.v(TAG, "SonyCameraApiListFragment::onActivityCreated()");
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ adapter = new ArrayAdapter<>(inflater.getContext(), android.R.layout.simple_list_item_1, dataItems);
+ setListAdapter(adapter);
+ return (super.onCreateView(inflater, container, savedInstanceState));
+ }
+
+ @Override
+ public void onListItemClick (ListView l, View v, int position, long id)
+ {
+ try
+ {
+ ListAdapter listAdapter = l.getAdapter();
+ final String apiName = (String) listAdapter.getItem(position);
+ final SendRequestDialog.Callback apiCallback = this;
+ Log.v(TAG, "onListItemClick() [" + position + "] " + apiName);
+ Activity activity = getActivity();
+ if (activity != null)
+ {
+ activity.runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ SendRequestDialog dialog = SendRequestDialog.newInstance(interfaceProvider.getSonyInterface().getCameraApi(), apiName, apiCallback);
+ FragmentManager manager = getFragmentManager();
+ String tag = "dialog";
+ if (manager != null)
+ {
+ dialog.show(manager, tag);
+ }
+ }
+ });
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * API のコマンドを発行する。
+ *
+ * ※ 注意: 引数パラメータはカンマ区切りで複数個を入力してもらう
+ * key & Value 値 keyとvalueのあいだを : で区切る (key:value みたいな感じ)
+ * $T Boolean値の True
+ * $F Boolean値の False
+ * #xx 数値(integer)
+ * #xx.xx 数値(double)
+ */
+ @Override
+ public void sendRequest(final String service, final String apiName, final String parameter, final String version)
+ {
+ String logValue = "sendRequest(" + service + ", " + apiName + ", [ " + parameter + "], " + version + ");";
+ Log.v(TAG, logValue);
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ // parameterを parseして、メッセージを送信する
+ JSONArray params = parseParams(parameter);
+ receivedReply(interfaceProvider.getSonyInterface().getCameraApi().callGenericSonyApiMethod(service, apiName, params, version));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private JSONArray parseParams(final String parameter)
+ {
+ JSONArray params = new JSONArray();
+ final String[] parameterItems = parameter.split(",");
+ if (parameter.length() != 0)
+ {
+ for (int index = 0; index < parameterItems.length; index++)
+ {
+ String oneItem = parameterItems[index];
+ if (oneItem.contains(":"))
+ {
+ // key & value と判断
+ try
+ {
+ String[] keyValue = oneItem.split(":");
+ try
+ {
+ String key = keyValue[0];
+ String value = keyValue[1];
+ if (value.contains("$T"))
+ {
+ params.put(new JSONObject().put(key, true));
+ }
+ else if (value.contains("$F"))
+ {
+ params.put(new JSONObject().put(key, false));
+ }
+ else if (value.contains("#"))
+ {
+ if (value.contains("."))
+ {
+ double doubleValue = Double.parseDouble(value.substring(1));
+ params.put(new JSONObject().put(key, doubleValue));
+ }
+ else
+ {
+ int intValue = Integer.parseInt(value.substring(1));
+ params.put(new JSONObject().put(key, intValue));
+ }
+ }
+ else
+ {
+ params.put(new JSONObject().put(keyValue[0], keyValue[1]));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ params.put(oneItem);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ params.put(oneItem);
+ }
+ } else {
+ try
+ {
+ if (oneItem.contains("$T"))
+ {
+ params.put(true);
+ }
+ else if (oneItem.contains("$F"))
+ {
+ params.put(false);
+ }
+ else if (oneItem.contains("#"))
+ {
+ if (oneItem.contains("."))
+ {
+ double doubleValue = Double.parseDouble(oneItem.substring(1));
+ params.put(doubleValue);
+ } else {
+ int intValue = Integer.parseInt(oneItem.substring(1));
+ params.put(intValue);
+ }
+ }
+ else
+ {
+ params.put(oneItem);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ params.put(oneItem);
+ }
+ }
+ }
+ }
+ return (params);
+ }
+
+ @Override
+ public void cancelled()
+ {
+ Log.v(TAG, "cancelled()");
+ }
+
+
+ private void receivedReply(final JSONObject reply)
+ {
+ try
+ {
+ final Activity activity = getActivity();
+ if (activity != null)
+ {
+ activity.runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ ConfirmationDialog dialog = ConfirmationDialog.newInstance(getActivity());
+ String replyString;
+ try
+ {
+ replyString = reply.getString("result");
+ }
+ catch (Exception ee)
+ {
+ replyString = reply.getString("results");
+ }
+ dialog.show(android.R.drawable.ic_dialog_info, getString(R.string.dialog_title_reply), replyString);
+ }
+ catch (Exception e)
+ {
+ ConfirmationDialog dialog = ConfirmationDialog.newInstance(getActivity());
+ String replyString = "";
+ try
+ {
+ replyString = reply.toString(4);
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ dialog.show(android.R.drawable.ic_dialog_alert, getString(R.string.dialog_title_reply), "RECEIVE ERROR \r\n" + replyString);
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.cameraproperty;
+
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import net.osdn.gokigen.pkremote.scene.IChangeScene;
+
+/**
+ *
+ *
+ */
+public class SonyCameraApiListViewer implements Preference.OnPreferenceClickListener
+{
+ private final String TAG = toString();
+ private final IChangeScene changeScene;
+
+ /**
+ *
+ *
+ */ public SonyCameraApiListViewer(IChangeScene changeScene)
+ {
+ this.changeScene = changeScene;
+ }
+
+ /**
+ *
+ *
+ */ public void prepare()
+ {
+ Log.v(TAG, "prepare() ");
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public boolean onPreferenceClick(Preference preference)
+ {
+ if (!preference.hasKey())
+ {
+ return (false);
+ }
+
+ String preferenceKey = preference.getKey();
+ if ((preferenceKey.contains("sony_api_list"))&&(changeScene != null))
+ {
+ try
+ {
+ // API Listを表示する
+ changeScene.changeSceneToApiList();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (true);
+ }
+ return (false);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.operation;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+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;
+
+/**
+ * Preferenceがクリックされた時に処理するクラス
+ *
+ */
+public class CameraPowerOffSony implements Preference.OnPreferenceClickListener, ConfirmationDialog.Callback
+{
+
+ private final Context context;
+ private final IChangeScene changeScene;
+ private String preferenceKey = null;
+
+ /**
+ * コンストラクタ
+ *
+ */
+ public CameraPowerOffSony(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_exit_application, 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.sony.operation;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICaptureControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.operation.takepicture.SingleShotControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+public class SonyCameraCaptureControl implements ICaptureControl
+{
+ private static final String TAG = SonyCameraCaptureControl.class.getSimpleName();
+ private final SingleShotControl singleShotControl;
+
+ public SonyCameraCaptureControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+ {
+ singleShotControl = new SingleShotControl(frameDisplayer, indicator);
+ }
+
+ public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi)
+ {
+ singleShotControl.setCameraApi(sonyCameraApi);
+ }
+
+ /**
+ * 撮影する
+ *
+ */
+ @Override
+ public void doCapture(int kind)
+ {
+ Log.v(TAG, "doCapture() : " + kind);
+ try
+ {
+ singleShotControl.singleShot();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.operation;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IFocusingControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.operation.takepicture.SonyAutoFocusControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+public class SonyCameraFocusControl implements IFocusingControl
+{
+ private final String TAG = toString();
+ private final SonyAutoFocusControl afControl;
+ private final IAutoFocusFrameDisplay frameDisplay;
+
+ public SonyCameraFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, @NonNull final IIndicatorControl indicator)
+ {
+ this.frameDisplay = frameDisplayer;
+ afControl = new SonyAutoFocusControl(frameDisplayer, indicator);
+ }
+
+ public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi)
+ {
+ afControl.setCameraApi(sonyCameraApi);
+ }
+
+ @Override
+ public boolean driveAutoFocus(final MotionEvent motionEvent)
+ {
+ Log.v(TAG, "driveAutoFocus()");
+ if (motionEvent.getAction() != MotionEvent.ACTION_DOWN)
+ {
+ return (false);
+ }
+ try
+ {
+ PointF point = frameDisplay.getPointWithEvent(motionEvent);
+ if (frameDisplay.isContainsPoint(point))
+ {
+ afControl.lockAutoFocus(point);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (false);
+ }
+
+ @Override
+ public void unlockAutoFocus()
+ {
+ Log.v(TAG, "unlockAutoFocus()");
+ try
+ {
+ afControl.unlockAutoFocus();
+ frameDisplay.hideFocusFrame();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void halfPressShutter(boolean isPressed)
+ {
+ Log.v(TAG, "halfPressShutter() " + isPressed);
+ try
+ {
+ afControl.halfPressShutter(isPressed);
+ if (!isPressed)
+ {
+ // フォーカスを外す
+ frameDisplay.hideFocusFrame();
+ afControl.unlockAutoFocus();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.operation;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.IZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+import org.json.JSONObject;
+
+public class SonyCameraZoomLensControl implements IZoomLensControl
+{
+ private final String TAG = toString();
+ private ISonyCameraApi cameraApi = null;
+
+ public SonyCameraZoomLensControl()
+ {
+ Log.v(TAG, "SonyCameraZoomLensControl()");
+ }
+
+ public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi)
+ {
+ cameraApi = sonyCameraApi;
+ }
+
+ @Override
+ public boolean canZoom() {
+ Log.v(TAG, "canZoom()");
+ return (true);
+ }
+
+ @Override
+ public void updateStatus()
+ {
+ Log.v(TAG, "updateStatus()");
+ }
+
+ @Override
+ public float getMaximumFocalLength()
+ {
+ Log.v(TAG, "getMaximumFocalLength()");
+ return (0);
+ }
+
+ @Override
+ public float getMinimumFocalLength()
+ {
+ Log.v(TAG, "getMinimumFocalLength()");
+ return (0);
+ }
+
+ @Override
+ public float getCurrentFocalLength()
+ {
+ Log.v(TAG, "getCurrentFocalLength()");
+ return 0;
+ }
+
+ @Override
+ public void driveZoomLens(float targetLength)
+ {
+ Log.v(TAG, "driveZoomLens() : " + targetLength);
+ }
+
+ @Override
+ public void moveInitialZoomPosition()
+ {
+ Log.v(TAG, "moveInitialZoomPosition()");
+ }
+
+ @Override
+ public boolean isDrivingZoomLens()
+ {
+ Log.v(TAG, "isDrivingZoomLens()");
+ return (false);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void driveZoomLens(boolean isZoomIn)
+ {
+ Log.v(TAG, "driveZoomLens() : " + isZoomIn);
+ if (cameraApi == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ final String direction = (isZoomIn) ? "in" : "out";
+ final String movement = "1shot";
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject resultsObj = cameraApi.actZoom(direction, movement);
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "driveZoomLens() reply is null.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.operation.takepicture;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+import org.json.JSONObject;
+
+public class SingleShotControl
+{
+ private static final String TAG = SingleShotControl.class.getSimpleName();
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private final IIndicatorControl indicator;
+ private ISonyCameraApi cameraApi = null;
+
+ /**
+ *
+ *
+ */
+ public SingleShotControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi)
+ {
+ this.cameraApi = sonyCameraApi;
+ }
+
+ /**
+ *
+ *
+ */
+ public void singleShot()
+ {
+ Log.v(TAG, "singleShot()");
+ if (cameraApi == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ //JSONObject resultsObj = cameraApi.awaitTakePicture();
+ JSONObject resultsObj = cameraApi.actTakePicture();
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "setTouchAFPosition() reply is null.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ frameDisplayer.hideFocusFrame();
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.operation.takepicture;
+
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.IIndicatorControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ *
+ *
+ */
+public class SonyAutoFocusControl
+{
+ private static final String TAG = SonyAutoFocusControl.class.getSimpleName();
+ private final IIndicatorControl indicator;
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private ISonyCameraApi cameraApi = null;
+
+ /**
+ *
+ *
+ */
+ public SonyAutoFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, final IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCameraApi(@NonNull ISonyCameraApi sonyCameraApi)
+ {
+ this.cameraApi = sonyCameraApi;
+ }
+
+ /**
+ *
+ *
+ */
+ public void lockAutoFocus(@NonNull final PointF point)
+ {
+ Log.v(TAG, "lockAutoFocus() : [" + point.x + ", " + point.y + "]");
+ if (cameraApi == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ RectF preFocusFrameRect = getPreFocusFrameRect(point);
+ try
+ {
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Running, 0.0);
+
+ double posX = point.x * 100.0;
+ double posY = point.y * 100.0;
+ Log.v(TAG, "AF (" + posX + ", " + posY + ")");
+ JSONObject resultsObj = cameraApi.setTouchAFPosition(posX, posY);
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "setTouchAFPosition() reply is null.");
+ }
+ if (findTouchAFPositionResult(resultsObj))
+ {
+ // AF FOCUSED
+ Log.v(TAG, "lockAutoFocus() : FOCUSED");
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Focused, 0.0);
+ }
+ else
+ {
+ // AF ERROR
+ Log.v(TAG, "lockAutoFocus() : ERROR");
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Failed, 1.0);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ try
+ {
+ showFocusFrame(preFocusFrameRect, IAutoFocusFrameDisplay.FocusFrameStatus.Errored, 1.0);
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * シャッター半押し処理
+ *
+ */
+ public void halfPressShutter(final boolean isPressed)
+ {
+ Log.v(TAG, "halfPressShutter() : " + isPressed);
+ if (cameraApi == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject resultsObj = (isPressed) ? cameraApi.actHalfPressShutter() : cameraApi.cancelHalfPressShutter();
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "halfPressShutter() [" + isPressed + "] reply is null.");
+ }
+ else
+ {
+ indicator.onAfLockUpdate(isPressed);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ public void unlockAutoFocus()
+ {
+ Log.v(TAG, "unlockAutoFocus()");
+ if (cameraApi == null)
+ {
+ Log.v(TAG, "ISonyCameraApi is null...");
+ return;
+ }
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject resultsObj = cameraApi.cancelTouchAFPosition();
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "cancelTouchAFPosition() reply is null.");
+ }
+ hideFocusFrame();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ private void showFocusFrame(RectF rect, IAutoFocusFrameDisplay.FocusFrameStatus status, double duration)
+ {
+ frameDisplayer.showFocusFrame(rect, status, duration);
+ indicator.onAfLockUpdate(IAutoFocusFrameDisplay.FocusFrameStatus.Focused == status);
+ }
+
+ /**
+ *
+ *
+ */
+ private void hideFocusFrame()
+ {
+ frameDisplayer.hideFocusFrame();
+ indicator.onAfLockUpdate(false);
+ }
+
+ /**
+ *
+ *
+ */
+ private RectF getPreFocusFrameRect(@NonNull PointF point)
+ {
+ float imageWidth = frameDisplayer.getContentSizeWidth();
+ float imageHeight = frameDisplayer.getContentSizeHeight();
+
+ // Display a provisional focus frame at the touched point.
+ float focusWidth = 0.125f; // 0.125 is rough estimate.
+ float focusHeight = 0.125f;
+ if (imageWidth > imageHeight)
+ {
+ focusHeight *= (imageWidth / imageHeight);
+ }
+ else
+ {
+ focusHeight *= (imageHeight / imageWidth);
+ }
+ return (new RectF(point.x - focusWidth / 2.0f, point.y - focusHeight / 2.0f,
+ point.x + focusWidth / 2.0f, point.y + focusHeight / 2.0f));
+ }
+
+ /**
+ *
+ *
+ */
+ private static boolean findTouchAFPositionResult(JSONObject replyJson)
+ {
+ boolean afResult = false;
+ try
+ {
+ int indexOfTouchAFPositionResult = 1;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfTouchAFPositionResult))
+ {
+ JSONObject touchAFPositionResultObj = resultsObj.getJSONObject(indexOfTouchAFPositionResult);
+ afResult = touchAFPositionResultObj.getBoolean("AFResult");
+ Log.v(TAG, "AF Result : " + afResult);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (afResult);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+public interface ISonyApiService
+{
+ String getName();
+ String getActionUrl();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import java.util.List;
+
+public interface ISonyCamera
+{
+ boolean hasApiService(String serviceName);
+ List<ISonyApiService> getApiServices();
+
+ String getFriendlyName();
+ String getModelName();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+public interface ISonyCameraApi
+{
+ JSONObject getAvailableApiList();
+ JSONObject getApplicationInfo();
+
+ JSONObject getShootMode();
+ JSONObject setShootMode(@NonNull String shootMode);
+ JSONObject getAvailableShootMode();
+ JSONObject getSupportedShootMode();
+
+ JSONObject setTouchAFPosition(double Xpos, double Ypos);
+ JSONObject getTouchAFPosition();
+ JSONObject cancelTouchAFPosition();
+
+ JSONObject actHalfPressShutter();
+ JSONObject cancelHalfPressShutter();
+
+ JSONObject setFocusMode(String focusMode);
+ JSONObject getFocusMode();
+ JSONObject getSupportedFocusMode();
+ JSONObject getAvailableFocusMode();
+
+ JSONObject startLiveview();
+ JSONObject stopLiveview();
+
+ JSONObject startRecMode();
+ JSONObject actTakePicture();
+ JSONObject awaitTakePicture();
+
+ JSONObject startMovieRec();
+ JSONObject stopMovieRec();
+
+ JSONObject actZoom(@NonNull String direction, @NonNull String movement);
+
+ JSONObject getEvent(@NonNull String version, boolean longPollingFlag);
+
+ JSONObject setCameraFunction(@NonNull String cameraFunction);
+
+ JSONObject getCameraMethodTypes();
+
+ JSONObject getAvcontentMethodTypes();
+
+ JSONObject getSchemeList();
+ JSONObject getSourceList(String scheme);
+
+ JSONObject getContentList(JSONArray params);
+
+ JSONObject setStreamingContent(String uri);
+
+ JSONObject startStreaming();
+ JSONObject stopStreaming();
+
+ List<String> getSonyApiServiceList();
+ JSONObject callGenericSonyApiMethod(@NonNull String service, @NonNull String method, @NonNull JSONArray params, @NonNull String version);
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+public interface ISonyCameraHolder
+{
+ void detectedCamera(@NonNull ISonyCamera camera);
+ void prepare();
+ void startRecMode();
+ void startEventWatch(@Nullable ICameraChangeListener listener);
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+class SonyApiService implements ISonyApiService
+{
+ private final String name;
+ private final String actionUrl;
+
+ SonyApiService(String name, String actionUrl)
+ {
+ this.name = name;
+ this.actionUrl = actionUrl;
+ }
+
+ @Override
+ public String getName()
+ {
+ return (name);
+ }
+
+ @Override
+ public String getActionUrl()
+ {
+ return (actionUrl);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class SonyCameraApi implements ISonyCameraApi
+{
+ private static final String TAG = SonyCameraApi.class.getSimpleName();
+ private static final boolean FULL_LOG = true;
+
+ // API server device you want to send requests.
+ private final ISonyCamera sonyCamera;
+ private int requestId;
+
+
+ public static ISonyCameraApi newInstance(@NonNull ISonyCamera target)
+ {
+ return (new SonyCameraApi(target));
+ }
+
+ private SonyCameraApi(final @NonNull ISonyCamera target)
+ {
+ sonyCamera = target;
+ requestId = 1;
+ }
+
+ private String findActionListUrl(String service)
+ {
+ List<ISonyApiService> services = sonyCamera.getApiServices();
+ for (ISonyApiService apiService : services)
+ {
+ if (apiService.getName().equals(service))
+ {
+ return (apiService.getActionUrl());
+ }
+ }
+ Log.v(TAG, "actionUrl not found. service : " + service);
+ return (null);
+ }
+
+ private int id()
+ {
+ requestId++;
+ if (requestId == 0)
+ {
+ requestId++;
+ }
+ return (requestId);
+ }
+
+ private void log(String msg)
+ {
+ if (FULL_LOG)
+ {
+ Log.d(TAG, msg);
+ }
+ }
+
+
+ private JSONObject communicateJSON(@NonNull String service, @NonNull String method, @NonNull JSONArray params, @NonNull String version, int timeoutMs)
+ {
+ try
+ {
+ JSONObject requestJson = new JSONObject().put("method", method)
+ .put("params", params)
+ .put("id", id())
+ .put("version", version);
+ String url = findActionListUrl(service) + "/" + service;
+ log("Request: " + requestJson.toString());
+ String responseJson = SimpleHttpClient.httpPost(url, requestJson.toString(), timeoutMs);
+ log("Response: " + responseJson);
+ return (new JSONObject(responseJson));
+ }
+ catch (Exception e)
+ {
+ log("Exception : " + method + " " + version);
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getAvailableApiList()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getAvailableApiList", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getApplicationInfo()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getApplicationInfo", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getShootMode()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getShootMode", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject setShootMode(@NonNull String shootMode)
+ {
+ try
+ {
+ return (communicateJSON("camera", "getShootMode", new JSONArray().put(shootMode), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getAvailableShootMode()
+ {
+ try {
+ return (communicateJSON("camera", "getAvailableShootMode", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getSupportedShootMode()
+ {
+ try {
+ return (communicateJSON("camera", "getSupportedShootMode", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject setTouchAFPosition(double Xpos, double Ypos)
+ {
+ try
+ {
+ Log.v(TAG, "setTouchAFPosition (" + Xpos + ", " + Ypos + ")");
+ return (communicateJSON("camera", "setTouchAFPosition", new JSONArray().put(Xpos).put(Ypos), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getTouchAFPosition()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getTouchAFPosition", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject cancelTouchAFPosition()
+ {
+ try
+ {
+ return (communicateJSON("camera", "cancelTouchAFPosition", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject actHalfPressShutter()
+ {
+ try
+ {
+ return (communicateJSON("camera", "actHalfPressShutter", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject cancelHalfPressShutter()
+ {
+ try
+ {
+ return (communicateJSON("camera", "cancelHalfPressShutter", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject setFocusMode(String focusMode)
+ {
+ try
+ {
+ Log.v(TAG, "setFocusMode (" + focusMode + ")");
+ return (communicateJSON("camera", "setFocusMode", new JSONArray().put(focusMode), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getFocusMode()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getFocusMode", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getSupportedFocusMode()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getSupportedFocusMode", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getAvailableFocusMode()
+ {
+ try
+ {
+ return (communicateJSON("camera", "getAvailableFocusMode", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject startLiveview()
+ {
+ try {
+ return (communicateJSON("camera", "startLiveview", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject stopLiveview()
+ {
+ try {
+ return (communicateJSON("camera", "stopLiveview", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject startRecMode()
+ {
+ try {
+ return (communicateJSON("camera", "startRecMode", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject actTakePicture()
+ {
+ try {
+ return (communicateJSON("camera", "actTakePicture", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject awaitTakePicture()
+ {
+ try
+ {
+ return (communicateJSON("camera", "awaitTakePicture", new JSONArray(), "1.0", -1));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject startMovieRec()
+ {
+ try {
+ return (communicateJSON("camera", "startMovieRec", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject stopMovieRec()
+ {
+ try {
+ return (communicateJSON("camera", "stopMovieRec", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject actZoom(@NonNull String direction, @NonNull String movement)
+ {
+ try {
+ return (communicateJSON("camera", "actZoom", new JSONArray().put(direction).put(movement), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject getEvent(@NonNull String version, boolean longPollingFlag)
+ {
+ try {
+ int longPollingTimeout = (longPollingFlag) ? 20000 : 8000; // msec
+ return (communicateJSON("camera", "getEvent", new JSONArray().put(longPollingFlag), version, longPollingTimeout));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject setCameraFunction(@NonNull String cameraFunction)
+ {
+ try {
+ return (communicateJSON("camera", "setCameraFunction", new JSONArray().put(cameraFunction), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject getCameraMethodTypes()
+ {
+ try {
+ return (communicateJSON("camera", "getCameraMethodTypes", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject getAvcontentMethodTypes()
+ {
+ try {
+ return (communicateJSON("avContent", "getMethodTypes", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getSchemeList()
+ {
+ try {
+ return (communicateJSON("avContent", "getSchemeList", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+
+ @Override
+ public JSONObject getSourceList(String scheme)
+ {
+ try {
+ JSONObject params = new JSONObject().put("scheme", scheme);
+ return (communicateJSON("avContent", "getSourceList", new JSONArray().put(0, params), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+ }
+
+ @Override
+ public JSONObject getContentList(JSONArray params)
+ {
+ try {
+ return (communicateJSON("avContent", "getContentList", new JSONArray().put(0, params), "1.3", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+
+ }
+
+ @Override
+ public JSONObject setStreamingContent(String uri)
+ {
+ try {
+ JSONObject params = new JSONObject().put("remotePlayType", "simpleStreaming").put("uri", uri);
+ return (communicateJSON("avContent", "setStreamingContent", new JSONArray().put(0, params), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+
+ }
+
+ @Override
+ public JSONObject startStreaming()
+ {
+ try {
+ return (communicateJSON("avContent", "startStreaming", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+
+ }
+
+ @Override
+ public JSONObject stopStreaming()
+ {
+ try {
+ return (communicateJSON("avContent", "stopStreaming", new JSONArray(), "1.0", -1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (new JSONObject());
+
+ }
+
+ @Override
+ public List<String> getSonyApiServiceList()
+ {
+ try
+ {
+ List<String> serviceList = new ArrayList<>();
+ List<ISonyApiService> services = sonyCamera.getApiServices();
+ for (ISonyApiService apiService : services)
+ {
+ serviceList.add(apiService.getName());
+ }
+ return (serviceList);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (null);
+ }
+
+ @Override
+ public JSONObject callGenericSonyApiMethod(@NonNull String service, @NonNull String method, @NonNull JSONArray params, @NonNull String version)
+ {
+ return (communicateJSON(service, method, params, version, -1));
+ }
+
+ public static boolean isErrorReply(JSONObject replyJson)
+ {
+ return ((replyJson != null && replyJson.has("error")));
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.pkremote.camera.utils.XmlElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SonyCameraDeviceProvider implements ISonyCamera
+{
+ private static final String TAG = SonyCameraDeviceProvider.class.getSimpleName();
+ private final List<ISonyApiService> apiServices;
+ private final String ddUrl;
+ private final String udn;
+ private final String friendlyName;
+ private final String modelName;
+ private final String iconUrl;
+
+ /**
+ * コンストラクタ: staticメソッド searchPanasonicCameraDevice() で生成する
+ *
+ */
+ private SonyCameraDeviceProvider(String ddUrl, String friendlyName, String modelName, String udn, String iconUrl)
+ {
+ this.ddUrl = ddUrl;
+ this.friendlyName = friendlyName;
+ this.modelName = modelName;
+ this.udn = udn;
+ this.iconUrl = iconUrl;
+ Log.v(TAG, "Sony Device : " + this.friendlyName + "(" + this.modelName + ") " + this.ddUrl + " " + this.udn + " " + this.iconUrl);
+
+ apiServices = new ArrayList<>();
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public boolean hasApiService(@NonNull String serviceName)
+ {
+ try
+ {
+ for (ISonyApiService apiService : apiServices)
+ {
+ if (serviceName.equals(apiService.getName()))
+ {
+ return (true);
+ }
+ }
+ Log.v(TAG, "no API Service : " + serviceName + "[" + apiServices.size() + "]");
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (false);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public List<ISonyApiService> getApiServices()
+ {
+ return (apiServices);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getFriendlyName()
+ {
+ return (friendlyName);
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public String getModelName()
+ {
+ return (modelName);
+ }
+
+
+ /**
+ *
+ *
+ */
+ private void addApiService(String name, String actionUrl)
+ {
+ Log.v(TAG, "API : " + name + " : " + actionUrl);
+ SonyApiService service = new SonyApiService(name, actionUrl);
+ apiServices.add(service);
+ }
+
+ /**
+ *
+ *
+ */
+ public static ISonyCamera searchSonyCameraDevice(@NonNull String ddUrl)
+ {
+ SonyCameraDeviceProvider device = null;
+ String ddXml;
+ try
+ {
+ ddXml = SimpleHttpClient.httpGet(ddUrl, -1);
+ Log.d(TAG, "fetch () httpGet done. : " + ddXml.length());
+ if (ddXml.length() < 2)
+ {
+ // 内容がないときは...終了する
+ Log.v(TAG, "NO BODY");
+ return (null);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return (null);
+ }
+ try
+ {
+ //Log.v(TAG, "ddXml : " + ddXml);
+ XmlElement rootElement = XmlElement.parse(ddXml);
+
+ // "root"
+ if ("root".equals(rootElement.getTagName()))
+ {
+ // "device"
+ XmlElement deviceElement = rootElement.findChild("device");
+ String friendlyName = deviceElement.findChild("friendlyName").getValue();
+ String modelName = deviceElement.findChild("modelName").getValue();
+ String udn = deviceElement.findChild("UDN").getValue();
+
+ // "iconList"
+ String iconUrl = "";
+ XmlElement iconListElement = deviceElement.findChild("iconList");
+ List<XmlElement> iconElements = iconListElement.findChildren("icon");
+ for (XmlElement iconElement : iconElements)
+ {
+ // Choose png icon to show Android UI.
+ if ("image/png".equals(iconElement.findChild("mimetype").getValue()))
+ {
+ String uri = iconElement.findChild("url").getValue();
+ String hostUrl = toSchemeAndHost(ddUrl);
+ iconUrl = hostUrl + uri;
+ }
+ }
+ device = new SonyCameraDeviceProvider(ddUrl, friendlyName, modelName, udn, iconUrl);
+
+ // "av:X_ScalarWebAPI_DeviceInfo"
+ XmlElement wApiElement = deviceElement.findChild("X_ScalarWebAPI_DeviceInfo");
+ XmlElement wApiServiceListElement = wApiElement.findChild("X_ScalarWebAPI_ServiceList");
+ List<XmlElement> wApiServiceElements = wApiServiceListElement.findChildren("X_ScalarWebAPI_Service");
+ for (XmlElement wApiServiceElement : wApiServiceElements)
+ {
+ String serviceName = wApiServiceElement.findChild("X_ScalarWebAPI_ServiceType").getValue();
+ String actionUrl = wApiServiceElement.findChild("X_ScalarWebAPI_ActionList_URL").getValue();
+ device.addApiService(serviceName, actionUrl);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Log.d(TAG, "fetch () parsing XML done.");
+ if (device == null)
+ {
+ Log.v(TAG, "device is null.");
+ }
+ return (device);
+ }
+
+ private static String toSchemeAndHost(String url)
+ {
+ int i = url.indexOf("://"); // http:// or https://
+ if (i == -1) {
+ return ("");
+ }
+
+ int j = url.indexOf("/", i + 3);
+ if (j == -1) {
+ return ("");
+ }
+
+ return (url.substring(0, j));
+ }
+
+ private static String toHost(String url)
+ {
+ int i = url.indexOf("://"); // http:// or https://
+ if (i == -1) {
+ return ("");
+ }
+
+ int j = url.indexOf(":", i + 3);
+ if (j == -1) {
+ return ("");
+ }
+ return (url.substring(i + 3, j));
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+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.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraInformation;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.ISonyInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.operation.SonyCameraCaptureControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.operation.SonyCameraFocusControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.operation.SonyCameraZoomLensControl;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.connection.SonyCameraConnection;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener.CameraEventObserver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener.ICameraEventObserver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener.ICameraStatusHolder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class SonyCameraWrapper implements ISonyCameraHolder, ISonyInterfaceProvider, IDisplayInjector
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private final ICameraStatusReceiver provider;
+ private final ICameraChangeListener listener;
+ private ISonyCamera sonyCamera = null;
+ private ISonyCameraApi sonyCameraApi = null;
+ private ICameraEventObserver eventObserver = null;
+ private SonyLiveViewControl liveViewControl = null;
+ private SonyCameraFocusControl focusControl = null;
+ private SonyCameraCaptureControl captureControl = null;
+ private SonyCameraZoomLensControl zoomControl = null;
+
+ public SonyCameraWrapper(final Activity context, final ICameraStatusReceiver statusReceiver , final @NonNull ICameraChangeListener listener)
+ {
+ this.context = context;
+ this.provider = statusReceiver;
+ this.listener = listener;
+ }
+
+ @Override
+ public void prepare()
+ {
+ Log.v(TAG, " prepare : " + sonyCamera.getFriendlyName() + " " + sonyCamera.getModelName());
+ try
+ {
+ this.sonyCameraApi = SonyCameraApi.newInstance(sonyCamera);
+ eventObserver = CameraEventObserver.newInstance(context, sonyCameraApi);
+ liveViewControl = new SonyLiveViewControl(sonyCameraApi);
+
+ focusControl.setCameraApi(sonyCameraApi);
+ captureControl.setCameraApi(sonyCameraApi);
+ zoomControl.setCameraApi(sonyCameraApi);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startRecMode()
+ {
+ try {
+ List<String> apiCommands = getApiCommands();
+ int index = apiCommands.indexOf("startRecMode");
+ if (index > 0)
+ {
+ // startRecMode発行
+ Log.v(TAG, "----- THIS CAMERA NEEDS COMMAND 'startRecMode'.");
+ sonyCameraApi.startRecMode();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ }
+
+ @Override
+ public void startEventWatch(@Nullable ICameraChangeListener listener)
+ {
+ try
+ {
+ if (eventObserver != null)
+ {
+ if (listener != null)
+ {
+ eventObserver.setEventListener(listener);
+ }
+ eventObserver.activate();
+ eventObserver.start();
+ ICameraStatusHolder holder = eventObserver.getCameraStatusHolder();
+ holder.getLiveviewStatus();
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void detectedCamera(@NonNull ISonyCamera camera)
+ {
+ Log.v(TAG, "detectedCamera()");
+ sonyCamera = camera;
+ }
+
+ @Override
+ public ICameraConnection getSonyCameraConnection()
+ {
+ return (new SonyCameraConnection(context, provider, this, listener));
+ }
+
+ @Override
+ public ILiveViewControl getSonyLiveViewControl()
+ {
+ return (liveViewControl);
+ }
+
+ @Override
+ public ILiveViewListener getLiveViewListener()
+ {
+ return (liveViewControl.getLiveViewListener());
+ }
+
+ @Override
+ public IFocusingControl getFocusingControl()
+ {
+ return (focusControl);
+ }
+
+ @Override
+ public ICameraInformation getCameraInformation()
+ {
+ return null;
+ }
+
+ @Override
+ public IZoomLensControl getZoomLensControl()
+ {
+ return (zoomControl);
+ }
+
+ @Override
+ public ICaptureControl getCaptureControl()
+ {
+ return (captureControl);
+ }
+
+ @Override
+ public IDisplayInjector getDisplayInjector()
+ {
+ return (this);
+ }
+
+ @Override
+ public List<String> getApiCommands()
+ {
+ List<String> availableApis = new ArrayList<>();
+ try
+ {
+ String apiList = sonyCameraApi.getAvailableApiList().getString("result");
+ apiList = apiList.replace("[","").replace("]", "").replace("\"","");
+ String[] apiListSplit = apiList.split(",");
+ availableApis = Arrays.asList(apiListSplit);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (availableApis);
+ }
+
+ @Override
+ public ISonyCameraApi getCameraApi()
+ {
+ return (sonyCameraApi);
+ }
+
+ @Override
+ public void injectDisplay(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator, @NonNull IFocusingModeNotify focusingModeNotify)
+ {
+ Log.v(TAG, "injectDisplay()");
+
+ focusControl = new SonyCameraFocusControl(frameDisplayer, indicator);
+ captureControl = new SonyCameraCaptureControl(frameDisplayer, indicator);
+ zoomControl = new SonyCameraZoomLensControl();
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewControl;
+import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ILiveViewListener;
+import net.osdn.gokigen.pkremote.camera.liveview.CameraLiveViewListenerImpl;
+import net.osdn.gokigen.pkremote.camera.utils.SimpleLiveviewSlicer;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class SonyLiveViewControl implements ILiveViewControl
+{
+ private final String TAG = toString();
+ private final ISonyCameraApi cameraApi;
+ //private final BlockingQueue<byte[]> mJpegQueue = new ArrayBlockingQueue<>(2);
+ private final CameraLiveViewListenerImpl liveViewListener;
+ private boolean whileFetching = false;
+ private static final int FETCH_ERROR_MAX = 30;
+
+ SonyLiveViewControl(@NonNull ISonyCameraApi cameraApi)
+ {
+ this.cameraApi = cameraApi;
+ liveViewListener = new CameraLiveViewListenerImpl();
+ }
+
+ @Override
+ public void changeLiveViewSize(String size)
+ {
+
+ }
+
+ @Override
+ public void startLiveView(boolean isCameraScreen)
+ {
+ Log.v(TAG, "startLiveView() : " + isCameraScreen);
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject replyJson;
+ replyJson = cameraApi.startLiveview();
+ if (!SonyCameraApi.isErrorReply(replyJson))
+ {
+ try
+ {
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (1 <= resultsObj.length())
+ {
+ // Obtain liveview URL from the result.
+ final String liveviewUrl = resultsObj.getString(0);
+ start(liveviewUrl);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stopLiveView()
+ {
+ Log.v(TAG, "stopLiveView()");
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject resultsObj = cameraApi.stopLiveview();
+ if (resultsObj == null)
+ {
+ Log.v(TAG, "stopLiveview() reply is null.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void updateDigitalZoom()
+ {
+
+ }
+
+ @Override
+ public void updateMagnifyingLiveViewScale(boolean isChangeScale)
+ {
+
+ }
+
+ @Override
+ public float getMagnifyingLiveViewScale()
+ {
+ return (1.0f);
+ }
+
+ @Override
+ public float getDigitalZoomScale()
+ {
+ return (1.0f);
+ }
+
+
+
+ public boolean start(final String streamUrl)
+ {
+ if (streamUrl == null)
+ {
+ Log.e(TAG, "start() streamUrl is null.");
+ return (false);
+ }
+ if (whileFetching)
+ {
+ Log.v(TAG, "start() already starting.");
+ }
+ whileFetching = true;
+
+ // A thread for retrieving liveview data from server.
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ Log.d(TAG, "Starting retrieving streaming data from server.");
+ SimpleLiveviewSlicer slicer = null;
+ int continuousNullDataReceived = 0;
+ try
+ {
+ // Create Slicer to open the stream and parse it.
+ slicer = new SimpleLiveviewSlicer();
+ slicer.open(streamUrl);
+
+ while (whileFetching)
+ {
+ final SimpleLiveviewSlicer.Payload payload = slicer.nextPayload();
+ if (payload == null)
+ {
+ //Log.v(TAG, "Liveview Payload is null.");
+ continuousNullDataReceived++;
+ if (continuousNullDataReceived > FETCH_ERROR_MAX)
+ {
+ Log.d(TAG, " FETCH ERROR MAX OVER ");
+ break;
+ }
+ continue;
+ }
+ //if (mJpegQueue.size() == 2)
+ //{
+ // mJpegQueue.remove();
+ //}
+ //mJpegQueue.add(payload.getJpegData());
+ liveViewListener.onUpdateLiveView(payload.getJpegData(), null);
+ continuousNullDataReceived = 0;
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ try
+ {
+ if (slicer != null)
+ {
+ slicer.close();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ //mJpegQueue.clear();
+ if ((!whileFetching)&&(continuousNullDataReceived > FETCH_ERROR_MAX))
+ {
+ // 再度ライブビューのスタートをやってみる。
+ whileFetching = false;
+ //continuousNullDataReceived = 0;
+ start(streamUrl);
+ }
+ }
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (true);
+ }
+
+ public ILiveViewListener getLiveViewListener()
+ {
+ return (liveViewListener);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.connection;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCamera;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraHolder;
+
+/**
+ * SONYカメラとの接続処理
+ *
+ */
+public class SonyCameraConnectSequence implements Runnable, SonySsdpClient.ISearchResultCallback
+{
+ private final String TAG = this.toString();
+ private final Activity context;
+ private final ICameraConnection cameraConnection;
+ private final ISonyCameraHolder cameraHolder;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final ICameraChangeListener listener;
+ private final SonySsdpClient client;
+
+ SonyCameraConnectSequence(Activity context, ICameraStatusReceiver statusReceiver, final ICameraConnection cameraConnection, final @NonNull ISonyCameraHolder cameraHolder, final @NonNull ICameraChangeListener listener)
+ {
+ Log.v(TAG, "SonyCameraConnectSequence");
+ this.context = context;
+ this.cameraConnection = cameraConnection;
+ this.cameraStatusReceiver = statusReceiver;
+ this.cameraHolder = cameraHolder;
+ this.listener = listener;
+ client = new SonySsdpClient(context, this, statusReceiver, 1);
+ }
+
+ @Override
+ public void run()
+ {
+ Log.v(TAG, "search()");
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start));
+ client.search();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onDeviceFound(ISonyCamera cameraDevice)
+ {
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_detected) + " " + cameraDevice.getFriendlyName());
+ cameraHolder.detectedCamera(cameraDevice);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onFinished()
+ {
+ Log.v(TAG, "SonyCameraConnectSequence.onFinished()");
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ cameraHolder.prepare();
+ cameraHolder.startRecMode();
+ cameraHolder.startEventWatch(listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Log.v(TAG, "CameraConnectSequence:: connected.");
+ onConnectNotify();
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ 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();
+ }
+ }
+ }
+
+
+ @Override
+ public void onErrorFinished(String reason)
+ {
+ cameraConnection.alertConnectingFailed(reason);
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.connection;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraHolder;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ *
+ *
+ */
+public class SonyCameraConnection implements ICameraConnection
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private final ICameraStatusReceiver statusReceiver;
+ private final BroadcastReceiver connectionReceiver;
+ private final ISonyCameraHolder cameraHolder;
+ //private final ConnectivityManager connectivityManager;
+ private final Executor cameraExecutor = Executors.newFixedThreadPool(1);
+ private final ICameraChangeListener listener;
+ //private final Handler networkConnectionTimeoutHandler;
+ //private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
+ private CameraConnectionStatus connectionStatus = CameraConnectionStatus.UNKNOWN;
+
+ public SonyCameraConnection(final Activity context, final ICameraStatusReceiver statusReceiver, @NonNull ISonyCameraHolder cameraHolder, final @NonNull ICameraChangeListener listener)
+ {
+ Log.v(TAG, "SonyCameraConnection()");
+ this.context = context;
+ this.statusReceiver = statusReceiver;
+ this.cameraHolder = cameraHolder;
+ this.listener = listener;
+/*
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ networkConnectionTimeoutHandler = new Handler()
+ {
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch (msg.what)
+ {
+ case MESSAGE_CONNECTIVITY_TIMEOUT:
+ Log.d(TAG, "Network connection timeout");
+ alertConnectingFailed(context.getString(R.string.network_connection_timeout));
+ connectionStatus = CameraConnectionStatus.DISCONNECTED;
+ break;
+ }
+ }
+ };
+*/
+ 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();
+ }
+ }
+
+
+ /**
+ * Wifi接続状態の監視
+ * (接続の実処理は onReceiveBroadcastOfConnection() で実施)
+ */
+ @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);
+ }
+
+ /**
+ * Wifi接続状態の監視終了
+ */
+ @Override
+ public void stopWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "stopWatchWifiStatus()");
+ context.unregisterReceiver(connectionReceiver);
+ disconnect(false);
+ }
+
+ /**
+ * カメラとの接続を解除する
+ *
+ * @param powerOff 真ならカメラの電源オフを伴う
+ */
+ @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();
+ }
+
+ /**
+ * 接続リトライのダイアログを出す
+ *
+ * @param message 表示用のメッセージ
+ */
+ @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))
+ .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()
+ {
+ builder.show();
+ }
+ });
+ }
+
+ @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 SonyCameraDisconnectSequence(powerOff));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラとの接続処理
+ */
+ private void connectToCamera()
+ {
+ Log.v(TAG, "connectToCamera()");
+ connectionStatus = CameraConnectionStatus.CONNECTING;
+ try
+ {
+ cameraExecutor.execute(new SonyCameraConnectSequence(context,statusReceiver, this, cameraHolder, listener));
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, "connectToCamera() EXCEPTION : " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.connection;
+
+
+public class SonyCameraDisconnectSequence implements Runnable
+{
+ //private final String TAG = this.toString();
+ //private final boolean powerOff;
+
+ SonyCameraDisconnectSequence(boolean isOff)
+ {
+ //this.powerOff = isOff;
+ }
+
+
+ @Override
+ public void run()
+ {
+ // カメラをPowerOffして接続を切る
+
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.connection;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.R;
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCamera;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.SonyCameraDeviceProvider;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Sony SSDP Client : SonyのCameraRemoteSampleApp にある SimpleSsdpClient を参考にインプリメントした
+ * (API Level 14を minSdkVersion に設定したので... NsdManager.DiscoveryListener を使わなかった)
+ *
+ * SSDP : Simple Service Discovery Protocol
+ *
+ */
+class SonySsdpClient
+{
+ private final String TAG = toString();
+ private static final int SEND_TIMES_DEFAULT = 3;
+ private static final int SEND_WAIT_DURATION_MS = 100;
+ private static final int SSDP_RECEIVE_TIMEOUT = 10 * 1000; // msec
+ private static final int PACKET_BUFFER_SIZE = 2048;
+ private static final int SSDP_PORT = 1900;
+ private static final int SSDP_MX = 1;
+ private static final String SSDP_ADDR = "239.255.255.250";
+ private static final String SSDP_ST = "urn:schemas-sony-com:service:ScalarWebAPI:1";
+ private final Context context;
+ private final ISearchResultCallback callback;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final String ssdpRequest;
+ private final int sendRepeatCount;
+
+ SonySsdpClient(@NonNull Context context, @NonNull ISearchResultCallback callback, @NonNull ICameraStatusReceiver statusReceiver, int sendRepeatCount)
+ {
+ this.context = context;
+ this.callback = callback;
+ this.cameraStatusReceiver = statusReceiver;
+ this.sendRepeatCount = (sendRepeatCount >= 0) ? sendRepeatCount : SEND_TIMES_DEFAULT;
+ ssdpRequest = "M-SEARCH * HTTP/1.1\r\n"
+ + String.format(Locale.US, "HOST: %s:%d\r\n", SSDP_ADDR, SSDP_PORT)
+ + "MAN: \"ssdp:discover\"\r\n"
+ + String.format(Locale.US, "MX: %d\r\n", SSDP_MX)
+ + String.format("ST: %s\r\n", SSDP_ST) + "\r\n";
+ }
+
+ void search()
+ {
+ final byte[] sendData = ssdpRequest.getBytes();
+ String detailString = "";
+ DatagramSocket socket = null;
+ DatagramPacket receivePacket;
+ DatagramPacket packet;
+
+ // 要求の送信
+ try
+ {
+ socket = new DatagramSocket();
+ socket.setReuseAddress(true);
+ InetSocketAddress iAddress = new InetSocketAddress(SSDP_ADDR, SSDP_PORT);
+ packet = new DatagramPacket(sendData, sendData.length, iAddress);
+
+ // 要求を繰り返し送信する
+ for (int loop = 1; loop <= sendRepeatCount; loop++)
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_search_request) + " " + loop);
+ socket.send(packet);
+ Thread.sleep(SEND_WAIT_DURATION_MS);
+ }
+ }
+ catch (Exception e)
+ {
+ if ((socket != null) && (!socket.isClosed()))
+ {
+ socket.close();
+ }
+ e.printStackTrace();
+
+ // エラー応答する
+ callback.onErrorFinished(detailString + " : " + e.getLocalizedMessage());
+ return;
+ }
+
+ // 応答の受信
+ long startTime = System.currentTimeMillis();
+ long currentTime = System.currentTimeMillis();
+ List<String> foundDevices = new ArrayList<>();
+ byte[] array = new byte[PACKET_BUFFER_SIZE];
+ try
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_wait_reply));
+ while (currentTime - startTime < SSDP_RECEIVE_TIMEOUT)
+ {
+ receivePacket = new DatagramPacket(array, array.length);
+ socket.setSoTimeout(SSDP_RECEIVE_TIMEOUT);
+ socket.receive(receivePacket);
+ String ssdpReplyMessage = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
+ String ddUsn;
+ if (ssdpReplyMessage.contains("HTTP/1.1 200"))
+ {
+ ddUsn = findParameterValue(ssdpReplyMessage, "USN");
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_received_reply));
+ if (!foundDevices.contains(ddUsn))
+ {
+ String ddLocation = findParameterValue(ssdpReplyMessage, "LOCATION");
+ foundDevices.add(ddUsn);
+
+ //// Fetch Device Description XML and parse it.
+ if (ddLocation != null)
+ {
+ cameraStatusReceiver.onStatusNotify("LOCATION : " + ddLocation);
+ ISonyCamera device = SonyCameraDeviceProvider.searchSonyCameraDevice(ddLocation);
+ if ((device != null) && (device.hasApiService("camera")))
+ {
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_found) + " " + device.getFriendlyName());
+ callback.onDeviceFound(device);
+ // カメラが見つかった場合は breakする
+ break;
+ }
+ else
+ {
+ // カメラが見つからない...
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.camera_not_found));
+ }
+ }
+ }
+ else
+ {
+ Log.v(TAG, "Already received. : " + ddUsn);
+ }
+ }
+ currentTime = System.currentTimeMillis();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+
+ // エラー応答する
+ callback.onErrorFinished(detailString + " : " + e.getLocalizedMessage());
+ return;
+ }
+ finally
+ {
+ try
+ {
+ if (!socket.isClosed())
+ {
+ socket.close();
+ }
+ } catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ callback.onFinished();
+ }
+
+ private static String findParameterValue(@NonNull String ssdpMessage, @NonNull String paramName)
+ {
+ String name = paramName;
+ if (!name.endsWith(":"))
+ {
+ name = name + ":";
+ }
+ int start = ssdpMessage.indexOf(name);
+ int end = ssdpMessage.indexOf("\r\n", start);
+ if ((start != -1)&&(end != -1))
+ {
+ start += name.length();
+ try
+ {
+ return ((ssdpMessage.substring(start, end)).trim());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ return (null);
+ }
+
+ /**
+ * 検索結果のコールバック
+ *
+ */
+ public interface ISearchResultCallback
+ {
+ void onDeviceFound(ISonyCamera cameraDevice); // デバイスが見つかった!
+ void onFinished(); // 通常の終了をしたとき
+ void onErrorFinished(String reason); // エラーが発生して応答したとき
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener;
+
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+import java.util.List;
+
+public class CameraChangeListerTemplate implements ICameraChangeListener
+{
+ private static final String TAG = CameraChangeListerTemplate.class.getSimpleName();
+
+ public CameraChangeListerTemplate()
+ {
+ Log.v(TAG, "CameraChangeListerTemplate");
+
+ }
+
+ @Override
+ public void onApiListModified(List<String> apis)
+ {
+ Log.v(TAG, "onApiListModified() : " + apis.size());
+ }
+
+ @Override
+ public void onCameraStatusChanged(String status)
+ {
+ Log.v(TAG, "onCameraStatusChanged() : " + status);
+ }
+
+ @Override
+ public void onLiveviewStatusChanged(boolean status)
+ {
+ Log.v(TAG, "onLiveviewStatusChanged() : " + status);
+ }
+
+ @Override
+ public void onShootModeChanged(String shootMode)
+ {
+ Log.v(TAG, "onShootModeChanged() : " + shootMode);
+ }
+
+ @Override
+ public void onZoomPositionChanged(int zoomPosition)
+ {
+ Log.v(TAG, "onZoomPositionChanged() : " + zoomPosition);
+ }
+
+ @Override
+ public void onStorageIdChanged(String storageId)
+ {
+ Log.v(TAG, "onStorageIdChanged() : " + storageId);
+ }
+
+ @Override
+ public void onFocusStatusChanged(String focusStatus)
+ {
+ Log.v(TAG, "onFocusStatusChanged() : " + focusStatus);
+ }
+
+ @Override
+ public void onResponseError()
+ {
+ Log.v(TAG, "onResponseError() ");
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+import net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.ISonyCameraApi;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ *
+ *
+ */
+public class CameraEventObserver implements ICameraEventObserver
+{
+ private static final String TAG = CameraEventObserver.class.getSimpleName();
+ private boolean isEventMonitoring;
+ private boolean isActive;
+
+ private final ISonyCameraApi remoteApi;
+ private final ReplyJsonParser replyParser;
+ private String eventVersion = "1.1"; // 初期値を "1.0" から "1.1" に更新
+
+ public static ICameraEventObserver newInstance(@NonNull Context context, @NonNull ISonyCameraApi apiClient)
+ {
+ return (new CameraEventObserver(context, apiClient));
+ }
+
+ private CameraEventObserver(@NonNull Context context, @NonNull ISonyCameraApi apiClient)
+ {
+ super();
+ remoteApi = apiClient;
+ replyParser = new ReplyJsonParser(new Handler(context.getMainLooper()));
+ isEventMonitoring = false;
+ isActive = false;
+ }
+
+ @Override
+ public boolean start()
+ {
+ if (!isActive)
+ {
+ Log.w(TAG, "start() observer is not active.");
+ return (false);
+ }
+
+ if (isEventMonitoring)
+ {
+ Log.w(TAG, "start() already starting.");
+ return (false);
+ }
+
+ isEventMonitoring = true;
+ try
+ {
+ Thread thread = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ Log.d(TAG, "start() exec.");
+ boolean firstCall = true;
+ MONITORLOOP: while (isEventMonitoring)
+ {
+ // At first, call as non-Long Polling.
+ boolean longPolling = !firstCall;
+ try
+ {
+ // Call getEvent API.
+ JSONObject replyJson = remoteApi.getEvent(eventVersion, longPolling);
+
+ // Check error code at first.
+ int errorCode = findErrorCode(replyJson);
+ Log.d(TAG, "getEvent errorCode: " + errorCode);
+ switch (errorCode) {
+ case 0: // no error
+ // Pass through.
+ break;
+ case 1: // "Any" error
+ case 12: // "No such method" error
+ if (eventVersion.equals("1.1"))
+ {
+ // "1.1" でエラーが発生した時には "1.0" にダウングレードして再実行
+ eventVersion = "1.0";
+ continue MONITORLOOP;
+ }
+ replyParser.fireResponseErrorListener();
+ break MONITORLOOP; // end monitoring.
+
+ case 2: // "Timeout" error
+ // Re-call immediately.
+ continue MONITORLOOP;
+
+ case 40402: // "Already polling" error
+ // Retry after 5 sec.
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ // do nothing.
+ }
+ continue MONITORLOOP;
+
+ default:
+ Log.w(TAG, "SimpleCameraEventObserver: Unexpected error: " + errorCode);
+ replyParser.fireResponseErrorListener();
+ break MONITORLOOP; // end monitoring.
+ }
+
+ // parse
+ replyParser.parse(replyJson);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ firstCall = false;
+ } // MONITORLOOP end.
+ isEventMonitoring = false;
+ }
+ };
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (true);
+ }
+
+ @Override
+ public void stop()
+ {
+ isEventMonitoring = false;
+ }
+
+ @Override
+ public void release()
+ {
+ isEventMonitoring = false;
+ isActive = false;
+ }
+
+ @Override
+ public void setEventListener(@NonNull ICameraChangeListener listener)
+ {
+ try
+ {
+ replyParser.setEventChangeListener(listener);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void clearEventListener()
+ {
+ try
+ {
+ replyParser.clearEventChangeListener();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public ICameraStatusHolder getCameraStatusHolder()
+ {
+ return (replyParser);
+ }
+
+ @Override
+ public void activate()
+ {
+ isActive = true;
+ }
+
+ private static int findErrorCode(JSONObject replyJson)
+ {
+ int code = 0; // 0 means no error.
+ try
+ {
+ if (replyJson.has("error"))
+ {
+ JSONArray errorObj = replyJson.getJSONArray("error");
+ code = errorObj.getInt(0);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ code = -1;
+ }
+ return (code);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+public interface ICameraEventObserver
+{
+ void activate();
+ boolean start();
+ void stop();
+ void release();
+
+ void setEventListener(@NonNull ICameraChangeListener listener);
+ void clearEventListener();
+
+ ICameraStatusHolder getCameraStatusHolder();
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener;
+
+import java.util.List;
+
+public interface ICameraStatusHolder
+{
+ String getCameraStatus();
+ boolean getLiveviewStatus();
+ String getShootMode();
+ List<String> getAvailableShootModes();
+ int getZoomPosition();
+ String getStorageId();
+
+}
--- /dev/null
+package net.osdn.gokigen.pkremote.camera.vendor.sony.wrapper.eventlistener;
+
+
+import android.os.Handler;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraChangeListener;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ReplyJsonParser implements ICameraStatusHolder
+{
+ private static final String TAG = ReplyJsonParser.class.getSimpleName();
+ private String cameraStatus = null;
+ private final Handler uiHandler;
+ private ICameraChangeListener listener;
+
+ private boolean currentLiveviewStatus;
+ private String currentShootMode;
+ private List<String> currentAvailableShootModes = Collections.unmodifiableList(new ArrayList<String>());
+ private int currentZoomPosition;
+ private String currentStorageId;
+ private String currentFocusStatus;
+
+ ReplyJsonParser(final @NonNull Handler uiHandler)
+ {
+ this.uiHandler = uiHandler;
+ }
+
+ void parse(@NonNull JSONObject replyJson)
+ {
+ // AvailableApis
+ List<String> availableApis = findAvailableApiList(replyJson);
+ if (!availableApis.isEmpty()) {
+ fireApiListModifiedListener(availableApis);
+ }
+
+ // CameraStatus
+ String cameraStatus = findCameraStatus(replyJson);
+ Log.d(TAG, "getEvent cameraStatus: " + cameraStatus);
+ if (cameraStatus != null && !cameraStatus.equals(this.cameraStatus)) {
+ this.cameraStatus = cameraStatus;
+ fireCameraStatusChangeListener(cameraStatus);
+ }
+
+ // LiveviewStatus
+ Boolean liveviewStatus = findLiveviewStatus(replyJson);
+ Log.d(TAG, "getEvent liveviewStatus: " + liveviewStatus);
+ if (liveviewStatus != null && !liveviewStatus.equals(currentLiveviewStatus)) {
+ currentLiveviewStatus = liveviewStatus;
+ fireLiveviewStatusChangeListener(liveviewStatus);
+ }
+
+ // ShootMode
+ String shootMode = findShootMode(replyJson);
+ Log.d(TAG, "getEvent shootMode: " + shootMode);
+ if (shootMode != null && !shootMode.equals(currentShootMode)) {
+ currentShootMode = shootMode;
+
+ // Available Shoot Modes
+ List<String> shootModes = findAvailableShootModes(replyJson);
+ currentAvailableShootModes = Collections.unmodifiableList(shootModes);
+ fireShootModeChangeListener(shootMode);
+ }
+
+ // zoomPosition
+ int zoomPosition = findZoomInformation(replyJson);
+ Log.d(TAG, "getEvent zoomPosition: " + zoomPosition);
+ if (zoomPosition != -1) {
+ currentZoomPosition = zoomPosition;
+ fireZoomInformationChangeListener(0, 0, zoomPosition, 0);
+ }
+
+ // storageId
+ String storageId = findStorageId(replyJson);
+ Log.d(TAG, "getEvent storageId:" + storageId);
+ if (storageId != null && !storageId.equals(currentStorageId)) {
+ currentStorageId = storageId;
+ fireStorageIdChangeListener(storageId);
+ }
+
+ // focusStatus (v1.1)
+ String focusStatus = findFocusStatus(replyJson);
+ Log.d(TAG, "getEvent focusStatus:" + focusStatus);
+ if (focusStatus != null && !focusStatus.equals(currentFocusStatus)) {
+ currentFocusStatus = focusStatus;
+ fireFocusStatusChangeListener(focusStatus);
+ }
+ }
+
+ void setEventChangeListener(ICameraChangeListener listener)
+ {
+ this.listener = listener;
+ }
+
+ void clearEventChangeListener()
+ {
+ listener = null;
+ }
+
+ void fireResponseErrorListener()
+ {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (listener != null) {
+ listener.onResponseError();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private void fireApiListModifiedListener(final List<String> availableApis)
+ {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (listener != null) {
+ listener.onApiListModified(availableApis);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private void fireCameraStatusChangeListener(final String status) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (listener != null) {
+ listener.onCameraStatusChanged(status);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private void fireLiveviewStatusChangeListener(final boolean status) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onLiveviewStatusChanged(status);
+ }
+ }
+ });
+ }
+
+ private void fireShootModeChangeListener(final String shootMode) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onShootModeChanged(shootMode);
+ }
+ }
+ });
+ }
+
+ private void fireZoomInformationChangeListener(final int zoomIndexCurrentBox, final int zoomNumberBox, final int zoomPosition, final int zoomPositionCurrentBox) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onZoomPositionChanged(zoomPosition);
+ }
+ }
+ });
+ }
+
+ private void fireStorageIdChangeListener(final String storageId) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onStorageIdChanged(storageId);
+ }
+ }
+ });
+ }
+
+ private void fireFocusStatusChangeListener(final String focusStatus) {
+ uiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onFocusStatusChanged(focusStatus);
+ }
+ }
+ });
+ }
+
+ private static List<String> findAvailableApiList(JSONObject replyJson) {
+ List<String> availableApis = new ArrayList<>();
+ int indexOfAvailableApiList = 0;
+ try {
+
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfAvailableApiList)) {
+ JSONObject availableApiListObj = resultsObj.getJSONObject(indexOfAvailableApiList);
+ String type = availableApiListObj.getString("type");
+ if ("availableApiList".equals(type)) {
+ JSONArray apiArray = availableApiListObj.getJSONArray("names");
+ for (int i = 0; i < apiArray.length(); i++) {
+ availableApis.add(apiArray.getString(i));
+ }
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (0: AvailableApiList) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (availableApis);
+ }
+
+ private static String findCameraStatus(JSONObject replyJson)
+ {
+ String cameraStatus = null;
+ int indexOfCameraStatus = 1;
+ try {
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfCameraStatus)) {
+ JSONObject cameraStatusObj = resultsObj.getJSONObject(indexOfCameraStatus);
+ String type = cameraStatusObj.getString("type");
+ if ("cameraStatus".equals(type)) {
+ cameraStatus = cameraStatusObj.getString("cameraStatus");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (1: CameraStatus) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (cameraStatus);
+ }
+
+ private static Boolean findLiveviewStatus(JSONObject replyJson)
+ {
+ Boolean liveviewStatus = null;
+ try {
+ int indexOfLiveviewStatus = 3;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfLiveviewStatus)) {
+ JSONObject liveviewStatusObj = resultsObj.getJSONObject(indexOfLiveviewStatus);
+ String type = liveviewStatusObj.getString("type");
+ if ("liveviewStatus".equals(type)) {
+ liveviewStatus = liveviewStatusObj.getBoolean("liveviewStatus");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (3: LiveviewStatus) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (liveviewStatus);
+ }
+
+
+ private static String findShootMode(JSONObject replyJson)
+ {
+ String shootMode = null;
+ try {
+ int indexOfShootMode = 21;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfShootMode)) {
+ JSONObject shootModeObj = resultsObj.getJSONObject(indexOfShootMode);
+ String type = shootModeObj.getString("type");
+ if ("shootMode".equals(type)) {
+ shootMode = shootModeObj.getString("currentShootMode");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (21: ShootMode) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (shootMode);
+ }
+
+ private static List<String> findAvailableShootModes(JSONObject replyJson)
+ {
+ List<String> shootModes = new ArrayList<>();
+ try {
+ int indexOfShootMode = 21;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfShootMode)) {
+ JSONObject shootModesObj = resultsObj.getJSONObject(indexOfShootMode);
+ String type = shootModesObj.getString("type");
+ if ("shootMode".equals(type)) {
+ JSONArray shootModesArray = shootModesObj.getJSONArray("shootModeCandidates");
+ if (shootModesArray != null) {
+ for (int i = 0; i < shootModesArray.length(); i++) {
+ shootModes.add(shootModesArray.getString(i));
+ }
+ }
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (21: ShootMode) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (shootModes);
+ }
+
+ private static int findZoomInformation(JSONObject replyJson)
+ {
+ int zoomPosition = -1;
+ try {
+ int indexOfZoomInformation = 2;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfZoomInformation)) {
+ JSONObject zoomInformationObj = resultsObj.getJSONObject(indexOfZoomInformation);
+ String type = zoomInformationObj.getString("type");
+ if ("zoomInformation".equals(type)) {
+ zoomPosition = zoomInformationObj.getInt("zoomPosition");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (2: zoomInformation) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (zoomPosition);
+ }
+
+ private static String findStorageId(JSONObject replyJson)
+ {
+ String storageId = null;
+ try {
+ int indexOfStorageInfomation = 10;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfStorageInfomation)) {
+ JSONArray storageInformationArray = resultsObj.getJSONArray(indexOfStorageInfomation);
+ if (!storageInformationArray.isNull(0)) {
+ JSONObject storageInformationObj = storageInformationArray.getJSONObject(0);
+ String type = storageInformationObj.getString("type");
+ if ("storageInformation".equals(type)) {
+ storageId = storageInformationObj.getString("storageID");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (11: storageInformation) " + type);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (storageId);
+ }
+
+ private static String findFocusStatus(JSONObject replyJson)
+ {
+ String focusStatus = null;
+ try {
+ int indexOfFocusStatus= 35;
+ JSONArray resultsObj = replyJson.getJSONArray("result");
+ if (!resultsObj.isNull(indexOfFocusStatus)) {
+ JSONObject focustatusObj = resultsObj.getJSONObject(indexOfFocusStatus);
+ String type = focustatusObj.getString("type");
+ if ("focusStatus".equals(type)) {
+ focusStatus = focustatusObj.getString("focusStatus");
+ } else {
+ Log.w(TAG, "Event reply: Illegal Index (21: ShootMode) " + type);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (focusStatus);
+ }
+
+ @Override
+ public String getCameraStatus()
+ {
+ return (cameraStatus);
+ }
+
+ @Override
+ public boolean getLiveviewStatus()
+ {
+ return (currentLiveviewStatus);
+ }
+
+ @Override
+ public String getShootMode()
+ {
+ return (currentShootMode);
+ }
+
+ @Override
+ public List<String> getAvailableShootModes()
+ {
+ return (currentAvailableShootModes);
+ }
+
+ @Override
+ public int getZoomPosition()
+ {
+ return (currentZoomPosition);
+ }
+
+ @Override
+ public String getStorageId()
+ {
+ return (currentStorageId);
+ }
+
+}
--- /dev/null
+<vector android:height="24dp" android:tint="#323232"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
+</vector>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:id="@+id/info_edit_data"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="6dp"
+ >
+ <LinearLayout
+ android:id="@+id/mode_change_button_area"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="6dp"
+ >
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tag="button"
+ android:id="@+id/change_to_liveview"
+ android:text="@string/dialog_button_liveview"
+ android:layout_gravity="center"
+ android:textSize="6pt" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tag="button"
+ android:id="@+id/change_to_playback"
+ android:text="@string/dialog_button_playback"
+ android:layout_gravity="center"
+ android:textSize="6pt" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/method_name"
+ android:tag="title"
+ android:maxWidth="130dp"
+ android:minWidth="130dp"
+ android:layout_gravity="start">
+ </TextView>
+
+
+ <EditText android:id="@+id/edit_service"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:inputType="text"
+ android:hint="@string/dialog_service_hint"
+ />
+ <EditText android:id="@+id/edit_command"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:inputType="text"
+ android:hint="@string/dialog_command_hint"
+ />
+
+ <EditText android:id="@+id/edit_parameter"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:inputType="text"
+ android:hint="@string/dialog_parameter_hint"
+ />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tag="button"
+ android:id="@+id/send_message_button"
+ android:text="@string/dialog_send_message"
+ android:layout_gravity="center"
+ android:textSize="6pt" />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="2dp"
+ android:background="@android:color/darker_gray"/>
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/panasonic_command_response_value"
+ android:text="@string/blank"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="2dp"
+ android:background="@android:color/darker_gray"/>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/info_edit_data"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="6dp"
+ >
+
+ <Spinner
+ android:id="@+id/spinner_selection_service"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/blank"
+ android:visibility="visible" />
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/method_name"
+ android:tag="title"
+ android:maxWidth="130dp"
+ android:minWidth="130dp"
+ android:layout_gravity="start">
+ </TextView>
+
+ <EditText android:id="@+id/edit_parameter"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:inputType="text"
+ android:hint="@string/dialog_parameter_hint"
+ />
+
+ <EditText android:id="@+id/edit_version"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:inputType="text"
+ android:hint="@string/dialog_version_hint"
+ />
+ </LinearLayout>
+ </ScrollView>
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:compat="http://schemas.android.com/apk/res-auto" >
+
+ <item
+ android:id="@+id/action_share"
+ compat:showAsAction="always"
+ android:icon="@drawable/ic_share_black_24dp"
+ android:title="@string/action_share"
+ android:visible="true" />
+ <item
+ android:id="@+id/action_refresh"
+ compat:showAsAction="ifRoom"
+ android:icon="@drawable/ic_refresh_black_24dp"
+ android:title="@string/action_refresh"
+ android:visible="true" />
+
+</menu>
<string name="dialog_confirm_message_output_log">ログを共有します。</string>
<string name="dialog_message_power_off">カメラの電源を切り、アプリケーションを終了します。</string>
+ <string name="dialog_message_exit_application">アプリケーションを終了します。</string>
+
<string name="camera_disconnected">カメラ切断</string>
<string name="only_opc_feature">この機能はOlympus Air専用です。</string>
<string name="connect_connecting11">接続中…(11/12)</string>
<string name="connect_connecting12">接続中…(12/12)</string>
<string name="connect_connect_finished">カメラと接続</string>
+
+ <string name="dialog_panasonic_command_title_command">メッセージ送信(Panasonic)</string>
+ <string name="panasonic_service_string">cam.cgi</string>
+
+ <string name="camera_search_request">カメラ検索</string>
+ <string name="camera_wait_reply">応答待ち</string>
+ <string name="camera_received_reply">応答受信</string>
+ <string name="camera_found">発見 : </string>
+ <string name="camera_rejected">接続に失敗…</string>
+ <string name="camera_detected">発見 : </string>
+ <string name="pref_sony_api_list">カメラAPI一覧</string>
+ <string name="dialog_title_reply">応答</string>
+ <string name="dialog_parameter_hint">(parameter)</string>
+ <string name="dialog_version_hint">1.0</string>
+ <string name="dialog_command_hint">(command)</string>
+ <string name="dialog_service_hint">(service)</string>
+ <string name="action_share">共有</string>
+
+
+
</resources>
<string name="dialog_confirm_message_output_log">Share the debug log, OK?</string>
<string name="dialog_message_power_off">Power Off</string>
+ <string name="dialog_message_exit_application">Exit Application</string>
<string name="camera_disconnected">Disconnected</string>
<string name="only_opc_feature">This feature is only available for a OPC Camera.</string>
<string name="connect_connecting11">Connecting…(11/12)</string>
<string name="connect_connecting12">Connecting…(12/12)</string>
<string name="connect_connect_finished">Connect Finished.</string>
+
+ <string name="dialog_panasonic_command_title_command">Send Message(Panasonic)</string>
+ <string name="panasonic_service_string">cam.cgi</string>
+
+ <string name="camera_search_request">Search Camera</string>
+ <string name="camera_wait_reply">Wait Reply</string>
+ <string name="camera_received_reply">Received.</string>
+ <string name="camera_found">Found : </string>
+ <string name="camera_rejected">Rejected…</string>
+ <string name="camera_detected">Detected : </string>
+
+ <string name="pref_sony_api_list">Sony Camera Api List</string>
+ <string name="dialog_title_reply">Reply</string>
+ <string name="dialog_parameter_hint">(parameter)</string>
+ <string name="dialog_version_hint">1.0</string>
+ <string name="dialog_command_hint">(command)</string>
+ <string name="dialog_service_hint">(service)</string>
+ <string name="action_share">Share</string>
+
</resources>