Android Tutorial - Hardware : Camera
Camera preview
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/preview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </RelativeLayout> import java.util.List; import android.app.Activity; import android.hardware.Camera; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; public class PreviewActivity extends Activity implements SurfaceHolder.Callback { Camera mCamera; SurfaceView mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mPreview = (SurfaceView)findViewById(R.id.preview); mPreview.getHolder().addCallback(this); mPreview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mCamera = Camera.open(); } @Override public void onPause() { super.onPause(); mCamera.stopPreview(); } @Override public void onDestroy() { super.onDestroy(); mCamera.release(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters params = mCamera.getParameters(); List<Camera.Size> sizes = params.getSupportedPreviewSizes(); Camera.Size selected = sizes.get(0); params.setPreviewSize(selected.width,selected.height); mCamera.setParameters(params); mCamera.startPreview(); } @Override public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(mPreview.getHolder()); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.i("PREVIEW","surfaceDestroyed"); }
}
Camera With Intent
package app.test; import java.io.File; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.content.pm.ActivityInfo; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.provider.MediaStore.Images.Media; import android.util.Log; import android.view.View; public class Test extends Activity { Uri myPicture = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } public void captureImage(View view){ ContentValues values = new ContentValues(); values.put(Media.TITLE, "My demo image"); values.put(Media.DESCRIPTION, "Image Captured by Camera via an Intent"); myPicture = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values); Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); i.putExtra(MediaStore.EXTRA_OUTPUT, myPicture); startActivityForResult(i, 0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode==0 && resultCode==Activity.RESULT_OK) { Intent inn = new Intent(Intent.ACTION_VIEW); inn.setData(myPicture); startActivity(inn); } } }
Camera Intent
package app.test; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { final static int CAMERA_RESULT = 0; ImageView imv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(i, CAMERA_RESULT); } protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (resultCode == RESULT_OK) { Bundle extras = intent.getExtras(); Bitmap bmp = (Bitmap) extras.get("data"); imv = (ImageView) findViewById(R.id.ReturnedImageView); imv.setImageBitmap(bmp); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/ReturnedImageView" android:layout_width="wrap_content" android:layout_height="wrap_content"> </ImageView> </LinearLayout>
Media Store Camera Intent
package app.test; import java.io.FileNotFoundException; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.provider.MediaStore.Images.Media; import android.content.ContentValues; public class Test extends Activity { final static int CAMERA_RESULT = 0; Uri imageFileUri; ImageView returnedImageView; Button takePictureButton; Button saveDataButton; TextView titleTextView; TextView descriptionTextView; EditText titleEditText; EditText descriptionEditText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); returnedImageView = (ImageView) findViewById(R.id.ReturnedImageView); takePictureButton = (Button) findViewById(R.id.TakePictureButton); saveDataButton = (Button) findViewById(R.id.SaveDataButton); titleTextView = (TextView) findViewById(R.id.TitleTextView); descriptionTextView = (TextView) findViewById(R.id.DescriptionTextView); titleEditText = (EditText) findViewById(R.id.TitleEditText); descriptionEditText = (EditText) findViewById(R.id.DescriptionEditText); returnedImageView.setVisibility(View.GONE); saveDataButton.setVisibility(View.GONE); titleTextView.setVisibility(View.GONE); descriptionTextView.setVisibility(View.GONE); titleEditText.setVisibility(View.GONE); descriptionEditText.setVisibility(View.GONE); takePictureButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { imageFileUri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI, new ContentValues()); Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); startActivityForResult(i, CAMERA_RESULT); } }); saveDataButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { ContentValues contentValues = new ContentValues(3); contentValues.put(Media.DISPLAY_NAME, titleEditText.getText().toString()); contentValues.put(Media.DESCRIPTION, descriptionEditText.getText().toString()); getContentResolver().update(imageFileUri, contentValues, null,null); Toast bread = Toast.makeText(Test.this,"Record Updated", Toast.LENGTH_SHORT); bread.show(); takePictureButton.setVisibility(View.VISIBLE); returnedImageView.setVisibility(View.GONE); saveDataButton.setVisibility(View.GONE); titleTextView.setVisibility(View.GONE); descriptionTextView.setVisibility(View.GONE); titleEditText.setVisibility(View.GONE); descriptionEditText.setVisibility(View.GONE); } }); } protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (resultCode == RESULT_OK) { takePictureButton.setVisibility(View.GONE); saveDataButton.setVisibility(View.VISIBLE); returnedImageView.setVisibility(View.VISIBLE); titleTextView.setVisibility(View.VISIBLE); descriptionTextView.setVisibility(View.VISIBLE); titleEditText.setVisibility(View.VISIBLE); descriptionEditText.setVisibility(View.VISIBLE); int dw = 200; // Make it at most 200 pixels wide int dh = 200; // Make it at most 200 pixels tall try { BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); bmpFactoryOptions.inJustDecodeBounds = true; Bitmap bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream( imageFileUri), null, bmpFactoryOptions); int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight/ (float) dh); int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth/ (float) dw); if (heightRatio > 1 && widthRatio > 1) { if (heightRatio > widthRatio) { bmpFactoryOptions.inSampleSize = heightRatio; } else { bmpFactoryOptions.inSampleSize = widthRatio; } } bmpFactoryOptions.inJustDecodeBounds = false; bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream( imageFileUri), null, bmpFactoryOptions); returnedImageView.setImageBitmap(bmp); } catch (FileNotFoundException e) { Log.v("ERROR", e.toString()); } } } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/ReturnedImageView" android:layout_width="wrap_content" android:layout_height="wrap_content"> </ImageView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Title:" android:id="@+id/TitleTextView"> </TextView> <EditText android:layout_height="wrap_content" android:id="@+id/TitleEditText" android:layout_width="fill_parent"> </EditText> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Description" android:id="@+id/DescriptionTextView"> </TextView> <EditText android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/DescriptionEditText"> </EditText> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/TakePictureButton" android:text="Take Picture"> </Button> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/SaveDataButton" android:text="Save Data"> </Button>
</LinearLayout>
Using Timer to control Camera
package app.test; import java.io.IOException; import java.io.OutputStream; import android.app.Activity; import android.content.ContentValues; import android.content.res.Configuration; import android.hardware.Camera; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore.Images.Media; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class Test extends Activity implements OnClickListener, SurfaceHolder.Callback, Camera.PictureCallback { SurfaceView cameraView; SurfaceHolder surfaceHolder; Camera camera; Button startStopButton; TextView countdownTextView; Handler timerUpdateHandler; boolean timelapseRunning = false; int currentTime = 0; final int SECONDS_BETWEEN_PHOTOS = 60; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); cameraView = (SurfaceView) this.findViewById(R.id.CameraView); surfaceHolder = cameraView.getHolder(); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceHolder.addCallback(this); countdownTextView = (TextView) findViewById(R.id.CountDownTextView); startStopButton = (Button) findViewById(R.id.CountDownButton); startStopButton.setOnClickListener(this); timerUpdateHandler = new Handler(); } public void onClick(View v) { if (!timelapseRunning) { startStopButton.setText("Stop"); timelapseRunning = true; timerUpdateHandler.post(timerUpdateTask); } else { startStopButton.setText("Start"); timelapseRunning = false; timerUpdateHandler.removeCallbacks(timerUpdateTask); } } private Runnable timerUpdateTask = new Runnable() { public void run() { if (currentTime < SECONDS_BETWEEN_PHOTOS) { currentTime++; } else { camera.takePicture(null, null, null, Test.this); currentTime = 0; } timerUpdateHandler.postDelayed(timerUpdateTask, 1000); countdownTextView.setText("" + currentTime); } }; public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { camera.startPreview(); } public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try { camera.setPreviewDisplay(holder); Camera.Parameters parameters = camera.getParameters(); if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { parameters.set("orientation", "portrait"); camera.setDisplayOrientation(90); } camera.setParameters(parameters); } catch (IOException exception) { camera.release(); } } public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } public void onPictureTaken(byte[] data, Camera camera) { Uri imageFileUri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI, new ContentValues()); try { OutputStream imageFileOS = getContentResolver().openOutputStream( imageFileUri); imageFileOS.write(data); imageFileOS.flush(); imageFileOS.close(); Toast t = Toast.makeText(this, "Saved JPEG!", Toast.LENGTH_SHORT); t.show(); } catch (Exception e) { Toast t = Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT); t.show(); } camera.startPreview(); } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <SurfaceView android:id="@+id/CameraView" android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/CountDownTextView" android:text="10" android:textSize="100dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal|center"></TextView> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/CountDownButton" android:text="Start Timer"></Button> </LinearLayout> </FrameLayout> </LinearLayout>
Camera orientation
package app.test; import java.io.IOException; import java.io.OutputStream; import android.app.Activity; import android.content.ContentValues; import android.content.res.Configuration; import android.hardware.Camera; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore.Images.Media; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class Test extends Activity implements OnClickListener, SurfaceHolder.Callback, Camera.PictureCallback { SurfaceView cameraView; SurfaceHolder surfaceHolder; Camera camera; Button startButton; TextView countdownTextView; Handler timerUpdateHandler; boolean timerRunning = false; int currentTime = 10; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); cameraView = (SurfaceView) this.findViewById(R.id.CameraView); surfaceHolder = cameraView.getHolder(); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceHolder.addCallback(this); countdownTextView = (TextView) findViewById(R.id.CountDownTextView); startButton = (Button) findViewById(R.id.CountDownButton); startButton.setOnClickListener(this); timerUpdateHandler = new Handler(); } public void onClick(View v) { if (!timerRunning) { timerRunning = true; timerUpdateHandler.post(timerUpdateTask); } } private Runnable timerUpdateTask = new Runnable() { public void run() { if (currentTime > 1) { currentTime--; timerUpdateHandler.postDelayed(timerUpdateTask, 1000); } else { camera.takePicture(null, null, Test.this); timerRunning = false; currentTime = 10; } countdownTextView.setText("" + currentTime); } }; public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { camera.startPreview(); } public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try { camera.setPreviewDisplay(holder); Camera.Parameters parameters = camera.getParameters(); if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { parameters.set("orientation", "portrait"); camera.setDisplayOrientation(90); } camera.setParameters(parameters); } catch (IOException exception) { camera.release(); } } public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } public void onPictureTaken(byte[] data, Camera camera) { Uri imageFileUri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI, new ContentValues()); try { OutputStream imageFileOS = getContentResolver().openOutputStream( imageFileUri); imageFileOS.write(data); imageFileOS.flush(); imageFileOS.close(); Toast t = Toast.makeText(this, "Saved JPEG!", Toast.LENGTH_SHORT); t.show(); } catch (Exception e) { Toast t = Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT); t.show(); } camera.startPreview(); } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <SurfaceView android:id="@+id/CameraView" android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/CountDownTextView" android:text="10" android:textSize="100dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal|center"></TextView> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/CountDownButton" android:text="Start Timer"></Button> </LinearLayout> </FrameLayout>
</LinearLayout>
Camera Preview and Camera.getNumberOfCameras()
package app.test; 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; // ---------------------------------------------------------------------- public class Test extends Activity { private Preview mPreview; Camera mCamera; int numberOfCameras; int cameraCurrentlyLocked; // 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); // 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(); } } //menu/camera_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>
Take a snapshot
package app.test; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import java.util.List; import android.app.Activity; import android.content.ContentValues; import android.content.res.Configuration; import android.hardware.Camera; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore.Images.Media; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; public class Test extends Activity implements OnClickListener, SurfaceHolder.Callback, Camera.PictureCallback { SurfaceView cameraView; SurfaceHolder surfaceHolder; Camera camera; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); cameraView = (SurfaceView) this.findViewById(R.id.CameraView); surfaceHolder = cameraView.getHolder(); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceHolder.addCallback(this); cameraView.setFocusable(true); cameraView.setFocusableInTouchMode(true); cameraView.setClickable(true); cameraView.setOnClickListener(this); } public void onClick(View v) { camera.takePicture(null, null, this); } public void onPictureTaken(byte[] data, Camera camera) { Uri imageFileUri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI, new ContentValues()); try { OutputStream imageFileOS = getContentResolver().openOutputStream( imageFileUri); imageFileOS.write(data); imageFileOS.flush(); imageFileOS.close(); } catch (Exception e) { Toast t = Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT); t.show(); } camera.startPreview(); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { camera.startPreview(); } public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try { camera.setPreviewDisplay(holder); Camera.Parameters parameters = camera.getParameters(); if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { parameters.set("orientation", "portrait"); camera.setDisplayOrientation(90); } List<String> colorEffects = parameters.getSupportedColorEffects(); Iterator<String> cei = colorEffects.iterator(); while (cei.hasNext()) { String currentEffect = cei.next(); if (currentEffect.equals(Camera.Parameters.EFFECT_SOLARIZE)) { parameters.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE); break; } } camera.setParameters(parameters); } catch (IOException exception) { camera.release(); } } public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <SurfaceView android:id="@+id/CameraView" android:layout_width="fill_parent" android:layout_height="fill_parent"> </SurfaceView> </LinearLayout>
Take and preview Photo
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/preview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <RelativeLayout android:layout_width="fill_parent" android:layout_height="100dip" android:layout_alignParentBottom="true" android:gravity="center_vertical" android:background="#A000"> <Button android:layout_width="100dip" android:layout_height="wrap_content" android:text="Cancel" android:onClick="onCancelClick" /> <Button android:layout_width="100dip" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="Snap Photo" android:onClick="onSnapClick" /> </RelativeLayout> </RelativeLayout> package app.test; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import android.app.Activity; import android.hardware.Camera; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Toast; public class PreviewActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback { Camera mCamera; SurfaceView mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mPreview = (SurfaceView)findViewById(R.id.preview); mPreview.getHolder().addCallback(this); mPreview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mCamera = Camera.open(); } @Override public void onPause() { super.onPause(); mCamera.stopPreview(); } @Override public void onDestroy() { super.onDestroy(); mCamera.release(); Log.d("CAMERA","Destroy"); } public void onCancelClick(View v) { finish(); } public void onSnapClick(View v) { mCamera.takePicture(this, null, null, this); } @Override public void onShutter() { Toast.makeText(this, "Click!", Toast.LENGTH_SHORT).show(); } @Override public void onPictureTaken(byte[] data, Camera camera) { //Here, we chose internal storage try { FileOutputStream out = openFileOutput("picture.jpg", Activity.MODE_PRIVATE); out.write(data); out.flush(); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } camera.startPreview(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters params = mCamera.getParameters(); List<Camera.Size> sizes = params.getSupportedPreviewSizes(); Camera.Size selected = sizes.get(0); params.setPreviewSize(selected.width,selected.height); mCamera.setParameters(params); mCamera.setDisplayOrientation(90); mCamera.startPreview(); } @Override public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(mPreview.getHolder()); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.i("PREVIEW","surfaceDestroyed"); } }