diff --git a/docs/html/shareables/training/PhotoIntentActivity.zip b/docs/html/shareables/training/PhotoIntentActivity.zip new file mode 100644 index 0000000000000..9fcc0e19a7c8a Binary files /dev/null and b/docs/html/shareables/training/PhotoIntentActivity.zip differ diff --git a/docs/html/training/camera/cameradirect.jd b/docs/html/training/camera/cameradirect.jd new file mode 100644 index 0000000000000..d37f2c49e0f5b --- /dev/null +++ b/docs/html/training/camera/cameradirect.jd @@ -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 + + +
+
+ +

This lesson teaches you to

+
    +
  1. Open the Camera Object
  2. +
  3. Create the Camera Preview
  4. +
  5. Modify Camera Settings
  6. +
  7. Set the Preview Orientation
  8. +
  9. Take a Picture
  10. +
  11. Restart the Preview
  12. +
  13. Stop the Preview and Release the Camera
  14. +
+ +

You should also read

+ +
+
+ +

In this lesson, we discuss how to control the camera hardware directly using +the framework APIs.

+ +

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.

+ + +

Open the Camera Object

+ +

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.

+ +
+private void openCameraPerIdAndSetPreview() {
+    if (! safeCameraOpen(mCameraId)) {
+        mCameraId = getFirstRearCameraID();
+        safeCameraOpen(mCameraId);
+    }
+
+    mPreview.setCamera(mCamera);
+}
+
+ +

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).

+ +

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.

+ +
+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;
+    }
+}
+
+ + +

Create the Camera Preview

+ +

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.

+ +

Preview Class

+ +

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.

+ +
+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);
+    }
+...
+}
+
+ +

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.

+ + +

Set and Start the Preview

+ +

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.

+ +
+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();
+    }
+}
+
+ + +

Modify Camera Settings

+ +

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:

+ +
+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();
+}
+
+ + +

Set the Preview Orientation

+ +

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.

+ + +

Take a Picture

+ +

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.

+ +

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()}.

+ + +

Restart the Preview

+ +

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.

+ +
+@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();
+}
+
+ + +

Stop the Preview and Release the Camera

+ +

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.

+ +

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.

+ +
+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;
+    }
+}
+
+ +

In the example application, this procedure is also part of the {@code +setCamera()} method, so initializing a camera always begins with stopping the +preview.

+ diff --git a/docs/html/training/camera/index.jd b/docs/html/training/camera/index.jd new file mode 100644 index 0000000000000..400f6368ad97b --- /dev/null +++ b/docs/html/training/camera/index.jd @@ -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 + +
+
+ + +

Dependencies and prerequisites

+ + + +

You should also read

+ + + +

Try it out

+ +
+ Download the Intent sample +

PhotoIntentActivity.zip

+
+ +
+
+ +

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.

+ +

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.

+ + +

Lessons

+ +
+
Taking Photos Simply
+
Leverage other applications and capture photos with just a few lines of code.
+
Recording Videos Simply
+
Leverage other applications and record videos with just a few lines of code.
+
Controlling the Camera
+
Control the camera hardware directly and implement your own camera application.
+
+ diff --git a/docs/html/training/camera/photobasics.jd b/docs/html/training/camera/photobasics.jd new file mode 100644 index 0000000000000..002dec7287219 --- /dev/null +++ b/docs/html/training/camera/photobasics.jd @@ -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 + + +
+
+ +

This lesson teaches you to

+
    +
  1. Request Camera Permission
  2. +
  3. Take a Photo with the Camera App
  4. +
  5. View the Photo
  6. +
  7. Save the Photo
  8. +
  9. Add the Photo to a Gallery
  10. +
  11. Decode a Scaled Image
  12. +
+ +

You should also read

+ + +

Try it out

+
+ Download the +sample +

PhotoIntentActivity.zip

+
+ +
+
+ +

This lesson explains how to capture photos using an existing camera +application.

+ +

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.

+ + +

Request Camera Permission

+ +

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 {@code +<uses-feature>} tag in your manifest file:

+ +
+<manifest ... >
+    <uses-feature android:name="android.hardware.camera" />
+    ...
+</manifest ... >
+
+ +

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.

+ + +

Take a Photo with the Camera App

+ +

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.

+ +

Here's a function that invokes an intent to capture a photo.

+ +
+private void dispatchTakePictureIntent(int actionCode) {
+    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+    startActivityForResult(takePictureIntent, actionCode);
+}
+
+ + +

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:

+ +
+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;
+}
+
+ + +

View the Photo

+ +

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.

+ +

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}.

+ +
+private void handleSmallCameraPhoto(Intent intent) {
+    Bundle extras = intent.getExtras();
+    mImageBitmap = (Bitmap) extras.get("data");
+    mImageView.setImageBitmap(mImageBitmap);
+}
+
+ +

Note: 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.

+ + +

Save the Photo

+ +

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.

+ +

There is an easy way to get the path for photos, but it works only on Android 2.2 (API level 8) +and later:

+ +
 
+storageDir = new File(
+    Environment.getExternalStoragePublicDirectory(
+        Environment.DIRECTORY_PICTURES
+    ), 
+    getAlbumName()
+);		
+
+ +

For earlier API levels, you have to provide the name of the photo +directory yourself.

+ +
 
+storageDir = new File (
+    Environment.getExternalStorageDirectory()
+        + PICTURES_DIR
+        + getAlbumName()
+);
+
+ +

Note: The path component {@code PICTURES_DIR} is +just {@code Pictures/}, the standard location for shared photos on the external/shared +storage.

+ + +

Set the file name

+ +

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:

+ +
 
+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;
+}
+
+ + +

Append the file name onto the Intent

+ +

Once you have a place to save your image, pass that location to the camera +application via the {@link android.content.Intent}.

+ +
+File f = createImageFile();
+takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
+
+ + +

Add the Photo to a Gallery

+ +

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.

+ +

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.

+ +
+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);
+}
+
+ + +

Decode a Scaled Image

+ +

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.

+ +
+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);
+}
+
+ diff --git a/docs/html/training/camera/videobasics.jd b/docs/html/training/camera/videobasics.jd new file mode 100644 index 0000000000000..a0f57325dbbb5 --- /dev/null +++ b/docs/html/training/camera/videobasics.jd @@ -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 + + +
+
+ +

This lesson teaches you to

+
    +
  1. Request Camera Permission
  2. +
  3. Record a Video with a Camera App +
  4. View the Video
  5. +
+ +

You should also read

+ + +

Try it out

+ +
+ Download the +sample +

PhotoIntentActivity.zip

+
+
+
+ + +

This lesson explains how to capture video using existing camera +applications.

+ +

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.

+ + + +

Request Camera Permission

+ +

To advertise that your application depends on having a camera, put a +{@code <uses-feature>} tag in the manifest file:

+ +
+<manifest ... >
+    <uses-feature android:name="android.hardware.camera" />
+    ...
+</manifest ... >
+
+ +

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.

+ + +

Record a Video with a Camera App

+ +

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.

+ +

Here's a function that invokes an intent to capture video.

+ +
+private void dispatchTakeVideoIntent() {
+    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
+    startActivityForResult(takeVideoIntent, ACTION_TAKE_VIDEO);
+}
+
+ + +

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:

+ +
+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;
+}
+
+ + +

View the Video

+ +

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}.

+ +
+private void handleCameraVideo(Intent intent) {
+    mVideoUri = intent.getData();
+    mVideoView.setVideoURI(mVideoUri);
+}
+
+