• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&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, 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&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
260