blob: e6ab43e37fd068976b517ca5c153b44d2bb919f8 [file] [log] [blame]
Scott Main564e8aa2011-12-15 15:59:34 -08001page.title=Taking Photos Simply
Scott Main580f0142011-12-15 16:47:26 -08002parent.title=Capturing Photos
Scott Main564e8aa2011-12-15 15:59:34 -08003parent.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/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">
Scott Main580f0142011-12-15 16:47:26 -080034 <a href="http://developer.android.com/shareables/training/PhotoIntentActivity.zip"
35class="button">Download the
Scott Main564e8aa2011-12-15 15:59:34 -080036sample</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 in Android Market 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&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
71android:required="false"} to the tag. In doing so, Android Market 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&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
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