android {
compileSdkVersion 29
- buildToolsVersion '29.0.1'
defaultConfig {
applicationId "net.osdn.gokigen.a01d"
minSdkVersion 14
targetSdkVersion 29
- versionCode 10304
- versionName "1.3.4"
+ versionCode 10400
+ versionName "1.4.0"
}
buildTypes {
release {
package net.osdn.gokigen.a01d;
-import android.Manifest;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import net.osdn.gokigen.a01d.camera.CameraInterfaceProvider;
-import net.osdn.gokigen.a01d.camera.IInterfaceProvider;
-import net.osdn.gokigen.a01d.camera.fujix.cameraproperty.FujiXCameraCommandSendDialog;
-import net.osdn.gokigen.a01d.camera.fujix.cameraproperty.FujiXCameraStatusDialog;
-import net.osdn.gokigen.a01d.camera.olympus.cameraproperty.OlyCameraPropertyListFragment;
-import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
-import net.osdn.gokigen.a01d.camera.ICameraConnection;
-import net.osdn.gokigen.a01d.camera.olympus.wrapper.connection.ble.ICameraPowerOn;
-import net.osdn.gokigen.a01d.camera.sony.cameraproperty.SonyCameraApiListFragment;
-import net.osdn.gokigen.a01d.liveview.IStatusViewDrawer;
-import net.osdn.gokigen.a01d.liveview.LiveViewFragment;
-import net.osdn.gokigen.a01d.logcat.LogCatFragment;
-import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor;
-import net.osdn.gokigen.a01d.preference.fujix.FujiXPreferenceFragment;
-import net.osdn.gokigen.a01d.preference.olympus.PreferenceFragment;
-import net.osdn.gokigen.a01d.preference.ricohgr2.RicohGr2PreferenceFragment;
-import net.osdn.gokigen.a01d.preference.sony.SonyPreferenceFragment;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceManager;
+ import android.Manifest;
+ import android.content.SharedPreferences;
+ import android.content.pm.PackageManager;
+ import android.os.Bundle;
+ import android.util.Log;
+ import android.view.WindowManager;
+ import android.widget.Toast;
+
+ import net.osdn.gokigen.a01d.camera.CameraInterfaceProvider;
+ import net.osdn.gokigen.a01d.camera.IInterfaceProvider;
+ import net.osdn.gokigen.a01d.camera.fujix.cameraproperty.FujiXCameraCommandSendDialog;
+ import net.osdn.gokigen.a01d.camera.olympus.cameraproperty.OlyCameraPropertyListFragment;
+ import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+ import net.osdn.gokigen.a01d.camera.ICameraConnection;
+ import net.osdn.gokigen.a01d.camera.olympus.wrapper.connection.ble.ICameraPowerOn;
+ import net.osdn.gokigen.a01d.camera.sony.cameraproperty.SonyCameraApiListFragment;
+ import net.osdn.gokigen.a01d.liveview.IStatusViewDrawer;
+ import net.osdn.gokigen.a01d.liveview.LiveViewFragment;
+ import net.osdn.gokigen.a01d.logcat.LogCatFragment;
+ import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor;
+ import net.osdn.gokigen.a01d.preference.fujix.FujiXPreferenceFragment;
+ import net.osdn.gokigen.a01d.preference.olympus.PreferenceFragment;
+ import net.osdn.gokigen.a01d.preference.panasonic.PanasonicPreferenceFragment;
+ import net.osdn.gokigen.a01d.preference.ricohgr2.RicohGr2PreferenceFragment;
+ import net.osdn.gokigen.a01d.preference.sony.SonyPreferenceFragment;
+
+ import androidx.annotation.NonNull;
+ import androidx.appcompat.app.ActionBar;
+ import androidx.appcompat.app.AppCompatActivity;
+ import androidx.core.app.ActivityCompat;
+ import androidx.core.content.ContextCompat;
+ import androidx.fragment.app.FragmentTransaction;
+ import androidx.preference.PreferenceFragmentCompat;
+ import androidx.preference.PreferenceManager;
/**
* A01d ;
}
else if (method == ICameraConnection.CameraConnectionMethod.SONY)
{
+ // SONYの場合は、API一覧画面へ遷移させる
+ changeSceneToApiList();
+ }
+ else if (method == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
// OPCカメラでない場合には、「OPCカメラのみ有効です」表示をして画面遷移させない
Toast.makeText(getApplicationContext(), getText(R.string.only_opc_feature), Toast.LENGTH_SHORT).show();
}
preferenceFragment = RicohGr2PreferenceFragment.newInstance(this, this);
} else if (connectionMethod == ICameraConnection.CameraConnectionMethod.SONY) {
preferenceFragment = SonyPreferenceFragment.newInstance(this, this);
+ } else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC) {
+ preferenceFragment = PanasonicPreferenceFragment.newInstance(this, this);
} else if (connectionMethod == ICameraConnection.CameraConnectionMethod.FUJI_X) {
preferenceFragment = FujiXPreferenceFragment.newInstance(this, this);
} else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
{
connection = interfaceProvider.getSonyInterface().getSonyCameraConnection();
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ connection = interfaceProvider.getPanasonicInterface().getPanasonicCameraConnection();
+ }
else if (connectionMethod == ICameraConnection.CameraConnectionMethod.FUJI_X)
{
connection = interfaceProvider.getFujiXInterface().getFujiXCameraConnection();
import net.osdn.gokigen.a01d.camera.olympus.wrapper.IOlympusLiveViewListener;
import net.osdn.gokigen.a01d.camera.olympus.IOlympusInterfaceProvider;
import net.osdn.gokigen.a01d.camera.olympus.wrapper.OlympusInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.panasonic.IPanasonicInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.PanasonicCameraWrapper;
import net.osdn.gokigen.a01d.camera.ricohgr2.IRicohGr2InterfaceProvider;
import net.osdn.gokigen.a01d.camera.ricohgr2.wrapper.RicohGr2InterfaceProvider;
import net.osdn.gokigen.a01d.camera.sony.ISonyInterfaceProvider;
private final SonyCameraWrapper sony;
private final RicohGr2InterfaceProvider ricohGr2;
private final FujiXInterfaceProvider fujiX;
+ private final PanasonicCameraWrapper panasonic;
private final CameraStatusListener statusListener;
public CameraInterfaceProvider(@NonNull Activity context, @NonNull ICameraStatusReceiver provider)
olympus = new OlympusInterfaceProvider(context, provider);
sony = new SonyCameraWrapper(context, provider, statusListener);
fujiX = new FujiXInterfaceProvider(context, provider, statusListener);
+ panasonic = new PanasonicCameraWrapper(context, provider, statusListener);
ricohGr2 = new RicohGr2InterfaceProvider(context, provider);
}
return (fujiX);
}
+ @Override
+ public IPanasonicInterfaceProvider getPanasonicInterface()
+ {
+ return (panasonic);
+ }
+
/**
* OPCカメラを使用するかどうか
*
{
ret = ICameraConnection.CameraConnectionMethod.FUJI_X;
}
+ else if (connectionMethod.contains("PANASONIC"))
+ {
+ ret = ICameraConnection.CameraConnectionMethod.PANASONIC;
+ }
}
catch (Exception e)
{
-package net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener;
+package net.osdn.gokigen.a01d.camera;
import java.util.List;
SONY,
RICOH_GR2,
FUJI_X,
+ PANASONIC,
}
enum CameraConnectionStatus
import net.osdn.gokigen.a01d.camera.fujix.IFujiXInterfaceProvider;
import net.osdn.gokigen.a01d.camera.olympus.wrapper.IOlympusLiveViewListener;
import net.osdn.gokigen.a01d.camera.olympus.IOlympusInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.panasonic.IPanasonicInterfaceProvider;
import net.osdn.gokigen.a01d.camera.ricohgr2.IRicohGr2InterfaceProvider;
import net.osdn.gokigen.a01d.camera.sony.ISonyInterfaceProvider;
import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
ISonyInterfaceProvider getSonyInterface();
IRicohGr2InterfaceProvider getRicohGr2Infterface();
IFujiXInterfaceProvider getFujiXInterface();
+ IPanasonicInterfaceProvider getPanasonicInterface();
void setUpdateReceiver(@NonNull ICameraStatusUpdateNotify receiver);
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic;
+
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraInformation;
+import net.osdn.gokigen.a01d.camera.ICaptureControl;
+import net.osdn.gokigen.a01d.camera.IFocusingControl;
+import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+import net.osdn.gokigen.a01d.camera.IZoomLensControl;
+import net.osdn.gokigen.a01d.camera.IDisplayInjector;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
+
+import java.util.List;
+
+public interface IPanasonicInterfaceProvider
+{
+ ICameraConnection getPanasonicCameraConnection();
+ ILiveViewControl getPanasonicLiveViewControl();
+ ILiveViewListener getLiveViewListener();
+ IFocusingControl getFocusingControl();
+ ICameraInformation getCameraInformation();
+ IZoomLensControl getZoomLensControl();
+ ICaptureControl getCaptureControl();
+ IDisplayInjector getDisplayInjector();
+ List<String> getApiCommands();
+ IPanasonicCameraApi getCameraApi();
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.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 net.osdn.gokigen.a01d.ConfirmationDialog;
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.IInterfaceProvider;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+
+
+public class PanasonicCameraApiListFragment 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 PanasonicCameraApiListFragment newInstance(@NonNull IInterfaceProvider interfaceProvider)
+ {
+ PanasonicCameraApiListFragment instance = new PanasonicCameraApiListFragment();
+ 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_panasonic_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_panasonic_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.getPanasonicInterface().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.a01d.camera.panasonic.cameraproperty;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.IChangeScene;
+
+import androidx.preference.Preference;
+
+/**
+ *
+ *
+ */
+public class PanasonicCameraApiListViewer implements Preference.OnPreferenceClickListener
+{
+ private final String TAG = toString();
+ private final IChangeScene changeScene;
+
+ /**
+ *
+ *
+ */
+ public PanasonicCameraApiListViewer(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("panasonic_api_list"))&&(changeScene != null))
+ {
+ try
+ {
+ // API Listを表示する
+ changeScene.changeSceneToApiList();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (true);
+ }
+ return (false);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.cameraproperty;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+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 net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+
+/**
+ *
+ *
+ */
+public class SendRequestDialog extends DialogFragment
+{
+ private final String TAG = toString();
+ private IPanasonicCameraApi cameraApi;
+ private String method = "";
+ private int selectedPosition = 0;
+ private SendRequestDialog.Callback callback = null;
+ Dialog myDialog = null;
+
+ /**
+ *
+ *
+ */
+ public static SendRequestDialog newInstance(@NonNull IPanasonicCameraApi 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 IPanasonicCameraApi 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.getPanasonicApiServiceList());
+
+ 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.a01d.camera.panasonic.operation;
+
+import android.content.Context;
+import net.osdn.gokigen.a01d.ConfirmationDialog;
+import net.osdn.gokigen.a01d.IChangeScene;
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor;
+
+import androidx.preference.Preference;
+
+
+/**
+ * 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.a01d.camera.panasonic.operation;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.ICaptureControl;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.takepicture.SingleShotControl;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+import androidx.annotation.NonNull;
+
+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 setCameraApi(@NonNull IPanasonicCameraApi panasonicCameraApi)
+ {
+ singleShotControl.setCameraApi(panasonicCameraApi);
+ }
+
+ /**
+ * 撮影する
+ *
+ */
+ @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.a01d.camera.panasonic.operation;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import net.osdn.gokigen.a01d.camera.IFocusingControl;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.takepicture.PanasonicAutoFocusControl;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+import androidx.annotation.NonNull;
+
+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 setCameraApi(@NonNull IPanasonicCameraApi panasonicCameraApi)
+ {
+ afControl.setCameraApi(panasonicCameraApi);
+ }
+
+ @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.a01d.camera.panasonic.operation;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.IZoomLensControl;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.camera.sony.wrapper.ISonyCameraApi;
+
+import org.json.JSONObject;
+
+import androidx.annotation.NonNull;
+
+public class PanasonicCameraZoomLensControl implements IZoomLensControl
+{
+ private final String TAG = toString();
+ private IPanasonicCameraApi cameraApi = null;
+
+ public PanasonicCameraZoomLensControl()
+ {
+ Log.v(TAG, "SonyCameraZoomLensControl()");
+ }
+
+ public void setCameraApi(@NonNull IPanasonicCameraApi panasonicCameraApi)
+ {
+ cameraApi = panasonicCameraApi;
+ }
+
+ @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, "IPanasonicCameraApi 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.a01d.camera.panasonic.operation.takepicture;
+
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import androidx.annotation.NonNull;
+
+
+/**
+ *
+ *
+ */
+public class PanasonicAutoFocusControl
+{
+ private static final String TAG = PanasonicAutoFocusControl.class.getSimpleName();
+ private final IIndicatorControl indicator;
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private IPanasonicCameraApi cameraApi = null;
+
+ /**
+ *
+ *
+ */
+ public PanasonicAutoFocusControl(@NonNull final IAutoFocusFrameDisplay frameDisplayer, final IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCameraApi(@NonNull IPanasonicCameraApi panasonicCameraApi)
+ {
+ this.cameraApi = panasonicCameraApi;
+ }
+
+ /**
+ *
+ *
+ */
+ 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.a01d.camera.panasonic.operation.takepicture;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+
+import org.json.JSONObject;
+
+import androidx.annotation.NonNull;
+
+public class SingleShotControl
+{
+ private static final String TAG = SingleShotControl.class.getSimpleName();
+ private final IAutoFocusFrameDisplay frameDisplayer;
+ private final IIndicatorControl indicator;
+ private IPanasonicCameraApi cameraApi = null;
+
+ /**
+ *
+ *
+ */
+ public SingleShotControl(@NonNull IAutoFocusFrameDisplay frameDisplayer, @NonNull IIndicatorControl indicator)
+ {
+ this.frameDisplayer = frameDisplayer;
+ this.indicator = indicator;
+ }
+
+ /**
+ *
+ *
+ */
+ public void setCameraApi(@NonNull IPanasonicCameraApi panasonicCameraApi)
+ {
+ this.cameraApi = panasonicCameraApi;
+ }
+
+ /**
+ *
+ *
+ */
+ 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.a01d.camera.panasonic.wrapper;
+
+public interface IPanasonicApiService
+{
+ String getName();
+ String getActionUrl();
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.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();
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.wrapper;
+
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public interface IPanasonicCameraApi
+{
+ /**/
+ 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> getPanasonicApiServiceList();
+ JSONObject callGenericSonyApiMethod(@NonNull String service, @NonNull String method, @NonNull JSONArray params, @NonNull String version);
+/**/
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.wrapper;
+
+
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+
+public interface IPanasonicCameraHolder
+{
+ void detectedCamera(@NonNull IPanasonicCamera camera);
+ void prepare();
+ void startRecMode();
+ void startEventWatch(@Nullable ICameraChangeListener listener);
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.wrapper;
+
+class PanasonicApiService implements IPanasonicApiService
+{
+ private final String name;
+ private final String actionUrl;
+
+ PanasonicApiService(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.a01d.camera.panasonic.wrapper;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.utils.SimpleHttpClient;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+class PanasonicCameraApi implements IPanasonicCameraApi
+{
+ private static final String TAG = PanasonicCameraApi.class.getSimpleName();
+ private static final boolean FULL_LOG = true;
+
+ // API server device you want to send requests.
+ private final IPanasonicCamera panasonicCamera;
+ private int requestId;
+
+
+ public static IPanasonicCameraApi newInstance(@NonNull IPanasonicCamera target)
+ {
+ return (new PanasonicCameraApi(target));
+ }
+
+ private PanasonicCameraApi(final @NonNull IPanasonicCamera target)
+ {
+ panasonicCamera = target;
+ requestId = 1;
+ }
+
+ private String findActionListUrl(String service)
+ {
+ List<IPanasonicApiService> services = panasonicCamera.getApiServices();
+ for (IPanasonicApiService 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> getPanasonicApiServiceList()
+ {
+ try
+ {
+ List<String> serviceList = new ArrayList<>();
+ List<IPanasonicApiService> services = panasonicCamera.getApiServices();
+ for (IPanasonicApiService 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.a01d.camera.panasonic.wrapper;
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.utils.SimpleHttpClient;
+import net.osdn.gokigen.a01d.camera.utils.XmlElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+/**
+ *
+ *
+ */
+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;
+
+ /**
+ * コンストラクタ: 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 + "]");
+
+ 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/");
+ }
+
+/*
+ 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.a01d.camera.panasonic.wrapper;
+
+import android.app.Activity;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraInformation;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.ICaptureControl;
+import net.osdn.gokigen.a01d.camera.IDisplayInjector;
+import net.osdn.gokigen.a01d.camera.IFocusingControl;
+import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+import net.osdn.gokigen.a01d.camera.IZoomLensControl;
+import net.osdn.gokigen.a01d.camera.IFocusingModeNotify;
+import net.osdn.gokigen.a01d.camera.panasonic.IPanasonicInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.PanasonicCameraCaptureControl;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.PanasonicCameraFocusControl;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.PanasonicCameraZoomLensControl;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.connection.PanasonicCameraConnection;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.eventlistener.CameraEventObserver;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.eventlistener.ICameraEventObserver;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.eventlistener.ICameraStatusHolder;
+import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
+import net.osdn.gokigen.a01d.liveview.IIndicatorControl;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class PanasonicCameraWrapper implements IPanasonicCameraHolder, IPanasonicInterfaceProvider, IDisplayInjector
+{
+ private final String TAG = toString();
+ private final Activity context;
+ 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;
+
+ 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);
+ eventObserver = CameraEventObserver.newInstance(context, panasonicCameraApi);
+ liveViewControl = new PanasonicLiveViewControl(panasonicCameraApi);
+
+ focusControl.setCameraApi(panasonicCameraApi);
+ captureControl.setCameraApi(panasonicCameraApi);
+ zoomControl.setCameraApi(panasonicCameraApi);
+ }
+ 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'.");
+ panasonicCameraApi.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 IPanasonicCamera camera)
+ {
+ Log.v(TAG, "detectedCamera()");
+ panasonicCamera = camera;
+ }
+
+ @Override
+ public ICameraConnection getPanasonicCameraConnection()
+ {
+ return (new PanasonicCameraConnection(context, provider, this, listener));
+ }
+
+ @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 List<String> getApiCommands()
+ {
+ List<String> availableApis = new ArrayList<>();
+ try
+ {
+ String apiList = panasonicCameraApi.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 IPanasonicCameraApi getCameraApi()
+ {
+ return (panasonicCameraApi);
+ }
+
+ @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.a01d.camera.panasonic.wrapper;
+
+
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.ILiveViewControl;
+import net.osdn.gokigen.a01d.camera.utils.SimpleLiveviewSlicer;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
+import net.osdn.gokigen.a01d.liveview.liveviewlistener.CameraLiveViewListenerImpl;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import androidx.annotation.NonNull;
+
+public class PanasonicLiveViewControl implements ILiveViewControl
+{
+ private final String TAG = toString();
+ private final IPanasonicCameraApi 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;
+
+ PanasonicLiveViewControl(@NonNull IPanasonicCameraApi cameraApi)
+ {
+ this.cameraApi = cameraApi;
+ liveViewListener = new CameraLiveViewListenerImpl();
+ }
+
+ @Override
+ public void changeLiveViewSize(String size)
+ {
+
+ }
+
+ @Override
+ public void startLiveView()
+ {
+ Log.v(TAG, "startLiveView()");
+ try
+ {
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ JSONObject replyJson;
+ replyJson = cameraApi.startLiveview();
+ if (!PanasonicCameraApi.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.a01d.camera.panasonic.wrapper.connection;
+
+import android.app.Activity;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCamera;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraHolder;
+
+import androidx.annotation.NonNull;
+
+
+/**
+ * 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, "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.a01d.camera.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 net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraHolder;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+/**
+ *
+ *
+ */
+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 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.a01d.camera.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.a01d.camera.panasonic.wrapper.connection;
+
+import android.content.Context;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCamera;
+import net.osdn.gokigen.a01d.camera.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;
+
+import androidx.annotation.NonNull;
+
+/**
+ * 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 = 10 * 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());
+ 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(IPanasonicCamera cameraDevice); // デバイスが見つかった!
+ void onFinished(); // 通常の終了をしたとき
+ void onErrorFinished(String reason); // エラーが発生して応答したとき
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.panasonic.wrapper.eventlistener;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.panasonic.wrapper.IPanasonicCameraApi;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import androidx.annotation.NonNull;
+
+/**
+ *
+ *
+ */
+public class CameraEventObserver implements ICameraEventObserver
+{
+ private static final String TAG = CameraEventObserver.class.getSimpleName();
+ private boolean isEventMonitoring;
+ private boolean isActive;
+
+ private final IPanasonicCameraApi remoteApi;
+ private final ReplyJsonParser replyParser;
+ private String eventVersion = "1.1"; // 初期値を "1.0" から "1.1" に更新
+
+ public static ICameraEventObserver newInstance(@NonNull Context context, @NonNull IPanasonicCameraApi apiClient)
+ {
+ return (new CameraEventObserver(context, apiClient));
+ }
+
+ private CameraEventObserver(@NonNull Context context, @NonNull IPanasonicCameraApi 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.a01d.camera.panasonic.wrapper.eventlistener;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.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.a01d.camera.panasonic.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.a01d.camera.panasonic.wrapper.eventlistener;
+
+import android.os.Handler;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+
+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);
+ }
+
+}
package net.osdn.gokigen.a01d.camera.sony.wrapper;
-import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
private final String iconUrl;
/**
- * コンストラクタ: staticメソッド searchSonyCameraDevice() で生成する
+ * コンストラクタ: staticメソッド searchPanasonicCameraDevice() で生成する
*
*/
private SonyCameraDeviceProvider(String ddUrl, String friendlyName, String modelName, String udn, String iconUrl)
import net.osdn.gokigen.a01d.camera.sony.operation.SonyCameraZoomLensControl;
import net.osdn.gokigen.a01d.camera.sony.wrapper.connection.SonyCameraConnection;
import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.CameraEventObserver;
-import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraEventObserver;
import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraStatusHolder;
import net.osdn.gokigen.a01d.liveview.IAutoFocusFrameDisplay;
import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
import net.osdn.gokigen.a01d.camera.sony.wrapper.ISonyCamera;
import net.osdn.gokigen.a01d.camera.sony.wrapper.ISonyCameraHolder;
-import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.CameraChangeListerTemplate;
-import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
import androidx.annotation.NonNull;
import net.osdn.gokigen.a01d.camera.ICameraConnection;
import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
import net.osdn.gokigen.a01d.camera.sony.wrapper.ISonyCameraHolder;
-import net.osdn.gokigen.a01d.camera.sony.wrapper.eventlistener.ICameraChangeListener;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import android.util.Log;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+
import java.util.List;
public class CameraChangeListerTemplate implements ICameraChangeListener
import android.os.Handler;
import android.util.Log;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
import net.osdn.gokigen.a01d.camera.sony.wrapper.ISonyCameraApi;
import org.json.JSONArray;
import androidx.annotation.NonNull;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+
public interface ICameraEventObserver
{
void activate();
import androidx.annotation.NonNull;
+import net.osdn.gokigen.a01d.camera.ICameraChangeListener;
+
public class ReplyJsonParser implements ICameraStatusHolder
{
private static final String TAG = ReplyJsonParser.class.getSimpleName();
this.cameraConnection = interfaceProvider.getFujiXInterface().getFujiXCameraConnection();
this.zoomLensControl = interfaceProvider.getFujiXInterface().getZoomLensControl();
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ this.focusingControl = interfaceProvider.getPanasonicInterface().getFocusingControl();
+ this.captureControl = interfaceProvider.getPanasonicInterface().getCaptureControl();
+ this.propertyProvider = interfaceProvider.getOlympusInterface().getCameraPropertyProvider(); // 要変更
+ this.cameraInformation = interfaceProvider.getPanasonicInterface().getCameraInformation();
+ this.cameraConnection = interfaceProvider.getPanasonicInterface().getPanasonicCameraConnection();
+ this.zoomLensControl = interfaceProvider.getPanasonicInterface().getZoomLensControl();
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
{
this.focusingControl = interfaceProvider.getOlympusInterface().getFocusingControl();
{
manualFocus.setVisibility(View.INVISIBLE);
}
- propertyButton.setVisibility(View.INVISIBLE);
+ propertyButton.setVisibility(View.VISIBLE); // 押すとAPI一覧に遷移
}
});
}
focusIndicator.setVisibility(View.INVISIBLE);
}
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ if ((favoriteButton != null)&&(manualFocus != null))
+ {
+ runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ favoriteButton.setVisibility(View.INVISIBLE);
+ if (manualFocus != null)
+ {
+ manualFocus.setVisibility(View.INVISIBLE);
+ }
+ propertyButton.setVisibility(View.INVISIBLE); // 押すとAPI一覧に遷移
+ }
+ });
+ }
+ if (changeLiveViewScale != null)
+ {
+ changeLiveViewScale.setVisibility(View.INVISIBLE);
+ }
+ if (focusIndicator != null)
+ {
+ focusIndicator.setVisibility(View.VISIBLE);
+ }
+ }
else if (connectionMethod == ICameraConnection.CameraConnectionMethod.FUJI_X)
{
if (favoriteButton != null)
{
interfaceInjector = interfaceProvider.getFujiXInterface().getDisplayInjector();
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ interfaceInjector = interfaceProvider.getPanasonicInterface().getDisplayInjector();
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
{
interfaceInjector = interfaceProvider.getOlympusInterface().getDisplayInjector();
this.zoomLensControl = interfaceProvider.getFujiXInterface().getZoomLensControl();
this.cameraInformation = interfaceProvider.getFujiXInterface().getCameraInformation();
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ this.liveViewControl = interfaceProvider.getPanasonicInterface().getPanasonicLiveViewControl();
+ this.zoomLensControl = interfaceProvider.getPanasonicInterface().getZoomLensControl();
+ this.cameraInformation = interfaceProvider.getPanasonicInterface().getCameraInformation();
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
{
this.liveViewControl = interfaceProvider.getOlympusInterface().getLiveViewControl();
{
lvListener = interfaceProvider.getFujiXInterface().getLiveViewListener();
}
+ else if (connectionMethod == ICameraConnection.CameraConnectionMethod.PANASONIC)
+ {
+ lvListener = interfaceProvider.getPanasonicInterface().getLiveViewListener();
+ }
else // if (connectionMethod == ICameraConnection.CameraConnectionMethod.OPC)
{
interfaceProvider.getOlympusLiveViewListener().setOlympusLiveViewListener(liveViewListener);
--- /dev/null
+package net.osdn.gokigen.a01d.preference.panasonic;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+
+import net.osdn.gokigen.a01d.IChangeScene;
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.panasonic.cameraproperty.PanasonicCameraApiListViewer;
+import net.osdn.gokigen.a01d.camera.panasonic.operation.CameraPowerOffPanasonic;
+import net.osdn.gokigen.a01d.logcat.LogCatViewer;
+import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor;
+
+import java.util.Map;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceManager;
+
+/**
+ *
+ *
+ */
+public class PanasonicPreferenceFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener
+{
+ private final String TAG = toString();
+ private SharedPreferences preferences = null;
+ private CameraPowerOffPanasonic powerOffController = null;
+ private LogCatViewer logCatViewer = null;
+ private PanasonicCameraApiListViewer cameraApiListViewer = null;
+
+ /**
+ *
+ *
+ */
+ public static PanasonicPreferenceFragment newInstance(@NonNull AppCompatActivity context, @NonNull IChangeScene changeScene)
+ {
+ PanasonicPreferenceFragment instance = new PanasonicPreferenceFragment();
+ instance.prepare(context, changeScene);
+
+ // パラメータはBundleにまとめておく
+ Bundle arguments = new Bundle();
+ //arguments.putString("title", title);
+ //arguments.putString("message", message);
+ instance.setArguments(arguments);
+
+ return (instance);
+ }
+
+ /**
+ *
+ *
+ */
+ private void prepare(@NonNull AppCompatActivity context, @NonNull IChangeScene changeScene)
+ {
+ try
+ {
+ powerOffController = new CameraPowerOffPanasonic(context, changeScene);
+ powerOffController.prepare();
+
+ logCatViewer = new LogCatViewer(changeScene);
+ logCatViewer.prepare();
+
+ cameraApiListViewer = new PanasonicCameraApiListViewer(changeScene);
+ cameraApiListViewer.prepare();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void onAttach(Context activity)
+ {
+ super.onAttach(activity);
+ Log.v(TAG, "onAttach()");
+
+ try
+ {
+ // Preference をつかまえる
+ preferences = PreferenceManager.getDefaultSharedPreferences(activity);
+
+ // Preference を初期設定する
+ initializePreferences();
+
+ preferences.registerOnSharedPreferenceChangeListener(this);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Preferenceの初期化...
+ *
+ */
+ private void initializePreferences()
+ {
+ try
+ {
+ Map<String, ?> items = preferences.getAll();
+ SharedPreferences.Editor editor = preferences.edit();
+
+ if (!items.containsKey(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA)) {
+ editor.putBoolean(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, true);
+ }
+ if (!items.containsKey(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW)) {
+ editor.putBoolean(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, true);
+ }
+ if (!items.containsKey(IPreferencePropertyAccessor.CONNECTION_METHOD)) {
+ editor.putString(IPreferencePropertyAccessor.CONNECTION_METHOD, IPreferencePropertyAccessor.CONNECTION_METHOD_DEFAULT_VALUE);
+ }
+ editor.apply();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
+ {
+ Log.v(TAG, "onSharedPreferenceChanged() : " + key);
+ boolean value;
+ if (key != null)
+ {
+ switch (key)
+ {
+ case IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA:
+ value = preferences.getBoolean(key, true);
+ Log.v(TAG, " " + key + " , " + value);
+ break;
+
+ case IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW:
+ value = preferences.getBoolean(key, true);
+ Log.v(TAG, " " + key + " , " + value);
+ break;
+
+ default:
+ String strValue = preferences.getString(key, "");
+ setListPreference(key, key, strValue);
+ break;
+ }
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
+ {
+ Log.v(TAG, "onCreatePreferences()");
+ try
+ {
+ //super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences_sony);
+
+ ListPreference connectionMethod = (ListPreference) findPreference(IPreferencePropertyAccessor.CONNECTION_METHOD);
+ connectionMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ preference.setSummary(newValue + " ");
+ return (true);
+ }
+ });
+ connectionMethod.setSummary(connectionMethod.getValue() + " ");
+
+ findPreference("exit_application").setOnPreferenceClickListener(powerOffController);
+ findPreference("debug_info").setOnPreferenceClickListener(logCatViewer);
+ findPreference("panasonic_api_list").setOnPreferenceClickListener(cameraApiListViewer);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ Log.v(TAG, "onResume() Start");
+
+ try
+ {
+ synchronizedProperty();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ Log.v(TAG, "onResume() End");
+
+ }
+
+ /**
+ *
+ *
+ */
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ Log.v(TAG, "onPause() Start");
+
+ try
+ {
+ // Preference変更のリスナを解除
+ preferences.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ Log.v(TAG, "onPause() End");
+ }
+
+ /**
+ * ListPreference の表示データを設定
+ *
+ * @param pref_key Preference(表示)のキー
+ * @param key Preference(データ)のキー
+ * @param defaultValue Preferenceのデフォルト値
+ */
+ private void setListPreference(String pref_key, String key, String defaultValue)
+ {
+ try
+ {
+ ListPreference pref;
+ pref = (ListPreference) findPreference(pref_key);
+ String value = preferences.getString(key, defaultValue);
+ if (pref != null)
+ {
+ pref.setValue(value);
+ pref.setSummary(value);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * BooleanPreference の表示データを設定
+ *
+ * @param pref_key Preference(表示)のキー
+ * @param key Preference(データ)のキー
+ * @param defaultValue Preferenceのデフォルト値
+ */
+ private void setBooleanPreference(String pref_key, String key, boolean defaultValue)
+ {
+ try
+ {
+ CheckBoxPreference pref = (CheckBoxPreference) findPreference(pref_key);
+ if (pref != null) {
+ boolean value = preferences.getBoolean(key, defaultValue);
+ pref.setChecked(value);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ private void synchronizedProperty()
+ {
+ final FragmentActivity activity = getActivity();
+ final boolean defaultValue = true;
+ if (activity != null)
+ {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try
+ {
+ // Preferenceの画面に反映させる
+ setBooleanPreference(IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, IPreferencePropertyAccessor.AUTO_CONNECT_TO_CAMERA, defaultValue);
+ setBooleanPreference(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, defaultValue);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+
+}
<item >Sony</item>
<item>Ricoh GR II / PENTAX DSLR</item>
<item >Fuji X Series</item>
+ <item >Panasonic</item>
</string-array>
<string-array name="connection_method_value">
<item >SONY</item>
<item >RICOH_GR2</item>
<item >FUJI_X</item>
+ <item >PANASONIC</item>
</string-array>
<item >3</item>
</string-array>
-
</resources>
<string name="pref_sony_api_list">カメラAPI一覧</string>
<string name="pref_summary_sony_api_list">カメラのAPI一覧を表示します。</string>
+ <string name="pref_panasonic_api_list">カメラAPI一覧</string>
+ <string name="pref_summary_panasonic_api_list">カメラのAPI一覧を表示します。</string>
+
<string name="dialog_parameter_hint">(parameter)</string>
<string name="dialog_version_hint">1.0</string>
<string name="dialog_title_reply">応答</string>
<item >Sony</item>
<item>Ricoh GR II / PENTAX DSLR</item>
<item >Fuji X Series</item>
+ <item >Panasonic</item>
</string-array>
<string-array name="connection_method_value">
<item >SONY</item>
<item >RICOH_GR2</item>
<item >FUJI_X</item>
+ <item >PANASONIC</item>
</string-array>
<string-array name="gr2_display_mode">
<string name="action_share">Share</string>
<string name="finish_refresh">Finished Refresh</string>
+ <string name="pref_panasonic_api_list">Panasonic Camera Api List</string>
+ <string name="pref_summary_panasonic_api_list">Show available camera apis.</string>
+
<string name="pref_sony_api_list">Sony Camera Api List</string>
<string name="pref_summary_sony_api_list">Show available camera apis.</string>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
+ <PreferenceCategory
+ android:title="@string/pref_cat_application_control">
+
+ <PreferenceScreen
+ android:key="exit_application"
+ android:icon="@drawable/ic_power_settings_new_black_24dp"
+ android:title="@string/pref_exit_power_off_sony" />
+
+ <ListPreference
+ android:title="@string/pref_connection_method"
+ android:entryValues="@array/connection_method_value"
+ android:entries="@array/connection_method"
+ android:key="connection_method"
+ android:defaultValue="OPC"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/pref_cat_camera">
+
+ <PreferenceScreen
+ android:key="panasonic_api_list"
+ android:title="@string/pref_panasonic_api_list"
+ android:summary="@string/pref_summary_panasonic_api_list" />
+
+ <CheckBoxPreference
+ android:key="capture_both_camera_and_live_view"
+ android:title="@string/pref_capture_both_camera_and_live_view" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/pref_cat_initialize">
+
+ <CheckBoxPreference
+ android:key="auto_connect_to_camera"
+ android:title="@string/pref_auto_connect_camera"
+ android:summary="@string/pref_summary_auto_connect_camera" />
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/pref_cat_gokigen">
+
+ <Preference
+ android:key="instruction_link"
+ android:title="@string/pref_instruction_manual"
+ android:summary="https://osdn.net/projects/gokigen/wiki/A01d"
+ android:selectable="true">
+ <intent android:action="android.intent.action.VIEW"
+ android:data="https://osdn.net/projects/gokigen/wiki/A01d" />
+ </Preference>
+
+ <Preference
+ android:key="privacy_policy"
+ android:title="@string/pref_privacy_policy"
+ android:summary="https://osdn.net/projects/gokigen/wiki/PrivacyPolicy"
+ android:selectable="true">
+ <intent android:action="android.intent.action.VIEW"
+ android:data="https://osdn.net/projects/gokigen/wiki/PrivacyPolicy" />
+ </Preference>
+
+ <PreferenceScreen
+ android:key="debug_info"
+ android:title="@string/pref_degug_info"
+ android:summary="@string/pref_summary_debug_info" />
+
+ </PreferenceCategory>
+</PreferenceScreen>