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();
}
}
}
Related
I have a MainActivity which is only used if phone number is not set in Shared Preference. After setting phone number once there is no need of MainActivity and everytime user opens app he should goto CameraActivity Activity which have Camera API working in SurfaceView in it.
There is no problem in opening CameraActivity using button on MainActivity but if I open CameraActivity from MainACtivity onCreate method then I am facing following Error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.Camera.setDisplayOrientation(int)' on a null object reference
at com.vivertechnologies.camera.ShowCamera.refreshCamera(ShowCamera.java:208)
at com.vivertechnologies.camera.ShowCamera.surfaceChanged(ShowCamera.java:281)
at android.view.SurfaceView.updateWindow(SurfaceView.java:590)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:176)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:847)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1983)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1081)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5818)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5234)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)
My Code from Camera API is:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_show);
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
// update TextView here!
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String formattedDate = df.format(c.getTime());
TextView txtView = (TextView)findViewById(R.id.dateTime);
txtView.setText(formattedDate);
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
new Thread(new SavePicThread(data)).start();
//
// Intent i = new Intent(ShowCamera.this, UploadActivity.class);
// i.putExtra("isImage", data);
// startActivity(i);
refreshCamera();
}
};
}
Refresh Camera Method which is generating error:
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
int rotation = ((WindowManager)ShowCamera.this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = 0;
// specifically for back facing camera
switch (rotation) {
case Surface.ROTATION_0:
degrees = 90;
break;
case Surface.ROTATION_90:
degrees = 0;
break;
case Surface.ROTATION_180:
degrees = 270;
break;
case Surface.ROTATION_270:
degrees = 180;
break;
}
camera.setDisplayOrientation(degrees);
setCamera(camera);
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Log.d("AAAAA", "Error starting camera preview: " + e.getMessage());
}
}
I am unable to identify how it can be solved.
Edit:
Complete Code:
package com.vivertechnologies.camera;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* Created by usman on 27/11/15.
*/
public class ShowCamera extends MainActivity implements SurfaceHolder.Callback {
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera.PictureCallback rawCallback;
Camera.ShutterCallback shutterCallback;
Camera.PictureCallback jpegCallback;
private Camera.Size mPreviewSize;
private List<Camera.Size> mSupportedPreviewSizes;
private Context mContext;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private final String TAG = "CameraSurfaceView";
private Camera mCamera;
private List<String> mSupportedFlashModes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_show);
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
// update TextView here!
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String formattedDate = df.format(c.getTime());
TextView txtView = (TextView)findViewById(R.id.dateTime);
txtView.setText(formattedDate);
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
new Thread(new SavePicThread(data)).start();
//
// Intent i = new Intent(ShowCamera.this, UploadActivity.class);
// i.putExtra("isImage", data);
// startActivity(i);
refreshCamera();
}
};
}
private void galleryAddPic(File file) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
ShowCamera.this.sendBroadcast(mediaScanIntent);
}
public class SavePicThread implements Runnable {
byte[] data;
public SavePicThread(byte[] data) {
this.data = data;
}
public void run() {
// make a new picture file
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
// write to the file
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.flush();
fos.close();
ShowCamera.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Toast toast = Toast.makeText(ShowCamera.this, "Picture saved", Toast.LENGTH_SHORT);
// toast.show();
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// make the picture visible to the rest of the device
galleryAddPic(pictureFile);
Intent i = new Intent(ShowCamera.this, UploadActivity.class);
i.putExtra("filePath", pictureFile.getPath());
startActivity(i);
}
}
// make picture and save to a folder
private File getOutputMediaFile() {
// make a new file directory inside the "sdcard" folder
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "imgCaptureApp");
// if the directory does not exist
if (!mediaStorageDir.exists()) {
// if you cannot make this directory return
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
// take the current timeStamp
String timeStamp = new SimpleDateFormat("dd-MM-yyyy_HH:mm:ss").format(new Date());
File mediaFile;
// and make a media file:
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
public void captureImage(View v) throws IOException {
camera.takePicture(null, null, jpegCallback);
}
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
int rotation = ((WindowManager)ShowCamera.this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = 0;
// specifically for back facing camera
switch (rotation) {
case Surface.ROTATION_0:
degrees = 90;
break;
case Surface.ROTATION_90:
degrees = 0;
break;
case Surface.ROTATION_180:
degrees = 270;
break;
case Surface.ROTATION_270:
degrees = 180;
break;
}
camera.setDisplayOrientation(degrees);
setCamera(camera);
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Log.d("AAAAA", "Error starting camera preview: " + e.getMessage());
}
}
public void setCamera(Camera camera)
{
Camera mCamera = camera;
if (mCamera != null)
{
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))
{
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
}
surfaceView.requestLayout();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
}
catch (RuntimeException e) {
System.err.println(e);
return;
}
Camera.Parameters param;
param = camera.getParameters();
List<Camera.Size> sizes = param.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
for(int i=0;i<sizes.size();i++)
{
if(sizes.get(i).width > size.width)
size = sizes.get(i);
}
param.setPictureSize(size.width, size.height);
param.setRotation(90);
param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// param.setPreviewSize(352, 288);
camera.setParameters(param);
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
}
catch (Exception e) {
System.err.println(e);
return;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
refreshCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
}
From your description, your problem appears to be that ShowCamera is a subclass of MainActivity. Presumably, you have something similar to the following in MainActivity's onCreate() method:
SharedPreferences prefs = ...
if(prefs.getBoolean("phone_number_set", false)) {
startActivity(new Intent(this, ShowCamera.class));
}
Since ShowCamera is a subclass of MainActivity, calling super.onCreate(savedInstanceState); in ShowCamera's onCreate() method is executing MainActivity's onCreate() method again. When you open ShowCamera with the Button, you've not yet set the phone number, so the if conditional shown above is false, and the startActivity() method doesn't get called again.
However, after you've set the phone number, the conditional is true, and it starts ShowCamera again, which is calling MainActivity's onCreate(), which executes the if block, which starts ShowCamera, which calls MainActivity's onCreate(), which executes the if block, which starts ShowCamera... This is easily verified by adding a static int to the ShowCamera class, printing it to the Log in onCreate(), and then immediately incrementing it.
Eventually, one of the ShowCamera instances will layout its SurfaceView and call refreshCamera() from the surfaceChanged() callback, but it will have a null Camera object, because a previous Activity already has the camera.open, and it will throw the NullPointerException you're getting.
The solution is simple. Change the ShowCamera class to be a direct subclass of Activity. That is:
public class ShowCamera extends Activity implements SurfaceHolder.Callback {
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'm developing an application that when i press a button launches an activity (for result) that will take the picture and store it. Than the previous activity will display the photo.
I'm using a CameraPreview class and a CameraActivity activity to achieve it.
Everything must be in portrait mode and it all works perfectly: i start the new activity with the preview, take the picture in portrait mode and return to the previous activity with the picture shown in a box.
The only problem is that the picture is shown (and stored) turned 90° counterclockwise. How can I avoid it?
Here's my Activity:
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
// Create an instance of Camera
mCamera = getCameraInstance();
mCamera.setDisplayOrientation(90);
Parameters params = mCamera.getParameters();
params.setRotation(90);
params.setPictureSize(100, 200);
mCamera.setParameters(params);
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions");
Intent intent = getIntent();
setResult(RESULT_CANCELED, intent);
finish();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Intent intent = getIntent();
setResult(RESULT_OK, intent);
finish();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
return;
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
Intent intent = getIntent();
setResult(RESULT_CANCELED, intent);
finish();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
return;
}
};
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void scatta(View v) {
mCamera.takePicture(null, null, mPicture);
}
private File getOutputMediaFile(){
HERE I RETURN A VALID FILE.
return file;
}
}
And here's the Preview:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(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);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// 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
}
// set preview size and make any resize, rotate or
// reformatting changes here
mCamera.setDisplayOrientation(90);
Parameters params = mCamera.getParameters();
params.setRotation(90);
mCamera.setParameters(params);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Thank you
Yes, I've found the solution:
This is my Camera activity:
package it......utils;
import it.......R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cam);
// Create an instance of Camera
mCamera = getCameraInstance();
Parameters params = mCamera.getParameters();
params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
params.setPictureFormat(ImageFormat.JPEG);
Camera.Size size = getSmallestPictureSize(params);
params.setPictureSize(size.width, size.height);
mCamera.setParameters(params);
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
private Camera.Size getSmallestPictureSize(Camera.Parameters parameters) {
List<Size> list = parameters.getSupportedPictureSizes();
Collections.sort(list, new AreasComparator());
return list.get(1); // I choose the second one becasue the first one is too small.
}
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Intent intent = getIntent();
setResult(RESULT_CANCELED, intent);
finish();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
System.gc();
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
System.gc();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
Intent intent = getIntent();
setResult(RESULT_OK, intent);
finish();
System.gc();
return;
} catch (FileNotFoundException e) {
//TODO
} catch (IOException e) {
//TODO
}
Intent intent = getIntent();
setResult(RESULT_CANCELED, intent);
finish();
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
System.gc();
return;
}
};
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void scatta(View v) {
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
mCamera.takePicture(null, null, mPicture);
}
}
});
}
private File getOutputMediaFile(){
File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String filePath = downloads.getParent() + File.separator + "PicturesTaken";
File path = new File(filePath);
path.mkdirs();
File file;
file = new File(path, "pic.jpg");
if (file.exists()) {
file.delete();
}
return file;
}
#Override
public void onBackPressed() {
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
mPreview = null;
System.gc();
super.onBackPressed();
}
public class AreasComparator implements Comparator<Camera.Size> {
#Override
public int compare(Camera.Size s1, Camera.Size s2) {
int resultArea=s1.width * s1.height;
int newArea=s2.width * s2.height;
if (newArea < resultArea) {
return 1;
}
return -1;
}
}
}
With its' layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
tools:context=".CameraActivity" >
<FrameLayout
android:id="#+id/camera_preview"
android:onClick="scatta"
android:layout_width="match_parent"
android:layout_height="700dp" >
</FrameLayout>
</RelativeLayout>
And this is my Camera Preview:
package it........utils;
import java.io.IOException;
import java.util.List;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(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);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
//TODO
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// 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
}
// set preview size and make any resize, rotate or
// reformatting changes here
mCamera.setDisplayOrientation(90);
Parameters params = mCamera.getParameters();
params.setRotation(90);
mCamera.setParameters(params);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
//TODO
}
}
}
And finally, this is what I do in my main activity to call the Camera and show the taken picture:
private void startCamera() {
Intent intent = new Intent(Pag4Activity.this, CameraActivity.class);
startActivityForResult(intent, CODE_CAM);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK) {
if(requestCode == CODE_CAM){
File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String filePath = downloads.getParent() + File.separator + "PicturesTaken";
File path = new File(filePath);
path.mkdirs();
File file = new File(path, "pic.jpg");
ImageView iv = (ImageView)findViewById(R.id.imageTaken);
Bitmap img = decodeScaledBitmapFromSdCard(file.getPath(), 170, 210);
if(img!=null) {
iv.setImageBitmap(img);
}
}
}
}
public static Bitmap decodeScaledBitmapFromSdCard(String filePath,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
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!