adding camera preview to a frame layout in a fragment xml programatically - android

I am trying to set the camera preview in my fragment and add some xml elements like buttons and signs over the preview.
however while using addview the preview of the camera appears different based on devices ratio and camera. sometime it's on top and sometimes it's at bottom pushing the capture button out of the layout.
Note: I've been trying to set the framelayout containing the preview to alignparenttop or centercrop. however the after adding the preview usign addView programatically it keeps showing unaligned while pushing elements off the layout view in certain devices.
meanwhile in some devices it displays the layout aligned to top and elements located over the framlayout.
here is my fragment code
public class KycCameraFragment extends Fragment {
public static final String TAG = "KycCameraFragment";
// Native camera.
private Camera mCamera;
// View to display the camera output.
private CameraPreview mPreview;
// Reference to the containing view.
private View mCameraView;
public KycCameraFragment() {
// Required empty public constructor
}
#Override
public void onStart() {
super.onStart();
// register the event to listen.
GlobalBus.getBus().register(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_kyc_camera, container, false);
// Create our Preview view and set it as the content of our activity.
boolean opened = safeCameraOpenInView(view);
if(opened == false){
Log.d("CameraGuide","Error, Camera failed to open");
return view;
}
// Trap the capture button_round.
Button captureButton = (Button) view.findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
return view;
}
#Subscribe(sticky = true)
public void getMessage(Events.FragmentIdTypeMessage fragmentIdTypeMessage) {
TextView _tvEKYCCamera = (TextView) getView().findViewById(R.id.tvEKYCCamera);
_tvEKYCCamera.setText("Message from Fragment ID type" + " " + fragmentIdTypeMessage.getMessage());
Toast.makeText(getContext(),
"Message Received: " + fragmentIdTypeMessage.getMessage(),
Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroyView() {
super.onDestroyView();
// unregister the registered event.
releaseCameraAndPreview();
GlobalBus.getBus().unregister(this);
}
/**
* Recommended "safe" way to open the camera.
* #param view
* #return
*/
private boolean safeCameraOpenInView(View view) {
boolean qOpened = false;
releaseCameraAndPreview();
mCamera = getCameraInstance();
mCameraView = view;
qOpened = (mCamera != null);
if(qOpened == true){
mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.startCameraPreview();
}
return qOpened;
}
/**
* Safe method for getting a camera instance.
* #return
*/
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
/**
* Clear any existing preview / camera.
*/
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if(mPreview != null){
mPreview.destroyDrawingCache();
mPreview.mCamera = null;
}
}
/**
* Surface on which the camera projects it's capture results. This is derived both from Google's docs and the
* excellent StackOverflow answer provided below.
*
* Reference / Credit: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
*/
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* #param camera
*/
private void setCamera(Camera camera)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* #param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* #param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* #param holder
* #param format
* #param w
* #param h
*/
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 {
Camera.Parameters parameters = mCamera.getParameters();
// Set the auto-focus mode to "continuous"
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// Preview size must exist.
if(mPreviewSize != null) {
Camera.Size previewSize = mPreviewSize;
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (Exception e){
e.printStackTrace();
}
}
/**
* Calculate the measurements of the layout
* #param widthMeasureSpec
* #param heightMeasureSpec
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
/**
* Update the layout based on rotation and orientation changes.
* #param changed
* #param left
* #param top
* #param right
* #param bottom
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
Log.d(TAG,"0 degree camera orientation got hit");
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
//added to fix rotation issue
Log.d(TAG,"90 degree camera orientation got hit");
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
//added to fix rotation issue
mCamera.setDisplayOrientation(0);
Log.d(TAG,"180 degree camera orientation got hit");
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
Log.d(TAG,"270 degree camera orientation got hit");
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
/**
*
* #param sizes
* #param width
* #param height
* #return
*/
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
.show();
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
// Restart the camera preview.
safeCameraOpenInView(mCameraView);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* Used to return the camera File output.
* #return
*/
private File getOutputMediaFile(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MM");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("CameraGuide", "Required media storage does not exist");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
Toast.makeText(getActivity(),"Your picture has been saved!", Toast.LENGTH_LONG).show();
// DialogHelper.showDialog( "Success!","Your picture has been saved!",getActivity());
return mediaFile;
}
}
my fragment XML:
<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:background="#color/black"
>
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/tvEKYCCamera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#color/black"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="center"
>
<View
android:id="#+id/myRectangleView"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#drawable/rectangle"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Place ID Within Here"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="#+id/button_capture"
android:text=""
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"
android:background="#drawable/camera_button"
/>
</LinearLayout>

Related

Android Camera preview rotated 90degree and stretched in certain devices

I have been working on a piece of code to preview and capture photo inside my fragment. I have made this by following Airpair guides on camera.
Problem is: Android Camera preview is rotated by 90degree and therefore looks stretched as well in certain devices.
Note: I tried this on my Samsung Galaxy Alpha (4.9 inch screen) and it worked properly. However in Huawei P8 (5 inch screen) and nexus 5x (5.2 inch screen) it was showing 90 degree rotated stretched preview.
I have seen others posting similar issue on `SO', however those solutions have already been integrated to this code.
for instance overriding protected void onLayout(boolean changed, int left, int top, int right, int bottom) is used to fix the rotation.
I would appreciate if you could point out what I've been missing.
/**
* A simple {#link Fragment} subclass.
*/
public class KycCameraFragment extends Fragment {
public static final String TAG = "KycCameraFragment";
// Native camera.
private Camera mCamera;
// View to display the camera output.
private CameraPreview mPreview;
// Reference to the containing view.
private View mCameraView;
public KycCameraFragment() {
// Required empty public constructor
}
#Override
public void onStart() {
super.onStart();
// register the event to listen.
GlobalBus.getBus().register(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_kyc_camera, container, false);
// Create our Preview view and set it as the content of our activity.
boolean opened = safeCameraOpenInView(view);
if(opened == false){
Log.d("CameraGuide","Error, Camera failed to open");
return view;
}
// Trap the capture button.
Button captureButton = (Button) view.findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
return view;
}
#Subscribe(sticky = true)
public void getMessage(Events.FragmentIdTypeMessage fragmentIdTypeMessage) {
TextView _tvEKYCCamera = (TextView) getView().findViewById(R.id.tvEKYCCamera);
_tvEKYCCamera.setText("Message from Fragment ID type" + " " + fragmentIdTypeMessage.getMessage());
Toast.makeText(getContext(),
"Message Received: " + fragmentIdTypeMessage.getMessage(),
Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroyView() {
super.onDestroyView();
// unregister the registered event.
releaseCameraAndPreview();
GlobalBus.getBus().unregister(this);
}
/**
* Recommended "safe" way to open the camera.
* #param view
* #return
*/
private boolean safeCameraOpenInView(View view) {
boolean qOpened = false;
releaseCameraAndPreview();
mCamera = getCameraInstance();
mCameraView = view;
qOpened = (mCamera != null);
if(qOpened == true){
mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.startCameraPreview();
}
return qOpened;
}
/**
* Safe method for getting a camera instance.
* #return
*/
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
/**
* Clear any existing preview / camera.
*/
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if(mPreview != null){
mPreview.destroyDrawingCache();
mPreview.mCamera = null;
}
}
/**
* Surface on which the camera projects it's capture results. This is derived both from Google's docs and the
* excellent StackOverflow answer provided below.
*
* Reference / Credit: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
*/
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* #param camera
*/
private void setCamera(Camera camera)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* #param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* #param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* #param holder
* #param format
* #param w
* #param h
*/
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 {
Camera.Parameters parameters = mCamera.getParameters();
// Set the auto-focus mode to "continuous"
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// Preview size must exist.
if(mPreviewSize != null) {
Camera.Size previewSize = mPreviewSize;
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (Exception e){
e.printStackTrace();
}
}
/**
* Calculate the measurements of the layout
* #param widthMeasureSpec
* #param heightMeasureSpec
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
/**
* Update the layout based on rotation and orientation changes.
* #param changed
* #param left
* #param top
* #param right
* #param bottom
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
/**
*
* #param sizes
* #param width
* #param height
* #return
*/
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
Camera.Size optimalSize = null;
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
// Try to find a size match which suits the whole screen minus the menu on the left.
for (Camera.Size size : sizes){
if (size.height != width) continue;
double ratio = (double) size.width / size.height;
if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
optimalSize = size;
}
}
// If we cannot find the one that matches the aspect ratio, ignore the requirement.
if (optimalSize == null) {
// TODO : Backup in case we don't get a size.
}
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
.show();
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
// Restart the camera preview.
safeCameraOpenInView(mCameraView);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* Used to return the camera File output.
* #return
*/
private File getOutputMediaFile(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MM");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("CameraGuide", "Required media storage does not exist");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
Toast.makeText(getActivity(),"Your picture has been saved!", Toast.LENGTH_LONG).show();
// DialogHelper.showDialog( "Success!","Your picture has been saved!",getActivity());
return mediaFile;
}
}
Fragment 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:background="#color/colorPrimary"
>
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/tvEKYCCamera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="center"
>
<View
android:id="#+id/myRectangleView"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#drawable/rectangle"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Place ID Within Here"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="#+id/button_capture"
android:text=""
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"
android:background="#drawable/camera_button"
/>
</LinearLayout>
Well after some experimenting I figured out that by setting the case Surface.ROTATION_90: while overriding the protected void onLayout(boolean changed, int left, int top, int right, int bottom) solved the orientation issue.
apparently some camera's come with default orientation of 0degree and some 90 degree.
here is what i've changed for people who might face the same issue:
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
//added to fix rotation issue
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
//added to fix rotation issue
mCamera.setDisplayOrientation(180);
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}

Android camera preview of image taken not showing on specific devices

Normally the android camera api with a PreviewCallback freezes the camera after a picture is taken and this can be used as an approval screen for the image taken. My problem is this is not the behavior on phones like the samsung S6 and S6 edge. those two phones continue with the live preview after the picture is taken.
The pictures taken are still good and can be used for later use but the preview isnt showing, and the way my app is set up, i have a check and an x mark for the user to approve what they just took a photo of. Instead they have this overlay for check and "x" and a live preview on the background. And this only happens on the samsung s6/s6 edge.
Any idea what can cause an issue like this on specific devices?
Code used for preview and picture taking with some logging everywhere:
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
private List<Camera.Size> mSupportPictureSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
Log.d(TAG, "CameraPreview: ");
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
// mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
Log.d(TAG, "startCameraPreview: ");
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* #param camera
*/
private void setCamera(Camera camera)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportPictureSizes = mCamera.getParameters().getSupportedPictureSizes();
for(Camera.Size size : mSupportedPreviewSizes){
Log.d(TAG, "supportedPreviewSizes width: " + size.width + " x " + size.height);
}
for(Camera.Size size : mSupportPictureSizes){
Log.d(TAG, "mSupportPictureSizes width: " + size.width + " x " + size.height);
}
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
}
mCamera.setParameters(parameters);
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* #param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated: ");
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* #param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed: ");
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* #param holder
* #param format
* #param w
* #param h
*/
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
Log.d(TAG, "surfaceChanged: preview surface does not exist");
return;
}
Log.d(TAG, "surfaceChanged: start & stop preview");
// 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
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public SurfaceHolder getHolder() {
return super.getHolder();
}
/**
* Calculate the measurements of the layout
* #param widthMeasureSpec
* #param heightMeasureSpec
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
Log.d(TAG, "onMeasure: w x h: " + width + " x " + height);
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
/**
* Update the layout based on rotation and orientation changes.
* #param changed
* #param left
* #param top
* #param right
* #param bottom
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
Log.d(TAG, "onLayout: ");
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
Log.d(TAG, "onLayout: rotation0");
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
Log.d(TAG, "onLayout: rotation90");
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
Log.d(TAG, "onLayout: rotation180");
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
Log.d(TAG, "onLayout: rotation270");
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
Log.d(TAG, "getOptimalPreviewSize: ");
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Camera.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) {
Log.d(TAG, "getOptimalPreviewSize: found a match");
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
Log.d(TAG, "getOptimalPreviewSize: couldn't find match");
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
Log.d(TAG, "getOptimalPreviewSize: " + optimalSize.width + " x HEIGHT: " + optimalSize.height);
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size mPictureTakenSize = parameters.getPictureSize();
System.out.println("picture taken size: " + mPictureTakenSize.width + " x " + mPictureTakenSize.height);
if(data!=null){
Log.d(TAG, "onPictureTaken: data not null, setting data to currentData");
// currentData = data;
setPictureTakenData(data);
cameraViewModel.setPreview(true);
}
else{
onProgress = false;
Log.d(TAG, "onPictureTaken: data is null");
}
}
};
I just ran into the same issue. It looks like you can fix it by manually calling camera.stopPreview() in the onPictureTaken method of the PictureCallback.
The camera will not stop preview automatically after picture taken, so you need call mCamera.stopPreview() manually:
if (mCamera != null) {
try {
mCamera.stopPreview();
pauseFlash();
} catch (Exception e) {
e.printStackTrace();
}
}
// if current camera flash mode is TORCH, you need pause it.
private void pauseFlash() {
if (currentFlashMode.equals(Camera.Parameters.FLASH_MODE_TORCH)) {
params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
}
}
And then, after do something and navigate back to camera preview:
#Override
public void startCameraPreview() {
if (mCamera != null) {
try {
mCamera.startPreview();
resumeFlash();
} catch (Exception e) {
e.printStackTrace();
// TAKE CARE IF YOUR CAMERA HAS BEEN RELEASED
}
}
}
void resumeFlash() {
flashChange(currentFlashMode);
}
And I have some performance tips: You should find the best picture size and preview size at the first time user use your app, store those in SharedPreferences and you can use after without re-caculate.
Hope this help.

Camera live preview freezes on camera switch

I am creating a custom camera app. The problem I am facing is that the camera preview freezes when I switch between the front and the back camera. When starting the activity with either the front or back camera by calling
boolean opened = safeCameraOpenInView(view, Camera.CameraInfo.CAMERA_FACING_BACK)
in the OnCreateView method of the fragment, both cameras will display on startup as expected. As soon as I call the same method in the on click listener of my switch button, the camera freezes immediately.
This is a new implementation which I tried where all the code is within the same fragment instead of a custom class based on the question here: Custom class camera live preview freezes on camera switch yet the result is exactly the same. I am pretty sure I need to do something with the surface view to bind it to the new camera but I am at a loss of how to do this. Anybody have some pointers?
My activity:
public class Camera2ActivityFragment extends Fragment {
// Native camera.
private Camera mCamera;
// View to display the camera output.
private CameraPreview mPreview;
// Reference to the containing view.
private View mCameraView;
/**
* Default empty constructor.
*/
public Camera2ActivityFragment(){
super();
}
/**
* Static factory method
* #param sectionNumber
* #return
*/
public static Camera2ActivityFragment newInstance(int sectionNumber) {
Camera2ActivityFragment fragment = new Camera2ActivityFragment();
//Bundle args = new Bundle();
//args.putInt(ARG_SECTION_NUMBER, sectionNumber);
//fragment.setArguments(args);
return fragment;
}
/**
* OnCreateView fragment override
* #param inflater
* #param container
* #param savedInstanceState
* #return
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_camera2, container, false);
boolean opened = safeCameraOpenInView(view, Camera.CameraInfo.CAMERA_FACING_BACK);
if(opened == false){
Log.d("CameraGuide","Error, Camera failed to open");
return view;
}
// Trap the capture button.
Button captureButton = (Button) view.findViewById(R.id.btnCameraStart);
captureButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
Button switchCameraButton = (Button) view.findViewById(R.id.btnSwitchCamera);
switchCameraButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
safeCameraOpenInView(getView(), Camera.CameraInfo.CAMERA_FACING_FRONT); //ISSUE OCCURS HERE!
}
}
);
return view;
}
/**
* Recommended "safe" way to open the camera.
* #param view
* #return
*/
private boolean safeCameraOpenInView(View view, int camID) {
boolean qOpened = false;
releaseCameraAndPreview();
//mCamera = getCameraInstance(Camera.CameraInfo.CAMERA_FACING_BACK);
mCamera = getCameraInstance(camID);
mCameraView = view;
qOpened = (mCamera != null);
if(qOpened == true){
mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_view);
preview.addView(mPreview);
mPreview.startCameraPreview();
}
return qOpened;
}
/**
* Safe method for getting a camera instance.
* #return
*/
public static Camera getCameraInstance(int camID){
Camera c = null;
try {
c = Camera.open(camID); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
releaseCameraAndPreview();
}
/**
* Clear any existing preview / camera.
*/
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if(mPreview != null){
mPreview.destroyDrawingCache();
mPreview.mCamera = null;
}
}
/**
* Surface on which the camera projects it's capture results. This is derived both from Google's docs and the
* excellent StackOverflow answer provided below.
*
* Reference / Credit: https://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
*/
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* #param camera
*/
private void setCamera(Camera camera)
{
// Source: https://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
parameters.setRotation(90);
//parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
}
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* #param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
//mCam = Camera.open();
//mCam.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* #param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* #param holder
* #param format
* #param w
* #param h
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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();
//mCamera.release();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setRotation(90);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.enableShutterSound(true);
mCamera.startPreview();
} catch (Exception e){
//Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
/**
* Calculate the measurements of the layout
* #param widthMeasureSpec
* #param heightMeasureSpec
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
/*
// Source: https://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
*/
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
/**
* Update the layout based on rotation and orientation changes.
* #param changed
* #param left
* #param top
* #param right
* #param bottom
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// Source: https://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
/**
*
* #param sizes
* #param width
* #param height
* #return
*/
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null){
Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
.show();
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* Used to return the camera File output.
* #return
*/
private File getOutputMediaFile(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Pocket Booth");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("Camera Guide", "Required media storage does not exist");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
//DialogHelper.showDialog( "Success!","Your picture has been saved!",getActivity());
return mediaFile;
}
}
Well, Here I'm going to write a tutorial for you about capturing an
image using Camera by enabling some common features of camera.
Step 1 : Create a preview class
/**
* A basic Camera preview class
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
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
// start preview with new settings
startPreview();
}
public void resetCamera(Camera camera) {
mCamera = camera;
}
public void startPreview() {
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Step 2 : Use FrameLayout to hold the preview.
<FrameLayout
android:id="#+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Step 3 : Get the camera and send to the preview class. you may need to set the parameters that you need prior passing the camera.
/**
* Create our Preview view and set it as the content of UI.
*/
private void initCameraPreview(final int cameraId, final boolean createPreview) {
mCamera = getCameraInstance(cameraId);
setupCameraParameters(cameraId);
if (createPreview) {
mPreview = new CameraPreview(this, mCamera);
mPreviewHolder.addView(mPreview);
}
mReadyToCapture = true;
}
/**
* A safe way to get an instance of the Camera object.
*/
private Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
c = Camera.open(cameraId); // attempt to get a Camera instance
} catch (Exception e) {
e.printStackTrace();
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
/**
* Measure and Setup the camera parameters.
*/
private void setupCameraParameters(int cameraId) {
boolean hasFlash;
Camera.Parameters parameters = mCamera.getParameters();
mPreviewSize = determineBestPreviewSize(parameters);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
Camera.Size bestPictureSize = determineBestPictureSize(parameters);
parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
hasFlash = Util.hasSystemFeature(this, PackageManager.FEATURE_CAMERA_FLASH);
if (mCurrentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
hasFlash = Util.hasFrontCameraFlash(parameters);
} else {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
if (hasFlash)
parameters.setFlashMode(mFlashMode);
int[] orientations = Util.getCameraDisplayOrientation(this, cameraId);
mDisplayOrientation = orientations[0];
mLayoutOrientation = orientations[1];
mCamera.setDisplayOrientation(mDisplayOrientation);
mCamera.setParameters(parameters);
}
private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
return determineBestSize(sizes);
}
private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
return determineBestSize(sizes);
}
private Camera.Size determineBestSize(List<Camera.Size> sizes) {
Camera.Size bestSize = null;
for (Camera.Size currentSize : sizes) {
boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
boolean isInBounds = currentSize.width <= PICTURE_SIZE_MAX_WIDTH;
if (isDesiredRatio && isInBounds && isBetterSize) {
bestSize = currentSize;
}
}
if (bestSize == null) {
return sizes.get(0);
}
return bestSize;
}
Step 4 : Writing method for swapping camera
/**
* Swapping between system cameras
*/
private void swapCamera() {
if (!(Camera.getNumberOfCameras() > 1)) {
/* No front facing camera to switch.*/
return;
}
mReadyToCapture = false;
mCamera.stopPreview();
releaseCamera(false);
if (mCurrentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
mCurrentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
else
mCurrentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
initCameraPreview(mCurrentCameraId, false);
mPreview.resetCamera(mCamera);
mPreview.startPreview();
}
Step 5 : Method for toggling flash
/**
* Toggling camera flash to ON/OFF
*/
private void toggleFlash() {
if (Util.hasSystemFeature(this, PackageManager.FEATURE_CAMERA_FLASH)) {
Camera.Parameters parameters = mCamera.getParameters();
if (mCurrentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
if (!Util.hasFrontCameraFlash(parameters)) {
/* Front facing camera doesn\'t supported flash. */
return;
}
}
mReadyToCapture = false;
if (Camera.Parameters.FLASH_MODE_ON.equals(parameters.getFlashMode())) {
mFlashMode = Camera.Parameters.FLASH_MODE_OFF;
} else {
mFlashMode = Camera.Parameters.FLASH_MODE_ON;
}
mCameraHandler.post(new Runnable() {
#Override
public void run() {
mCamera.stopPreview();
releaseCamera(false);
initCameraPreview(mCurrentCameraId, false);
mPreview.resetCamera(mCamera);
mPreview.startPreview();
}
});
} else {
/* warning_no_flash */
}
}
Step 6: Methods for handling camera during the states changes of a screen
/**
* Release the camera for other applications
*/
private void releaseCamera(boolean remove) {
if (mCamera != null) {
if (remove)
mPreview.getHolder().removeCallback(mPreview);
mCamera.release();
mCamera = null;
}
}
Step 7: Utility classes.
/**
* Check whether the given feature available in s/m
*
* #return Returns true if the devices supports the feature, else
* false.
*/
public static boolean hasSystemFeature(Context context, String feature) {
return context.getPackageManager().hasSystemFeature(feature);
}
/**
* Check whether front camera flash feature available in s/m
*/
public static boolean hasFrontCameraFlash(Camera.Parameters cameraParameters) {
boolean result = true;
if (cameraParameters.getFlashMode() == null) {
result = false;
}
List<String> supportedFlashModes = cameraParameters.getSupportedFlashModes();
if (supportedFlashModes == null || supportedFlashModes.isEmpty()
|| supportedFlashModes.size() == 1 &&
supportedFlashModes.get(0).equals(Camera.Parameters.FLASH_MODE_OFF)) {
result = false;
}
return result;
}
/**
* Showing camera in the same orientation as the display
*/
public static int[] getCameraDisplayOrientation(Activity activity,
int cameraId) {
Camera.CameraInfo info =
new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return new int[]{result, degrees};
}
Step 8: Capturing
// Get an image from the camera
if (null != mCamera && mReadyToCapture) {
mCameraOrientationListener.rememberOrientation();
mCamera.takePicture(mShutter, null, mPicture)
}
/**
* Camera shutter sound callback,
* used to enable sound while capture
*/
private Camera.ShutterCallback mShutter = new Camera.ShutterCallback() {
#Override
public void onShutter() {
}
};
/**
* Camera picture callback
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
mReadyToCapture = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
int rotation = ((mCurrentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK ? mDisplayOrientation :
((360 - mDisplayOrientation) % 360)) + mCameraOrientationListener.getRememberedOrientation()
+ mLayoutOrientation) % 360;
if (rotation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
}
}
};
Step 9: Camera orientation listener for handling image rotation
/**
* Orientation listener to remember the device's orientation when the user presses
* the shutter button.
* <p/>
* The orientation will be normalized to return it in steps of 90 degrees
* (0, 90, 180, 270).
*/
public class CameraOrientationListener extends OrientationEventListener {
private int currentNormalizedOrientation;
private int rememberedNormalizedOrientation;
public CameraOrientationListener(Context context) {
super(context, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onOrientationChanged(int orientation) {
if (orientation != ORIENTATION_UNKNOWN) {
currentNormalizedOrientation = normalize(orientation);
}
}
private int normalize(int degrees) {
if (degrees > 315 || degrees <= 45) {
return 0;
}
if (degrees > 45 && degrees <= 135) {
return 90;
}
if (degrees > 135 && degrees <= 225) {
return 180;
}
if (degrees > 225 && degrees <= 315) {
return 270;
}
throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies.");
}
public void rememberOrientation() {
rememberedNormalizedOrientation = currentNormalizedOrientation;
}
public int getRememberedOrientation() {
return rememberedNormalizedOrientation;
}
}
Step 10: States handling
#Override
public void onPause() {
super.onPause();
mReadyToCapture = false;
releaseCamera(true);
}
#Override
public void onResume() {
super.onResume();
removePreview();
mReadyToCapture = false;
smoothCameraLoading();
}
private void removePreview() {
mPreviewHolder.removeAllViews();
}
private void smoothCameraLoading() {
mCameraHandler.post(new Runnable() {
#Override
public void run() {
initCameraPreview(mCurrentCameraId, true);
}
});
}
Step 11: Instance variable used
private String mFlashMode = Camera.Parameters.FLASH_MODE_OFF;
private int mCurrentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
private int mDisplayOrientation;
private int mLayoutOrientation;
private boolean mReadyToCapture = false;
private Camera.Size mPreviewSize;
private FrameLayout mPreviewHolder;
private Camera mCamera;
private CameraPreview mPreview;
private Handler mCameraHandler;
private CameraOrientationListener mCameraOrientationListener;
private FrameLayout mRootView;
In my camera app, it works with somethings different from yours:
1. Open camera when surfaceCreated.
2. StartPreview and no stopPreview in surfaceChanged.
3. Release camera in surfaceDestoryed.
To change the camera, simply set the surfaceView to INVISIBLE, then set your camera parameters, then set the surfaceView to VISIBLE again. In my app, I only do it like this:
mbtCamera.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(cameraMax > 1){
mSurfaceView.setVisibility(View.INVISIBLE);
if(mCameraParam.isZoomSupported()) cameraZoomRatios.clear();
if(cameraUsing == 0) cameraUsing = 1; else cameraUsing = 0;
mCameraOverlayView.setScaleFactor(1.0f);
mSurfaceView.setVisibility(View.VISIBLE);
}
}
});
Hope this will help!
The complete callback:
class CameraSurfaceHolderCallback implements SurfaceHolder.Callback {
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open(cameraUsing);
mCameraParam = mCamera.getParameters();
supportFlashMode = mCameraParam.getSupportedFlashModes();
if(supportFlashMode == null) mbtFlash.setVisibility(View.INVISIBLE);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraUsing, info);
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT){
rotation = (info.orientation - rt + 360) % 360;
if(mCameraParam.getSupportedFlashModes() == null) mbtFlash.setVisibility(View.INVISIBLE);
}
else{ // back-facing camera
rotation = (info.orientation + rt) % 360;
mbtFlash.setVisibility(View.VISIBLE);
if(flashMode.equals(Camera.Parameters.FLASH_MODE_AUTO)) icons[0] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_flash_automatic);
else if(flashMode.equals(Camera.Parameters.FLASH_MODE_OFF)) icons[0] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_flash_off);
else if(flashMode.equals(Camera.Parameters.FLASH_MODE_ON)) icons[0] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_flash_on);
Matrix rot = new Matrix();
rot.setRotate(360-rt, icons[0].getWidth()/2, icons[0].getHeight()/2);
icons[0] = Bitmap.createBitmap(icons[0], 0, 0, icons[0].getWidth(), icons[0].getHeight(), rot, true);
mbtFlash.setImageBitmap(icons[0]);
mCameraParam.setFlashMode(flashMode);
}
if(mCameraParam.isZoomSupported()){
cameraZoomRatios = mCameraParam.getZoomRatios();
mCameraOverlayView.setMaxScaleFactor(cameraZoomRatios.get(mCameraParam.getMaxZoom())/100f);
}else mCameraOverlayView.setMaxScaleFactor(1.0f);
List<Size> ss = mCameraParam.getSupportedPictureSizes();
Size maxResolution = ss.get(0);
long pixel1, pixel2;
pixel1 = maxResolution.width * maxResolution.height;
for(int i=0; i<ss.size(); i++){
pixel2 = ss.get(i).width * ss.get(i).height;
if(pixel2 > pixel1){
maxResolution = ss.get(i);
pixel1 = pixel2;
}
}
mCameraParam.setPictureSize(maxResolution.width, maxResolution.height);
mCameraParam.setJpegQuality(100);
LayoutParams rlParams = (LayoutParams) mSurfaceView.getLayoutParams();
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display dp = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
dp.getMetrics(dm);
float dpiScale = dm.density;
float wScaleFactor = (dm.widthPixels-10*dpiScale)/maxResolution.height;
float hScaleFactor = (dm.heightPixels-mllTopButtons.getHeight()-mllBotButtons.getHeight()-10*dpiScale)/maxResolution.width;
if(wScaleFactor < hScaleFactor){
rlParams.width = (int) (dm.widthPixels - 10*dpiScale);
rlParams.height = (int) (maxResolution.width * wScaleFactor);
}else{
rlParams.width = (int) (maxResolution.height * hScaleFactor);
rlParams.height = (int) (dm.heightPixels-mllTopButtons.getHeight()-mllBotButtons.getHeight()-10*dpiScale);
}
mSurfaceView.setLayoutParams(rlParams);
mCameraOverlayView.setLayoutParams(rlParams);
ss = mCameraParam.getSupportedJpegThumbnailSizes();
float photoAspectRatio, thumbAspectRatio;
photoAspectRatio = (float)maxResolution.width / maxResolution.height;
thumbAspectRatio = 0;
pixel1 = 0;
for(int i=0; i<ss.size(); i++){
if(ss.get(i).height != 0) thumbAspectRatio = (float)ss.get(i).width / ss.get(i).height;
if(thumbAspectRatio == photoAspectRatio){
if(pixel1 == 0)
{
maxResolution = ss.get(i);
pixel1 = ss.get(i).width * ss.get(i).height;
}else{
pixel2 = ss.get(i).width * ss.get(i).height;
if((pixel2 < pixel1)&&(pixel2 != 0)){
maxResolution = ss.get(i);
pixel1 = pixel2;
}
}
}
}
if(pixel1 != 0){
mCameraParam.setJpegThumbnailSize(maxResolution.width, maxResolution.height);
mCameraParam.setJpegThumbnailQuality(100);
}
List<String> focusModes = mCameraParam.getSupportedFocusModes();
if(focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)){
mCameraParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
focusingColor = Color.YELLOW;
}
int minEv = mCameraParam.getMinExposureCompensation();
int maxEv = mCameraParam.getMaxExposureCompensation();
if((minEv == 0)&&(maxEv == 0)) mCameraOverlayView.setEVCompensate(false);
else mCameraOverlayView.setEVCompensate(minEv, maxEv);
mCameraParam.setRotation(rotation);
mCamera.setParameters(mCameraParam);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
List<Size> ss = mCameraParam.getSupportedPreviewSizes();
Size maxResolution = ss.get(0);
long pixel1, pixel2;
float photoAspectRatio, previewAspectRatio;
photoAspectRatio = (float)mCameraParam.getPictureSize().width / mCameraParam.getPictureSize().height;
previewAspectRatio = 0;
pixel1 = 0;
for(int i=0; i<ss.size(); i++){
if(ss.get(i).height != 0) previewAspectRatio = (float)ss.get(i).width / ss.get(i).height;
if(previewAspectRatio == photoAspectRatio){
if(pixel1 == 0)
{
maxResolution = ss.get(i);
pixel1 = ss.get(i).width * ss.get(i).height;
}else{
pixel2 = ss.get(i).width * ss.get(i).height;
if(pixel2 > pixel1){
maxResolution = ss.get(i);
pixel1 = pixel2;
}
}
}
}
if(pixel1 != 0) mCameraParam.setPreviewSize(maxResolution.width, maxResolution.height);
mCamera.setParameters(mCameraParam);
mCamera.startPreview();
}
catch(Exception e){}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
}
}
I used it in activity and no fragment. I am not sure this will make something different.
I think that there is a little problem in the safeCameraOpenInView method and that is:
Your new camera view is made under the frozen picture.
So you should edit this line: preview.addView(mPreview);
as this: preview.addView(mPreview, preview.getChildCount());
Or you can first delete the previous camera view and then add new one :
preview.removeAllViews();
preview.addView(mPreview);
Hope that this will work.

Want larger camera preview using ZBar scanner Library in Android

I am using ZBarScannerActivity in my android app. but I am getting a small surface view on device. Actually I want full Screen camera preview to scan the QR code.
Any help would be appreciated.
Thank you.
here is the code of ZbarScanner Activity
package com.dm.zbar.android.scanner;
public class ZBarScannerActivity extends Activity implements Camera.PreviewCallback, ZBarConstants {
private static final String TAG = "ZBarScannerActivity";
private CameraPreview mPreview;
private Camera mCamera;
private ImageScanner mScanner;
private Handler mAutoFocusHandler;
private boolean mPreviewing = true;
static {
System.loadLibrary("iconv");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!isCameraAvailable()) {
// Cancel request if there is no rear-facing camera.
cancelRequest();
return;
}
// Hide the window title.
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
mAutoFocusHandler = new Handler();
// Create and configure the ImageScanner;
setupScanner();
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new CameraPreview(this, this, autoFocusCB);
setContentView(mPreview);
}
public void setupScanner() {
mScanner = new ImageScanner();
mScanner.setConfig(0, Config.X_DENSITY, 3);
mScanner.setConfig(0, Config.Y_DENSITY, 3);
int[] symbols = getIntent().getIntArrayExtra(SCAN_MODES);
if (symbols != null) {
mScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
for (int symbol : symbols) {
mScanner.setConfig(symbol, Config.ENABLE, 1);
}
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
if(mCamera == null) {
// Cancel request if mCamera is null.
cancelRequest();
return;
}
mPreview.setCamera(mCamera);
mPreview.showSurfaceView();
mPreviewing = true;
}
#Override
protected void onPause() {
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
// According to Jason Kuang on http://stackoverflow.com/questions/6519120/how-to-recover-camera-preview-from-sleep,
// there might be surface recreation problems when the device goes to sleep. So lets just hide it and
// recreate on resume
mPreview.hideSurfaceView();
mPreviewing = false;
mCamera = null;
}
}
public boolean isCameraAvailable() {
PackageManager pm = getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
public void cancelRequest() {
Intent dataIntent = new Intent();
dataIntent.putExtra(ERROR_INFO, "Camera unavailable.");
setResult(Activity.RESULT_CANCELED, dataIntent);
finish();
}
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = mScanner.scanImage(barcode);
if (result != 0) {
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mPreviewing = false;
SymbolSet syms = mScanner.getResults();
for (Symbol sym : syms) {
String symData = sym.getData();
if (!TextUtils.isEmpty(symData)) {
Intent dataIntent = new Intent();
dataIntent.putExtra(SCAN_RESULT, symData);
dataIntent.putExtra(SCAN_RESULT_TYPE, sym.getType());
setResult(Activity.RESULT_OK, dataIntent);
finish();
break;
}
}
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if(mCamera != null && mPreviewing) {
mCamera.autoFocus(autoFocusCB);
}
}
};
// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
and CameraPreview Class
class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;
CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
super(context);
mPreviewCallback = previewCallback;
mAutoFocusCallback = autoFocusCb;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
//Changes********
mCamera.setDisplayOrientation(90);
mCamera.getParameters().getMaxNumFocusAreas();
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void hideSurfaceView() {
mSurfaceView.setVisibility(View.INVISIBLE);
}
public void showSurfaceView() {
mSurfaceView.setVisibility(View.VISIBLE);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.cancelAutoFocus();
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (holder.getSurface() == null){
// preview surface does not exist
return;
}
if (mCamera != null) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
// mCamera.setDisplayOrientation(90);
mCamera.setParameters(parameters);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
}
}
}
Please help me getting the scenario of Camera Preview size.
I am getting a small surface view on device. Actually I want full Screen camera preview to scan the QR code
If you are saying that camera isn't occupying the entire screen then try to change the
android:layout_width="match_parent"
android:layout_height="match_parent"
of SurfaceView and parent_layout
If it is about the scan area that you want to be in full screen, here it goes:
mScannerView = new ZBarScannerView(this) {
/**
* this will alter the scanning area
**/
#Override
protected IViewFinder createViewFinderView(Context context) {
return new CustomViewFinderView(context);
}
};
private class CustomViewFinderView extends ViewFinderView {
Context context;
public CustomViewFinderView(Context context) {
super(context);
this.context = context;
setLaserEnabled(true);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getFramingRect() != null) {
updateFrameRect();
setBorderColor(ContextCompat.getColor(context, R.color.colorPrimary));
}
}
private void updateFrameRect() {
Point viewResolution = new Point(this.getWidth(), this.getHeight());
int height = (int) ((float) this.getHeight());
int width = (int) ((float) this.getWidth());
int leftOffset = (viewResolution.x - width) / 2;
int topOffset = (viewResolution.y - height) / 2;
getFramingRect().left = leftOffset;
getFramingRect().top = topOffset;
getFramingRect().right = leftOffset + width;
getFramingRect().bottom = topOffset + height;
}
}
Result:
I have solved this by removing following code from Camerapreview Class
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
it worked for me.
It will give you full screen camera.
Thank you.

Camera Preview stretched on setDisplayOrientation(90)

I am able to rotate the camera preview from portrait to landscape by using the setDisplayOrientation(90) method but preview won't look realistic and is stretched in landscape mode. I have gone through multiple posts related to the same but not able to succeed with required view. I am trying this on the rooted android Jellybeans version.
Can you please suggest the ways to improve the preview in landscape mode?
below is my code set of CameraPreview and Activity class:
import java.io.IOException;
import java.util.List;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = null;
private SurfaceHolder mHolder;
private Camera mCamera;
List<Size> sizes;
Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
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
// start preview with new settings
setCamera(mCamera);
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
mCamera.setDisplayOrientation(90);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
sizes = mCamera.getParameters().getSupportedPreviewSizes();
if (sizes != null) {
mPreviewSize = getOptimalPreviewSize(sizes, width, height);
}
}
}
public class TestCameraActivity extends Activity {
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
protected static final String TAG = null;
private PictureCallback mPicture;
/** Called when the activity is first created. */
Context ctx;
Camera mCamera;
CameraPreview mPreview;
Camera.Size optimalSize;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
boolean cameraAvailable = checkCameraHardware(this);
if(cameraAvailable){
mCamera = getCameraInstance();
}else Toast.makeText(this, "No Camera Available",Toast.LENGTH_LONG).show();
double aspectRatio =0;
mPreview = new CameraPreview(this,mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPicture = getPictureCallback();
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = mPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
// if(optimalSize!= null){
// FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
// preview.setLayoutParams(params);
// LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
// mPreview.setLayoutParams(surfaceParams);
// }
mPreview.setCamera(mCamera);
Button capture = (Button) findViewById(R.id.button_capture);
capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
mCamera.takePicture(null, null, mPicture);
}
});
}
private PictureCallback getPictureCallback() {
PictureCallback picture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " );
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
return picture;};
#Override
protected void onPause() {
super.onPause();
releaseCamera(); // release the camera immediately on pause event
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
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
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;`enter code here`
} else {
// no camera on this device
return false;
}
}
}
The value that you pass to setDisplayOrientation is not fixed: it's dependent on the individual camera's orientation (where the "top" of the camera is) as well as the current orientation of the device itself. By setting it to a constant value, your preview may look correct in one orientation but in another will be as you described.
The documentation provides the math that you need to take both into account when setting this value:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}

Categories

Resources