/* <!-- +++
package com.almalence.opencam_plus.cameracontroller;
+++ --> */
//<!-- -+-
package com.almalence.opencam.cameracontroller;
//-+- -->
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.SharedPreferences;
import android.hardware.Camera.Area;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import com.almalence.SwapHeap;
import com.almalence.sony.cameraremote.PictureCallbackSonyRemote;
import com.almalence.sony.cameraremote.ServerDevice;
import com.almalence.sony.cameraremote.SimpleCameraEventObserver;
import com.almalence.sony.cameraremote.SimpleRemoteApi;
import com.almalence.sony.cameraremote.SimpleStreamSurfaceView;
import com.almalence.sony.cameraremote.ZoomCallbackSonyRemote;
import com.almalence.util.ImageConversion;
/* <!-- +++
import com.almalence.opencam_plus.ApplicationScreen;
import com.almalence.opencam_plus.ApplicationInterface;
import com.almalence.opencam_plus.PluginManager;
import com.almalence.opencam_plus.PluginManagerInterface;
import com.almalence.opencam_plus.R;
+++ --> */
//<!-- -+-
import com.almalence.opencam.ApplicationScreen;
import com.almalence.opencam.ApplicationInterface;
import com.almalence.opencam.PluginManager;
import com.almalence.opencam.PluginManagerInterface;
import com.almalence.opencam.R;
//-+- -->
public class SonyRemoteCamera
{
private static final String TAG = "SonyRemoteCamera";
protected static Context mainContext = null;
private static PluginManagerInterface pluginManager = null;
private static ApplicationInterface appInterface = null;
protected static Handler messageHandler = null;
public static ServerDevice mTargetDevice;
private static SimpleRemoteApi mRemoteApi;
private static Set<String> mAvailableCameraApiSet = new HashSet<String>();
private static Set<String> mAvailableApiSet = new HashSet<String>();
private static SimpleCameraEventObserver mEventObserver;
private static SimpleCameraEventObserver.ChangeListener mEventListener;
public static List<CameraController.Size> mPreviewSizes = new ArrayList<CameraController.Size>();
public static List<CameraController.Size> mPictureSizes = new ArrayList<CameraController.Size>();
private static int minExpoCompensation = 0;
private static int maxExpoCompensation = 0;
private static float expoCompensationStep = 0;
public static List<String> availableWBModes = new ArrayList<String>();
public static List<String> availableFocusModes = new ArrayList<String>();
public static List<String> availableIsoModes = new ArrayList<String>();
public static List<String> availableFlashModes = new ArrayList<String>();
public static boolean isZoomAvailable = false;
public static HashMap<Long, JSONObject> mPictureSizeNames = new HashMap<Long, JSONObject>();
public static int previewWidth = 640;
public static int previewHeight = 480;
public static String currentWBMode = "Auto WB";
public static String currentIsoMode = "auto";
public static String currentFlashMode = "off";
public static int currentExposureCompensation = 0;
public static Handler UIhandler = new Handler(
Looper.getMainLooper());
public static List<Thread> requestQueue = new LinkedList<Thread>();
public static boolean opening = false;
public static ProgressDialog progress;
public static ProgressDialog progressImageDownloading;
public static ZoomCallbackSonyRemote zoomCallbackSonyRemote = null;
public static double focusX = 50;
public static double focusY = 50;
public static void onCreateSonyRemoteCamera(Context context, ApplicationInterface app,
PluginManagerInterface pluginManagerBase, Handler msgHandler)
{
mainContext = context;
appInterface = app;
pluginManager = pluginManagerBase;
messageHandler = msgHandler;
mEventListener = new SimpleCameraEventObserver.ChangeListenerTmpl()
{
@Override
public void onShootModeChanged(String shootMode)
{
Log.d(TAG, "onShootModeChanged() called: " + shootMode);
// refreshUi();
}
@Override
public void onCameraStatusChanged(String status)
{
Log.d(TAG, "onCameraStatusChanged() called: " + status);
// refreshUi();
}
@Override
public void onApiListModified(List<String> apis)
{
Log.d(TAG, "onApiListModified() called");
synchronized (mAvailableCameraApiSet)
{
mAvailableCameraApiSet.clear();
for (String api : apis)
{
mAvailableCameraApiSet.add(api);
}
if (!mEventObserver.getLiveviewStatus() //
&& isCameraApiAvailable("startLiveview"))
{
if (!CameraController.isRemoteCamera())
return;
if (appInterface.getSimpleStreamSurfaceView() != null
&& !appInterface.getSimpleStreamSurfaceView().isStarted())
{
startLiveview();
}
}
if (zoomCallbackSonyRemote != null)
{
if (isCameraApiAvailable("actZoom"))
{
isZoomAvailable = true;
zoomCallbackSonyRemote.onZoomAvailabelChanged(true);
} else
{
isZoomAvailable = false;
zoomCallbackSonyRemote.onZoomAvailabelChanged(false);
}
}
}
}
@Override
public void onZoomPositionChanged(int zoomPosition)
{
if (zoomCallbackSonyRemote != null)
{
zoomCallbackSonyRemote.onZoomPositionChanged(zoomPosition);
}
}
@Override
public void onLiveviewStatusChanged(boolean status)
{
Log.d(TAG, "onLiveviewStatusChanged() called = " + status);
}
@Override
public void onStorageIdChanged(String storageId)
{
Log.d(TAG, "onStorageIdChanged() called: " + storageId);
// refreshUi();
}
@Override
public void onPictureTaken(String takePictureUrl)
{
downloadAndProcessImage(takePictureUrl, false);
}
};
}
static Boolean isBusy = false;
public static void sendRequest()
{
synchronized (isBusy)
{
if (!isBusy && requestQueue.size() > 0)
{
isBusy = true;
requestQueue.get(0).start();
requestQueue.remove(0);
} else if (requestQueue.size() == 0 && opening && previewImagesCount >= 3)
{
if (progress != null)
{
progress.dismiss();
}
opening = false;
messageHandler.sendEmptyMessage(ApplicationInterface.MSG_SURFACE_READY);
}
}
}
public static void onRequestResult()
{
synchronized (isBusy)
{
isBusy = false;
}
CameraController.sendMessage(ApplicationInterface.MSG_BROADCAST,
ApplicationInterface.MSG_REMOTE_CAMERA_PARAMETR_CHANGED);
sendRequest();
}
public static void setZoomCallbackSonyRemote(ZoomCallbackSonyRemote callback)
{
zoomCallbackSonyRemote = callback;
}
public static void openCameraSonyRemote()
{
mRemoteApi = new SimpleRemoteApi(mTargetDevice);
mEventObserver = new SimpleCameraEventObserver(mainContext, mRemoteApi);
mEventObserver.activate();
opening = true;
previewImagesCount = 0;
progress = ProgressDialog.show(mainContext, mainContext.getResources().getString(R.string.title_connecting),
mainContext.getResources().getString(R.string.msg_connecting), true);
progress.setCancelable(true);
progress.setOnCancelListener(new OnCancelListener()
{
@Override
public void onCancel(DialogInterface dialog)
{
switchBackToDeviceCamera();
}
});
prepareOpenConnection();
}
private static void prepareOpenConnection()
{
Log.d(TAG, "prepareToOpenConection() exec");
// setProgressBarIndeterminateVisibility(true);
requestQueue.add(new Thread()
{
@Override
public void run()
{
try
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
// Get available API list (Camera API)
JSONObject replyJsonCamera = mRemoteApi.getCameraMethodTypes();
loadAvailableApiList(replyJsonCamera);
try
{
// Get available API list (AvContent API)
JSONObject replyJsonAvcontent = mRemoteApi.getAvcontentMethodTypes();
loadAvailableApiList(replyJsonAvcontent);
} catch (IOException e)
{
Log.d(TAG, "AvContent is not support.");
}
if (!isApiAvailable("setCameraFunction"))
{
// this device does not support setCameraFunction.
// No need to check camera status.
openConnection();
} else
{
// this device supports setCameraFunction.
// after confirmation of camera state, open connection.
Log.d(TAG, "this device support set camera function");
if (!isApiAvailable("getEvent"))
{
Log.e(TAG, "this device is not support getEvent");
openConnection();
return;
}
// confirm current camera status
String cameraStatus = null;
JSONObject replyJson = mRemoteApi.getEvent(false);
JSONArray resultsObj = replyJson.getJSONArray("result");
JSONObject cameraStatusObj = resultsObj.getJSONObject(1);
String type = cameraStatusObj.getString("type");
if ("cameraStatus".equals(type))
{
cameraStatus = cameraStatusObj.getString("cameraStatus");
} else
{
throw new IOException();
}
if (isShootingStatus(cameraStatus))
{
Log.d(TAG, "camera function is Remote Shooting.");
openConnection();
} else
{
// set Listener
startOpenConnectionAfterChangeCameraState();
// set Camera function to Remote Shooting
replyJson = mRemoteApi.setCameraFunction("Remote Shooting");
}
}
} catch (IOException e)
{
Log.w(TAG, "prepareToStartContentsListMode: IOException: " + e.getMessage());
// DisplayHelper.toast(getApplicationContext(),
// R.string.msg_error_api_calling);
// DisplayHelper.setProgressIndicator(SampleCameraActivity.this,
// false);
} catch (JSONException e)
{
Log.w(TAG, "prepareToStartContentsListMode: JSONException: " + e.getMessage());
// DisplayHelper.toast(getApplicationContext(),
// R.string.msg_error_api_calling);
// DisplayHelper.setProgressIndicator(SampleCameraActivity.this,
// false);
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
/**
* Open connection to the camera device to start monitoring Camera events
* and showing liveview.
*/
private static void openConnection()
{
mEventObserver.setEventChangeListener(mEventListener);
requestQueue.add(new Thread()
{
@Override
public void run()
{
Log.d(TAG, "openConnection(): exec.");
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
JSONObject replyJson = null;
// getAvailableApiList
replyJson = mRemoteApi.getAvailableApiList();
loadAvailableCameraApiList(replyJson);
// check version of the server device
if (isCameraApiAvailable("getApplicationInfo"))
{
Log.d(TAG, "openConnection(): getApplicationInfo()");
replyJson = mRemoteApi.getApplicationInfo();
if (!isAvailableServerVersion(replyJson))
{
return;
}
} else
{
// never happens;
return;
}
// startRecMode if necessary.
if (isCameraApiAvailable("startRecMode"))
{
Log.d(TAG, "openConnection(): startRecMode()");
replyJson = mRemoteApi.startRecMode();
// Call again.
replyJson = mRemoteApi.getAvailableApiList();
loadAvailableCameraApiList(replyJson);
}
String modeName = PluginManager.getInstance().getActiveModeID();
if (modeName.contains("video"))
{
setShootMode("movie");
} else
{
setShootMode("still");
}
// getEvent start
if (isCameraApiAvailable("getEvent"))
{
Log.d(TAG, "openConnection(): EventObserver.start()");
mEventObserver.start();
}
// Liveview start
if (isCameraApiAvailable("startLiveview"))
{
Log.d(TAG, "openConnection(): LiveviewSurface.start()");
startLiveview();
}
// Set exposure mode
if (isCameraApiAvailable("setExposureMode"))
{
Log.d(TAG, "openConnection(): setExposureMode");
setExposureMode();
}
if (zoomCallbackSonyRemote != null)
{
if (isCameraApiAvailable("actZoom"))
{
isZoomAvailable = true;
zoomCallbackSonyRemote.onZoomAvailabelChanged(true);
} else
{
isZoomAvailable = false;
zoomCallbackSonyRemote.onZoomAvailabelChanged(false);
}
}
Log.d(TAG, "openConnection(): completed.");
} catch (IOException e)
{
Log.w(TAG, "openConnection : IOException: " + e.getMessage());
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
public static void onPauseSonyRemoteCamera()
{
closeConnection();
}
/**
* Stop monitoring Camera events and close liveview connection.
*/
private static void closeConnection()
{
Log.d(TAG, "closeConnection(): exec.");
// Liveview stop
Log.d(TAG, "closeConnection(): LiveviewSurface.stop()");
stopLiveview();
// getEvent stop
Log.d(TAG, "closeConnection(): EventObserver.release()");
if (mEventObserver != null)
{
mEventObserver.release();
}
// stopRecMode if necessary.
if (isCameraApiAvailable("stopRecMode"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
Log.d(TAG, "closeConnection(): stopRecMode()");
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
if (mRemoteApi != null)
{
mRemoteApi.stopRecMode();
}
} catch (IOException e)
{
Log.w(TAG, "closeConnection: IOException: " + e.getMessage());
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
currentWBMode = "Auto WB";
currentIsoMode = "auto";
currentFlashMode = "off";
currentExposureCompensation = 0;
requestQueue.clear();
mPreviewSizes.clear();
mPictureSizes.clear();
minExpoCompensation = 0;
maxExpoCompensation = 0;
expoCompensationStep = 0;
availableWBModes.clear();
availableFocusModes.clear();
availableIsoModes.clear();
availableFlashModes.clear();
isZoomAvailable = false;
mPictureSizeNames.clear();
previewWidth = 640;
previewHeight = 480;
opening = false;
if (progress != null)
{
progress.dismiss();
}
if (progressImageDownloading != null)
{
progressImageDownloading.dismiss();
}
Log.d(TAG, "closeConnection(): completed.");
}
private static void startOpenConnectionAfterChangeCameraState()
{
Log.d(TAG, "startOpenConectiontAfterChangeCameraState() exec");
((Activity) mainContext).runOnUiThread(new Runnable()
{
@Override
public void run()
{
mEventObserver.setEventChangeListener(new SimpleCameraEventObserver.ChangeListenerTmpl()
{
@Override
public void onCameraStatusChanged(String status)
{
Log.d(TAG, "onCameraStatusChanged:" + status);
if ("IDLE".equals(status))
{
openConnection();
}
// refreshUi();
}
@Override
public void onShootModeChanged(String shootMode)
{
// refreshUi();
}
@Override
public void onStorageIdChanged(String storageId)
{
// refreshUi();
}
@Override
public void onPictureTaken(String takePictureUrl)
{
downloadAndProcessImage(takePictureUrl, false);
}
});
mEventObserver.start();
}
});
}
private static boolean isShootingStatus(String currentStatus)
{
Set<String> shootingStatus = new HashSet<String>();
shootingStatus.add("IDLE");
shootingStatus.add("StillCapturing");
shootingStatus.add("StillSaving");
shootingStatus.add("MovieWaitRecStart");
shootingStatus.add("MovieRecording");
shootingStatus.add("MovieWaitRecStop");
shootingStatus.add("MovieSaving");
shootingStatus.add("IntervalWaitRecStart");
shootingStatus.add("IntervalRecording");
shootingStatus.add("IntervalWaitRecStop");
shootingStatus.add("AudioWaitRecStart");
shootingStatus.add("AudioRecording");
shootingStatus.add("AudioWaitRecStop");
shootingStatus.add("AudioSaving");
return shootingStatus.contains(currentStatus);
}
/**
* Call cancelTouchAFPosition
*
* @param mode
*/
public static void cancelAutoFocusSonyRemote()
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
if (mRemoteApi == null)
{
return;
}
JSONObject replyJson = mRemoteApi.cancelTouchAFPosition();
JSONArray resultsObj = replyJson.getJSONArray("result");
int resultCode = resultsObj.getInt(0);
if (resultCode != 0)
{
Log.w(TAG, "setShootMode: error: " + resultCode);
}
} catch (IOException e)
{
Log.w(TAG, "setShootMode: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "setShootMode: JSON format error.");
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
/**
* Call setTouchAFPosition
*
* @param mode
*/
public static boolean autoFocusSonyRemote()
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
CameraController.onAutoFocus(false);
onRequestResult();
return;
}
boolean result = false;
try
{
JSONObject replyJson = mRemoteApi.setTouchAFPosition(focusX, focusY);
JSONArray resultsArray = replyJson.getJSONArray("result");
int resultCode = resultsArray.getInt(0);
if (resultCode != 0)
{
Log.w(TAG, "setTouchAFPosition: error: " + resultCode);
} else
{
JSONObject resObj = resultsArray.getJSONObject(1);
result = resObj.getBoolean("AFResult");
}
} catch (IOException e)
{
Log.w(TAG, "setTouchAFPosition: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "setTouchAFPosition: JSON format error.");
} finally
{
final boolean res = result;
UIhandler.post(new Runnable()
{
@Override
public void run()
{
CameraController.onAutoFocus(res);
}
});
onRequestResult();
}
}
});
sendRequest();
return true;
}
/**
* Call setShootMode
*
* @param mode
*/
public static void setShootMode(final String mode)
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
JSONObject replyJson = mRemoteApi.setShootMode(mode);
JSONArray resultsObj = replyJson.getJSONArray("result");
int resultCode = resultsObj.getInt(0);
if (resultCode != 0)
{
Log.w(TAG, "setShootMode: error: " + resultCode);
}
} catch (IOException e)
{
Log.w(TAG, "setShootMode: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "setShootMode: JSON format error.");
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
public static void setCameraFocusAreasSonyRemote(List<Area> focusAreas)
{
if (focusAreas != null && focusAreas.size() > 0)
{
Area area = focusAreas.get(0);
int x = area.rect.centerX();
int y = area.rect.centerY();
focusX = (double) (((previewWidth / 2000) * x + previewWidth / 2) / previewHeight);
focusY = (double) (((previewHeight / 2000) * y + previewHeight / 2) / previewHeight);
} else
{
focusX = 50;
focusY = 50;
}
}
public static void takePicture(final PictureCallbackSonyRemote pictureListener)
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
JSONObject replyJson = mRemoteApi.actTakePicture();
JSONArray resultsObj = replyJson.getJSONArray("result");
JSONArray imageUrlsObj = resultsObj.getJSONArray(0);
String postImageUrl = null;
if (1 <= imageUrlsObj.length())
{
postImageUrl = imageUrlsObj.getString(0);
}
if (postImageUrl == null)
{
Log.w(TAG, "takeAndFetchPicture: post image URL is null.");
return;
}
downloadAndProcessImage(postImageUrl, true);
} catch (IOException e)
{
Log.w(TAG, "IOException while closing slicer: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "JSONException while closing slicer");
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
public static void downloadAndProcessImage(final String postImageUrl, final boolean fromRequest)
{
((Activity) mainContext).runOnUiThread(new Runnable()
{
@Override
public void run()
{
progressImageDownloading = ProgressDialog.show(mainContext,
mainContext.getResources().getString(R.string.title_downloading), mainContext.getResources()
.getString(R.string.msg_downloading), true);
}
});
requestQueue.add(new Thread()
{
@Override
public void run()
{
try
{
URL url = new URL(postImageUrl);
InputStream istream = new BufferedInputStream(url.openStream());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = istream.read(data, 0, data.length)) != -1)
{
buffer.write(data, 0, nRead);
}
buffer.flush();
CameraController.getInstance().onPictureTakenSonyRemote(buffer.toByteArray(), fromRequest);
} catch (IOException e)
{
e.printStackTrace();
} finally
{
((Activity) mainContext).runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (progressImageDownloading != null)
{
progressImageDownloading.dismiss();
}
}
});
onRequestResult();
}
}
});
sendRequest();
}
/**
* Call startMovieRec
*/
public static void startMovieRec()
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
Log.d(TAG, "startMovieRec: exec.");
JSONObject replyJson = mRemoteApi.startMovieRec();
JSONArray resultsObj = replyJson.getJSONArray("result");
int resultCode = resultsObj.getInt(0);
if (resultCode != 0)
{
Log.w(TAG, "startMovieRec: error: " + resultCode);
}
} catch (IOException e)
{
Log.w(TAG, "startMovieRec: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "startMovieRec: JSON format error.");
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
/**
* Call stopMovieRec
*/
public static void stopMovieRec()
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
Log.d(TAG, "stopMovieRec: exec.");
JSONObject replyJson = mRemoteApi.stopMovieRec();
JSONArray resultsObj = replyJson.getJSONArray("result");
String thumbnailUrl = resultsObj.getString(0);
if (thumbnailUrl == null)
{
Log.w(TAG, "stopMovieRec: error");
}
} catch (IOException e)
{
Log.w(TAG, "stopMovieRec: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "stopMovieRec: JSON format error.");
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
public static boolean isZoomAvailable()
{
return isZoomAvailable;
}
/**
* Call actZoom
*
* @param direction
* @param movement
*/
public static void actZoom(final String direction, final String movement)
{
new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
JSONObject replyJson = mRemoteApi.actZoom(direction, movement);
JSONArray resultsObj = replyJson.getJSONArray("result");
int resultCode = resultsObj.getInt(0);
if (resultCode == 0)
{
// Success, but no refresh UI at the point.
Log.v(TAG, "actZoom: success");
} else
{
Log.w(TAG, "actZoom: error: " + resultCode);
}
} catch (IOException e)
{
Log.w(TAG, "actZoom: IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "actZoom: JSON format error.");
}
}
}.start();
}
private static void setExposureMode()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.setExposureMode();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
int result = resultArrayJson.getInt(0);
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
private static void startLiveview()
{
if (!CameraController.isRemoteCamera())
return;
if (appInterface.getSimpleStreamSurfaceView() == null)
{
Log.w(TAG, "startLiveview mLiveviewSurface is null.");
return;
}
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
JSONObject replyJson = null;
replyJson = mRemoteApi.startLiveview();
if (!SimpleRemoteApi.isErrorReply(replyJson))
{
JSONArray resultsObj = replyJson.getJSONArray("result");
if (1 <= resultsObj.length())
{
initRemoteCameraFeatures();
// Obtain liveview URL from the result.
final String liveviewUrl = resultsObj.getString(0);
((Activity) mainContext).runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (!CameraController.isRemoteCamera())
return;
appInterface.getSimpleStreamSurfaceView().start(liveviewUrl,
new SimpleStreamSurfaceView.StreamFrameListener()
{
@Override
public void onFrameAvailable(byte[] jpegData)
{
onPreviewFrame(jpegData);
}
}, new SimpleStreamSurfaceView.StreamErrorListener()
{
@Override
public void onError(StreamErrorReason reason)
{
switchBackToDeviceCamera();
}
});
appInterface.getSimpleStreamSurfaceView().setVisibility(View.VISIBLE);
appInterface.getSimpleStreamSurfaceView().bringToFront();
}
});
}
}
} catch (IOException e)
{
Log.w(TAG, "startLiveview IOException: " + e.getMessage());
} catch (JSONException e)
{
Log.w(TAG, "startLiveview JSONException: " + e.getMessage());
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
private static void switchBackToDeviceCamera()
{
((Activity) mainContext).runOnUiThread(new Runnable()
{
@Override
public void run()
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen
.getMainContext());
prefs.edit().putInt(ApplicationScreen.sCameraModePref, 0).commit();
appInterface.relaunchCamera();
}
});
}
private static void stopLiveview()
{
Log.e("SonyRemoteCamera", "stopLiveview");
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
if (mRemoteApi != null)
{
mRemoteApi.stopLiveview();
}
} catch (IOException e)
{
Log.w(TAG, "stopLiveview IOException: " + e.getMessage());
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
static int previewImagesCount = 0;
public static void onPreviewFrame(byte[] jpegData)
{
previewImagesCount++;
if (!opening)
{
int frame = ImageConversion.JpegConvert(jpegData, previewWidth, previewHeight, false, false, 0);
int frameLen = previewWidth * previewHeight + 2 * ((previewWidth + 1) / 2) * ((previewHeight + 1) / 2);
final byte[] data = SwapHeap.SwapFromHeap(frame, frameLen);
UIhandler.post(new Runnable()
{
@Override
public void run()
{
pluginManager.onPreviewFrame(data);
}
});
}
if (requestQueue.size() == 0 && opening && previewImagesCount >= 3)
{
if (progress != null)
{
progress.dismiss();
}
opening = false;
messageHandler.sendEmptyMessage(ApplicationInterface.MSG_SURFACE_READY);
}
}
/**
* Retrieve a list of APIs that are available at present.
*
* @param replyJson
*/
private static void loadAvailableCameraApiList(JSONObject replyJson)
{
synchronized (mAvailableCameraApiSet)
{
mAvailableCameraApiSet.clear();
try
{
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray apiListJson = resultArrayJson.getJSONArray(0);
for (int i = 0; i < apiListJson.length(); i++)
{
mAvailableCameraApiSet.add(apiListJson.getString(i));
}
} catch (JSONException e)
{
Log.w(TAG, "loadAvailableCameraApiList: JSON format error.");
}
}
}
/**
* Retrieve a list of APIs that are available by the target device.
*
* @param replyJson
*/
private static void loadAvailableApiList(JSONObject replyJson)
{
synchronized (mAvailableApiSet)
{
try
{
JSONArray resultArrayJson = replyJson.getJSONArray("results");
for (int i = 0; i < resultArrayJson.length(); i++)
{
mAvailableApiSet.add(resultArrayJson.getJSONArray(i).getString(0));
}
} catch (JSONException e)
{
Log.w(TAG, "loadAvailableApiList: JSON format error.");
}
}
}
/**
* Check if the version of the server is available in this application.
*
* @param replyJson
* @return
*/
private static boolean isAvailableServerVersion(JSONObject replyJson)
{
try
{
JSONArray resultArrayJson = replyJson.getJSONArray("result");
String version = resultArrayJson.getString(1);
String[] separated = version.split("\\.");
int major = Integer.valueOf(separated[0]);
if (2 <= major)
{
return true;
}
} catch (JSONException e)
{
Log.w(TAG, "isAvailableServerVersion: JSON format error.");
} catch (NumberFormatException e)
{
Log.w(TAG, "isAvailableServerVersion: Number format error.");
}
return false;
}
/**
* Check if the specified API is available. This is for camera and avContent
* service API. The result of this method does not change dynamically.
*
* @param apiName
* @return
*/
private static boolean isApiAvailable(String apiName)
{
boolean isAvailable = false;
synchronized (mAvailableApiSet)
{
isAvailable = mAvailableApiSet.contains(apiName);
}
return isAvailable;
}
/**
* Check if the specified API is available at present. This works correctly
* only for Camera API.
*
* @param apiName
* @return
*/
private static boolean isCameraApiAvailable(String apiName)
{
boolean isAvailable = false;
synchronized (mAvailableCameraApiSet)
{
isAvailable = mAvailableCameraApiSet.contains(apiName);
}
return isAvailable;
}
/**
* Sets a target ServerDevice object.
*
* @param device
*/
public static void setTargetServerDevice(ServerDevice device)
{
mTargetDevice = device;
}
/**
* Returns a target ServerDevice object.
*
* @return return ServiceDevice
*/
public static ServerDevice getTargetServerDevice()
{
return mTargetDevice;
}
/**
* Sets a SimpleRemoteApi object to transmit to Activity.
*
* @param remoteApi
*/
public static void setRemoteApi(SimpleRemoteApi remoteApi)
{
mRemoteApi = remoteApi;
}
/**
* Returns a SimpleRemoteApi object.
*
* @return return SimpleRemoteApi
*/
public static SimpleRemoteApi getRemoteApi()
{
return mRemoteApi;
}
/**
* Sets a List of available APIs.
*
* @param apiList
*/
public static void setAvailableApiList(Set<String> apiList)
{
mAvailableApiSet = apiList;
}
/**
* Returns a list of available APIs.
*
* @return Returns a list of available APIs.
*/
public static Set<String> getAvailableApiList()
{
return mAvailableApiSet;
}
public static void initRemoteCameraFeatures()
{
if (isCameraApiAvailable("getAvailableLiveviewSize"))
{
initPreviewSizeList();
} else
{
mPreviewSizes.add(new CameraController.Size(640, 480));
}
mPictureSizes.add(new CameraController.Size(1920, 1080));
if (isCameraApiAvailable("getAvailableStillSize"))
{
initPictureSizeList();
}
if (isCameraApiAvailable("getAvailableExposureCompensation"))
{
initExposureCompensationAvailable();
}
if (isCameraApiAvailable("getAvailableFocusMode"))
{
initAvailableFocusMode();
}
if (isCameraApiAvailable("getAvailableIsoSpeedRate"))
{
initAvailableIsoMode();
}
if (isCameraApiAvailable("getAvailableWhiteBalance"))
{
initAvailableWhiteBalance();
}
if (isCameraApiAvailable("getAvailableFlashMode"))
{
initAvailableFlashMode();
}
}
public static List<CameraController.Size> getPreviewSizeListRemote()
{
if (mPreviewSizes == null || mPreviewSizes.size() == 0)
{
mPreviewSizes = new ArrayList<CameraController.Size>();
mPreviewSizes.add(new CameraController.Size(640, 480));
}
return mPreviewSizes;
}
public static List<CameraController.Size> initPreviewSizeList()
{
mPreviewSizes = new ArrayList<CameraController.Size>();
mPreviewSizes.add(new CameraController.Size(640, 480));
if (mRemoteApi == null) {
return mPreviewSizes;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableLiveviewSize();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray availableLiveviewArrayJson = resultArrayJson.getJSONArray(1);
for (int i = 0; i < availableLiveviewArrayJson.length(); i++)
{
if (availableLiveviewArrayJson.getString(i).equals("L"))
{
CameraController.Size size = new CameraController.Size(1024, 768);
mPreviewSizes.add(size);
}
if (availableLiveviewArrayJson.getString(i).equals("M"))
{
CameraController.Size size = new CameraController.Size(640, 480);
mPreviewSizes.add(size);
}
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return mPreviewSizes;
}
private static CameraController.Size convertJsonToSize(JSONObject json) throws NumberFormatException, JSONException
{
CameraController.Size size = null;
long totalPixelCount = Long.valueOf(json.getString("size").replace("M", "")) * 1000000;
int horizontalRation = Integer.valueOf(json.getString("aspect").replaceAll(":.*", ""));
int verticalRation = Integer.valueOf(json.getString("aspect").replaceAll(".*:", ""));
double horizontalToVerticalRation = (double) ((double) horizontalRation / (double) verticalRation);
double verticalToHorizontalRation = (double) ((double) verticalRation / (double) horizontalRation);
int width = (int) Math.sqrt(totalPixelCount * horizontalToVerticalRation);
int height = (int) Math.sqrt(totalPixelCount * verticalToHorizontalRation);
size = new CameraController.Size(width, height);
mPictureSizeNames.put((long) (width * height), json);
return size;
}
public static void initPictureSizeList()
{
synchronized (mPictureSizes)
{
mPictureSizes = new ArrayList<CameraController.Size>();
mPictureSizes.add(new CameraController.Size(1920, 1080));
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableStillSize();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray availableStillArrayJson = resultArrayJson.getJSONArray(1);
if (availableStillArrayJson.length() > 0)
{
mPictureSizes.clear();
mPictureSizeNames.clear();
}
for (int i = 0; i < availableStillArrayJson.length(); i++)
{
CameraController.Size size = convertJsonToSize(availableStillArrayJson.getJSONObject(i));
if (size != null)
{
mPictureSizes.add(size);
}
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
public static void fillPictureSizeListRemote(List<CameraController.Size> pictureSizes)
{
synchronized (mPictureSizes)
{
pictureSizes.clear();
pictureSizes.addAll(mPictureSizes);
}
}
public static List<CameraController.Size> getPictureSizeListRemote()
{
synchronized (mPictureSizes)
{
if (mPictureSizes.size() == 0)
{
mPictureSizes.add(new CameraController.Size(1920, 1080));
}
return mPictureSizes;
}
}
public static void initExposureCompensationAvailable()
{
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableExposureCompensation();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
maxExpoCompensation = resultArrayJson.getInt(1);
minExpoCompensation = resultArrayJson.getInt(2);
int step = resultArrayJson.getInt(3);
if (step == 1)
{
expoCompensationStep = 1f / 3f;
}
if (step == 2)
{
expoCompensationStep = 1f / 2f;
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static boolean isExposureCompensationAvailable()
{
boolean res = false;
if (minExpoCompensation != maxExpoCompensation && expoCompensationStep != 0)
{
res = true;
}
return res;
}
public static int getMinExposureCompensationRemote()
{
return minExpoCompensation;
}
public static int getMaxExposureCompensationRemote()
{
return maxExpoCompensation;
}
public static float getExposureCompensationStepRemote()
{
return expoCompensationStep;
}
public static String getWhiteBalanceRemote()
{
return currentWBMode;
}
public static String getIsoModeRemote()
{
return currentIsoMode;
}
public static String getFlashModeRemote()
{
return currentFlashMode;
}
public static int getExposureCompensationRemote()
{
return currentExposureCompensation;
}
public static List<String> getAvailableWhiteBalanceRemote()
{
return availableWBModes;
}
public static void initAvailableWhiteBalance()
{
availableWBModes = new ArrayList<String>();
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableWhiteBalance();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONObject currentMode = resultArrayJson.getJSONObject(0);
currentWBMode = currentMode.getString("whiteBalanceMode");
JSONArray availableWhiteBalanceArrayJson = resultArrayJson.getJSONArray(1);
for (int i = 0; i < availableWhiteBalanceArrayJson.length(); i++)
{
JSONObject wb = availableWhiteBalanceArrayJson.getJSONObject(i);
availableWBModes.add(wb.getString("whiteBalanceMode"));
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static List<String> getAvailableFocusModeRemote()
{
return availableFocusModes;
}
public static void initAvailableFocusMode()
{
availableFocusModes = new ArrayList<String>();
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableFocusMode();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray availableFocusModeArrayJson = resultArrayJson.getJSONArray(1);
for (int i = 0; i < availableFocusModeArrayJson.length(); i++)
{
String focusMode = availableFocusModeArrayJson.getString(i);
if (focusMode.equals("AF-S"))
{
focusMode = "auto";
availableFocusModes.add(focusMode);
}
if (focusMode.equals("AF-C"))
{
focusMode = "continuous-picture";
availableFocusModes.add(focusMode);
}
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static boolean isFlashAvailableRemote()
{
return (availableFlashModes != null && availableFlashModes.size() > 1);
}
public static List<String> getAvailableFlashModeRemote()
{
return availableFlashModes;
}
public static void initAvailableFlashMode()
{
availableFlashModes = new ArrayList<String>();
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableFlashMode();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray availableFlashModeArrayJson = resultArrayJson.getJSONArray(1);
for (int i = 0; i < availableFlashModeArrayJson.length(); i++)
{
String flash = availableFlashModeArrayJson.getString(i);
availableFlashModes.add(flash);
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static boolean isISOModeAvailableRemote()
{
return (availableIsoModes != null && availableIsoModes.size() > 1);
}
public static List<String> getAvailableIsoModeRemote()
{
return availableIsoModes;
}
public static void initAvailableIsoMode()
{
availableIsoModes = new ArrayList<String>();
if (mRemoteApi == null) {
return;
}
JSONObject replyJson = null;
try
{
replyJson = mRemoteApi.getAvailableIsoSpeedRate();
JSONArray resultArrayJson = replyJson.getJSONArray("result");
JSONArray availableISOModeArrayJson = resultArrayJson.getJSONArray(1);
for (int i = 0; i < availableISOModeArrayJson.length(); i++)
{
String iso = availableISOModeArrayJson.getString(i);
availableIsoModes.add(iso);
}
} catch (JSONException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static void setExposureCompensationRemote(final int value)
{
if (isCameraApiAvailable("setExposureCompensation"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
mRemoteApi.setExposureCompensation(value);
currentExposureCompensation = value;
} catch (IOException e)
{
e.printStackTrace();
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
}
public static void setFlashModeRemote(final String value)
{
if (isCameraApiAvailable("setFlashMode"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
mRemoteApi.setFlashMode(value.toLowerCase());
currentFlashMode = value;
} catch (IOException e)
{
e.printStackTrace();
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
}
public static void setIsoSpeedRateRemote(final String value)
{
if (isCameraApiAvailable("setIsoSpeedRate"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
mRemoteApi.setIsoSpeedRate(value.toUpperCase());
currentIsoMode = value;
} catch (IOException e)
{
e.printStackTrace();
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
}
public static void setWhiteBalanceRemote(final String value)
{
if (isCameraApiAvailable("setWhiteBalance"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
mRemoteApi.setWhiteBalance(value);
currentWBMode = value;
} catch (IOException e)
{
e.printStackTrace();
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
}
public static void setPictureSizeRemote(int width, int height)
{
final JSONObject jsonObject = mPictureSizeNames.get((long) (width * height));
if (jsonObject == null)
{
return;
}
if (isCameraApiAvailable("setStillSize"))
{
requestQueue.add(new Thread()
{
@Override
public void run()
{
if (mRemoteApi == null) {
onRequestResult();
return;
}
try
{
mRemoteApi.setStillSize(jsonObject.getString("aspect"), jsonObject.getString("size"));
mRemoteApi.setPostviewImageSize("Original");
} catch (IOException e)
{
e.printStackTrace();
} catch (JSONException e)
{
e.printStackTrace();
} finally
{
onRequestResult();
}
}
});
sendRequest();
}
}
}