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/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" 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 <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 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<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