I have a small project. I need to implement a motion detection in android to close the device screen when more than 5 mins have passed, and wake it up if motion is detected.
The problem is that the camera preview freezes when the device is going to sleep, and doesn't send any more previews to the activity, so the application is stuck with the screen turned off.
I tried with wake locks but it doesn't work. It still makes the app call onPause, onStop.
My camera service:
import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.camera2.*;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class CameraHandler extends Service {
private static final String TAG = "CameraHandler";
private static final String START_SERVICE_COMMAND = "startServiceCommands";
private static final int COMMAND_NONE = -1;
private static final int COMMAND_START_RECORDING = 0;
private Context context;
private Camera camera;
private boolean inPreview;
private AtomicReference<byte[]> nextData = new AtomicReference<>();
private AtomicInteger nextWidth = new AtomicInteger();
private AtomicInteger nextHeight = new AtomicInteger();
private IBinder cameraServiceBinder = new CameraServiceBinder();
private Camera.PreviewCallback previewCallback;
//private SurfaceHolder.Callback surfaceCallback;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CameraHandler() {
}
public static void starService(Context context){
Intent intent = new Intent(context, CameraHandler.class);
intent.putExtra(START_SERVICE_COMMAND, COMMAND_START_RECORDING);
context.startService(intent);
}
private void setPreviewHolder() {
// previewHolder = this.surfaceView.getHolder();
//previewHolder.addCallback(surfaceCallback);
//previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// surfaceCallback.surfaceCreated(previewHolder);
//surfaceCallback.surfaceChanged(previewHolder, 0, 0, 0);
Log.i(TAG, "Surface was set");
}
public AtomicReference<byte[]> getNextData() {
return nextData;
}
public AtomicInteger getNextWidth() {
return nextWidth;
}
public AtomicInteger getNextHeight() {
return nextHeight;
}
private boolean checkCameraHardware() {
// if this device has a camera or not
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
public void releaseCamera(){
//if (previewHolder != null) {
// previewHolder.removeCallback(surfaceCallback);
// }
if (camera != null){
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release(); // release the camera for other applications
camera = null;
Log.i(TAG, "Released camera");
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
throw new IllegalStateException("Must start the service with intent");
}
switch (intent.getIntExtra(START_SERVICE_COMMAND, COMMAND_NONE)) {
case COMMAND_START_RECORDING:
initialize();
break;
default:
throw new UnsupportedOperationException("Cannot start service with illegal commands");
}
return START_NOT_STICKY;
}
private void initialize(){
camera = initializeCameraInstance();
previewCallback = createCameraPreviewCallback();
setPreviewHolder();
if (camera != null) {
SurfaceView sv = new SurfaceView(this);
Log.i(TAG, "aci is still null!");
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(1, 1,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
SurfaceHolder sh = sv.getHolder();
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
sv.setZOrderOnTop(true);
sh.setFormat(PixelFormat.TRANSPARENT);
sh.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
Camera.Parameters params = camera.getParameters();
camera.setParameters(params);
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getWorstPreviewSize(parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
camera.setPreviewCallback(previewCallback);
camera.startPreview();
//mCamera.unlock();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
wm.addView(sv, params);
}
}
private Camera initializeCameraInstance() {
/*if (this.camera != null) {
releaseCamera();
}*/
Camera camera = null;
try {
if (Camera.getNumberOfCameras() > 1) {
//if you want to open front facing camera use this line
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else {
camera = Camera.open();
}
}
catch (Exception e){
// Camera is not available (in use or does not exist)
Log.i(TAG, "Kamera nicht zur Benutzung freigegeben");
}
return camera; // returns null if camera is unavailable
}
private void consumeData(byte[] data, int width, int height) {
nextData.set(data);
nextWidth.set(width);
nextHeight.set(height);
}
private Camera.PreviewCallback createCameraPreviewCallback() {
return new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.i(TAG, "-----Preview frame received-----");
if (data == null) return;
Camera.Size size = camera.getParameters().getPreviewSize();
if (size == null) return;
consumeData(data, size.width, size.height);
}
};
}
private static Camera.Size getWorstPreviewSize(Camera.Parameters parameters) {
Camera.Size result = null;
int width = Integer.MAX_VALUE;
int height = Integer.MAX_VALUE;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea < resultArea) result = size;
}
}
}
return result;
}
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
public class CameraServiceBinder extends Binder {
public CameraHandler getService() {
return CameraHandler.this;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return cameraServiceBinder;
}
}
My Activity:
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.TextView;
import android.util.Log;
public class MotionDetectorActivity extends Activity {
private static final String TAG = "MotionDetectorActivity";
//private SurfaceView surfaceView;
private TextView txtStatus;
private MotionDetectorService motionDetectorService;
private boolean serviceBounded = false;
private ServiceConnection serviceConnection = createServiceConnection();
// private CameraHandler cameraHandler;
private AndroidScreenManager screenManager;
private long lastMotion;
PowerManager.WakeLock partialWakeLock;
private void createWakeLocks() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
//fullWakeLock = powerManager.newWakeLock(/*PowerManager.PARTIAL_WAKE_LOCK | */PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.FULL_WAKE_LOCK,
// "MotionDetectorActivity::FullWakelockTag");
partialWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
"MotionDetectorActivity::PartialWakelockTag");
}
private ServiceConnection createServiceConnection() {
return new ServiceConnection() {
public void onServiceConnected(ComponentName cName, IBinder serviceBinder) {
Log.i(TAG, "Service is getting connected");
MotionDetectorServiceBinder binder = (MotionDetectorServiceBinder) serviceBinder;
MotionDetectorActivity.this.motionDetectorService = binder.getService();
serviceBounded = true;
//motionDetectorService.setCameraHandler(cameraHandler);
motionDetectorService.setMotionDetectorCallback(new IMotionDetectorCallback() {
#Override
public void onMotionDetected() {
Log.v(TAG, "Motion detected");
txtStatus.setText("Motion detected");
lastMotion = System.currentTimeMillis();
if (!screenManager.isScreenOn()) {
Log.v(TAG, "Screen is turned off so waking it up");
screenManager.turnOn();
if (partialWakeLock.isHeld()) {
partialWakeLock.release();
}
}
/*if (!fullWakeLock.isHeld()) {
fullWakeLock.acquire();
}*/
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
txtStatus.setText("No motion detected");
/*if (fullWakeLock.isHeld()) {
fullWakeLock.release();
}*/
}
}, 750);
}
#Override
public void onNoMotionDetected() {
long now = System.currentTimeMillis();
if (now - lastMotion > 5*1000) {
Log.i(TAG, "No motion for more than 5 seconds, turning screen off");
//screenManager.turnOff();
}
}
#Override
public void onTooDark() {
Log.v(TAG, "Too dark here");
txtStatus.setText("Too dark here");
}
});
// Custom config options
motionDetectorService.setCheckIntervalMs(500);
motionDetectorService.setLeniency(30);
motionDetectorService.setMinLuma(500);
}
public void onServiceDisconnected(ComponentName cName){
serviceBounded = false;
}
};
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
screenManager = new AndroidScreenManager(this);
CameraHandler.starService(this);
createWakeLocks();
txtStatus = (TextView) findViewById(R.id.txtStatus);
lastMotion = System.currentTimeMillis();
}
#Override
protected void onStart() {
super.onStart();
Intent motionDetectorServiceIntent = new Intent(this, MotionDetectorService.class);
bindService(motionDetectorServiceIntent, serviceConnection, BIND_AUTO_CREATE);
startService(motionDetectorServiceIntent);
}
#Override
protected void onResume() {
Log.i(TAG, "-----onResume-----");
super.onResume();
/*if (motionDetectorService != null) {
motionDetectorService.releasePartialWakeLocK();
}
if (partialWakeLock.isHeld()) {
partialWakeLock.release();
Log.v(TAG, "Released partial wake lock in the activity");
}*/
}
private void acquirePartialWakeLock() {
if (!partialWakeLock.isHeld()) {
partialWakeLock.acquire();
Log.v(TAG, "Acquired partial wake lock in the activity");
}
}
#Override
protected void onPause() {
Log.i(TAG, "-----onPause-----");
//CameraHandler cameraHandler = new CameraHandler(this, surfaceView);
/*motionDetectorService.acquirePartialWakeLocK();*/
//acquirePartialWakeLock();
super.onPause();
}
private void unbindServiceIfBounded() {
if (serviceBounded) {
unbindService(serviceConnection);
serviceBounded = false;
Log.i(TAG, "Service is unbounded");
}
}
#Override
protected void onDestroy() {
Log.v(TAG, "Destroying app");
motionDetectorService.onDestroy();
unbindServiceIfBounded();
super.onDestroy();
}
#Override
protected void onStop() {
Log.i(TAG, "-----onStop-----");
//cameraHandler.releaseCamera();
//CameraHandler cameraHandler = new CameraHandler(this, surfaceView);
//acquirePartialWakeLock();
//unbindServiceIfBounded();
super.onStop();
}
}
Related
Today I had faced an issue in android surfaceview for camera customization.
I tried the below code.
The Issue occurred when I captured the image, it stops the camera
preview and doesn't return to the activity.
Following code will be implemented in the program. I took this code from an existing reference on stackoverflow
Supporting Class.
public class AndroidCameraSurfaceview extends Activity implements
SurfaceHolder.Callback {
TextView testView;
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean preview;
PictureCallback rawCallback;
ShutterCallback shutterCallback;
PictureCallback jpegCallback;
int displayheight, displaywidth;
Camera.PreviewCallback previewCallback;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.camerasurfaceview);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Bundle b = new Bundle();
b.putByteArray("Image", data);
Intent intent = new Intent();
intent.putExtras(b);
setResult(RESULT_OK, intent);
finish();
// refreshCamera();
}
};
}
public void captureImage(View v) throws IOException {
// take the picture
camera.takePicture(null, null, jpegCallback);
}
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
try {
camera.stopPreview();
} catch (Exception e) {
}
try {
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if (preview) {
camera.stopPreview();
}
try{
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, width, height);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(parameters);
try {
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(holder);
camera.startPreview();
preview = true;
} catch (IOException e) {
e.printStackTrace();
}
}catch(Exception e){
System.out.println("Surface Exception---=>"+e);
}
}
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
if (camera != null) {
Camera.Parameters params = camera.getParameters();
camera.setDisplayOrientation(90);
camera.setParameters(params);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// stop preview and release camera
camera.stopPreview();
camera.release();
camera = null;
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
2.Implemented in Activity
public void captureImage() {
Intent intentDriver = new Intent(AddNewDevice_Activity.this,
AndroidCameraSurfaceview.class);
startActivityForResult(intentDriver, 0);
//
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//
// Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
//
// intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
//
// // start the image capture Intent
// startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//
// fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
//
// intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
//
// // start the image capture Intent
// startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
System.out.println("Result Code: " + resultCode);
if (resultCode == RESULT_OK && data != null) {
Bundle bundle = data.getExtras();
byte[] test = bundle.getByteArray("Image");
Bitmap bpCamera = BitmapFactory.decodeByteArray(test, 0,
test.length);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bpCamera = Bitmap
.createBitmap(bpCamera, 0, 0, bpCamera.getWidth(),
bpCamera.getHeight(), matrix, true);
imageView_camera.setImageBitmap(bpCamera);
selectedImageStr = encodeTobase64(bpCamera);
}
} else {
finish();
}
}
You shold split activity and surface view.
public class AndroidCameraActivity extends Activity {
AndroidCameraSurfaceview surfaceView;
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
surfaceView = (AndroidCameraSurfaceview) findViewById(R.id.surfaceView);
}
}
class AndroidCameraSurfaceview extends SurfaceView implements SurfaceHolder.Callback {
public AndroidCameraSurfaceview(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
...
}
public void surfaceCreated(SurfaceHolder holder) {
...
}
public void surfaceDestroyed(SurfaceHolder holder) {
...
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
...
}
}
Google had revised the camera API from in API version 21, henceforth we have to adopt new camera2 package and has to be adhered in cases where camera functionalities comes into picture. Here is the link to sample code published by google which uses surface view implementation and it works flawless in Android 5.0. I believe it solves a bit of mystery.
https://github.com/googlesamples/android-Camera2Basic
try this, I have made it from my self :
package com.fragments;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import com.jsonparsing.JsonMainActivity;
import com.jsonparsing.MailFragment;
import com.mobehc.R;
import com.sendmail.main;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class CamImageCapture2 extends Fragment implements
MediaRecorder.OnInfoListener {
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
Camera c = null;
ImageView myButton, myButton1, backcam;
SurfaceHolder surfaceHolder;
boolean recording;
private Button startButton;
private Button pauseButton;
private TextView timerValue;
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
String path = Environment.getExternalStorageDirectory().toString()
+ "/00 MHC/VID.MP4";
/** Called when the activity is first created. */
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_captureimage, container,
false);
recording = false;
getActivity().getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
timerValue = (TextView) v.findViewById(R.id.timer);
// Get Camera for preview
myCamera = getCameraInstance();
if (myCamera == null) {
Toast.makeText(getActivity(), "Fail to get Camera",
Toast.LENGTH_LONG).show();
}
myCameraSurfaceView = new MyCameraSurfaceView(getActivity(), myCamera);
FrameLayout myCameraPreview = (FrameLayout) v
.findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton = (ImageView) v.findViewById(R.id.rec);
myButton1 = (ImageView) v.findViewById(R.id.rec1);
backcam = (ImageView) v.findViewById(R.id.backcamera);
backcam.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent ik = new Intent(getActivity(), Camrec2.class);
startActivity(ik);
// getActivity().finish();
getActivity().getFragmentManager().popBackStack();
}
});
myButton1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
myCamera.takePicture(null, null, mPicture);
}
});
myButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
File attachment1 = new File(Environment
.getExternalStorageDirectory(), "/00 MHC/image.jpg");
if (attachment1.exists()) {
attachment1.delete();
}
if (recording) {
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
// Exit after saved
getActivity().finish();
} else {
// Release Camera before MediaRecorder start
releaseCamera();
if (!prepareMediaRecorder()) {
Toast.makeText(getActivity(),
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
getActivity().finish();
}
mediaRecorder.start();
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
/*
* final TextView _tv = (TextView) findViewById(R.id.timer);
* _tv.setVisibility(View.VISIBLE); new
* CountDownTimer(60000, 1000) {
*
* public void onTick(long millisUntilFinished) {
* _tv.setText(new SimpleDateFormat("00:ss") .format(new
* Date(millisUntilFinished))); }
*
* public void onFinish() { _tv.setText("done!"); Intent ii
* = new Intent(Camrecord.this, Emailtry.class);
* startActivity(ii); finish(); } }.start();
*/recording = true;
// myButton.setText("STOP");
Drawable myDrawable = getResources().getDrawable(
R.drawable.stp);
myButton.setImageDrawable(myDrawable);
backcam.setVisibility(View.INVISIBLE);
}
}
});
return v;
}
PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File externalStorage = Environment.getExternalStorageDirectory();
String sdcardPath = externalStorage.getAbsolutePath() + "/00 MHC/";
File pictureFile = new File(sdcardPath + "/image" + ".jpg");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
File attachment1 = new File(
Environment.getExternalStorageDirectory(),
"/00 MHC/VID.mp4");
if (attachment1.exists()) {
attachment1.delete();
}
Toast.makeText(getActivity(), "Captured Successfully...",
Toast.LENGTH_LONG).show();
Fragment fr = new main();
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
// getActivity().finish();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
};
private Camera getCameraInstance() {
// TODO Auto-generated method stub
try {
// c = Camera.open(); // attempt to get a Camera instance
if (Camera.getNumberOfCameras() >= 2) {
// backcam.setVisibility(View.VISIBLE);
// if you want to open front facing camera use this line
c = Camera.open(CameraInfo.CAMERA_FACING_FRONT);
c = Camera.open(CameraInfo.CAMERA_FACING_BACK);
} else {
c = Camera.open(CameraInfo.CAMERA_FACING_BACK);
}
/*
* c.setDisplayOrientation(90); c.setPreviewDisplay(surfaceHolder);
*
* Camera.Parameters p = c.getParameters(); p.set("camera-id", 2);
* c.setParameters(p);
*/
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
private boolean prepareMediaRecorder() {
myCamera = getCameraInstance();
myCamera.setDisplayOrientation(90);
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setOrientationHint(270);
mediaRecorder.setOutputFile(path);
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setOnInfoListener(this);
mediaRecorder.setMaxFileSize(2500000); // Set max file size 5M
// mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder()
.getSurface());
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
#Override
public void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it
// first
releaseCamera(); // release the camera immediately on pause event
}
private void releaseMediaRecorder() {
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
}
}
private void releaseCamera() {
if (myCamera != null) {
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}
public class MyCameraSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int weight, int height) {
// If your preview can change or rotate, take care of those events
// here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw
// the preview.
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
private Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
int mins = secs / 60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
timerValue.setText("" + mins + ":" + String.format("%02d", secs)
+ ":" + String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
}
};
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
Log.v("VIDEOCAPTURE", "Maximum Duration Reached");
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
// Exit after saved
// getActivity().finish();
getActivity().getFragmentManager().popBackStack();
}
}
}
I Tried the Camera API 2, but i don't have time fix the issue within
the time line. This is the way I found the solutions for the issue
using camera API 1. When the Multiple Views are Handle Single
Activity. Please try this code in case of the Camera Handling.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_CAPTURE_CODE) {
if (resultCode == RESULT_OK) {
Bitmap bp = (Bitmap) data.getExtras().get("data");
Bitmap resized = Bitmap.createScaledBitmap(bp,
(int) (bp.getWidth() * 0.8),
(int) (bp.getHeight() * 0.8), true);
imageView_camera.setImageBitmap(resized);
SharedPreferences value_1_Details = getSharedPreferences(
"Value_1_Key", MODE_PRIVATE);
Value_1_SelectedPosId = Integer.parseInt(value_1_Details.getString(
"Value_1_ID", ""));
String value_1_Name = value_1_Details.getString("Value_1_Data", "");
btn_popup_value_1_Name.setText(value_1_Name);
SharedPreferences value_2_Details = getSharedPreferences(
"Value_2_Key", MODE_PRIVATE);
value_2_SelectedPosId = Integer.parseInt(value_2_Details.getString(
"Value_2_ID", ""));
String value_2_Name = value_2_Details.getString("Value_2_Data", "");
btn_dropdown_value_2_Name.setText(value_2_Name);
SharedPreferences value_3_Details = getSharedPreferences(
"Value_3_Key", MODE_PRIVATE);
value_3_PosId = Integer.parseInt(value_3_Details
.getString("Value_3_ID", ""));
String value_3_Name = value_3_Details.getString("Value_3_Data",
"");
btn_dropdown_value_3_Name.setText(value_3_Name);
rL_include_ViewDetails.setVisibility(View.GONE);
rL_include_AddNew.setVisibility(View.VISIBLE);
rL_include_View.setVisibility(View.GONE);
selectedImageStr = encodeTobase64(resized);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
}
}
}
For some weird reason the camera in the camerafragment is all stretched, it only appears when the theme is set to fullscreen/no action bar. Though my camera fragment has to be in fullscreen.
I have read some articles that your surfaceview should be equal to your camerapreview but when I change the resolution of the camerapreview the application crashes when entering the camerafragment.
Portrait camera:
Landscape camera:
The Camera fragment class:
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.io.IOException;
import java.io.OutputStream;
/**
* Created by Gebruiker on 29-10-2014.
*/
public class SecondFragment extends Fragment {
View rootView;
ImageButton cameraShootButton;
ImageButton cameraChangeButton;
ImageButton cameraFlitsButton;
ImageButton timelineButton;
ImageButton profileButton;
ViewPager mViewPager;
Boolean switching = false;
View.OnClickListener tapper = null;
SurfaceView cameraPreview = null;
SurfaceHolder cameraPreviewHolder = null;
Camera camera = null;
boolean inPreview = false;
boolean cameraConfigured = false;
Integer currentCamera;
public static SecondFragment newInstance(String text) {
SecondFragment f = new SecondFragment();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.second_frag, container, false);
timelineButton = (ImageButton) rootView.findViewById(R.id.timelineB);
profileButton = (ImageButton) rootView.findViewById(R.id.profileB);
cameraShootButton = (ImageButton) rootView.findViewById(R.id.captureB);
cameraChangeButton = (ImageButton) rootView.findViewById(R.id.changeCameraB);
cameraFlitsButton = (ImageButton) rootView.findViewById(R.id.flitserB);
cameraPreview = (SurfaceView) rootView.findViewById(R.id.cameraView);
cameraPreviewHolder = cameraPreview.getHolder();
cameraPreviewHolder.addCallback(surfaceCallback);
cameraPreviewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mViewPager = (ViewPager) getActivity().findViewById(R.id.viewPager);
tapper = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.timelineB) {
mViewPager.setCurrentItem(0);
} else if (v.getId() == R.id.captureB) {
camera.takePicture(ShutterCallback, PictureCallbackRaw, null, PictureCallbackJpeg);
} else if(v.getId() == R.id.profileB){
mViewPager.setCurrentItem(2);
} else if (v.getId() == R.id.changeCameraB) {
if (switching == true){
return;
}
changeCamera();
} else if (v.getId() == R.id.flitserB){
}
}
};
cameraShootButton.setOnClickListener(tapper);
cameraChangeButton.setOnClickListener(tapper);
cameraFlitsButton.setOnClickListener(tapper);
timelineButton.setOnClickListener(tapper);
profileButton.setOnClickListener(tapper);
return rootView;
}
#Override
public void onResume() {
super.onResume();
camera = getCamera("back");
currentCamera = 1;
startPreview();
}
#Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && cameraPreviewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(cameraPreviewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
}
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Log.v("CAMERA", parameters.toString());
Camera.Size size = getBestPreviewSize(width, height,
parameters);
if (size != null) {
Log.v("CameraPreviewHeight", ""+cameraPreview.getMeasuredHeight());
Log.v("CameraRES", size.width + " " + size.height);
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
}
}
}
}
private void startPreview() {
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
camera.setDisplayOrientation(90);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
camera.enableShutterSound(false);
}
}
}
private void changeCamera() {
switching = true;
if (inPreview) {
camera.stopPreview();
camera.setPreviewCallback(null);
}
camera.release();
camera = null;
inPreview = false;
if (currentCamera==1){
camera = getCamera("front");
currentCamera =2;
}
else{
camera = getCamera("back");
currentCamera = 1;
}
camera.setDisplayOrientation(90);
try {
camera.setPreviewDisplay(cameraPreviewHolder);
cameraPreviewHolder.addCallback(surfaceCallback);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
inPreview = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
camera.enableShutterSound(false);
}
switching = false;
}
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
};
Camera.ShutterCallback ShutterCallback = new Camera.ShutterCallback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
#Override
public void onShutter() {
}
};
Camera.PictureCallback PictureCallbackRaw = new Camera.PictureCallback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
Camera.PictureCallback PictureCallbackJpeg = new Camera.PictureCallback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
#Override
public void onPictureTaken(byte[] byteData, Camera camera) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
OutputStream bos = null;
Bitmap m = BitmapFactory.decodeByteArray(byteData, 0, byteData.length, options);
//m.compress(Bitmap.CompressFormat.PNG, 75, bos);
//Log.v("CAPTURED", ""+bos);
}
};
private Camera getCamera(String getCamera) {
int cameraCount = 0;
Camera cam = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if ((cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) && (getCamera == "front")) {
try {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e("TEST", "Camera failed to open: " + e.getLocalizedMessage());
}
}
else if ((cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) && (getCamera == "back")) {
try {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e("TEST", "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
return cam;
}
}
EDIT:
I've editted the onPictureTaken to:
#Override
public void onPictureTaken(byte[] byteData, Camera camera) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
OutputStream bos = null;
Bitmap bmp = BitmapFactory.decodeByteArray(byteData, 0, byteData.length, options);
FileOutputStream out = null;
String path = Environment.getExternalStorageDirectory().toString();
File file = new File(path, "TestFile.png");
try {
out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 0, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//m.compress(Bitmap.CompressFormat.PNG, 75, bos);
//Log.v("CAPTURED", ""+bos);
}
Now there is a preview of the picture on the sd card and when I check it, the result is really weird. I've taken it in portrait modus.
Zoomed in:
I have created separate thread to open the camera for preview with setPreviewCallbackWithBuffer. However, how do I set the of the camera with the mHolder of SurfaceView? The Handler has to pass it as a message to the mThread?
package com.example.cameraactivity;
import java.io.IOException;
import java.util.concurrent.Semaphore;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Button;
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private CameraHandlerThread mThread = null;
private static class CameraHandlerThread extends HandlerThread implements PreviewCallback{
private static final String TAG = "CameraHandlerThread";
Handler mHandler = null;
private Camera mCamera;
private float framerate = 0;
int i = 0, t = 0;
long now, oldnow, count = 0;
private int preview_width = 640, preview_height = 320;
private int bitsPerPixel = 8;
private int bufSize = preview_width * preview_height * bitsPerPixel/ 8;
static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
CameraHandlerThread() {
super("CameraHandlerThread");
start();
mHandler = new Handler(getLooper());
}
synchronized void notifyCameraOpened() {
notify();
}
void openCamera() {
mHandler.post(new Runnable() {
#Override
public void run() {
getCameraInstance();
notifyCameraOpened();
}
});
try {
wait();
}
catch (InterruptedException e) {
Log.w(TAG, "wait was interrupted");
}
}
private void getCameraInstance(){
try {
mCamera = Camera.open(1);
}
catch (RuntimeException e) {
Log.e(TAG, "failed to open front camera");
}
setParameters();
for (int i = 0; i < NUM_CAMERA_PREVIEW_BUFFERS; i++) {
byte [] cameraBuffer = new byte[bufSize];
mCamera.addCallbackBuffer(cameraBuffer);
}
mCamera.setPreviewCallbackWithBuffer(this);
//mCamera.setPreviewDisplay(mHolder);
}
private void setParameters(){
Camera.Parameters params = mCamera.getParameters();
//params.setPreviewSize(640, 320);
params.setPreviewFpsRange(150000, 150000);
params.setAutoWhiteBalanceLock(true);
params.setAutoExposureLock(true);
mCamera.setParameters(params);
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
i++;
now = System.nanoTime()/1000;
t = (int)( now - oldnow);
framerate = (int) (1000000/t);
oldnow = now;
Log.i(TAG, "Framerate: " + framerate);
mCamera.addCallbackBuffer(data);
}
void startPreview() {
mCamera.startPreview();
}
void stopPreview() {
mCamera.stopPreview();
}
}
private void openCamera() {
if (mThread == null) {
mThread = new CameraHandlerThread();
}
synchronized (mThread) {
mThread.openCamera();
}
}
private void startPreview() {
synchronized (mThread) {
mThread.startPreview();
}
}
private void stopPreview() {
synchronized (mThread) {
mThread.stopPreview();
}
}
public CameraPreview(Context context) {
super(context);
//mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
//mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Log.i(TAG, "init");
}
public void surfaceCreated(SurfaceHolder holder) {
try {
openCamera();
startPreview();
Log.i(TAG, "surfaceCreated");
} catch (Exception e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
stopPreview();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null){
return;
}
try {
stopPreview();
} catch (Exception e){
}
try {
startPreview();
Log.i(TAG, "surfaceChanged");
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
You really want to limit your interactions with Camera to a single thread. You should be able to wrap accesses from multiple threads with explicit mutex synchronization, but it's usually simpler to do everything on one. If the camera handling and your surface callbacks run on different threads, it's probably best to pass the SurfaceHolder through a message to a Handler.
Grafika demonstrates a couple of different approaches. In "Show + capture camera", the camera is handled on the UI thread. In "Texture from camera", it's handled on the renderer thread. See the notes near the top of each activity class for additional info.
Things can get complicated in a hurry when you try to manage the Camera object so that it is handled correctly with regard to the lifecycles of the app (pause/resume) and surface (created/destroyed), which aren't as tightly coupled as one might hope. Some details about that can be found here (also referenced from the comments in Grafika).
I am trying to switch between the device's Front and Back Camera while showing the camera preview. I am following the sample provide by common ware. Below is the code which I am using. Whenever I click on the Flip button, the surface view goes black, and I don't know where I am going wrong. I have tried to restart the current activity, but I don't want like that.
package com.commonsware.android.camera;
import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Toast;
import android.widget.ToggleButton;
public class PreviewDemo extends Activity {
private SurfaceView preview = null;
private SurfaceHolder previewHolder = null;
private Camera camera = null;
private boolean inPreview = false;
private boolean cameraConfigured = false;
private ToggleButton flipCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
flipCamera = (ToggleButton) findViewById(R.id.flip);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
flipCamera.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
restartPreview(isChecked);
}
});
}
#Override
public void onResume() {
super.onResume();
// camera=Camera.open();
int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
if (Camera.getNumberOfCameras() > 1
&& camId < Camera.getNumberOfCameras() - 1) {
// startCamera(camId + 1);
camera = Camera.open(camId + 1);
} else {
// startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
camera = Camera.open(camId);
}
startPreview();
}
void restartPreview(boolean isFront) {
if (inPreview) {
camera.stopPreview();
}
//
camera.release();
// camera=null;
// inPreview=false;
// /*int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
// if (Camera.getNumberOfCameras() > 1 && camId <
// Camera.getNumberOfCameras() - 1) {
// //startCamera(camId + 1);
// camera = Camera.open(camId + 1);
// } else {
// //startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
// camera = Camera.open(camId);
// }*/
int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
if (isFront) {
camera = Camera.open(camId);
camera.startPreview();
} else {
camera = Camera.open(camId + 1);
camera.startPreview();
}
// startPreview();
}
#Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
Toast.makeText(PreviewDemo.this, t.getMessage(),
Toast.LENGTH_LONG).show();
}
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
}
}
}
}
private void startPreview() {
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
}
}
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
if (camera != null) {
/*
* Call stopPreview() to stop updating the preview surface.
*/
camera.stopPreview();
/*
* Important: Call release() to release the camera for use by
* other applications. Applications should release the camera
* immediately in onPause() (and re-open() it in onResume()).
*/
camera.release();
camera = null;
}
}
};
}
You seem to have forgotten to call setPreviewDisplay() (or, in your case, initPreview()) before calling startPreview() from your restartPreviev() method. Effectively, you're trying to start preview without specifying a surface to render the preview into.
if anyone has any idea that how to switch between front and back camera when using MediaRecorder . I defing a button for this function, but have no idea how to define the onclickListener.
the total activity is the following:
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.widget.Button;
public class Test_cameraActivity extends Activity implements Callback {
// Camera variables to fiddle with video preview.
// private Camera cam;
// Viewholders etc
private SurfaceHolder recordViewHolder;
private SurfaceView recordSurface;
private int width, height;
// Button
private Button recordBut;
private Button switchBut;
private Button libraryBut;
private final static String DIRECTORY = "/hdrecorder"; // Directory where
// the film is
// stored
private final static String recordFileName = "/hdtestfile.mp4";
private final static String saveFileName = "/hdsavefile.mp4";
private MyMediaRecorder recorder = null;
private final static String LOG_TAG = "HD Recorder";
private String filePath;
// Activity overrides
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// *******************************************
// fullscreen mode
// *******************************************
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// *******************************************
setContentView(R.layout.main);
File dir = new File(Environment.getExternalStorageDirectory()
+ DIRECTORY);
if (!dir.exists()) {
if (dir.mkdir()) {
Log.v(LOG_TAG, "Created directory");
} else {
Log.v(LOG_TAG, "Failed to create Directory");
}
}
File videoFile = new File(Environment.getExternalStorageDirectory()
+ DIRECTORY + recordFileName);
if (!videoFile.exists()) {
videoFile.delete(); // Reset recording
}
filePath = videoFile.getAbsolutePath();
Log.v(LOG_TAG, "PATH:" + filePath);
Log.v(LOG_TAG, "PATH:" + filePath);
recordSurface = (SurfaceView) findViewById(R.id.videoSurface);
recordBut = (Button) findViewById(R.id.RecordBut);
recordBut.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (recorder.getState() != MyMediaRecorder.RECORDING) {
startRecord();
} else {
stopRecord();
recorder.release();
moveRecordFileToSave();
if (recorder == null) {
Log.v(LOG_TAG, "Recorder is null");
}
Log.v(LOG_TAG, "Value of recorder:" + recorder);
createRecorder();
initiateRecorder(recordViewHolder, width, height);
}
}
});
switchBut = (Button) findViewById(R.id.SwitchBut);
switchBut.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
libraryBut = (Button) findViewById(R.id.LibraryBut);
libraryBut.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Test_cameraActivity.this,
FileExplorer.class);
Test_cameraActivity.this.startActivity(intent);
}
});
recordViewHolder = recordSurface.getHolder();
recordViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
recordViewHolder.addCallback(this);
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
createRecorder();
}
#Override
protected void onStart() {
super.onStart();
Log.v(LOG_TAG, "OnStart");
if (recorder != null) {
if (recorder.getState() == MyMediaRecorder.RELEASED) {
createRecorder();
}
}
Log.v(LOG_TAG, "SurfaceView create initiated. OnStart Done");
}
#Override
protected void onStop() {
super.onStop();
Log.v(LOG_TAG, "onStop received");
forceStopRecorder();
}
// General Helpers.
private void createRecorder() {
recorder = new MyMediaRecorder();
}
private void startRecord() {
if (recorder.getState() != MyMediaRecorder.PREPARED) {
Log.e(LOG_TAG, "Not recordable yet");
return;
}
recorder.start();
Log.v(LOG_TAG, "Recording started");
recordBut.setText("Stop Record");
}
private void stopRecord() {
Log.v(LOG_TAG, "Stop of recorder");
if (recorder.getState() == MyMediaRecorder.RECORDING) {
recorder.stop();
}
recorder.reset();
recordBut.setText("Record");
}
private void initiateRecorder(SurfaceHolder holder, int width, int height) {
Log.v(LOG_TAG, "H: " + height + " W:" + width);
if (recorder.getState() != MyMediaRecorder.INITIAL) {
Log.v(LOG_TAG, "Dude - not existing MediaRecorder - quitting");
return;
}
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(this.filePath);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setVideoSize(width, height);
recorder.setVideoFrameRate(24);
recorder.setPreviewDisplay(holder.getSurface());
Log.d(LOG_TAG, "Preview restarted");
try {
recorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// isPrepared = true;
}
private void forceStopRecorder() {
Log.v(LOG_TAG, "Force release of recorder");
if (recorder.getState() != MyMediaRecorder.RELEASED) {
stopRecord();
recorder.release();
}
}
private void moveRecordFileToSave() {
File source = new File(filePath);
File dest = new File(Environment.getExternalStorageDirectory()
+ DIRECTORY + saveFileName);
if (dest.exists()) {
Log.v(LOG_TAG, "Delete old save file");
dest.delete();
}
source.renameTo(dest);
}
// ***** Implementing Callback ********/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
recordViewHolder = holder;
this.width = width;
this.height = height;
if (recorder.getState() == MyMediaRecorder.RECORDING) {
stopRecord();
}
if (recorder.getState() == MyMediaRecorder.PREPARED) {
recorder.reset();
}
initiateRecorder(holder, width, height);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.v(LOG_TAG, "Surface is created: Path to use" + filePath);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.v(LOG_TAG, "Surface is Destroyed");
forceStopRecorder();
}
}
I have something that might also help, in order to jump to the other camera, follow this method:
public void flipit() {
//myCamera is the Camera object
if (Camera.getNumberOfCameras()>=2) {
myCamera.stopPreview();
myCamera.release();
//"which" is just an integer flag
switch (which) {
case 0:
myCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
which = 1;
break;
case 1:
myCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
which = 0;
break;
}
try {
myCamera.setPreviewDisplay(mHolder);
//"this" is a SurfaceView which implements SurfaceHolder.Callback,
//as found in the code examples
myCamera.setPreviewCallback(this);
myCamera.startPreview();
} catch (IOException exception) {
myCamera.release();
myCamera = null;
}
}
}
Now... for the magic trick, don't call this method from the main thread. Instead this method has to be kicked off from a separate thread, my code does this:
//btn is a Button that the user clicks on
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//onClick is invoked from main thread
//kick-off a different Thread to handle this call
Thread t = new Thread() {
public void run() {
//myViewer is the SurfaceView object which uses
//the camera
myViewer.flipit();
}
};
t.start();
}
});
I've tested this on Android 4.1.1 so I think it might work for you. (or until Google decides to break the way the camera opening/closing/releasing/unlocking/reconnecting/surfaceholder/onPause/onResume/etc..? works)
First, check if your device has more than one camera:
Camera.getNumberOfCameras();
Then, assign a camId value:
camId = Camera.CameraInfo.CAMERA_FACING_BACK;
or
camId = Camera.CameraInfo.CAMERA_FACING_FRONT;
and then creates a new Camera object to access a particular hardware camera (camId).
mCamera = Camera.open(camId);
Hope this help!