Home | History | Annotate | Download | only in camera
      1 page.title=Taking Photos Simply
      2 parent.title=Capturing Photos
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 next.title=Recording Videos Simply
      7 next.link=videobasics.html
      8 
      9 @jd:body
     10 
     11 
     12 <div id="tb-wrapper">
     13   <div id="tb">
     14 
     15     <h2>This lesson teaches you to</h2>
     16     <ol>
     17       <li><a href="#TaskManifest">Request Camera Permission</a></li>
     18       <li><a href="#TaskCaptureIntent">Take a Photo with the Camera App</a></li>
     19       <li><a href="#TaskPhotoView">View the Photo</a></li>
     20       <li><a href="#TaskPath">Save the Photo</a></li>
     21       <li><a href="#TaskGallery">Add the Photo to a Gallery</a></li>
     22       <li><a href="#TaskScalePhoto">Decode a Scaled Image</a></li>
     23     </ol>
     24 
     25     <h2>You should also read</h2>
     26     <ul>
     27       <li><a href="{@docRoot}guide/topics/media/camera.html">Camera</a></li>
     28       <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent 
     29       Filters</a></li>
     30     </ul>
     31 
     32     <h2>Try it out</h2>
     33     <div class="download-box">
     34       <a href="http://developer.android.com/shareables/training/PhotoIntentActivity.zip"
     35 class="button">Download the
     36 sample</a>
     37       <p class="filename">PhotoIntentActivity.zip</p>
     38     </div>
     39 
     40   </div>
     41 </div>
     42 
     43 <p>This lesson explains how to capture photos using an existing camera
     44 application.</p>
     45 
     46 <p>Suppose you are implementing a crowd-sourced weather service that makes a
     47 global weather map by blending together pictures of the sky taken by devices
     48 running your client app. Integrating photos is only a small part of your
     49 application. You want to take photos with minimal fuss, not reinvent the
     50 camera. Happily, most Android-powered devices already have at least one camera
     51 application installed. In this lesson, you learn how to make it take a picture
     52 for you.</p>
     53 
     54 
     55 <h2 id="TaskManifest">Request Camera Permission</h2>
     56 
     57 <p>If an essential function of your application is taking pictures, then restrict
     58 its visibility on Google Play to devices that have a camera.  To advertise
     59 that your application depends on having a camera, put a <a
     60 href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> {@code
     61 &lt;uses-feature&gt;}</a> tag in your manifest file:</p>
     62 
     63 <pre>
     64 &lt;manifest ... >
     65     &lt;uses-feature android:name="android.hardware.camera" /&gt;
     66     ...
     67 &lt;/manifest ... >
     68 </pre>
     69 
     70 <p>If your application uses, but does not require a camera in order to function, add {@code
     71 android:required="false"} to the tag. In doing so, Google Play will allow devices without a
     72 camera to download your application. It's then your responsibility to check for the availability
     73 of the camera at runtime by calling {@link
     74 android.content.pm.PackageManager#hasSystemFeature hasSystemFeature(PackageManager.FEATURE_CAMERA)}.
     75 If a camera is not available, you should then disable your camera features.</p>
     76 
     77 
     78 <h2 id="TaskCaptureIntent">Take a Photo with the Camera App</h2> 
     79 
     80 <p>The Android way of delegating actions to other applications is to invoke an {@link
     81 android.content.Intent} that describes what you want done. This process involves three pieces: The
     82 {@link android.content.Intent} itself, a call to start the external {@link android.app.Activity},
     83 and some code to handle the image data when focus returns to your activity.</p>
     84 
     85 <p>Here's a function that invokes an intent to capture a photo.</p>
     86 
     87 <pre>
     88 private void dispatchTakePictureIntent(int actionCode) {
     89     Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
     90     startActivityForResult(takePictureIntent, actionCode);
     91 }
     92 </pre>
     93 
     94 
     95 <p>Congratulations: with this code, your application has gained the ability to
     96 make another camera application do its bidding! Of course, if no compatible
     97 application is ready to catch the intent, then your app will fall down like a
     98 botched stage dive. Here is a function to check whether an app can handle your intent:</p>
     99 
    100 <pre>
    101 public static boolean isIntentAvailable(Context context, String action) {
    102     final PackageManager packageManager = context.getPackageManager();
    103     final Intent intent = new Intent(action);
    104     List&lt;ResolveInfo> list =
    105             packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    106     return list.size() > 0;
    107 }
    108 </pre>
    109 
    110 
    111 <h2 id="TaskPhotoView">View the Photo</h2>
    112 
    113 <p>If the simple feat of taking a photo is not the culmination of your app's
    114 ambition, then you probably want to get the image back from the camera
    115 application and do something with it.</p>
    116 
    117 <p>The Android Camera application encodes the photo in the return {@link android.content.Intent}
    118 delivered to {@link android.app.Activity#onActivityResult onActivityResult()} as a small {@link
    119 android.graphics.Bitmap} in the extras, under the key {@code "data"}. The following code retrieves
    120 this image and displays it in an {@link android.widget.ImageView}.</p>
    121 
    122 <pre>
    123 private void handleSmallCameraPhoto(Intent intent) {
    124     Bundle extras = intent.getExtras();
    125     mImageBitmap = (Bitmap) extras.get("data");
    126     mImageView.setImageBitmap(mImageBitmap);
    127 }
    128 </pre>
    129 
    130 <p class="note"><strong>Note:</strong> This thumbnail image from {@code "data"} might be good for an
    131 icon, but not a lot more. Dealing with a full-sized image takes a bit more
    132 work.</p>
    133 
    134 
    135 <h2 id="TaskPath">Save the Photo</h2> 
    136 
    137 <p>The Android Camera application saves a full-size photo if you give it a file to
    138 save into. You must provide a path that includes the storage volume,
    139 folder, and file name.</p>
    140 
    141 <p>There is an easy way to get the path for photos, but it works only on Android 2.2 (API level 8)
    142 and later:</p>
    143 
    144 <pre> 
    145 storageDir = new File(
    146     Environment.getExternalStoragePublicDirectory(
    147         Environment.DIRECTORY_PICTURES
    148     ), 
    149     getAlbumName()
    150 );		
    151 </pre> 
    152 
    153 <p>For earlier API levels, you have to provide the name of the photo
    154 directory yourself.</p>
    155 
    156 <pre> 
    157 storageDir = new File (
    158     Environment.getExternalStorageDirectory()
    159         + PICTURES_DIR
    160         + getAlbumName()
    161 );
    162 </pre> 
    163 
    164 <p class="note"><strong>Note:</strong> The path component {@code PICTURES_DIR} is
    165 just {@code Pictures/}, the standard location for shared photos on the external/shared
    166 storage.</p>
    167 
    168 
    169 <h3 id="TaskFileName">Set the file name</h3> 
    170 
    171 <p>As shown in the previous section, the file location for an image should be
    172 driven by the device environment. What you need to do yourself is choose a
    173 collision-resistant file-naming scheme. You may wish also to save the path in a
    174 member variable for later use. Here's an example solution:</p>
    175 
    176 <pre> 
    177 private File createImageFile() throws IOException {
    178     // Create an image file name
    179     String timeStamp = 
    180         new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    181     String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
    182     File image = File.createTempFile(
    183         imageFileName, 
    184         JPEG_FILE_SUFFIX, 
    185         getAlbumDir()
    186     );
    187     mCurrentPhotoPath = image.getAbsolutePath();
    188     return image;
    189 }
    190 </pre> 
    191 
    192 
    193 <h3 id="TaskIntentFileName">Append the file name onto the Intent</h3>
    194 
    195 <p>Once you have a place to save your image, pass that location to the camera
    196 application via the {@link android.content.Intent}.</p>
    197 
    198 <pre>
    199 File f = createImageFile();
    200 takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
    201 </pre>
    202 
    203 
    204 <h2 id="TaskGallery">Add the Photo to a Gallery</h2>
    205 
    206 <p>When you create a photo through an intent, you should know where your image is located, because
    207 you said where to save it in the first place.  For everyone else, perhaps the easiest way to make
    208 your photo accessible is to make it accessible from the system's Media Provider.</p>
    209 
    210 <p>The following example method demonstrates how to invoke the system's media scanner to add your
    211 photo to the Media Provider's database, making it available in the Android Gallery application
    212 and to other apps.</p>
    213 
    214 <pre>
    215 private void galleryAddPic() {
    216     Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    217     File f = new File(mCurrentPhotoPath);
    218     Uri contentUri = Uri.fromFile(f);
    219     mediaScanIntent.setData(contentUri);
    220     this.sendBroadcast(mediaScanIntent);
    221 }
    222 </pre>
    223 
    224 
    225 <h2 id="TaskScalePhoto">Decode a Scaled Image</h2>
    226 
    227 <p>Managing multiple full-sized images can be tricky with limited memory. If
    228 you find your application running out of memory after displaying just a few
    229 images, you can dramatically reduce the amount of dynamic heap used by
    230 expanding the JPEG into a memory array that's already scaled to match the size
    231 of the destination view. The following example method demonstrates this
    232 technique.</p>
    233 
    234 <pre>
    235 private void setPic() {
    236     // Get the dimensions of the View
    237     int targetW = mImageView.getWidth();
    238     int targetH = mImageView.getHeight();
    239   
    240     // Get the dimensions of the bitmap
    241     BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    242     bmOptions.inJustDecodeBounds = true;
    243     BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    244     int photoW = bmOptions.outWidth;
    245     int photoH = bmOptions.outHeight;
    246   
    247     // Determine how much to scale down the image
    248     int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
    249   
    250     // Decode the image file into a Bitmap sized to fill the View
    251     bmOptions.inJustDecodeBounds = false;
    252     bmOptions.inSampleSize = scaleFactor;
    253     bmOptions.inPurgeable = true;
    254   
    255     Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    256     mImageView.setImageBitmap(bitmap);
    257 }
    258 </pre>
    259 
    260