1page.title=Taking Photos Simply 2parent.title=Capturing Photos 3parent.link=index.html 4 5trainingnavtop=true 6next.title=Recording Videos Simply 7next.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/components/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" 35class="button">Download the 36sample</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 44application.</p> 45 46<p>Suppose you are implementing a crowd-sourced weather service that makes a 47global weather map by blending together pictures of the sky taken by devices 48running your client app. Integrating photos is only a small part of your 49application. You want to take photos with minimal fuss, not reinvent the 50camera. Happily, most Android-powered devices already have at least one camera 51application installed. In this lesson, you learn how to make it take a picture 52for 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 58its visibility on Google Play to devices that have a camera. To advertise 59that your application depends on having a camera, put a <a 60href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> {@code 61<uses-feature>}</a> tag in your manifest file:</p> 62 63<pre> 64<manifest ... > 65 <uses-feature android:name="android.hardware.camera" /> 66 ... 67</manifest ... > 68</pre> 69 70<p>If your application uses, but does not require a camera in order to function, add {@code 71android:required="false"} to the tag. In doing so, Google Play will allow devices without a 72camera to download your application. It's then your responsibility to check for the availability 73of the camera at runtime by calling {@link 74android.content.pm.PackageManager#hasSystemFeature hasSystemFeature(PackageManager.FEATURE_CAMERA)}. 75If 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 81android.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}, 83and 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> 88private 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 96make another camera application do its bidding! Of course, if no compatible 97application is ready to catch the intent, then your app will fall down like a 98botched stage dive. Here is a function to check whether an app can handle your intent:</p> 99 100<pre> 101public static boolean isIntentAvailable(Context context, String action) { 102 final PackageManager packageManager = context.getPackageManager(); 103 final Intent intent = new Intent(action); 104 List<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 114ambition, then you probably want to get the image back from the camera 115application and do something with it.</p> 116 117<p>The Android Camera application encodes the photo in the return {@link android.content.Intent} 118delivered to {@link android.app.Activity#onActivityResult onActivityResult()} as a small {@link 119android.graphics.Bitmap} in the extras, under the key {@code "data"}. The following code retrieves 120this image and displays it in an {@link android.widget.ImageView}.</p> 121 122<pre> 123private 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 131icon, but not a lot more. Dealing with a full-sized image takes a bit more 132work.</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 138save into. You must provide a path that includes the storage volume, 139folder, 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) 142and later:</p> 143 144<pre> 145storageDir = 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 154directory yourself.</p> 155 156<pre> 157storageDir = 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 165just {@code Pictures/}, the standard location for shared photos on the external/shared 166storage.</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 172driven by the device environment. What you need to do yourself is choose a 173collision-resistant file-naming scheme. You may wish also to save the path in a 174member variable for later use. Here's an example solution:</p> 175 176<pre> 177private 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 196application via the {@link android.content.Intent}.</p> 197 198<pre> 199File f = createImageFile(); 200takePictureIntent.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 207you said where to save it in the first place. For everyone else, perhaps the easiest way to make 208your 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 211photo to the Media Provider's database, making it available in the Android Gallery application 212and to other apps.</p> 213 214<pre> 215private 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 228you find your application running out of memory after displaying just a few 229images, you can dramatically reduce the amount of dynamic heap used by 230expanding the JPEG into a memory array that's already scaled to match the size 231of the destination view. The following example method demonstrates this 232technique.</p> 233 234<pre> 235private 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