am 564e8aa4: docs: Android University - Camera class
* commit '564e8aa41c29ebd10cb691851d4ecc347f8eee71': docs: Android University - Camera class
This commit is contained in:
BIN
docs/html/shareables/training/PhotoIntentActivity.zip
Normal file
BIN
docs/html/shareables/training/PhotoIntentActivity.zip
Normal file
Binary file not shown.
308
docs/html/training/camera/cameradirect.jd
Normal file
308
docs/html/training/camera/cameradirect.jd
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
page.title=Controlling the Camera
|
||||||
|
parent.title=Capturing Photos with the Camera
|
||||||
|
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
|
||||||
|
from existing camera applications. However, if you want to build a specialized camera application or
|
||||||
|
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
|
||||||
|
since it can take a while and might bog down the UI thread. However, in the sample application
|
||||||
|
associated with this lesson, opening the camera is deferred to the {@link
|
||||||
|
android.app.Activity#onResume onResume()} method to facilitate code reuse and keep the flow of
|
||||||
|
control simple.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void openCameraPerIdAndSetPreview() {
|
||||||
|
if (! safeCameraOpen(mCameraId)) {
|
||||||
|
mCameraId = getFirstRearCameraID();
|
||||||
|
safeCameraOpen(mCameraId);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreview.setCamera(mCamera);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<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. Dealing with multiple cameras
|
||||||
|
is an advanced topic and beyond the scope of this lesson. If you are really
|
||||||
|
interested, check out the implementation of {@code getFirstRearCameraID()} in
|
||||||
|
the sample app (downloadable at the top).</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();
|
||||||
|
mCamera = Camera.open(mCameraId);
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<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
|
||||||
|
data from the camera hardware the application.</p>
|
||||||
|
|
||||||
|
<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
|
||||||
|
image preview can be started, as seen in {@code setCamera()} method of the sample,
|
||||||
|
as shown in the next section.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="TaskStartPreview">Set and Start the Preview</h2>
|
||||||
|
|
||||||
|
<p>A camera instance and its related preview must be created in a specific
|
||||||
|
order, with the camera object being first. In the sample application, the
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Important: Call startPreview() to start updating the preview surface. Preview must
|
||||||
|
be started before you can take a picture.
|
||||||
|
*/
|
||||||
|
mCamera.startPreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskSettings">Modify Camera Settings</h2>
|
||||||
|
|
||||||
|
<p>Camera settings change the way that the camera takes pictures, from the zoom
|
||||||
|
level to exposure compensation. This example doesn’t do a whole lot with camera
|
||||||
|
settings, but the APIs provide a wide array of options. The {@code surfaceChanged()} method in the
|
||||||
|
sample app demonstrates how to get and set camera parameters:</p>
|
||||||
|
|
||||||
|
<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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Important: Call startPreview() to start updating the preview surface. Preview must be
|
||||||
|
started before you can take a picture.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
android.hardware.Camera#takePicture Camera.takePicture()}. Since the Android
|
||||||
|
Camera application already does a great job capturing JPEG images, you should
|
||||||
|
probably implement the raw-image callback.</p>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<p>After a picture is taken, you must to restart the preview before the user
|
||||||
|
can take another picture. In the example, the restart is done by overloading
|
||||||
|
the shutter button, as shown below.</p>
|
||||||
|
|
||||||
|
<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) {
|
||||||
|
/*
|
||||||
|
Call stopPreview() to stop updating the preview surface.
|
||||||
|
*/
|
||||||
|
mCamera.stopPreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this function returns, mCamera will be null.
|
||||||
|
*/
|
||||||
|
private void stopPreviewAndFreeCamera() {
|
||||||
|
|
||||||
|
if (mCamera != null) {
|
||||||
|
/*
|
||||||
|
Call stopPreview() to stop updating the preview surface.
|
||||||
|
*/
|
||||||
|
mCamera.stopPreview();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Important: Call release() to release the camera for use by other applications.
|
||||||
|
Applications should release the camera immediately in onPause() (and re-open() it in
|
||||||
|
onResume()).
|
||||||
|
*/
|
||||||
|
mCamera.release();
|
||||||
|
|
||||||
|
mCamera = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>In the example application, this procedure is also part of the {@code
|
||||||
|
setCamera()} method, so initializing a camera always begins with stopping the
|
||||||
|
preview.</p>
|
||||||
|
|
||||||
60
docs/html/training/camera/index.jd
Normal file
60
docs/html/training/camera/index.jd
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
page.title=Capturing Photos with the Camera
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
startpage=true
|
||||||
|
next.title=Taking Photos Simply
|
||||||
|
next.link=photobasics.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Dependencies and prerequisites</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Android 1.5 (API level 3) or higher</li>
|
||||||
|
<li>A device with a camera</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/media/camera.html">Camera</a></li>
|
||||||
|
<li><a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/PhotoIntentActivity.zip" class="button">Download the Intent sample</a>
|
||||||
|
<p class="filename">PhotoIntentActivity.zip</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>The world was a dismal and featureless place before rich media became
|
||||||
|
prevalent. Remember Gopher? We don't, either. For your app to become
|
||||||
|
part of your users' lives, give them a way to put their lives into it.
|
||||||
|
Using the on-board cameras, your application can enable users to augment what
|
||||||
|
they see around them, make unique avatars, look for zombies around the corner,
|
||||||
|
or simply share their experiences.</p>
|
||||||
|
|
||||||
|
<p>This class gets you clicking fast with some super-easy ways of
|
||||||
|
leveraging existing camera applications. In later lessons, you dive deeper
|
||||||
|
and learn how to control the camera hardware directly.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Lessons</h2>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><b><a href="photobasics.html">Taking Photos Simply</a></b></dt>
|
||||||
|
<dd>Leverage other applications and capture photos with just a few lines of code.</dd>
|
||||||
|
<dt><b><a href="videobasics.html">Recording Videos Simply</a></b></dt>
|
||||||
|
<dd>Leverage other applications and record videos with just a few lines of code.</dd>
|
||||||
|
<dt><b><a href="cameradirect.html">Controlling the Camera</a></b></dt>
|
||||||
|
<dd>Control the camera hardware directly and implement your own camera application.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
258
docs/html/training/camera/photobasics.jd
Normal file
258
docs/html/training/camera/photobasics.jd
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
page.title=Taking Photos Simply
|
||||||
|
parent.title=Capturing Photos with the Camera
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
next.title=Recording Videos Simply
|
||||||
|
next.link=videobasics.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#TaskManifest">Request Camera Permission</a></li>
|
||||||
|
<li><a href="#TaskCaptureIntent">Take a Photo with the Camera App</a></li>
|
||||||
|
<li><a href="#TaskPhotoView">View the Photo</a></li>
|
||||||
|
<li><a href="#TaskPath">Save the Photo</a></li>
|
||||||
|
<li><a href="#TaskGallery">Add the Photo to a Gallery</a></li>
|
||||||
|
<li><a href="#TaskScalePhoto">Decode a Scaled Image</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/media/camera.html">Camera</a></li>
|
||||||
|
<li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent
|
||||||
|
Filters</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/PhotoIntentActivity.zip" class="button">Download the
|
||||||
|
sample</a>
|
||||||
|
<p class="filename">PhotoIntentActivity.zip</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>This lesson explains how to capture photos using an existing camera
|
||||||
|
application.</p>
|
||||||
|
|
||||||
|
<p>Suppose you are implementing a crowd-sourced weather service that makes a
|
||||||
|
global weather map by blending together pictures of the sky taken by devices
|
||||||
|
running your client app. Integrating photos is only a small part of your
|
||||||
|
application. You want to take photos with minimal fuss, not reinvent the
|
||||||
|
camera. Happily, most Android-powered devices already have at least one camera
|
||||||
|
application installed. In this lesson, you learn how to make it take a picture
|
||||||
|
for you.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskManifest">Request Camera Permission</h2>
|
||||||
|
|
||||||
|
<p>If an essential function of your application is taking pictures, then restrict
|
||||||
|
its visibility in Android Market to devices that have a camera. To advertise
|
||||||
|
that your application depends on having a camera, put a <a
|
||||||
|
href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> {@code
|
||||||
|
<uses-feature>}</a> tag in your manifest file:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<manifest ... >
|
||||||
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
|
...
|
||||||
|
</manifest ... >
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If your application uses, but does not require a camera in order to function, add {@code
|
||||||
|
android:required="false"} to the tag. In doing so, Android Market will allow devices without a
|
||||||
|
camera to download your application. It's then your responsibility to check for the availability
|
||||||
|
of the camera at runtime by calling {@link
|
||||||
|
android.content.pm.PackageManager#hasSystemFeature hasSystemFeature(PackageManager.FEATURE_CAMERA)}.
|
||||||
|
If a camera is not available, you should then disable your camera features.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskCaptureIntent">Take a Photo with the Camera App</h2>
|
||||||
|
|
||||||
|
<p>The Android way of delegating actions to other applications is to invoke an {@link
|
||||||
|
android.content.Intent} that describes what you want done. This process involves three pieces: The
|
||||||
|
{@link android.content.Intent} itself, a call to start the external {@link android.app.Activity},
|
||||||
|
and some code to handle the image data when focus returns to your activity.</p>
|
||||||
|
|
||||||
|
<p>Here's a function that invokes an intent to capture a photo.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void dispatchTakePictureIntent(int actionCode) {
|
||||||
|
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
|
startActivityForResult(takePictureIntent, actionCode);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Congratulations: with this code, your application has gained the ability to
|
||||||
|
make another camera application do its bidding! Of course, if no compatible
|
||||||
|
application is ready to catch the intent, then your app will fall down like a
|
||||||
|
botched stage dive. Here is a function to check whether an app can handle your intent:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public static boolean isIntentAvailable(Context context, String action) {
|
||||||
|
final PackageManager packageManager = context.getPackageManager();
|
||||||
|
final Intent intent = new Intent(action);
|
||||||
|
List<ResolveInfo> list =
|
||||||
|
packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
return list.size() > 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskPhotoView">View the Photo</h2>
|
||||||
|
|
||||||
|
<p>If the simple feat of taking a photo is not the culmination of your app's
|
||||||
|
ambition, then you probably want to get the image back from the camera
|
||||||
|
application and do something with it.</p>
|
||||||
|
|
||||||
|
<p>The Android Camera application encodes the photo in the return {@link android.content.Intent}
|
||||||
|
delivered to {@link android.app.Activity#onActivityResult onActivityResult()} as a small {@link
|
||||||
|
android.graphics.Bitmap} in the extras, under the key {@code "data"}. The following code retrieves
|
||||||
|
this image and displays it in an {@link android.widget.ImageView}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void handleSmallCameraPhoto(Intent intent) {
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
mImageBitmap = (Bitmap) extras.get("data");
|
||||||
|
mImageView.setImageBitmap(mImageBitmap);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> This thumbnail image from {@code "data"} might be good for an
|
||||||
|
icon, but not a lot more. Dealing with a full-sized image takes a bit more
|
||||||
|
work.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskPath">Save the Photo</h2>
|
||||||
|
|
||||||
|
<p>The Android Camera application saves a full-size photo if you give it a file to
|
||||||
|
save into. You must provide a path that includes the storage volume,
|
||||||
|
folder, and file name.</p>
|
||||||
|
|
||||||
|
<p>There is an easy way to get the path for photos, but it works only on Android 2.2 (API level 8)
|
||||||
|
and later:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
storageDir = new File(
|
||||||
|
Environment.getExternalStoragePublicDirectory(
|
||||||
|
Environment.DIRECTORY_PICTURES
|
||||||
|
),
|
||||||
|
getAlbumName()
|
||||||
|
);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>For earlier API levels, you have to provide the name of the photo
|
||||||
|
directory yourself.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
storageDir = new File (
|
||||||
|
Environment.getExternalStorageDirectory()
|
||||||
|
+ PICTURES_DIR
|
||||||
|
+ getAlbumName()
|
||||||
|
);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> The path component {@code PICTURES_DIR} is
|
||||||
|
just {@code Pictures/}, the standard location for shared photos on the external/shared
|
||||||
|
storage.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="TaskFileName">Set the file name</h3>
|
||||||
|
|
||||||
|
<p>As shown in the previous section, the file location for an image should be
|
||||||
|
driven by the device environment. What you need to do yourself is choose a
|
||||||
|
collision-resistant file-naming scheme. You may wish also to save the path in a
|
||||||
|
member variable for later use. Here's an example solution:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private File createImageFile() throws IOException {
|
||||||
|
// Create an image file name
|
||||||
|
String timeStamp =
|
||||||
|
new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||||
|
String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
|
||||||
|
File image = File.createTempFile(
|
||||||
|
imageFileName,
|
||||||
|
JPEG_FILE_SUFFIX,
|
||||||
|
getAlbumDir()
|
||||||
|
);
|
||||||
|
mCurrentPhotoPath = image.getAbsolutePath();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="TaskIntentFileName">Append the file name onto the Intent</h3>
|
||||||
|
|
||||||
|
<p>Once you have a place to save your image, pass that location to the camera
|
||||||
|
application via the {@link android.content.Intent}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
File f = createImageFile();
|
||||||
|
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskGallery">Add the Photo to a Gallery</h2>
|
||||||
|
|
||||||
|
<p>When you create a photo through an intent, you should know where your image is located, because
|
||||||
|
you said where to save it in the first place. For everyone else, perhaps the easiest way to make
|
||||||
|
your photo accessible is to make it accessible from the system's Media Provider.</p>
|
||||||
|
|
||||||
|
<p>The following example method demonstrates how to invoke the system's media scanner to add your
|
||||||
|
photo to the Media Provider's database, making it available in the Android Gallery application
|
||||||
|
and to other apps.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void galleryAddPic() {
|
||||||
|
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||||
|
File f = new File(mCurrentPhotoPath);
|
||||||
|
Uri contentUri = Uri.fromFile(f);
|
||||||
|
mediaScanIntent.setData(contentUri);
|
||||||
|
this.sendBroadcast(mediaScanIntent);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskScalePhoto">Decode a Scaled Image</h2>
|
||||||
|
|
||||||
|
<p>Managing multiple full-sized images can be tricky with limited memory. If
|
||||||
|
you find your application running out of memory after displaying just a few
|
||||||
|
images, you can dramatically reduce the amount of dynamic heap used by
|
||||||
|
expanding the JPEG into a memory array that's already scaled to match the size
|
||||||
|
of the destination view. The following example method demonstrates this
|
||||||
|
technique.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void setPic() {
|
||||||
|
// Get the dimensions of the View
|
||||||
|
int targetW = mImageView.getWidth();
|
||||||
|
int targetH = mImageView.getHeight();
|
||||||
|
|
||||||
|
// Get the dimensions of the bitmap
|
||||||
|
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||||
|
bmOptions.inJustDecodeBounds = true;
|
||||||
|
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
|
||||||
|
int photoW = bmOptions.outWidth;
|
||||||
|
int photoH = bmOptions.outHeight;
|
||||||
|
|
||||||
|
// Determine how much to scale down the image
|
||||||
|
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
|
||||||
|
|
||||||
|
// Decode the image file into a Bitmap sized to fill the View
|
||||||
|
bmOptions.inJustDecodeBounds = false;
|
||||||
|
bmOptions.inSampleSize = scaleFactor;
|
||||||
|
bmOptions.inPurgeable = true;
|
||||||
|
|
||||||
|
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
|
||||||
|
mImageView.setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
118
docs/html/training/camera/videobasics.jd
Normal file
118
docs/html/training/camera/videobasics.jd
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
page.title=Recording Videos Simply
|
||||||
|
parent.title=Capturing Photos with the Camera
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
previous.title=Recording Photos Simply
|
||||||
|
previous.link=photobasics.html
|
||||||
|
next.title=Controlling the Camera
|
||||||
|
next.link=cameradirect.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#TaskManifest">Request Camera Permission</a></li>
|
||||||
|
<li><a href="#TaskCaptureIntent">Record a Video with a Camera App</a>
|
||||||
|
<li><a href="#TaskVideoView">View the Video</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/media/camera.html">Camera</a></li>
|
||||||
|
<li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent
|
||||||
|
Filters</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/PhotoIntentActivity.zip" class="button">Download the
|
||||||
|
sample</a>
|
||||||
|
<p class="filename">PhotoIntentActivity.zip</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>This lesson explains how to capture video using existing camera
|
||||||
|
applications.</p>
|
||||||
|
|
||||||
|
<p>Your application has a job to do, and integrating videos is only a small
|
||||||
|
part of it. You want to take videos with minimal fuss, and not reinvent the
|
||||||
|
camcorder. Happily, most Android-powered devices already have a camera application that
|
||||||
|
records video. In this lesson, you make it do this for you.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskManifest">Request Camera Permission</h2>
|
||||||
|
|
||||||
|
<p>To advertise that your application depends on having a camera, put a
|
||||||
|
{@code <uses-feature>} tag in the manifest file:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<manifest ... >
|
||||||
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
|
...
|
||||||
|
</manifest ... >
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If your application uses, but does not require a camera in order to function, add {@code
|
||||||
|
android:required="false"} to the tag. In doing so, Android Market will allow devices without a
|
||||||
|
camera to download your application. It's then your responsibility to check for the availability
|
||||||
|
of the camera at runtime by calling {@link
|
||||||
|
android.content.pm.PackageManager#hasSystemFeature hasSystemFeature(PackageManager.FEATURE_CAMERA)}.
|
||||||
|
If a camera is not available, you should then disable your camera features.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskCaptureIntent">Record a Video with a Camera App</h2>
|
||||||
|
|
||||||
|
<p>The Android way of delegating actions to other applications is to invoke
|
||||||
|
an {@link android.content.Intent} that describes what you want done. This
|
||||||
|
involves three pieces: the {@link android.content.Intent} itself, a call to start the external
|
||||||
|
{@link android.app.Activity}, and some code to handle the video when focus returns
|
||||||
|
to your activity.</p>
|
||||||
|
|
||||||
|
<p>Here's a function that invokes an intent to capture video.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void dispatchTakeVideoIntent() {
|
||||||
|
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||||
|
startActivityForResult(takeVideoIntent, ACTION_TAKE_VIDEO);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>It's a good idea to make sure an app exists to handle your intent
|
||||||
|
before invoking it. Here's a function that checks for apps that can handle your intent:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public static boolean isIntentAvailable(Context context, String action) {
|
||||||
|
final PackageManager packageManager = context.getPackageManager();
|
||||||
|
final Intent intent = new Intent(action);
|
||||||
|
List<ResolveInfo> list =
|
||||||
|
packageManager.queryIntentActivities(intent,
|
||||||
|
PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
return list.size() > 0;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="TaskVideoView">View the Video</h2>
|
||||||
|
|
||||||
|
<p>The Android Camera application returns the video in the {@link android.content.Intent} delivered
|
||||||
|
to {@link android.app.Activity#onActivityResult onActivityResult()} as a {@link
|
||||||
|
android.net.Uri} pointing to the video location in storage. The following code
|
||||||
|
retrieves this image and displays it in a {@link android.widget.VideoView}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void handleCameraVideo(Intent intent) {
|
||||||
|
mVideoUri = intent.getData();
|
||||||
|
mVideoView.setVideoURI(mVideoUri);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
Reference in New Issue
Block a user