2011-12-15 15:59:34 -08:00
|
|
|
|
page.title=Controlling the Camera
|
2011-12-15 16:47:26 -08:00
|
|
|
|
parent.title=Capturing Photos
|
2011-12-15 15:59:34 -08:00
|
|
|
|
parent.link=index.html
|
|
|
|
|
|
|
|
|
|
trainingnavtop=true
|
|
|
|
|
previous.title=Recording Videos Simply
|
|
|
|
|
previous.link=videobasics.html
|
|
|
|
|
|
|
|
|
|
@jd:body
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div id="tb-wrapper">
|
|
|
|
|
<div id="tb">
|
|
|
|
|
|
|
|
|
|
<h2>This lesson teaches you to</h2>
|
|
|
|
|
<ol>
|
|
|
|
|
<li><a href="#TaskOpenCamera">Open the Camera Object</a></li>
|
|
|
|
|
<li><a href="#camera-preview">Create the Camera Preview</a></li>
|
|
|
|
|
<li><a href="#TaskSettings">Modify Camera Settings</a></li>
|
|
|
|
|
<li><a href="#TaskOrientation">Set the Preview Orientation</a></li>
|
|
|
|
|
<li><a href="#TaskTakePicture">Take a Picture</a></li>
|
|
|
|
|
<li><a href="#TaskRestartPreview">Restart the Preview</a></li>
|
|
|
|
|
<li><a href="#TaskReleaseCamera">Stop the Preview and Release the Camera</a></li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<h2>You should also read</h2>
|
|
|
|
|
<ul>
|
|
|
|
|
<li><a href="{@docRoot}guide/topics/media/camera.html#custom-camera">Building
|
|
|
|
|
a Camera App</a></li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p>In this lesson, we discuss how to control the camera hardware directly using
|
|
|
|
|
the framework APIs.</p>
|
|
|
|
|
|
|
|
|
|
<p>Directly controlling a device camera requires a lot more code than requesting pictures or videos
|
2012-03-03 00:13:32 +08:00
|
|
|
|
from existing camera applications. However, if you want to build a specialized camera application
|
2011-12-15 15:59:34 -08:00
|
|
|
|
or something fully integrated in your app UI, this lesson shows you how.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskOpenCamera">Open the Camera Object</h2>
|
|
|
|
|
|
|
|
|
|
<p>Getting an instance of the {@link android.hardware.Camera} object is the first step in the
|
|
|
|
|
process of directly controlling the camera. As Android's own Camera application does, the
|
|
|
|
|
recommended way to access the camera is to open {@link android.hardware.Camera} on a separate thread
|
|
|
|
|
that's launched from {@link android.app.Activity#onCreate onCreate()}. This approach is a good idea
|
2011-12-15 16:53:35 -08:00
|
|
|
|
since it can take a while and might bog down the UI thread. In a more basic implementation,
|
|
|
|
|
opening the camera can be deferred to the {@link
|
2011-12-15 15:59:34 -08:00
|
|
|
|
android.app.Activity#onResume onResume()} method to facilitate code reuse and keep the flow of
|
|
|
|
|
control simple.</p>
|
|
|
|
|
|
|
|
|
|
<p>Calling {@link android.hardware.Camera#open Camera.open()} throws an
|
|
|
|
|
exception if the camera is already in use by another application, so we wrap it
|
|
|
|
|
in a {@code try} block.</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
private boolean safeCameraOpen(int id) {
|
|
|
|
|
boolean qOpened = false;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
releaseCameraAndPreview();
|
2011-12-15 16:53:35 -08:00
|
|
|
|
mCamera = Camera.open(id);
|
2011-12-15 15:59:34 -08:00
|
|
|
|
qOpened = (mCamera != null);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(getString(R.string.app_name), "failed to open Camera");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return qOpened;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void releaseCameraAndPreview() {
|
|
|
|
|
mPreview.setCamera(null);
|
|
|
|
|
if (mCamera != null) {
|
|
|
|
|
mCamera.release();
|
|
|
|
|
mCamera = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
2011-12-15 16:53:35 -08:00
|
|
|
|
<p>Since API level 9, the camera framework supports multiple cameras. If you use the
|
|
|
|
|
legacy API and call {@link android.hardware.Camera#open open()} without an
|
|
|
|
|
argument, you get the first rear-facing camera.</p>
|
|
|
|
|
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
<h2 id="camera-preview">Create the Camera Preview</h2>
|
|
|
|
|
|
|
|
|
|
<p>Taking a picture usually requires that your users see a preview of their subject before clicking
|
|
|
|
|
the shutter. To do so, you can use a {@link android.view.SurfaceView} to draw previews of what the
|
|
|
|
|
camera sensor is picking up.</p>
|
|
|
|
|
|
|
|
|
|
<h3 id="TaskSetPreview">Preview Class</h3>
|
|
|
|
|
|
|
|
|
|
<p>To get started with displaying a preview, you need preview class. The
|
|
|
|
|
preview requires an implementation of the {@code
|
|
|
|
|
android.view.SurfaceHolder.Callback} interface, which is used to pass image
|
2012-03-03 00:13:32 +08:00
|
|
|
|
data from the camera hardware to the application.</p>
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
class Preview extends ViewGroup implements SurfaceHolder.Callback {
|
|
|
|
|
|
|
|
|
|
SurfaceView mSurfaceView;
|
|
|
|
|
SurfaceHolder mHolder;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>The preview class must be passed to the {@link android.hardware.Camera} object before the live
|
2011-12-15 16:53:35 -08:00
|
|
|
|
image preview can be started, as shown in the next section.</p>
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3 id="TaskStartPreview">Set and Start the Preview</h2>
|
|
|
|
|
|
|
|
|
|
<p>A camera instance and its related preview must be created in a specific
|
2011-12-15 16:53:35 -08:00
|
|
|
|
order, with the camera object being first. In the snippet below, the
|
2011-12-15 15:59:34 -08:00
|
|
|
|
process of initializing the camera is encapsulated so that {@link
|
|
|
|
|
android.hardware.Camera#startPreview Camera.startPreview()} is called by the
|
|
|
|
|
{@code setCamera()} method, whenever the user does something to change the
|
|
|
|
|
camera. The preview must also be restarted in the preview class {@code
|
|
|
|
|
surfaceChanged()} callback method.</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
public void setCamera(Camera camera) {
|
|
|
|
|
if (mCamera == camera) { return; }
|
|
|
|
|
|
|
|
|
|
stopPreviewAndFreeCamera();
|
|
|
|
|
|
|
|
|
|
mCamera = camera;
|
|
|
|
|
|
|
|
|
|
if (mCamera != null) {
|
|
|
|
|
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
|
|
|
|
|
mSupportedPreviewSizes = localSizes;
|
|
|
|
|
requestLayout();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
mCamera.setPreviewDisplay(mHolder);
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-04 17:54:03 -08:00
|
|
|
|
// Important: Call startPreview() to start updating the preview
|
|
|
|
|
// surface. Preview must be started before you can take a picture.
|
2011-12-15 15:59:34 -08:00
|
|
|
|
mCamera.startPreview();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskSettings">Modify Camera Settings</h2>
|
|
|
|
|
|
|
|
|
|
<p>Camera settings change the way that the camera takes pictures, from the zoom
|
2011-12-15 16:53:35 -08:00
|
|
|
|
level to exposure compensation. This example changes only the preview size;
|
|
|
|
|
see the source code of the Camera application for many more.</p>
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
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);
|
|
|
|
|
|
2013-12-04 17:54:03 -08:00
|
|
|
|
// Important: Call startPreview() to start updating the preview surface.
|
|
|
|
|
// Preview must be started before you can take a picture.
|
2011-12-15 15:59:34 -08:00
|
|
|
|
mCamera.startPreview();
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskOrientation">Set the Preview Orientation</h2>
|
|
|
|
|
|
|
|
|
|
<p>Most camera applications lock the display into landscape mode because that is the natural
|
|
|
|
|
orientation of the camera sensor. This setting does not prevent you from taking portrait-mode
|
|
|
|
|
photos, because the orientation of the device is recorded in the EXIF header. The {@link
|
|
|
|
|
android.hardware.Camera#setDisplayOrientation setCameraDisplayOrientation()} method lets you change
|
|
|
|
|
how the preview is displayed without affecting how the image is recorded. However, in Android prior
|
|
|
|
|
to API level 14, you must stop your preview before changing the orientation and then restart it.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskTakePicture">Take a Picture</h2>
|
|
|
|
|
|
|
|
|
|
<p>Use the {@link android.hardware.Camera#takePicture Camera.takePicture()}
|
|
|
|
|
method to take a picture once the preview is started. You can create {@link
|
|
|
|
|
android.hardware.Camera.PictureCallback} and {@link
|
|
|
|
|
android.hardware.Camera.ShutterCallback} objects and pass them into {@link
|
2011-12-15 16:53:35 -08:00
|
|
|
|
android.hardware.Camera#takePicture Camera.takePicture()}.</p>
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
<p>If you want to grab images continously, you can create a {@link
|
|
|
|
|
android.hardware.Camera.PreviewCallback} that implements {@link
|
|
|
|
|
android.hardware.Camera.PreviewCallback#onPreviewFrame onPreviewFrame()}. For
|
|
|
|
|
something in between, you can capture only selected preview frames, or set up a
|
|
|
|
|
delayed action to call {@link android.hardware.Camera#takePicture
|
|
|
|
|
takePicture()}.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskRestartPreview">Restart the Preview</h2>
|
|
|
|
|
|
2012-03-03 00:13:32 +08:00
|
|
|
|
<p>After a picture is taken, you must restart the preview before the user
|
2011-12-15 16:53:35 -08:00
|
|
|
|
can take another picture. In this example, the restart is done by overloading
|
|
|
|
|
the shutter button.</p>
|
2011-12-15 15:59:34 -08:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
switch(mPreviewState) {
|
|
|
|
|
case K_STATE_FROZEN:
|
|
|
|
|
mCamera.startPreview();
|
|
|
|
|
mPreviewState = K_STATE_PREVIEW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
mCamera.takePicture( null, rawCallback, null);
|
|
|
|
|
mPreviewState = K_STATE_BUSY;
|
|
|
|
|
} // switch
|
|
|
|
|
shutterBtnConfig();
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="TaskReleaseCamera">Stop the Preview and Release the Camera</h2>
|
|
|
|
|
|
|
|
|
|
<p>Once your application is done using the camera, it's time to clean up. In
|
|
|
|
|
particular, you must release the {@link android.hardware.Camera} object, or you risk crashing other
|
|
|
|
|
applications, including new instances of your own application.</p>
|
|
|
|
|
|
|
|
|
|
<p>When should you stop the preview and release the camera? Well, having your
|
|
|
|
|
preview surface destroyed is a pretty good hint that it’s time to stop the
|
|
|
|
|
preview and release the camera, as shown in these methods from the {@code
|
|
|
|
|
Preview} class.</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
|
|
|
// Surface will be destroyed when we return, so stop the preview.
|
|
|
|
|
if (mCamera != null) {
|
2013-12-04 17:54:03 -08:00
|
|
|
|
// Call stopPreview() to stop updating the preview surface.
|
2011-12-15 15:59:34 -08:00
|
|
|
|
mCamera.stopPreview();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-12-04 17:54:03 -08:00
|
|
|
|
* When this function returns, mCamera will be null.
|
|
|
|
|
*/
|
2011-12-15 15:59:34 -08:00
|
|
|
|
private void stopPreviewAndFreeCamera() {
|
|
|
|
|
|
|
|
|
|
if (mCamera != null) {
|
2013-12-04 17:54:03 -08:00
|
|
|
|
// Call stopPreview() to stop updating the preview surface.
|
2011-12-15 15:59:34 -08:00
|
|
|
|
mCamera.stopPreview();
|
|
|
|
|
|
2013-12-04 17:54:03 -08:00
|
|
|
|
// Important: Call release() to release the camera for use by other
|
|
|
|
|
// applications. Applications should release the camera immediately
|
|
|
|
|
// during onPause() and re-open() it during onResume()).
|
2011-12-15 15:59:34 -08:00
|
|
|
|
mCamera.release();
|
|
|
|
|
|
|
|
|
|
mCamera = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
2011-12-15 16:53:35 -08:00
|
|
|
|
<p>Earlier in the lesson, this procedure was also part of the {@code
|
2011-12-15 15:59:34 -08:00
|
|
|
|
setCamera()} method, so initializing a camera always begins with stopping the
|
|
|
|
|
preview.</p>
|
|
|
|
|
|