/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* Author(s): Pararth Shah (pararthshah717@gmail.com)
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.probe.builtin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import com.google.gson.JsonObject;
import edu.mit.media.funf.Schedule;
import edu.mit.media.funf.config.Configurable;
import edu.mit.media.funf.probe.Probe.DisplayName;
import edu.mit.media.funf.probe.Probe.PassiveProbe;
import edu.mit.media.funf.probe.Probe.RequiredFeatures;
import edu.mit.media.funf.probe.Probe.RequiredPermissions;
import edu.mit.media.funf.probe.builtin.ProbeKeys.HighBandwidthKeys;
import edu.mit.media.funf.time.TimeUtil;
import edu.mit.media.funf.util.CameraUtil;
import edu.mit.media.funf.util.LogUtil;
import edu.mit.media.funf.util.NameGenerator;
import edu.mit.media.funf.util.NameGenerator.SystemUniqueTimestampNameGenerator;
@DisplayName("Image Capture Probe")
@RequiredPermissions({android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA})
@RequiredFeatures("android.hardware.camera")
@Schedule.DefaultSchedule(interval=1800)
public class ImageCaptureProbe extends ImpulseProbe implements PassiveProbe, HighBandwidthKeys, SurfaceHolder.Callback {
@Configurable
private String fileNameBase = "imgcapturetest";
@Configurable
private String folderName = "myimages";
@Configurable
private int selectedCamera = 1; // BACK_FACING = 0, FRONT_FACING = 1
@Configurable
private int jpegCompressionRatio = 90; // 0 - min size, 100 - max quality
@Configurable
private int cameraOpenDelay = 1; // allow delay for camera open in seconds
private String mFileName;
private String mFolderPath;
private NameGenerator mNameGenerator;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private WindowManager mWindowManager;
private LayoutParams mParams;
private Bitmap mBmp;
@Override
protected void onEnable() {
super.onEnable();
mNameGenerator = new SystemUniqueTimestampNameGenerator(getContext());
mFolderPath = Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/" + folderName;
File folder = new File(mFolderPath);
if (!folder.exists()) {
folder.mkdirs();
} else if (!folder.isDirectory()) {
folder.delete();
folder.mkdirs();
}
mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
mParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
}
@Override
protected void onStart() {
super.onStart();
Log.d(LogUtil.TAG, "ImageCaptureProbe: Probe initialization");
mSurfaceView = new SurfaceView(getContext());
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mWindowManager.addView(mSurfaceView, mParams);
mSurfaceView.setZOrderOnTop(false);
mHolder.setFormat(PixelFormat.TRANSPARENT);
mFileName = mFolderPath + "/" + mNameGenerator.generateName(fileNameBase) + ".jpg";
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//Log.d(LogUtil.TAG, "Image capture: surfaceCreated");
if (CameraUtil.safeCameraOpen(selectedCamera)) {
try {
CameraUtil.getCamera().setPreviewDisplay(mHolder);
} catch (IOException exception) {
CameraUtil.safeCameraRelease();
Log.e(LogUtil.TAG, "ImageCaptureProbe: error in surface initialization");
Log.e(LogUtil.TAG, exception.getLocalizedMessage());
}
} else {
abortCapture();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
//Log.d(LogUtil.TAG, "Image capture: surfaceChanged");
CameraUtil.configureCameraParameters(getContext(), mWindowManager.getDefaultDisplay().getRotation());
CameraUtil.getCamera().startPreview();
// to allow time for camera initiation on certain devices
try {
Thread.sleep(TimeUtil.secondsToMillis(cameraOpenDelay));
} catch (InterruptedException e) {
e.printStackTrace();
}
Camera.PictureCallback mCall = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
mBmp = BitmapFactory.decodeByteArray(data, 0, data.length);
finishCapture();
}
};
CameraUtil.getCamera().takePicture(null, null, mCall);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//Log.d(LogUtil.TAG, "Image capture: surfaceDestroyed");
CameraUtil.safeCameraClose();
}
protected void finishCapture() {
try {
File file = new File(mFileName);
if (file.exists())
file.delete();
FileOutputStream out = new FileOutputStream(file);
mBmp = rotate(mBmp, CameraUtil.computePictureRotation());
mBmp.compress(Bitmap.CompressFormat.JPEG, jpegCompressionRatio, out);
out.flush();
out.close();
Log.d(LogUtil.TAG, "ImageCaptureProbe: image capture finish");
JsonObject data = new JsonObject();
data.addProperty(FILENAME, mFileName);
sendData(data);
mWindowManager.removeView(mSurfaceView);
stop();
} catch (Exception e) {
Log.e(LogUtil.TAG, "ImageCaptureProbe: image capture error");
Log.e(LogUtil.TAG, e.getLocalizedMessage());
}
}
private void abortCapture() {
Log.e(LogUtil.TAG, "ImageCaptureProbe: image capture abort");
CameraUtil.safeCameraClose();
if (mHolder != null) {
mHolder.removeCallback(this);
}
if (mWindowManager != null) {
mWindowManager.removeView(mSurfaceView);
}
stop();
}
private static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
}