/*
HostDeviceCameraRecorder.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.host.recorder.camera;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import org.deviceconnect.android.deviceplugin.host.BuildConfig;
import org.deviceconnect.android.deviceplugin.host.recorder.HostDevicePhotoRecorder;
import org.deviceconnect.android.deviceplugin.host.recorder.HostDevicePreviewServer;
import org.deviceconnect.android.deviceplugin.host.recorder.util.MixedReplaceMediaServer;
import org.deviceconnect.android.provider.FileManager;
import java.util.ArrayList;
import java.util.List;
/**
* Host Device Camera Recorder.
*
* @author NTT DOCOMO, INC.
*/
@SuppressWarnings("deprecation")
public class HostDeviceCameraRecorder extends HostDevicePreviewServer implements HostDevicePhotoRecorder {
private static final boolean DEBUG = BuildConfig.DEBUG;
private static final String TAG = "HOST";
/**
* カメラターゲットIDの定義.
*/
private static final String ID_BASE = "photo";
/**
* カメラ名の定義.
*/
private static final String NAME_BASE = "AndroidHost Camera Recorder";
/**
* NotificationIDを定義.
*/
private static final int NOTIFICATION_ID = 1010;
/**
* デフォルトのプレビューサイズの閾値を定義.
*/
private static final int DEFAULT_PREVIEW_WIDTH_THRESHOLD = 640;
/**
* デフォルトのプレビューサイズの閾値を定義.
*/
private static final int DEFAULT_PREVIEW_HEIGHT_THRESHOLD = 480;
/**
* マイムタイプ一覧を定義.
*/
private List<String> mMimeTypes = new ArrayList<String>() {
{
add("image/png");
}
};
private CameraOverlay mCameraOverlay;
private String mMimeType;
private CameraFacing mFacing;
private int mCameraId;
private boolean mIsInitialized;
private final List<PictureSize> mSupportedPictureSizes = new ArrayList<>();
private final List<PictureSize> mSupportedPreviewSizes = new ArrayList<>();
private final Object mLockObj = new Object();
private MixedReplaceMediaServer mServer;
private RecorderState mState;
public HostDeviceCameraRecorder(final Context context, final int cameraId,
final CameraFacing facing, final FileManager fileMgr) {
super(context, NOTIFICATION_ID + cameraId);
mFacing = facing;
mCameraId = cameraId;
mMimeType = mMimeTypes.get(0);
mState = RecorderState.INACTTIVE;
if (mCameraOverlay == null) {
mCameraOverlay = new CameraOverlay(context, cameraId);
} else {
if (DEBUG) {
Log.d(TAG, "CameraOverlay create fail.");
}
}
mCameraOverlay.setFileManager(fileMgr);
mCameraOverlay.setFacingDirection(facing == CameraFacing.FRONT ? -1 : 1);
}
@Override
public void initialize() {
if (mIsInitialized) {
return;
}
try {
Camera camera = Camera.open(mCameraId);
Camera.Parameters params = camera.getParameters();
Camera.Size picture = params.getPictureSize();
setPictureSize(new PictureSize(picture.width, picture.height));
for (Camera.Size size : params.getSupportedPictureSizes()) {
mSupportedPictureSizes.add(new PictureSize(size.width, size.height));
}
Camera.Size preview = params.getPreviewSize();
for (Camera.Size size : params.getSupportedPreviewSizes()) {
mSupportedPreviewSizes.add(new PictureSize(size.width, size.height));
}
PictureSize defaultSize = getDefaultPreviewSize();
if (defaultSize != null) {
setPreviewSize(defaultSize);
} else {
setPreviewSize(new PictureSize(preview.width, preview.height));
}
camera.release();
mIsInitialized = true;
} catch (Exception e) {
if (DEBUG) {
Log.w(TAG, "", e);
}
}
}
@Override
public void clean() {
stopWebServer();
}
@Override
public String getId() {
return ID_BASE + "_" + mCameraId;
}
@Override
public String getName() {
return NAME_BASE + " - " + mFacing.getName();
}
@Override
public String getMimeType() {
return mMimeType;
}
@Override
public RecorderState getState() {
return mState;
}
@Override
public List<String> getSupportedMimeTypes() {
return mMimeTypes;
}
@Override
public PictureSize getPictureSize() {
return mCameraOverlay.getPictureSize();
}
@Override
public void setPictureSize(final PictureSize size) {
mCameraOverlay.setPictureSize(size);
}
@Override
public PictureSize getPreviewSize() {
return mCameraOverlay.getPreviewSize();
}
@Override
public void setPreviewSize(final PictureSize size) {
mCameraOverlay.setPreviewSize(size);
}
@Override
public double getMaxFrameRate() {
return mCameraOverlay.getPreviewMaxFrameRate();
}
@Override
public void setMaxFrameRate(final double max) {
mCameraOverlay.setPreviewFrameRate(max);
}
@Override
public List<PictureSize> getSupportedPictureSizes() {
return mSupportedPictureSizes;
}
@Override
public List<PictureSize> getSupportedPreviewSizes() {
return mSupportedPreviewSizes;
}
@Override
public boolean isSupportedPictureSize(final int width, final int height) {
if (mSupportedPictureSizes != null) {
for (PictureSize size : mSupportedPictureSizes) {
if (size.getWidth() == width && size.getHeight() == height) {
return true;
}
}
}
return false;
}
@Override
public boolean isSupportedPreviewSize(final int width, final int height) {
if (mSupportedPreviewSizes != null) {
for (PictureSize size : mSupportedPreviewSizes) {
if (size.getWidth() == width && size.getHeight() == height) {
return true;
}
}
}
return false;
}
@Override
public boolean isBack() {
return mFacing == CameraFacing.BACK;
}
@Override
public void turnOnFlashLight() {
if (mCameraOverlay != null) {
mCameraOverlay.turnOnFlashLight();
}
}
@Override
public void turnOffFlashLight() {
if (mCameraOverlay != null) {
mCameraOverlay.turnOffFlashLight();
}
}
@Override
public boolean isFlashLightState() {
return mCameraOverlay != null && mCameraOverlay.isFlashLightState();
}
@Override
public boolean isUseFlashLight() {
return mCameraOverlay != null && mCameraOverlay.isUseFlashLight();
}
@Override
public void startWebServer(final OnWebServerStartCallback callback) {
synchronized (mLockObj) {
if (mServer == null) {
mServer = new MixedReplaceMediaServer();
mServer.setServerName("HostDevicePlugin Server");
mServer.setContentType("image/jpg");
final String ip = mServer.start();
if (!mCameraOverlay.isShow()) {
mCameraOverlay.show(new CameraOverlay.Callback() {
@Override
public void onSuccess() {
sendNotification();
mCameraOverlay.setPreviewMode(true);
mCameraOverlay.setServer(mServer);
callback.onStart(ip);
}
@Override
public void onFail() {
callback.onFail();
}
});
} else {
mCameraOverlay.setPreviewMode(true);
mCameraOverlay.setServer(mServer);
callback.onStart(ip);
}
} else {
callback.onStart(mServer.getUrl());
}
}
}
@Override
public void stopWebServer() {
synchronized (mLockObj) {
if (mServer != null) {
mServer.stop();
mServer = null;
}
mCameraOverlay.hide();
hideNotification();
}
}
/**
* 写真撮影を行う.
*
* @param listener 写真撮影の結果を通知するリスナー
*/
@Override
public void takePhoto(final OnPhotoEventListener listener) {
if (!mIsInitialized) {
listener.onFailedTakePhoto();
return;
}
if (mState != RecorderState.INACTTIVE) {
listener.onFailedTakePhoto();
return;
}
mState = RecorderState.RECORDING;
mCameraOverlay.takePicture(new CameraOverlay.OnTakePhotoListener() {
@Override
public void onTakenPhoto(String uri, String filePath) {
listener.onTakePhoto(uri, filePath);
mState = RecorderState.INACTTIVE;
}
@Override
public void onFailedTakePhoto() {
listener.onFailedTakePhoto();
mState = RecorderState.INACTTIVE;
}
});
}
/**
* デフォルトのプレビューサイズを取得します.
* @return デフォルトのプレビューサイズ
*/
private PictureSize getDefaultPreviewSize() {
if (mSupportedPreviewSizes.size() == 0) {
return null;
}
PictureSize defaultSize = null;
for (PictureSize size : mSupportedPreviewSizes) {
if (size.getWidth() == DEFAULT_PREVIEW_WIDTH_THRESHOLD &&
size.getHeight() == DEFAULT_PREVIEW_HEIGHT_THRESHOLD) {
defaultSize = size;
}
}
if (defaultSize != null) {
return defaultSize;
}
for (PictureSize size : mSupportedPreviewSizes) {
if (size.getWidth() * size.getHeight() <=
DEFAULT_PREVIEW_WIDTH_THRESHOLD * DEFAULT_PREVIEW_HEIGHT_THRESHOLD) {
defaultSize = size;
}
}
if (defaultSize != null) {
return defaultSize;
}
return mSupportedPreviewSizes.get(0);
}
public enum CameraFacing {
BACK("back"),
FRONT("front"),
UNKNOWN("unknown");
private final String mName;
CameraFacing(final String name) {
mName = name;
}
public String getName() {
return mName;
}
}
}