I would like to make an app that have 2 activities. The first one is a CameraPreview from api demos that have an options menu by default. I added to it a second button that starts the second activity, what is a ImageSwitcher. I want to give back the selected photo to front of the preview at a specified width and height.
This block is fine for get and appear a photo in a plain activity's onCreate method, but I don't know how to do this with a CameraPreview:
setContentView(R.layout.picturelay);
int theID = getIntent().getExtras().getInt("the_image_id");
ImageView i = (ImageView) findViewById(R.id.cameralay);
i.setImageResource(theID);
My starting activity:
public class CameraPreview extends Activity {
private
Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
String uzenet;
// The first rear facing camera
int defaultCameraId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this);
setContentView(mPreview);
try {
int theID = getIntent().getExtras().getInt("the_image_id");
ImageView i = (ImageView) findViewById(R.id.cameralay);
i.setImageResource(theID);
} catch (Exception e){
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG);
}
// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
}
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
#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.release();
mCamera = null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(this.getString(R.string.camera_alert))
.setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}
// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera
.open((cameraCurrentlyLocked + 1) % numberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% numberOfCameras;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
case R.id.get_picture:
Intent intent2 = new Intent(CameraPreview.this, ImageSwitcher1.class);
//startActivityForResult(intent, 0);
startActivity(intent2);
return true;
}
return super.onOptionsItemSelected(item);
}
}
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context) {
super(context);
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) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#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 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.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) {
// 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.setParameters(parameters);
mCamera.startPreview();
}
}
The second activity:
public class ImageSwitcher1 extends Activity implements
AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.image_switcher_1);
mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
mSwitcher.setFactory(this);
mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));
mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));
Gallery g = (Gallery) findViewById(R.id.gallery);
g.setAdapter(new ImageAdapter(this));
g.setOnItemSelectedListener(this);
g.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
Intent intent = new Intent(ImageSwitcher1.this, CameraPreview.class);
intent.putExtra("the_image_id", mImageIds[position]);
startActivity(intent);
finish();
}
});
}
public void onItemSelected(AdapterView parent, View v, int position, long id) {
mSwitcher.setImageResource(mImageIds[position]);
}
public void onNothingSelected(AdapterView parent) {
}
public View makeView() {
ImageView i = new ImageView(this);
i.setBackgroundColor(0xFF000000);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
return i;
}
private ImageSwitcher mSwitcher;
public class ImageAdapter extends BaseAdapter {
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageResource(mThumbIds[position]);
i.setAdjustViewBounds(true);
i.setLayoutParams(new Gallery.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
i.setBackgroundResource(R.drawable.picture_frame);
return i;
}
private Context mContext;
}
private Integer[] mThumbIds = {
R.drawable.1, R.drawable.2,
R.drawable.3, R.drawable.4,
R.drawable.5, R.drawable.6,
R.drawable.7, R.drawable.8,
R.drawable.9
};
private Integer[] mImageIds = {
R.drawable.1, R.drawable.2,
R.drawable.3, R.drawable.4,
R.drawable.5, R.drawable.6,
R.drawable.7, R.drawable.8,
R.drawable.9
};
}
Thank You for your replies!
I had a solution with a different Preview activity. So I can see the selected image front of the camera preview. This is the used preview activity:
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 Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preview=(SurfaceView)findViewById(R.id.preview);
previewHolder=preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
try {
int theID = getIntent().getExtras().getInt("the_image_id");
ImageView i = (ImageView) findViewById(R.id.cameralay);
i.setImageResource(theID);
} catch (Exception e){
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG);
}
}
#Override
public void onResume() {
super.onResume();
camera=Camera.open();
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
}
};
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu2, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.take_photo:
//code of taking a photo will be here...
return true;
}
return super.onOptionsItemSelected(item);
}
}
And my layout file that contains the surface view and image view:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.view.SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.view.SurfaceView>
<ImageView
android:id="#+id/cameralay"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:contentDescription="#+id/app_name">
</ImageView>
</RelativeLayout>
Related
I am getting a very interesting behavior by Android Studio in my project. The calls to different activities are not executing sequentially!
I am building a project where in the calls are like this:
button.setOnClickListener()
{
(1) call to cusom camera acivity
(2) call to activity showing preview of latest captured image
(3) call to a doCrop() function
}
But when executed, the actual flow is:
(1) call to the doCrop() function
(2) call to activity showing preview of image captured
(3) call to cusom camera acivity
The custom camera activity handles all the necessary SurfaceHolder and SurfaceView operations.
Is this effect happening as the SurfaceView layout creation and destroying takes more time and android switches to easier one task first?
Even so, it should skip to preview activity and not to doCrop() call.
What is happening here? Please give some pointers !
Thank you!
EDIT:
The naming is:
MainActivity - main activity
Preview - creates camera instance
CameraPreview - Handles SurfaceView etc
ImagePreview -Shows specified image
Main activity code:
photo.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
File temp = new File(//path to store image);
imageUri=Uri.fromFile(temp);
Intent intent = new Intent(MainActivity.this,Preview.class);
startActivity(intent);
// Image Preview Activity
Intent intent1=new Intent(MainActivity.this,ImagePreview.class);
startActivity(intent1);
//Crop function
doCrop();
}
});
The preview activity code:
public class Preview extends Activity {
private static final String TAG = "CamTestActivity";
CameraPreview preview;
Button buttonClick;
Camera camera;
Activity act;
Context ctx;
Uri uri;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
act = this;
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_preview);
preview = new CameraPreview(this, (SurfaceView)findViewById(R.id.surfaceView));
preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
((FrameLayout) findViewById(R.id.layout)).addView(preview);
preview.setKeepScreenOn(true);
buttonClick = (Button) findViewById(R.id.btnCapture);
buttonClick.setOnClickListener(new OnClickListener()
{
public void onClick(View v) {
camera.takePicture(shutterCallback, rawCallback, pngCallback);
}
});
}
#Override
protected void onResume() {
super.onResume();
int numCams = Camera.getNumberOfCameras();
if(numCams > 0){
try{
camera = Camera.open(0);
camera.startPreview();
preview.setCamera(camera);
} catch (RuntimeException ex){
Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onPause() {
if(camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
private void resetCam() {
camera.startPreview();
preview.setCamera(camera);
}
private void refreshGallery(File file) {
Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
sendBroadcast(mediaScanIntent);
}
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
}
};
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
}
};
PictureCallback pngCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
new SaveImageTask().execute(data);
resetCam();
Log.d(TAG, "onPictureTaken - png");
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
// save the image
}
catch (Exception e) { e.printStackTrace();}
return null;
}
}
}
CameraPreview code:
class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
CameraPreview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
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 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.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(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}
I think this is more of a design issue.
Should you really be opening more than one activity at once?
When an activity is started, it's put on top of the history stack, which could give the illusion that it's happening the other way round.
But I can't comment any further until I see code.
UPDATE: Yep, design issue.
This is the way it should work:
Onclick action in MainActivity should ONLY open Preview activity using startActivityForResult().
User takes photo, triggering setResult() and closing the camera activity.
Result gets returned to MainActivity, triggering onActivityResult()
Code in onActivityResult starts ImagePreview activity.
onCreate function in ImagePreview triggers doCrop();
I do suggest you have a good read of the Android Documentation here:
http://developer.android.com/guide/components/activities.html
Android is less flexible (or more helpful) than other platforms and it's essential that you have a good understanding of the API.
Activity startup code is asynchronous, and if you launch several activities simultaneously, like this:
startActivity(intent1);
startActivity(intent2);
startActivity(intent3);
it is not guaranteed, that they'll be shown to user sequentially, that is, in "launch order".
This is expected behaviour, and you normally should not do such a thing, as it is indication of your application design flaw
So what you are trying to do is launch 3 activities simultaneously.These all need to be handled in onActivityResult(). But a user cannot access 3 activities simultaneously.
so modifying your flow.
it should be something like
start CameraActivity
In the onActivityResult() of your calling activity ,you call do crop and do what you want.
You need to revisit your workflow because:
you are not launching 3 activites.
you are triggerring events based on user interaction and hence the sequence of functions should not be controlled from your code.
Your tasks are executing in wrong order because they are called asynchronously. To execute them in the order you have specified make a synchronous call, which can be done using startActivityForResult(intent, requestCode);
I have some troubles with camera. I test my code on Xiaomi Mi2a and preview was distorted.
I have this line in manifest: android:screenOrientation="portrait"
I use camera with this fragment:
import android.app.Fragment;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.*;
import android.widget.
import java.io.IOException;
import java.util.List;
public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback, Camera.PreviewCallback, Camera.AutoFocusCallback, View.OnClickListener {
private Camera mCamera;
private SurfaceHolder mSurfaceHolder;
private SurfaceView mPreview;
private ImageButton mTakePicture;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.camera_fragment, container, false);
mPreview = (SurfaceView) v.findViewById(R.id.svCameraView);
mSurfaceHolder = mPreview.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mTakePicture = (ImageButton) v.findViewById(R.id.ibTakePicture);
mTakePicture.setOnClickListener(takePictureOnClickListener);
ImageButton switchCameraButton = (ImageButton) v.findViewById(R.id.ibSwitchCamera);
switchCameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return v;
}
View.OnClickListener takePictureOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
}
};
#Override
public void onResume() {
super.onResume();
mCamera = Camera.open();
}
#Override
public void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(this);
} catch (IOException e) {
e.printStackTrace();
return;
}
Camera.Parameters parameters = mCamera.getParameters();
List<String> flashModes = parameters.getSupportedFlashModes();
/*if (flashModes != null && flashModes.contains(Camera.Parameters.FLASH_MODE_OFF))
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);*/
List<String> whiteBalance = parameters.getSupportedWhiteBalance();
if (whiteBalance != null && whiteBalance.contains(Camera.Parameters.WHITE_BALANCE_AUTO))
parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes != null && focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
/*if (sizes != null && sizes.size() > 0) {
Camera.Size size = sizes.get(0);
parameters.setPictureSize(size.width, size.height);
}*/
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
/*if (previewSizes != null) {
Camera.Size previewSize = previewSizes.get(previewSizes.size() - 1);
parameters.setPreviewSize(previewSize.width, previewSize.height);
}*/
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
float aspect = (float) previewSize.width / previewSize.height;
int previewSurfaceWidth = mPreview.getWidth();
int previewSurfaceHeight = mPreview.getHeight();
ViewGroup.LayoutParams lp = mPreview.getLayoutParams();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
mCamera.setDisplayOrientation(90);
lp.height = previewSurfaceHeight;
lp.width = (int) (previewSurfaceHeight / aspect);
} else {
mCamera.setDisplayOrientation(0);
lp.width = previewSurfaceWidth;
lp.height = (int) (previewSurfaceWidth / aspect);
}
mPreview.setLayoutParams(lp);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void onClick(View v) {
if (v == mTakePicture) {
//mCamera.takePicture(null, null, null, this);
mCamera.autoFocus(this);
}
}
#Override
public void onPictureTaken(byte[] paramArrayOfByte, Camera paramCamera) {
paramCamera.startPreview();
}
#Override
public void onAutoFocus(boolean paramBoolean, Camera paramCamera) {
if (paramBoolean) {
paramCamera.takePicture(null, null, null, this);
}
}
#Override
public void onPreviewFrame(byte[] paramArrayOfByte, Camera paramCamera) {
}
I don't know how about resulting image, because I'm not need it at the moment. But preview is distorted. For example:
http://habrastorage.org/files/fc5/cd1/6fb/fc5cd16fb80f41f6ac7a8a800e0348b6.png
http://habrastorage.org/files/968/cd4/850/968cd48505564f93b0258a07fe48a545.png
What do I wrong? How to keep preview in normal state, without stretching? Or, maybe, is it problem with miui?
How to keep preview in normal state, without stretching?
Your SurfaceView needs to be in the same aspect ratio as is the camera preview. Otherwise, the camera preview will be stretched in one direction to fit the SurfaceView.
Take Video Size or Picture Size Available on Device
check in preview constructor-
List<Camera.Size> sizes = mCamera.getParameters()
.getSupportedVideoSizes();
if (sizes != null)
for (Camera.Size size : sizes) {
int h = size.height;
int w = size.width;
System.out.println("h=" + h + " w=" + w);
}
then decide what resolution you want for you requirment then make frame layout of same resoultion
abc.xml file
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="288dp"
android:layout_height="352dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
>
</FrameLayout>
preview in surface created-
if(mCamera!=null)
{
Parameters params=mCamera.getParameters();
params.setPictureSize(288, 352);
mCamera.setParameters(params);
}
please make change according to your need if you need any help then ask.
Set Camera Parameter as
Camera.Parameters params = mCamera.getParameters();
params.set("orientation", "portrait");
mCamera.setParameters(params);
this will help you..
In my library project I have the following code to initialize the camera, and start previewing.
public class CameraView {
private SurfaceView preview;
private SurfaceHolder previewHolder;
private Camera camera;
private boolean activeCamera;
private boolean cameraConfigured;
private Activity activity;
private final static int NINTY_DEGREES = 90;
public CameraView(Activity activity) {
this.activity = activity;
View rootView;
LayoutInflater inflater = activity.getLayoutInflater();
rootView = inflater.inflate(R.layout.layout_cameraview, null);
preview = (SurfaceView) rootView.findViewById(R.id.surfaceView);
previewHolder = preview.getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraConfigured = false;
}
private void initializeCamera(int w, int h) {
if(camera != null && previewHolder.getSurface() != null) {
try
{
camera.setPreviewDisplay(previewHolder);
}
catch(Exception e)
{
Log.e("Camera: ", e.getMessage());
}
if(!cameraConfigured) {
Camera.Parameters params = camera.getParameters();
Camera.Size size = getBestPreviewSize(w, h, params);
if(size != null) {
params.setPreviewSize(size.width, size.height);
cameraConfigured = true;
}
}
}
}
public void startCamera() {
camera = Camera.open();
previewHolder.addCallback(surfaceCallback);
}
public void stopCamera() {
stopPreviewingOnDisplay();
}
public void takePicture() {
View rootView;
LayoutInflater inflater = activity.getLayoutInflater();
rootView = inflater.inflate(R.layout.layout_cameraview, null);
Button capture = (Button) rootView.findViewById(R.id.capture);
capture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.e("CameraView: ", "Capture button pressed!");
}
});
}
private void startPreviewingOnDisplay() {
if(camera != null) {
camera.setDisplayOrientation(NINTY_DEGREES);
camera.startPreview();
activeCamera = true;
}
}
private void stopPreviewingOnDisplay() {
if(camera != null && activeCamera) {
camera.stopPreview();
activeCamera = false;
}
}
private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initializeCamera(width, height);
startPreviewingOnDisplay();
Log.d("CameraView: ", "SurfaceChanged");
}
};
private Camera.Size getBestPreviewSize(int w, int h, Camera.Parameters params) {
Camera.Size result = null;
for(Camera.Size size : params.getSupportedPreviewSizes()) {
if(size.width < w && size.height <= h) {
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);
}
}
The usage of this class:
public class History extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
camera = new CameraView(this);
}
#Override
public void onResume() {
super.onResume();
Log.i("History.class", "onResume called!");
camera.startCamera();
}
#Override
public void onPause() {
super.onPause();
camera.stopCamera();
}
}
I've debugged the code, and I notice that the camera object is being intitalized, but there is nothing appearing on the screen, it should have previewed the camera. Could anyone see whats wrong with this approach?
Thanks.
Now i am developing Camera app for i need front and back cameras simultaneously.My requirement is when i open my app first it will show back surface view and also i have one button when i press one button it will switch to front camera surface view and also when i press button second time it will again switch to back camera for that i write this code.
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;
import com.example.R;
public class MainActivity extends Activity {
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
// The first rear facing camera
int defaultCameraId;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this);
setContentView(mPreview);
// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++)
{
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
{
defaultCameraId = i;
}
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
#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.release();
mCamera = null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("camera_alert")
.setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}
// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera
.open((cameraCurrentlyLocked + 1) % numberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% numberOfCameras;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context) {
super(context);
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) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#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 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.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) {
// 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.setParameters(parameters);
mCamera.startPreview();
}
}
}
and my menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/switch_cam"
android:title="#string/switch_cam" />
</menu>
when i write this code i get error
menu cannot be resolved or is not a field and
switch_cam cannot be resolved or is not a field
pleae help me
if(valueofcam.equalsIgnoreCase("front")){
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
defaultCameraId = i;
// Toast.makeText(getApplicationContext(), "front", Toast.LENGTH_LONG).show();
}
else if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
// Toast.makeText(getApplicationContext(), ""+defaultCameraId, Toast.LENGTH_LONG).show();
}
}
}
camera = Camera.open(defaultCameraId);
Use cameraview from Google, and tune this Object in activity_main.xml:
<com.google.android.cameraview.CameraView
android:id="#+id/camera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:autoFocus="true"
app:aspectRatio="4:3"
app:facing="front"
app:flash="off"
android:background="#android:color/black" />
URL: https://github.com/google/cameraview
I have a cameraPreview class (see below) that is launching fullscreen and landscape... but the image is getting stretched/ and distorted.. is there a way to get this preview to remain fullscreen but not distort?
camLayer:
public class CamLayer extends SurfaceView implements SurfaceHolder.Callback {
Camera camera;
SurfaceHolder previewHolder;
String camID;
private static final String TAG = "Cam Preview";
public CamLayer(Context context, String facing)
{
super(context);
camID = facing;
previewHolder = this.getHolder();
previewHolder.addCallback(this);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
startCamera();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
Parameters params = camera.getParameters();
//params.setPreviewSize(width, height);
//params.setPictureFormat(PixelFormat.JPEG);
camera.setParameters(params);
camera.startPreview();
}
public void surfaceDestroyed(SurfaceHolder arg0)
{
stopCamera();
}
public void onResume() {
startCamera();
}
public void onPause() {
stopCamera();
}
public void stopCamera(){
System.out.println("stopCamera method");
if (camera != null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
previewHolder.removeCallback(this);
previewHolder = null;
}
}
private void startCamera(){
if(camID.equals("front")){
camera=Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
}else{
camera=Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
}
try {
camera.setPreviewDisplay(previewHolder);
}
catch (Throwable e){ Log.w("TAG,", "failed create surface !?!?"); }
}
public void draw(Canvas canvas) {
super.draw(canvas);
Paint p = new Paint(Color.RED);
Log.d(TAG, "draw");
canvas.drawText("PREVIEW", canvas.getWidth() / 2,
canvas.getHeight() / 2, p);
}
}
You need to run params.getSupportedPreviewSizes();
and from that find the best previewSize for your view
Look at this project: https://github.com/commonsguy/cw-advandroid/blob/master/Camera/Picture/src/com/commonsware/android/picture/PictureDemo.java
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);
}
In addition to what Lena Bru says about finding a good preview size, if there isn't an exact aspect ratio match between your CamLayer dimensions and the camera preview size you select, the only option to avoid distortion is to adjust the layout of your CamLayer.
The camera preview is simply stretched to cover the entire view, no matter what the aspect ratios are, so for an undistorted view, you have to configure the View's layout to match the selected preview aspect ratio. See the Android developer site custom components documentation; especially the part about onMeasure.
You'll want to report a width and height that's based on the preview aspect ratio, and you might need to trigger a relayout of your UI when you configure the camera preview size to update the View sizing.