blob: 35f0028b8cc219889fb055118271028bd26fb49c [file] [log] [blame]
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
Owen Lin101d5282009-04-03 16:20:08 -070019import com.android.camera.gallery.IImage;
20
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080021import android.app.Activity;
22import android.app.AlertDialog;
23import android.content.ActivityNotFoundException;
Owen Lin6795ff12009-06-09 13:39:00 -070024import android.content.Context;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080025import android.content.DialogInterface;
26import android.content.Intent;
Ray Chen0f0af522009-04-22 13:26:07 +080027import android.location.Address;
28import android.location.Geocoder;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080029import android.media.MediaMetadataRetriever;
30import android.net.Uri;
31import android.os.Environment;
32import android.os.Handler;
33import android.os.StatFs;
34import android.provider.MediaStore;
35import android.provider.MediaStore.Images;
Owen Lin937fc482009-04-14 02:02:51 -070036import android.text.format.Formatter;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080037import android.util.Log;
38import android.view.Menu;
39import android.view.MenuItem;
40import android.view.SubMenu;
41import android.view.View;
Owen Lin059daa32009-05-18 15:31:17 -070042import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080043import android.widget.ImageView;
44import android.widget.TextView;
45import android.widget.Toast;
46
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070047import java.io.Closeable;
Ray Chen0f0af522009-04-22 13:26:07 +080048import java.io.IOException;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070049import java.text.SimpleDateFormat;
50import java.util.ArrayList;
51import java.util.Date;
Ray Chend5142de2009-05-07 15:24:48 +080052import java.util.HashMap;
Ray Chen0f0af522009-04-22 13:26:07 +080053import java.util.List;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080054
Ray Chend5142de2009-05-07 15:24:48 +080055/**
56 * A utility class to handle various kinds of menu operations.
57 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080058public class MenuHelper {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070059 private static final String TAG = "MenuHelper";
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080060
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070061 public static final int GENERIC_ITEM = 1;
62 public static final int IMAGE_SAVING_ITEM = 2;
63 public static final int VIDEO_SAVING_ITEM = 3;
64 public static final int IMAGE_MODE_ITEM = 4;
65 public static final int VIDEO_MODE_ITEM = 5;
66 public static final int MENU_ITEM_MAX = 5;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080067
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070068 public static final int INCLUDE_ALL = 0xFFFFFFFF;
69 public static final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
70 public static final int INCLUDE_SHARE_MENU = (1 << 1);
71 public static final int INCLUDE_SET_MENU = (1 << 2);
72 public static final int INCLUDE_CROP_MENU = (1 << 3);
73 public static final int INCLUDE_DELETE_MENU = (1 << 4);
74 public static final int INCLUDE_ROTATE_MENU = (1 << 5);
75 public static final int INCLUDE_DETAILS_MENU = (1 << 6);
Ray Chen0a5a78c2009-04-24 14:13:01 +080076 public static final int INCLUDE_SHOWMAP_MENU = (1 << 7);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080077
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070078 public static final int MENU_SWITCH_CAMERA_MODE = 0;
79 public static final int MENU_CAPTURE_PICTURE = 1;
80 public static final int MENU_CAPTURE_VIDEO = 2;
81 public static final int MENU_IMAGE_SHARE = 10;
82 public static final int MENU_IMAGE_SET = 14;
83 public static final int MENU_IMAGE_SET_WALLPAPER = 15;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070084 public static final int MENU_IMAGE_CROP = 18;
85 public static final int MENU_IMAGE_ROTATE = 19;
86 public static final int MENU_IMAGE_ROTATE_LEFT = 20;
87 public static final int MENU_IMAGE_ROTATE_RIGHT = 21;
88 public static final int MENU_IMAGE_TOSS = 22;
89 public static final int MENU_VIDEO_PLAY = 23;
90 public static final int MENU_VIDEO_SHARE = 24;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080091
92 public static final int NO_STORAGE_ERROR = -1;
93 public static final int CANNOT_STAT_ERROR = -2;
Ray Chen0f0af522009-04-22 13:26:07 +080094 public static final String EMPTY_STRING = "";
Ray Chend5142de2009-05-07 15:24:48 +080095 public static final String JPEG_MIME_TYPE = "image/jpeg";
Ray Chen0a5a78c2009-04-24 14:13:01 +080096 // valid range is -180f to +180f
97 public static final float INVALID_LATLNG = 255f;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080098
99 /** Activity result code used to report crop results.
100 */
101 public static final int RESULT_COMMON_MENU_CROP = 490;
102
103 public interface MenuItemsResult {
Owen Lin101d5282009-04-03 16:20:08 -0700104 public void gettingReadyToOpen(Menu menu, IImage image);
105 public void aboutToCall(MenuItem item, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800106 }
107
108 public interface MenuInvoker {
109 public void run(MenuCallback r);
110 }
111
112 public interface MenuCallback {
Owen Lin101d5282009-04-03 16:20:08 -0700113 public void run(Uri uri, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800114 }
115
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700116 public static void closeSilently(Closeable c) {
117 if (c != null) {
118 try {
119 c.close();
120 } catch (Throwable e) {
121 // ignore
122 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800123 }
124 }
125
Owen Lin101d5282009-04-03 16:20:08 -0700126 public static long getImageFileSize(IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800127 java.io.InputStream data = image.fullSizeImageData();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800128 if (data == null) return -1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800129 try {
130 return data.available();
131 } catch (java.io.IOException ex) {
132 return -1;
133 } finally {
134 closeSilently(data);
135 }
136 }
137
Chih-Chung Chang47bf4ce2009-03-25 01:51:03 -0700138 // This is a hack before we find a solution to pass a permission to other
139 // applications. See bug #1735149.
140 // Checks if the URI starts with "content://mms".
141 public static boolean isMMSUri(Uri uri) {
142 return (uri != null) &&
143 uri.getScheme().equals("content") &&
144 uri.getAuthority().equals("mms");
145 }
Owen Lin937fc482009-04-14 02:02:51 -0700146
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700147 public static void enableShareMenuItem(Menu menu, boolean enabled) {
148 MenuItem item = menu.findItem(MENU_IMAGE_SHARE);
149 if (item != null) {
150 item.setVisible(enabled);
151 item.setEnabled(enabled);
152 }
153 }
154
Ray Chen0f0af522009-04-22 13:26:07 +0800155 private static void setDetailsValue(View d, String text, int valueId) {
156 ((TextView) d.findViewById(valueId)).setText(text);
157 }
158
159 private static void hideDetailsRow(View d, int rowId) {
160 d.findViewById(rowId).setVisibility(View.GONE);
161 }
162
Ray Chend5142de2009-05-07 15:24:48 +0800163 private static float[] getLatLng(HashMap<String, String> exifData) {
164 if (exifData == null) {
165 return null;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800166 }
167
Ray Chend5142de2009-05-07 15:24:48 +0800168 String latValue = exifData.get(ExifInterface.TAG_GPS_LATITUDE);
169 String latRef = exifData.get(ExifInterface.TAG_GPS_LATITUDE_REF);
170 String lngValue = exifData.get(ExifInterface.TAG_GPS_LONGITUDE);
171 String lngRef = exifData.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
172 float[] latlng = null;
173
174 if (latValue != null && latRef != null
175 && lngValue != null && lngRef != null) {
176 latlng = new float[2];
177 latlng[0] = ExifInterface.convertRationalLatLonToFloat(
178 latValue, latRef);
179 latlng[1] = ExifInterface.convertRationalLatLonToFloat(
180 lngValue, lngRef);
Ray Chen0f0af522009-04-22 13:26:07 +0800181 }
Ray Chend5142de2009-05-07 15:24:48 +0800182
183 return latlng;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800184 }
185
Ray Chend5142de2009-05-07 15:24:48 +0800186 private static void setLatLngDetails(View d, Activity context,
187 HashMap<String, String> exifData) {
188 float[] latlng = getLatLng(exifData);
189 if (latlng != null) {
190 setDetailsValue(d, String.valueOf(latlng[0]),
191 R.id.details_latitude_value);
192 setDetailsValue(d, String.valueOf(latlng[1]),
193 R.id.details_longitude_value);
194 setReverseGeocodingDetails(d, context, latlng[0], latlng[1]);
195 } else {
196 hideDetailsRow(d, R.id.details_latitude_row);
197 hideDetailsRow(d, R.id.details_longitude_row);
198 hideDetailsRow(d, R.id.details_location_row);
Ray Chen0f0af522009-04-22 13:26:07 +0800199 }
Ray Chen0f0af522009-04-22 13:26:07 +0800200 }
201
202 private static void setReverseGeocodingDetails(View d, Activity context,
203 float lat, float lng) {
204 // Fill in reverse-geocoded address
205 String value = EMPTY_STRING;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800206 if (lat == INVALID_LATLNG || lng == INVALID_LATLNG) {
207 hideDetailsRow(d, R.id.details_location_row);
208 return;
209 }
210
Ray Chen0f0af522009-04-22 13:26:07 +0800211 try {
212 Geocoder geocoder = new Geocoder(context);
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800213 List<Address> address = geocoder.getFromLocation(lat, lng, 1);
214 StringBuilder sb = new StringBuilder();
215 for (Address addr : address) {
216 int index = addr.getMaxAddressLineIndex();
217 sb.append(addr.getAddressLine(index));
Ray Chen0f0af522009-04-22 13:26:07 +0800218 }
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800219 value = sb.toString();
Ray Chen0f0af522009-04-22 13:26:07 +0800220 } catch (IOException ex) {
221 // Ignore this exception.
222 value = EMPTY_STRING;
223 Log.e(TAG, "Geocoder exception: ", ex);
224 } catch (RuntimeException ex) {
225 // Ignore this exception.
226 value = EMPTY_STRING;
227 Log.e(TAG, "Geocoder exception: ", ex);
228 }
229 if (value != EMPTY_STRING) {
230 setDetailsValue(d, value, R.id.details_location_value);
231 } else {
232 hideDetailsRow(d, R.id.details_location_row);
233 }
234 }
235
Ray Chend5142de2009-05-07 15:24:48 +0800236 private static HashMap<String, String> getExifData(IImage image) {
237 if (!JPEG_MIME_TYPE.equals(image.getMimeType())) {
238 return null;
239 }
240
241 ExifInterface exif = new ExifInterface(image.getDataPath());
242 HashMap<String, String> exifData = null;
243 if (exif != null) {
244 exifData = exif.getAttributes();
245 }
246 return exifData;
247 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800248 // Called when "Show on Maps" is clicked.
249 // Displays image location on Google Maps for further operations.
250 private static boolean onShowMapClicked(MenuInvoker onInvoke,
251 final Handler handler,
252 final Activity activity) {
253 onInvoke.run(new MenuCallback() {
254 public void run(Uri u, IImage image) {
255 if (image == null) {
256 return;
257 }
Ray Chend5142de2009-05-07 15:24:48 +0800258 float[] latlng = getLatLng(getExifData(image));
259 if (latlng == null) {
Ray Chen0a5a78c2009-04-24 14:13:01 +0800260 handler.post(new Runnable() {
261 public void run() {
262 Toast.makeText(activity,
263 R.string.no_location_image,
264 Toast.LENGTH_SHORT).show();
265 }
266 });
267 return;
268 }
269
270 // Can't use geo:latitude,longitude because it only centers
271 // the MapView to specified location, but we need a bubble
272 // for further operations (routing to/from).
273 // The q=(lat, lng) syntax is suggested by geo-team.
274 String uri = "http://maps.google.com/maps?f=q&" +
Ray Chend5142de2009-05-07 15:24:48 +0800275 "q=(" + latlng[0] + "," + latlng[1] + ")";
Ray Chen0a5a78c2009-04-24 14:13:01 +0800276 activity.startActivity(new Intent(
277 android.content.Intent.ACTION_VIEW,
278 Uri.parse(uri)));
279 }
280 });
281 return true;
282 }
283
Ray Chend5142de2009-05-07 15:24:48 +0800284 private static void hideExifInformation(View d) {
285 hideDetailsRow(d, R.id.details_resolution_row);
286 hideDetailsRow(d, R.id.details_make_row);
287 hideDetailsRow(d, R.id.details_model_row);
288 hideDetailsRow(d, R.id.details_whitebalance_row);
289 hideDetailsRow(d, R.id.details_latitude_row);
290 hideDetailsRow(d, R.id.details_longitude_row);
291 hideDetailsRow(d, R.id.details_location_row);
292 }
293
294 private static void showExifInformation(IImage image, View d, Activity activity) {
295 HashMap<String, String> exifData = getExifData(image);
296 if (exifData == null) {
297 hideExifInformation(d);
298 return;
299 }
300
301 String value = exifData.get(ExifInterface.TAG_MAKE);
302 if (value != null) {
303 setDetailsValue(d, value, R.id.details_make_value);
304 } else {
305 hideDetailsRow(d, R.id.details_make_row);
306 }
307
308 value = exifData.get(ExifInterface.TAG_MODEL);
309 if (value != null) {
310 setDetailsValue(d, value, R.id.details_model_value);
311 } else {
312 hideDetailsRow(d, R.id.details_model_row);
313 }
314
315 value = exifData.get(ExifInterface.TAG_WHITE_BALANCE);
316 if (value != null) {
317 value = ExifInterface.whiteBalanceToString(
318 Integer.parseInt(value));
319 }
320 if (value != null && value != EMPTY_STRING) {
321 setDetailsValue(d, value, R.id.details_whitebalance_value);
322 } else {
323 hideDetailsRow(d, R.id.details_whitebalance_row);
324 }
325
326 setLatLngDetails(d, activity, exifData);
327 }
328
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700329 // Called when "Details" is clicked.
330 // Displays detailed information about the image/video.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700331 private static boolean onDetailsClicked(MenuInvoker onInvoke,
Ray Chen0a5a78c2009-04-24 14:13:01 +0800332 final Handler handler,
333 final Activity activity,
334 final boolean isImage) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700335 onInvoke.run(new MenuCallback() {
336 public void run(Uri u, IImage image) {
337 if (image == null) {
338 return;
339 }
340
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800341 final AlertDialog.Builder builder =
342 new AlertDialog.Builder(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700343
344 final View d = View.inflate(activity, R.layout.detailsview,
345 null);
346
347 ImageView imageView = (ImageView) d.findViewById(
348 R.id.details_thumbnail_image);
349 imageView.setImageBitmap(image.miniThumbBitmap());
350
351 TextView textView = (TextView) d.findViewById(
352 R.id.details_image_title);
353 textView.setText(image.getDisplayName());
354
355 long length = getImageFileSize(image);
Owen Lin937fc482009-04-14 02:02:51 -0700356 String lengthString = length < 0
Ray Chen0f0af522009-04-22 13:26:07 +0800357 ? EMPTY_STRING
Owen Lin937fc482009-04-14 02:02:51 -0700358 : Formatter.formatFileSize(activity, length);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700359 ((TextView) d
360 .findViewById(R.id.details_file_size_value))
361 .setText(lengthString);
362
363 int dimensionWidth = 0;
364 int dimensionHeight = 0;
365 if (isImage) {
Ray Chen0f0af522009-04-22 13:26:07 +0800366 // getWidth is much slower than reading from EXIF
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700367 dimensionWidth = image.getWidth();
368 dimensionHeight = image.getHeight();
369 d.findViewById(R.id.details_duration_row)
370 .setVisibility(View.GONE);
371 d.findViewById(R.id.details_frame_rate_row)
372 .setVisibility(View.GONE);
373 d.findViewById(R.id.details_bit_rate_row)
374 .setVisibility(View.GONE);
375 d.findViewById(R.id.details_format_row)
376 .setVisibility(View.GONE);
377 d.findViewById(R.id.details_codec_row)
378 .setVisibility(View.GONE);
379 } else {
380 MediaMetadataRetriever retriever
381 = new MediaMetadataRetriever();
382 try {
383 retriever.setMode(MediaMetadataRetriever
384 .MODE_GET_METADATA_ONLY);
385 retriever.setDataSource(image.getDataPath());
386 try {
387 dimensionWidth = Integer.parseInt(
388 retriever.extractMetadata(
389 MediaMetadataRetriever
390 .METADATA_KEY_VIDEO_WIDTH));
391 dimensionHeight = Integer.parseInt(
392 retriever.extractMetadata(
393 MediaMetadataRetriever
394 .METADATA_KEY_VIDEO_HEIGHT));
395 } catch (NumberFormatException e) {
396 dimensionWidth = 0;
397 dimensionHeight = 0;
398 }
399
400 try {
401 int durationMs = Integer.parseInt(
402 retriever.extractMetadata(
403 MediaMetadataRetriever
404 .METADATA_KEY_DURATION));
405 String durationValue = formatDuration(
406 activity, durationMs);
407 ((TextView) d.findViewById(
408 R.id.details_duration_value))
409 .setText(durationValue);
410 } catch (NumberFormatException e) {
411 d.findViewById(
412 R.id.details_frame_rate_row)
413 .setVisibility(View.GONE);
414 }
415
416 try {
417 String frameRate = String.format(
418 activity.getString(R.string.details_fps),
419 Integer.parseInt(
420 retriever.extractMetadata(
421 MediaMetadataRetriever
422 .METADATA_KEY_FRAME_RATE)));
423 ((TextView) d.findViewById(
424 R.id.details_frame_rate_value))
425 .setText(frameRate);
426 } catch (NumberFormatException e) {
427 d.findViewById(
428 R.id.details_frame_rate_row)
429 .setVisibility(View.GONE);
430 }
431
432 try {
433 long bitRate = Long.parseLong(
434 retriever.extractMetadata(
435 MediaMetadataRetriever
436 .METADATA_KEY_BIT_RATE));
437 String bps;
438 if (bitRate < 1000000) {
439 bps = String.format(
440 activity.getString(
441 R.string.details_kbps),
442 bitRate / 1000);
443 } else {
444 bps = String.format(
445 activity.getString(
446 R.string.details_mbps),
Owen Lin937fc482009-04-14 02:02:51 -0700447 (bitRate) / 1000000.0);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700448 }
449 ((TextView) d.findViewById(
450 R.id.details_bit_rate_value))
451 .setText(bps);
452 } catch (NumberFormatException e) {
453 d.findViewById(R.id.details_bit_rate_row)
454 .setVisibility(View.GONE);
455 }
456
457 String format = retriever.extractMetadata(
458 MediaMetadataRetriever
459 .METADATA_KEY_VIDEO_FORMAT);
460 ((TextView) d.findViewById(
461 R.id.details_format_value))
462 .setText(format);
463
464 String codec = retriever.extractMetadata(
465 MediaMetadataRetriever.METADATA_KEY_CODEC);
Ray Chen0f0af522009-04-22 13:26:07 +0800466 if (codec != null) {
467 setDetailsValue(d, codec, R.id.details_codec_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700468 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800469 hideDetailsRow(d, R.id.details_codec_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700470 }
Ray Chen0f0af522009-04-22 13:26:07 +0800471
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700472 } catch (RuntimeException ex) {
473 // Assume this is a corrupt video file.
474 } finally {
475 try {
476 retriever.release();
477 } catch (RuntimeException ex) {
478 // Ignore failures while cleaning up.
479 }
480 }
481 }
482
Ray Chen0f0af522009-04-22 13:26:07 +0800483 String value = null;
484 if (dimensionWidth > 0 && dimensionHeight > 0) {
485 value = String.format(
486 activity.getString(R.string.details_dimension_x),
487 dimensionWidth, dimensionHeight);
Ray Chen0f0af522009-04-22 13:26:07 +0800488 }
Ray Chend5142de2009-05-07 15:24:48 +0800489
Ray Chen0f0af522009-04-22 13:26:07 +0800490 if (value != null) {
491 setDetailsValue(d, value, R.id.details_resolution_value);
492 } else {
493 hideDetailsRow(d, R.id.details_resolution_row);
494 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700495
Ray Chen0f0af522009-04-22 13:26:07 +0800496 value = EMPTY_STRING;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700497 long dateTaken = image.getDateTaken();
498 if (dateTaken != 0) {
499 Date date = new Date(image.getDateTaken());
500 SimpleDateFormat dateFormat = new SimpleDateFormat();
Ray Chen0f0af522009-04-22 13:26:07 +0800501 value = dateFormat.format(date);
502 }
503 if (value != EMPTY_STRING) {
504 setDetailsValue(d, value, R.id.details_date_taken_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700505 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800506 hideDetailsRow(d, R.id.details_date_taken_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700507 }
508
Ray Chend5142de2009-05-07 15:24:48 +0800509 // Show more EXIF header details for JPEG images.
510 if (JPEG_MIME_TYPE.equals(image.getMimeType())) {
511 showExifInformation(image, d, activity);
512 } else {
513 hideExifInformation(d);
514 }
515
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700516 builder.setNeutralButton(R.string.details_ok,
517 new DialogInterface.OnClickListener() {
518 public void onClick(DialogInterface dialog,
519 int which) {
520 dialog.dismiss();
521 }
522 });
523
Ray Chen993105a2009-04-10 02:11:35 -0700524 handler.post(
525 new Runnable() {
526 public void run() {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800527 builder.setIcon(
528 android.R.drawable.ic_dialog_info)
Ray Chen993105a2009-04-10 02:11:35 -0700529 .setTitle(R.string.details_panel_title)
530 .setView(d)
531 .show();
532 }
533 });
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700534 }
535 });
536 return true;
537 }
538
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700539 // Called when "Rotate left" or "Rotate right" is clicked.
540 private static boolean onRotateClicked(MenuInvoker onInvoke,
541 final int degree) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700542 onInvoke.run(new MenuCallback() {
543 public void run(Uri u, IImage image) {
544 if (image == null || image.isReadonly()) {
545 return;
546 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700547 image.rotateImageBy(degree);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700548 }
549 });
550 return true;
551 }
552
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700553 // Called when "Crop" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700554 private static boolean onCropClicked(MenuInvoker onInvoke,
555 final Activity activity) {
556 onInvoke.run(new MenuCallback() {
557 public void run(Uri u, IImage image) {
558 if (u == null) {
559 return;
560 }
561
562 Intent cropIntent = new Intent();
563 cropIntent.setClass(activity, CropImage.class);
564 cropIntent.setData(u);
565 activity.startActivityForResult(cropIntent,
566 RESULT_COMMON_MENU_CROP);
567 }
568 });
569 return true;
570 }
571
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700572 // Called when "Set as" is clicked.
573 private static boolean onSetAsClicked(MenuInvoker onInvoke,
574 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700575 onInvoke.run(new MenuCallback() {
576 public void run(Uri u, IImage image) {
577 if (u == null || image == null) {
578 return;
579 }
580
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700581 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
582 intent.setDataAndType(u, image.getMimeType());
583 intent.putExtra("mimeType", image.getMimeType());
584 activity.startActivity(Intent.createChooser(intent,
585 activity.getText(R.string.setImage)));
586 }
587 });
588 return true;
589 }
590
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700591 // Called when "Share" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700592 private static boolean onImageShareClicked(MenuInvoker onInvoke,
593 final Activity activity, final boolean isImage) {
594 onInvoke.run(new MenuCallback() {
595 public void run(Uri u, IImage image) {
596 if (image == null) return;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700597
598 Intent intent = new Intent();
599 intent.setAction(Intent.ACTION_SEND);
600 String mimeType = image.getMimeType();
601 intent.setType(mimeType);
602 intent.putExtra(Intent.EXTRA_STREAM, u);
603 boolean isImage = ImageManager.isImageMimeType(mimeType);
604 try {
605 activity.startActivity(Intent.createChooser(intent,
606 activity.getText(isImage
607 ? R.string.sendImage
608 : R.string.sendVideo)));
609 } catch (android.content.ActivityNotFoundException ex) {
610 Toast.makeText(activity, isImage
611 ? R.string.no_way_to_share_image
612 : R.string.no_way_to_share_video,
613 Toast.LENGTH_SHORT).show();
614 }
615 }
616 });
617 return true;
618 }
619
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700620 // Called when "Play" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700621 private static boolean onViewPlayClicked(MenuInvoker onInvoke,
622 final Activity activity) {
623 onInvoke.run(new MenuCallback() {
624 public void run(Uri uri, IImage image) {
625 if (image != null) {
626 Intent intent = new Intent(Intent.ACTION_VIEW,
627 image.fullSizeImageUri());
628 activity.startActivity(intent);
629 }
630 }});
631 return true;
632 }
633
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800634 static MenuItemsResult addImageMenuItems(
635 Menu menu,
636 int inclusions,
637 final boolean isImage,
638 final Activity activity,
Ray Chen993105a2009-04-10 02:11:35 -0700639 final Handler handler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800640 final Runnable onDelete,
641 final MenuInvoker onInvoke) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700642 final ArrayList<MenuItem> requiresWriteAccessItems =
643 new ArrayList<MenuItem>();
644 final ArrayList<MenuItem> requiresNoDrmAccessItems =
645 new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800646
647 if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700648 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
649 MENU_IMAGE_ROTATE, 40, R.string.rotate)
650 .setIcon(android.R.drawable.ic_menu_rotate);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800651 // Don't show the rotate submenu if the item at hand is read only
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700652 // since the items within the submenu won't be shown anyway. This
653 // is really a framework bug in that it shouldn't show the submenu
654 // if the submenu has no visible items.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800655 requiresWriteAccessItems.add(rotateSubmenu.getItem());
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800656 requiresWriteAccessItems.add(
657 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50,
658 R.string.rotate_left)
659 .setOnMenuItemClickListener(
660 new MenuItem.OnMenuItemClickListener() {
661 public boolean onMenuItemClick(MenuItem item) {
662 return onRotateClicked(onInvoke, -90);
663 }
664 }).setAlphabeticShortcut('l'));
665 requiresWriteAccessItems.add(
666 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60,
667 R.string.rotate_right)
668 .setOnMenuItemClickListener(
669 new MenuItem.OnMenuItemClickListener() {
670 public boolean onMenuItemClick(MenuItem item) {
671 return onRotateClicked(onInvoke, 90);
672 }
673 }).setAlphabeticShortcut('r'));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800674 }
675
676 if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
677 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700678 R.string.camera_crop);
679 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
680 autoCrop.setOnMenuItemClickListener(
681 new MenuItem.OnMenuItemClickListener() {
682 public boolean onMenuItemClick(MenuItem item) {
683 return onCropClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800684 }
685 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800686 requiresWriteAccessItems.add(autoCrop);
687 }
688
689 if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700690 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
691 R.string.camera_set);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800692 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700693 setMenu.setOnMenuItemClickListener(
694 new MenuItem.OnMenuItemClickListener() {
695 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700696 return onSetAsClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800697 }
698 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800699 }
700
701 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800702 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
703 R.string.camera_share).setOnMenuItemClickListener(
704 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700705 public boolean onMenuItemClick(MenuItem item) {
706 return onImageShareClicked(onInvoke, activity,
707 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800708 }
709 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800710 item1.setIcon(android.R.drawable.ic_menu_share);
711 MenuItem item = item1;
712 requiresNoDrmAccessItems.add(item);
713 }
714
715 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700716 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
717 70, R.string.camera_toss);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800718 requiresWriteAccessItems.add(deleteItem);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700719 deleteItem.setOnMenuItemClickListener(
720 new MenuItem.OnMenuItemClickListener() {
721 public boolean onMenuItemClick(MenuItem item) {
722 deleteImpl(activity, onDelete, isImage);
723 return true;
724 }
725 })
726 .setAlphabeticShortcut('d')
727 .setIcon(android.R.drawable.ic_menu_delete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800728 }
729
730 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700731 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
732 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800733 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800734 return onDetailsClicked(onInvoke, handler, activity,
735 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800736 }
737 });
738 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
739 }
740
Ray Chen0a5a78c2009-04-24 14:13:01 +0800741 if ((isImage) && ((inclusions & INCLUDE_SHOWMAP_MENU) != 0)) {
742 menu.add(0, 0, 80, R.string.show_on_map)
743 .setOnMenuItemClickListener(
744 new MenuItem.OnMenuItemClickListener() {
745 public boolean onMenuItemClick(MenuItem item) {
746 return onShowMapClicked(onInvoke,
747 handler, activity);
748 }
Ray Chen1e99d7c2009-05-13 13:55:29 +0800749 }).setIcon(R.drawable.ic_menu_3d_globe);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800750 }
751
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800752 if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
753 menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700754 .setOnMenuItemClickListener(
755 new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800756 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700757 return onViewPlayClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800758 }
759 });
760 }
761
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800762 return new MenuItemsResult() {
Owen Lin101d5282009-04-03 16:20:08 -0700763 public void gettingReadyToOpen(Menu menu, IImage image) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700764 // protect against null here. this isn't strictly speaking
765 // required but if a client app isn't handling sdcard removal
766 // properly it could happen
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800767 if (image == null) {
768 return;
769 }
770 boolean readOnly = image.isReadonly();
771 boolean isDrm = image.isDrm();
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800772
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700773 for (MenuItem item : requiresWriteAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700774 item.setVisible(!readOnly);
775 item.setEnabled(!readOnly);
776 }
777 for (MenuItem item : requiresNoDrmAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700778 item.setVisible(!isDrm);
779 item.setEnabled(!isDrm);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800780 }
781 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700782
783 // must override abstract method
Owen Lin101d5282009-04-03 16:20:08 -0700784 public void aboutToCall(MenuItem menu, IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800785 }
786 };
787 }
788
789 static void deletePhoto(Activity activity, Runnable onDelete) {
Ray Chen7638a542009-03-24 20:37:45 -0700790 deleteImpl(activity, onDelete, true);
791 }
Owen Lin095afa12009-03-24 23:41:27 -0700792
Ray Chen7638a542009-03-24 20:37:45 -0700793 static void deleteVideo(Activity activity, Runnable onDelete) {
794 deleteImpl(activity, onDelete, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800795 }
796
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700797 static void deleteImage(Activity activity, Runnable onDelete,
798 IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800799 if (image != null) {
Ray Chen7638a542009-03-24 20:37:45 -0700800 deleteImpl(activity, onDelete, ImageManager.isImage(image));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800801 }
802 }
803
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700804 private static void deleteImpl(Activity activity, final Runnable onDelete,
805 boolean isPhoto) {
806 boolean confirm = android.preference.PreferenceManager
807 .getDefaultSharedPreferences(activity)
808 .getBoolean("pref_gallery_confirm_delete_key", true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800809 if (!confirm) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700810 if (onDelete != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800811 onDelete.run();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700812 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800813 } else {
814 displayDeleteDialog(activity, onDelete, isPhoto);
815 }
816 }
817
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700818 private static void displayDeleteDialog(Activity activity,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800819 final Runnable onDelete, boolean isPhoto) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700820 android.app.AlertDialog.Builder b =
821 new android.app.AlertDialog.Builder(activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800822 b.setIcon(android.R.drawable.ic_dialog_alert);
823 b.setTitle(R.string.confirm_delete_title);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700824 b.setMessage(isPhoto
825 ? R.string.confirm_delete_message
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800826 : R.string.confirm_delete_video_message);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700827 b.setPositiveButton(android.R.string.ok,
828 new android.content.DialogInterface.OnClickListener() {
829 public void onClick(android.content.DialogInterface v,
830 int x) {
831 if (onDelete != null) {
832 onDelete.run();
833 }
834 }
835 });
836 b.setNegativeButton(android.R.string.cancel,
837 new android.content.DialogInterface.OnClickListener() {
838 public void onClick(android.content.DialogInterface v,
839 int x) {
840 }
841 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800842 b.create().show();
843 }
844
845 static void addSwitchModeMenuItem(Menu menu, final Activity activity,
846 final boolean switchToVideo) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700847 int group = switchToVideo
848 ? MenuHelper.IMAGE_MODE_ITEM
849 : MenuHelper.VIDEO_MODE_ITEM;
850 int labelId = switchToVideo
851 ? R.string.switch_to_video_lable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800852 : R.string.switch_to_camera_lable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700853 int iconId = switchToVideo
854 ? R.drawable.ic_menu_camera_video_view
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800855 : android.R.drawable.ic_menu_camera;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700856 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
857 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
858 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700859 return onSwitchModeClicked(activity, switchToVideo);
860 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700861 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800862 item.setIcon(iconId);
863 }
864
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700865 private static boolean onSwitchModeClicked(Activity activity,
866 boolean switchToVideo) {
867 String action = switchToVideo
868 ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
869 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
870 Intent intent = new Intent(action);
871 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
872 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800873
874 // Keep the camera instance for a while.
875 // This avoids re-opening the camera and saves time.
876 CameraHolder.instance().keep();
877
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700878 activity.startActivity(intent);
879 return true;
880 }
881
Owen Lin059daa32009-05-18 15:31:17 -0700882 public static void gotoCameraMode(Activity activity) {
883 onSwitchModeClicked(activity, false);
884 }
885
886 public static void gotoVideoMode(Activity activity) {
887 onSwitchModeClicked(activity, true);
888 }
889
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800890 static void gotoStillImageCapture(Activity activity) {
891 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
892 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
893 try {
894 activity.startActivity(intent);
895 } catch (ActivityNotFoundException e) {
896 Log.e(TAG, "Could not start still image capture activity", e);
897 }
898 }
899
900 static void gotoCameraImageGallery(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700901 gotoGallery(activity, R.string.gallery_camera_bucket_name,
902 ImageManager.INCLUDE_IMAGES);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800903 }
904
905 static void gotoCameraVideoGallery(Activity activity) {
906 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
907 ImageManager.INCLUDE_VIDEOS);
908 }
909
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700910 private static void gotoGallery(Activity activity, int windowTitleId,
911 int mediaTypes) {
912 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
913 .appendQueryParameter("bucketId",
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800914 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
915 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700916 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800917 intent.putExtra("windowTitle", activity.getString(windowTitleId));
918 intent.putExtra("mediaTypes", mediaTypes);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700919
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800920 try {
921 activity.startActivity(intent);
922 } catch (ActivityNotFoundException e) {
923 Log.e(TAG, "Could not start gallery activity", e);
924 }
925 }
926
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700927 static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800928 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700929 .setOnMenuItemClickListener(
930 new MenuItem.OnMenuItemClickListener() {
931 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700932 return onCapturePictureClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700933 }
934 }).setIcon(android.R.drawable.ic_menu_camera);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700935 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800936
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700937 private static boolean onCapturePictureClicked(Activity activity) {
938 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
939 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
940 try {
941 activity.startActivity(intent);
942 } catch (android.content.ActivityNotFoundException e) {
943 // Ignore exception
944 }
945 return true;
946 }
947
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700948 static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800949 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700950 .setOnMenuItemClickListener(
951 new MenuItem.OnMenuItemClickListener() {
952 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700953 return onCaptureVideoClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700954 }
955 }).setIcon(R.drawable.ic_menu_camera_video_view);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800956 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700957
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700958 private static boolean onCaptureVideoClicked(Activity activity) {
959 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
960 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
961 try {
962 activity.startActivity(intent);
963 } catch (android.content.ActivityNotFoundException e) {
964 // Ignore exception
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700965 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700966 return true;
967 }
968
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700969 public static void addCaptureMenuItems(Menu menu, final Activity activity) {
970 addCapturePictureMenuItems(menu, activity);
971 addCaptureVideoMenuItems(menu, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800972 }
973
Owen Lin6795ff12009-06-09 13:39:00 -0700974 public static String formatDuration(final Context context,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700975 int durationMs) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800976 int duration = durationMs / 1000;
977 int h = duration / 3600;
978 int m = (duration - h * 3600) / 60;
979 int s = duration - (h * 3600 + m * 60);
980 String durationValue;
981 if (h == 0) {
982 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -0700983 context.getString(R.string.details_ms), m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800984 } else {
985 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -0700986 context.getString(R.string.details_hms), h, m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800987 }
988 return durationValue;
989 }
990
991 public static void showStorageToast(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700992 showStorageToast(activity, calculatePicturesRemaining());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800993 }
994
995 public static void showStorageToast(Activity activity, int remaining) {
996 String noStorageText = null;
997
998 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
999 String state = Environment.getExternalStorageState();
1000 if (state == Environment.MEDIA_CHECKING) {
1001 noStorageText = activity.getString(R.string.preparing_sd);
1002 } else {
1003 noStorageText = activity.getString(R.string.no_storage);
1004 }
1005 } else if (remaining < 1) {
1006 noStorageText = activity.getString(R.string.not_enough_space);
1007 }
1008
1009 if (noStorageText != null) {
1010 Toast.makeText(activity, noStorageText, 5000).show();
1011 }
1012 }
1013
1014 public static int calculatePicturesRemaining() {
1015 try {
1016 if (!ImageManager.hasStorage()) {
1017 return NO_STORAGE_ERROR;
1018 } else {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001019 String storageDirectory =
1020 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001021 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001022 float remaining = ((float) stat.getAvailableBlocks()
1023 * (float) stat.getBlockSize()) / 400000F;
1024 return (int) remaining;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001025 }
1026 } catch (Exception ex) {
1027 // if we can't stat the filesystem then we don't know how many
1028 // pictures are remaining. it might be zero but just leave it
1029 // blank since we really don't know.
1030 return CANNOT_STAT_ERROR;
1031 }
1032 }
1033}