blob: 9515cbdd9189533e5a00cd879cc973ce220ffa16 [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;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080027import android.content.DialogInterface.OnClickListener;
Ray Chen0f0af522009-04-22 13:26:07 +080028import android.location.Address;
29import android.location.Geocoder;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080030import android.media.MediaMetadataRetriever;
31import android.net.Uri;
32import android.os.Environment;
33import android.os.Handler;
34import android.os.StatFs;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080035import android.preference.PreferenceManager;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080036import android.provider.MediaStore;
37import android.provider.MediaStore.Images;
Owen Lin937fc482009-04-14 02:02:51 -070038import android.text.format.Formatter;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080039import android.util.Log;
40import android.view.Menu;
41import android.view.MenuItem;
42import android.view.SubMenu;
43import android.view.View;
Owen Lin059daa32009-05-18 15:31:17 -070044import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080045import android.widget.ImageView;
46import android.widget.TextView;
47import android.widget.Toast;
48
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070049import java.io.Closeable;
Ray Chen0f0af522009-04-22 13:26:07 +080050import java.io.IOException;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070051import java.text.SimpleDateFormat;
52import java.util.ArrayList;
53import java.util.Date;
Ray Chend5142de2009-05-07 15:24:48 +080054import java.util.HashMap;
Ray Chen0f0af522009-04-22 13:26:07 +080055import java.util.List;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080056
Ray Chend5142de2009-05-07 15:24:48 +080057/**
58 * A utility class to handle various kinds of menu operations.
59 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080060public class MenuHelper {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070061 private static final String TAG = "MenuHelper";
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080062
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070063 public static final int GENERIC_ITEM = 1;
64 public static final int IMAGE_SAVING_ITEM = 2;
65 public static final int VIDEO_SAVING_ITEM = 3;
66 public static final int IMAGE_MODE_ITEM = 4;
67 public static final int VIDEO_MODE_ITEM = 5;
68 public static final int MENU_ITEM_MAX = 5;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080069
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070070 public static final int INCLUDE_ALL = 0xFFFFFFFF;
71 public static final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
72 public static final int INCLUDE_SHARE_MENU = (1 << 1);
73 public static final int INCLUDE_SET_MENU = (1 << 2);
74 public static final int INCLUDE_CROP_MENU = (1 << 3);
75 public static final int INCLUDE_DELETE_MENU = (1 << 4);
76 public static final int INCLUDE_ROTATE_MENU = (1 << 5);
77 public static final int INCLUDE_DETAILS_MENU = (1 << 6);
Ray Chen0a5a78c2009-04-24 14:13:01 +080078 public static final int INCLUDE_SHOWMAP_MENU = (1 << 7);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080079
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070080 public static final int MENU_SWITCH_CAMERA_MODE = 0;
81 public static final int MENU_CAPTURE_PICTURE = 1;
82 public static final int MENU_CAPTURE_VIDEO = 2;
83 public static final int MENU_IMAGE_SHARE = 10;
84 public static final int MENU_IMAGE_SET = 14;
85 public static final int MENU_IMAGE_SET_WALLPAPER = 15;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070086 public static final int MENU_IMAGE_CROP = 18;
87 public static final int MENU_IMAGE_ROTATE = 19;
88 public static final int MENU_IMAGE_ROTATE_LEFT = 20;
89 public static final int MENU_IMAGE_ROTATE_RIGHT = 21;
90 public static final int MENU_IMAGE_TOSS = 22;
91 public static final int MENU_VIDEO_PLAY = 23;
92 public static final int MENU_VIDEO_SHARE = 24;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080093
94 public static final int NO_STORAGE_ERROR = -1;
95 public static final int CANNOT_STAT_ERROR = -2;
Ray Chen0f0af522009-04-22 13:26:07 +080096 public static final String EMPTY_STRING = "";
Ray Chend5142de2009-05-07 15:24:48 +080097 public static final String JPEG_MIME_TYPE = "image/jpeg";
Ray Chen0a5a78c2009-04-24 14:13:01 +080098 // valid range is -180f to +180f
99 public static final float INVALID_LATLNG = 255f;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800100
101 /** Activity result code used to report crop results.
102 */
103 public static final int RESULT_COMMON_MENU_CROP = 490;
104
105 public interface MenuItemsResult {
Owen Lin101d5282009-04-03 16:20:08 -0700106 public void gettingReadyToOpen(Menu menu, IImage image);
107 public void aboutToCall(MenuItem item, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800108 }
109
110 public interface MenuInvoker {
111 public void run(MenuCallback r);
112 }
113
114 public interface MenuCallback {
Owen Lin101d5282009-04-03 16:20:08 -0700115 public void run(Uri uri, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800116 }
117
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700118 public static void closeSilently(Closeable c) {
119 if (c != null) {
120 try {
121 c.close();
122 } catch (Throwable e) {
123 // ignore
124 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800125 }
126 }
127
Owen Lin101d5282009-04-03 16:20:08 -0700128 public static long getImageFileSize(IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800129 java.io.InputStream data = image.fullSizeImageData();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800130 if (data == null) return -1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800131 try {
132 return data.available();
133 } catch (java.io.IOException ex) {
134 return -1;
135 } finally {
136 closeSilently(data);
137 }
138 }
139
Chih-Chung Chang47bf4ce2009-03-25 01:51:03 -0700140 // This is a hack before we find a solution to pass a permission to other
141 // applications. See bug #1735149.
142 // Checks if the URI starts with "content://mms".
143 public static boolean isMMSUri(Uri uri) {
144 return (uri != null) &&
145 uri.getScheme().equals("content") &&
146 uri.getAuthority().equals("mms");
147 }
Owen Lin937fc482009-04-14 02:02:51 -0700148
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700149 public static void enableShareMenuItem(Menu menu, boolean enabled) {
150 MenuItem item = menu.findItem(MENU_IMAGE_SHARE);
151 if (item != null) {
152 item.setVisible(enabled);
153 item.setEnabled(enabled);
154 }
155 }
156
Ray Chen0f0af522009-04-22 13:26:07 +0800157 private static void setDetailsValue(View d, String text, int valueId) {
158 ((TextView) d.findViewById(valueId)).setText(text);
159 }
160
161 private static void hideDetailsRow(View d, int rowId) {
162 d.findViewById(rowId).setVisibility(View.GONE);
163 }
164
Ray Chend5142de2009-05-07 15:24:48 +0800165 private static float[] getLatLng(HashMap<String, String> exifData) {
166 if (exifData == null) {
167 return null;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800168 }
169
Ray Chend5142de2009-05-07 15:24:48 +0800170 String latValue = exifData.get(ExifInterface.TAG_GPS_LATITUDE);
171 String latRef = exifData.get(ExifInterface.TAG_GPS_LATITUDE_REF);
172 String lngValue = exifData.get(ExifInterface.TAG_GPS_LONGITUDE);
173 String lngRef = exifData.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
174 float[] latlng = null;
175
176 if (latValue != null && latRef != null
177 && lngValue != null && lngRef != null) {
178 latlng = new float[2];
179 latlng[0] = ExifInterface.convertRationalLatLonToFloat(
180 latValue, latRef);
181 latlng[1] = ExifInterface.convertRationalLatLonToFloat(
182 lngValue, lngRef);
Ray Chen0f0af522009-04-22 13:26:07 +0800183 }
Ray Chend5142de2009-05-07 15:24:48 +0800184
185 return latlng;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800186 }
187
Ray Chend5142de2009-05-07 15:24:48 +0800188 private static void setLatLngDetails(View d, Activity context,
189 HashMap<String, String> exifData) {
190 float[] latlng = getLatLng(exifData);
191 if (latlng != null) {
192 setDetailsValue(d, String.valueOf(latlng[0]),
193 R.id.details_latitude_value);
194 setDetailsValue(d, String.valueOf(latlng[1]),
195 R.id.details_longitude_value);
196 setReverseGeocodingDetails(d, context, latlng[0], latlng[1]);
197 } else {
198 hideDetailsRow(d, R.id.details_latitude_row);
199 hideDetailsRow(d, R.id.details_longitude_row);
200 hideDetailsRow(d, R.id.details_location_row);
Ray Chen0f0af522009-04-22 13:26:07 +0800201 }
Ray Chen0f0af522009-04-22 13:26:07 +0800202 }
203
204 private static void setReverseGeocodingDetails(View d, Activity context,
205 float lat, float lng) {
206 // Fill in reverse-geocoded address
207 String value = EMPTY_STRING;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800208 if (lat == INVALID_LATLNG || lng == INVALID_LATLNG) {
209 hideDetailsRow(d, R.id.details_location_row);
210 return;
211 }
212
Ray Chen0f0af522009-04-22 13:26:07 +0800213 try {
214 Geocoder geocoder = new Geocoder(context);
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800215 List<Address> address = geocoder.getFromLocation(lat, lng, 1);
216 StringBuilder sb = new StringBuilder();
217 for (Address addr : address) {
218 int index = addr.getMaxAddressLineIndex();
219 sb.append(addr.getAddressLine(index));
Ray Chen0f0af522009-04-22 13:26:07 +0800220 }
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800221 value = sb.toString();
Ray Chen0f0af522009-04-22 13:26:07 +0800222 } catch (IOException ex) {
223 // Ignore this exception.
224 value = EMPTY_STRING;
225 Log.e(TAG, "Geocoder exception: ", ex);
226 } catch (RuntimeException ex) {
227 // Ignore this exception.
228 value = EMPTY_STRING;
229 Log.e(TAG, "Geocoder exception: ", ex);
230 }
231 if (value != EMPTY_STRING) {
232 setDetailsValue(d, value, R.id.details_location_value);
233 } else {
234 hideDetailsRow(d, R.id.details_location_row);
235 }
236 }
237
Ray Chend5142de2009-05-07 15:24:48 +0800238 private static HashMap<String, String> getExifData(IImage image) {
239 if (!JPEG_MIME_TYPE.equals(image.getMimeType())) {
240 return null;
241 }
242
243 ExifInterface exif = new ExifInterface(image.getDataPath());
244 HashMap<String, String> exifData = null;
245 if (exif != null) {
246 exifData = exif.getAttributes();
247 }
248 return exifData;
249 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800250 // Called when "Show on Maps" is clicked.
251 // Displays image location on Google Maps for further operations.
252 private static boolean onShowMapClicked(MenuInvoker onInvoke,
253 final Handler handler,
254 final Activity activity) {
255 onInvoke.run(new MenuCallback() {
256 public void run(Uri u, IImage image) {
257 if (image == null) {
258 return;
259 }
Ray Chend5142de2009-05-07 15:24:48 +0800260 float[] latlng = getLatLng(getExifData(image));
261 if (latlng == null) {
Ray Chen0a5a78c2009-04-24 14:13:01 +0800262 handler.post(new Runnable() {
263 public void run() {
264 Toast.makeText(activity,
265 R.string.no_location_image,
266 Toast.LENGTH_SHORT).show();
267 }
268 });
269 return;
270 }
271
272 // Can't use geo:latitude,longitude because it only centers
273 // the MapView to specified location, but we need a bubble
274 // for further operations (routing to/from).
275 // The q=(lat, lng) syntax is suggested by geo-team.
276 String uri = "http://maps.google.com/maps?f=q&" +
Ray Chend5142de2009-05-07 15:24:48 +0800277 "q=(" + latlng[0] + "," + latlng[1] + ")";
Ray Chen0a5a78c2009-04-24 14:13:01 +0800278 activity.startActivity(new Intent(
279 android.content.Intent.ACTION_VIEW,
280 Uri.parse(uri)));
281 }
282 });
283 return true;
284 }
285
Ray Chend5142de2009-05-07 15:24:48 +0800286 private static void hideExifInformation(View d) {
287 hideDetailsRow(d, R.id.details_resolution_row);
288 hideDetailsRow(d, R.id.details_make_row);
289 hideDetailsRow(d, R.id.details_model_row);
290 hideDetailsRow(d, R.id.details_whitebalance_row);
291 hideDetailsRow(d, R.id.details_latitude_row);
292 hideDetailsRow(d, R.id.details_longitude_row);
293 hideDetailsRow(d, R.id.details_location_row);
294 }
295
296 private static void showExifInformation(IImage image, View d, Activity activity) {
297 HashMap<String, String> exifData = getExifData(image);
298 if (exifData == null) {
299 hideExifInformation(d);
300 return;
301 }
302
303 String value = exifData.get(ExifInterface.TAG_MAKE);
304 if (value != null) {
305 setDetailsValue(d, value, R.id.details_make_value);
306 } else {
307 hideDetailsRow(d, R.id.details_make_row);
308 }
309
310 value = exifData.get(ExifInterface.TAG_MODEL);
311 if (value != null) {
312 setDetailsValue(d, value, R.id.details_model_value);
313 } else {
314 hideDetailsRow(d, R.id.details_model_row);
315 }
316
317 value = exifData.get(ExifInterface.TAG_WHITE_BALANCE);
318 if (value != null) {
319 value = ExifInterface.whiteBalanceToString(
320 Integer.parseInt(value));
321 }
322 if (value != null && value != EMPTY_STRING) {
323 setDetailsValue(d, value, R.id.details_whitebalance_value);
324 } else {
325 hideDetailsRow(d, R.id.details_whitebalance_row);
326 }
327
328 setLatLngDetails(d, activity, exifData);
329 }
330
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700331 // Called when "Details" is clicked.
332 // Displays detailed information about the image/video.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700333 private static boolean onDetailsClicked(MenuInvoker onInvoke,
Ray Chen0a5a78c2009-04-24 14:13:01 +0800334 final Handler handler,
335 final Activity activity,
336 final boolean isImage) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700337 onInvoke.run(new MenuCallback() {
338 public void run(Uri u, IImage image) {
339 if (image == null) {
340 return;
341 }
342
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800343 final AlertDialog.Builder builder =
344 new AlertDialog.Builder(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700345
346 final View d = View.inflate(activity, R.layout.detailsview,
347 null);
348
349 ImageView imageView = (ImageView) d.findViewById(
350 R.id.details_thumbnail_image);
351 imageView.setImageBitmap(image.miniThumbBitmap());
352
353 TextView textView = (TextView) d.findViewById(
354 R.id.details_image_title);
355 textView.setText(image.getDisplayName());
356
357 long length = getImageFileSize(image);
Owen Lin937fc482009-04-14 02:02:51 -0700358 String lengthString = length < 0
Ray Chen0f0af522009-04-22 13:26:07 +0800359 ? EMPTY_STRING
Owen Lin937fc482009-04-14 02:02:51 -0700360 : Formatter.formatFileSize(activity, length);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700361 ((TextView) d
362 .findViewById(R.id.details_file_size_value))
363 .setText(lengthString);
364
365 int dimensionWidth = 0;
366 int dimensionHeight = 0;
367 if (isImage) {
Ray Chen0f0af522009-04-22 13:26:07 +0800368 // getWidth is much slower than reading from EXIF
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700369 dimensionWidth = image.getWidth();
370 dimensionHeight = image.getHeight();
371 d.findViewById(R.id.details_duration_row)
372 .setVisibility(View.GONE);
373 d.findViewById(R.id.details_frame_rate_row)
374 .setVisibility(View.GONE);
375 d.findViewById(R.id.details_bit_rate_row)
376 .setVisibility(View.GONE);
377 d.findViewById(R.id.details_format_row)
378 .setVisibility(View.GONE);
379 d.findViewById(R.id.details_codec_row)
380 .setVisibility(View.GONE);
381 } else {
382 MediaMetadataRetriever retriever
383 = new MediaMetadataRetriever();
384 try {
385 retriever.setMode(MediaMetadataRetriever
386 .MODE_GET_METADATA_ONLY);
387 retriever.setDataSource(image.getDataPath());
388 try {
389 dimensionWidth = Integer.parseInt(
390 retriever.extractMetadata(
391 MediaMetadataRetriever
392 .METADATA_KEY_VIDEO_WIDTH));
393 dimensionHeight = Integer.parseInt(
394 retriever.extractMetadata(
395 MediaMetadataRetriever
396 .METADATA_KEY_VIDEO_HEIGHT));
397 } catch (NumberFormatException e) {
398 dimensionWidth = 0;
399 dimensionHeight = 0;
400 }
401
402 try {
403 int durationMs = Integer.parseInt(
404 retriever.extractMetadata(
405 MediaMetadataRetriever
406 .METADATA_KEY_DURATION));
407 String durationValue = formatDuration(
408 activity, durationMs);
409 ((TextView) d.findViewById(
410 R.id.details_duration_value))
411 .setText(durationValue);
412 } catch (NumberFormatException e) {
413 d.findViewById(
414 R.id.details_frame_rate_row)
415 .setVisibility(View.GONE);
416 }
417
418 try {
419 String frameRate = String.format(
420 activity.getString(R.string.details_fps),
421 Integer.parseInt(
422 retriever.extractMetadata(
423 MediaMetadataRetriever
424 .METADATA_KEY_FRAME_RATE)));
425 ((TextView) d.findViewById(
426 R.id.details_frame_rate_value))
427 .setText(frameRate);
428 } catch (NumberFormatException e) {
429 d.findViewById(
430 R.id.details_frame_rate_row)
431 .setVisibility(View.GONE);
432 }
433
434 try {
435 long bitRate = Long.parseLong(
436 retriever.extractMetadata(
437 MediaMetadataRetriever
438 .METADATA_KEY_BIT_RATE));
439 String bps;
440 if (bitRate < 1000000) {
441 bps = String.format(
442 activity.getString(
443 R.string.details_kbps),
444 bitRate / 1000);
445 } else {
446 bps = String.format(
447 activity.getString(
448 R.string.details_mbps),
Owen Lin937fc482009-04-14 02:02:51 -0700449 (bitRate) / 1000000.0);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700450 }
451 ((TextView) d.findViewById(
452 R.id.details_bit_rate_value))
453 .setText(bps);
454 } catch (NumberFormatException e) {
455 d.findViewById(R.id.details_bit_rate_row)
456 .setVisibility(View.GONE);
457 }
458
459 String format = retriever.extractMetadata(
460 MediaMetadataRetriever
461 .METADATA_KEY_VIDEO_FORMAT);
462 ((TextView) d.findViewById(
463 R.id.details_format_value))
464 .setText(format);
465
466 String codec = retriever.extractMetadata(
467 MediaMetadataRetriever.METADATA_KEY_CODEC);
Ray Chen0f0af522009-04-22 13:26:07 +0800468 if (codec != null) {
469 setDetailsValue(d, codec, R.id.details_codec_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700470 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800471 hideDetailsRow(d, R.id.details_codec_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700472 }
Ray Chen0f0af522009-04-22 13:26:07 +0800473
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700474 } catch (RuntimeException ex) {
475 // Assume this is a corrupt video file.
476 } finally {
477 try {
478 retriever.release();
479 } catch (RuntimeException ex) {
480 // Ignore failures while cleaning up.
481 }
482 }
483 }
484
Ray Chen0f0af522009-04-22 13:26:07 +0800485 String value = null;
486 if (dimensionWidth > 0 && dimensionHeight > 0) {
487 value = String.format(
488 activity.getString(R.string.details_dimension_x),
489 dimensionWidth, dimensionHeight);
Ray Chen0f0af522009-04-22 13:26:07 +0800490 }
Ray Chend5142de2009-05-07 15:24:48 +0800491
Ray Chen0f0af522009-04-22 13:26:07 +0800492 if (value != null) {
493 setDetailsValue(d, value, R.id.details_resolution_value);
494 } else {
495 hideDetailsRow(d, R.id.details_resolution_row);
496 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700497
Ray Chen0f0af522009-04-22 13:26:07 +0800498 value = EMPTY_STRING;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700499 long dateTaken = image.getDateTaken();
500 if (dateTaken != 0) {
501 Date date = new Date(image.getDateTaken());
502 SimpleDateFormat dateFormat = new SimpleDateFormat();
Ray Chen0f0af522009-04-22 13:26:07 +0800503 value = dateFormat.format(date);
504 }
505 if (value != EMPTY_STRING) {
506 setDetailsValue(d, value, R.id.details_date_taken_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700507 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800508 hideDetailsRow(d, R.id.details_date_taken_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700509 }
510
Ray Chend5142de2009-05-07 15:24:48 +0800511 // Show more EXIF header details for JPEG images.
512 if (JPEG_MIME_TYPE.equals(image.getMimeType())) {
513 showExifInformation(image, d, activity);
514 } else {
515 hideExifInformation(d);
516 }
517
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700518 builder.setNeutralButton(R.string.details_ok,
519 new DialogInterface.OnClickListener() {
520 public void onClick(DialogInterface dialog,
521 int which) {
522 dialog.dismiss();
523 }
524 });
525
Ray Chen993105a2009-04-10 02:11:35 -0700526 handler.post(
527 new Runnable() {
528 public void run() {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800529 builder.setIcon(
530 android.R.drawable.ic_dialog_info)
Ray Chen993105a2009-04-10 02:11:35 -0700531 .setTitle(R.string.details_panel_title)
532 .setView(d)
533 .show();
534 }
535 });
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700536 }
537 });
538 return true;
539 }
540
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700541 // Called when "Rotate left" or "Rotate right" is clicked.
542 private static boolean onRotateClicked(MenuInvoker onInvoke,
543 final int degree) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700544 onInvoke.run(new MenuCallback() {
545 public void run(Uri u, IImage image) {
546 if (image == null || image.isReadonly()) {
547 return;
548 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700549 image.rotateImageBy(degree);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700550 }
551 });
552 return true;
553 }
554
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700555 // Called when "Crop" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700556 private static boolean onCropClicked(MenuInvoker onInvoke,
557 final Activity activity) {
558 onInvoke.run(new MenuCallback() {
559 public void run(Uri u, IImage image) {
560 if (u == null) {
561 return;
562 }
563
564 Intent cropIntent = new Intent();
565 cropIntent.setClass(activity, CropImage.class);
566 cropIntent.setData(u);
567 activity.startActivityForResult(cropIntent,
568 RESULT_COMMON_MENU_CROP);
569 }
570 });
571 return true;
572 }
573
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700574 // Called when "Set as" is clicked.
575 private static boolean onSetAsClicked(MenuInvoker onInvoke,
576 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700577 onInvoke.run(new MenuCallback() {
578 public void run(Uri u, IImage image) {
579 if (u == null || image == null) {
580 return;
581 }
582
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700583 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
584 intent.setDataAndType(u, image.getMimeType());
585 intent.putExtra("mimeType", image.getMimeType());
586 activity.startActivity(Intent.createChooser(intent,
587 activity.getText(R.string.setImage)));
588 }
589 });
590 return true;
591 }
592
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700593 // Called when "Share" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700594 private static boolean onImageShareClicked(MenuInvoker onInvoke,
595 final Activity activity, final boolean isImage) {
596 onInvoke.run(new MenuCallback() {
597 public void run(Uri u, IImage image) {
598 if (image == null) return;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700599
600 Intent intent = new Intent();
601 intent.setAction(Intent.ACTION_SEND);
602 String mimeType = image.getMimeType();
603 intent.setType(mimeType);
604 intent.putExtra(Intent.EXTRA_STREAM, u);
605 boolean isImage = ImageManager.isImageMimeType(mimeType);
606 try {
607 activity.startActivity(Intent.createChooser(intent,
608 activity.getText(isImage
609 ? R.string.sendImage
610 : R.string.sendVideo)));
611 } catch (android.content.ActivityNotFoundException ex) {
612 Toast.makeText(activity, isImage
613 ? R.string.no_way_to_share_image
614 : R.string.no_way_to_share_video,
615 Toast.LENGTH_SHORT).show();
616 }
617 }
618 });
619 return true;
620 }
621
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700622 // Called when "Play" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700623 private static boolean onViewPlayClicked(MenuInvoker onInvoke,
624 final Activity activity) {
625 onInvoke.run(new MenuCallback() {
626 public void run(Uri uri, IImage image) {
627 if (image != null) {
628 Intent intent = new Intent(Intent.ACTION_VIEW,
629 image.fullSizeImageUri());
630 activity.startActivity(intent);
631 }
632 }});
633 return true;
634 }
635
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800636 static MenuItemsResult addImageMenuItems(
637 Menu menu,
638 int inclusions,
639 final boolean isImage,
640 final Activity activity,
Ray Chen993105a2009-04-10 02:11:35 -0700641 final Handler handler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800642 final Runnable onDelete,
643 final MenuInvoker onInvoke) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700644 final ArrayList<MenuItem> requiresWriteAccessItems =
645 new ArrayList<MenuItem>();
646 final ArrayList<MenuItem> requiresNoDrmAccessItems =
647 new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800648
649 if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700650 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
651 MENU_IMAGE_ROTATE, 40, R.string.rotate)
652 .setIcon(android.R.drawable.ic_menu_rotate);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800653 // Don't show the rotate submenu if the item at hand is read only
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700654 // since the items within the submenu won't be shown anyway. This
655 // is really a framework bug in that it shouldn't show the submenu
656 // if the submenu has no visible items.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800657 requiresWriteAccessItems.add(rotateSubmenu.getItem());
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800658 requiresWriteAccessItems.add(
659 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50,
660 R.string.rotate_left)
661 .setOnMenuItemClickListener(
662 new MenuItem.OnMenuItemClickListener() {
663 public boolean onMenuItemClick(MenuItem item) {
664 return onRotateClicked(onInvoke, -90);
665 }
666 }).setAlphabeticShortcut('l'));
667 requiresWriteAccessItems.add(
668 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60,
669 R.string.rotate_right)
670 .setOnMenuItemClickListener(
671 new MenuItem.OnMenuItemClickListener() {
672 public boolean onMenuItemClick(MenuItem item) {
673 return onRotateClicked(onInvoke, 90);
674 }
675 }).setAlphabeticShortcut('r'));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800676 }
677
678 if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
679 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700680 R.string.camera_crop);
681 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
682 autoCrop.setOnMenuItemClickListener(
683 new MenuItem.OnMenuItemClickListener() {
684 public boolean onMenuItemClick(MenuItem item) {
685 return onCropClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800686 }
687 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800688 requiresWriteAccessItems.add(autoCrop);
689 }
690
691 if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700692 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
693 R.string.camera_set);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800694 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700695 setMenu.setOnMenuItemClickListener(
696 new MenuItem.OnMenuItemClickListener() {
697 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700698 return onSetAsClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800699 }
700 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800701 }
702
703 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800704 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
705 R.string.camera_share).setOnMenuItemClickListener(
706 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700707 public boolean onMenuItemClick(MenuItem item) {
708 return onImageShareClicked(onInvoke, activity,
709 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800710 }
711 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800712 item1.setIcon(android.R.drawable.ic_menu_share);
713 MenuItem item = item1;
714 requiresNoDrmAccessItems.add(item);
715 }
716
717 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700718 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
719 70, R.string.camera_toss);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800720 requiresWriteAccessItems.add(deleteItem);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700721 deleteItem.setOnMenuItemClickListener(
722 new MenuItem.OnMenuItemClickListener() {
723 public boolean onMenuItemClick(MenuItem item) {
724 deleteImpl(activity, onDelete, isImage);
725 return true;
726 }
727 })
728 .setAlphabeticShortcut('d')
729 .setIcon(android.R.drawable.ic_menu_delete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800730 }
731
732 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700733 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
734 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800735 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800736 return onDetailsClicked(onInvoke, handler, activity,
737 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800738 }
739 });
740 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
741 }
742
Ray Chen0a5a78c2009-04-24 14:13:01 +0800743 if ((isImage) && ((inclusions & INCLUDE_SHOWMAP_MENU) != 0)) {
744 menu.add(0, 0, 80, R.string.show_on_map)
745 .setOnMenuItemClickListener(
746 new MenuItem.OnMenuItemClickListener() {
747 public boolean onMenuItemClick(MenuItem item) {
748 return onShowMapClicked(onInvoke,
749 handler, activity);
750 }
Ray Chen1e99d7c2009-05-13 13:55:29 +0800751 }).setIcon(R.drawable.ic_menu_3d_globe);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800752 }
753
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800754 if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
755 menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700756 .setOnMenuItemClickListener(
757 new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800758 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700759 return onViewPlayClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800760 }
761 });
762 }
763
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800764 return new MenuItemsResult() {
Owen Lin101d5282009-04-03 16:20:08 -0700765 public void gettingReadyToOpen(Menu menu, IImage image) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700766 // protect against null here. this isn't strictly speaking
767 // required but if a client app isn't handling sdcard removal
768 // properly it could happen
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800769 if (image == null) {
770 return;
771 }
772 boolean readOnly = image.isReadonly();
773 boolean isDrm = image.isDrm();
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800774
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700775 for (MenuItem item : requiresWriteAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700776 item.setVisible(!readOnly);
777 item.setEnabled(!readOnly);
778 }
779 for (MenuItem item : requiresNoDrmAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700780 item.setVisible(!isDrm);
781 item.setEnabled(!isDrm);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800782 }
783 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700784
785 // must override abstract method
Owen Lin101d5282009-04-03 16:20:08 -0700786 public void aboutToCall(MenuItem menu, IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800787 }
788 };
789 }
790
791 static void deletePhoto(Activity activity, Runnable onDelete) {
Ray Chen7638a542009-03-24 20:37:45 -0700792 deleteImpl(activity, onDelete, true);
793 }
Owen Lin095afa12009-03-24 23:41:27 -0700794
Ray Chen7638a542009-03-24 20:37:45 -0700795 static void deleteVideo(Activity activity, Runnable onDelete) {
796 deleteImpl(activity, onDelete, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800797 }
798
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800799 static void deleteImage(
800 Activity activity, Runnable onDelete, IImage image) {
801 deleteImpl(activity, onDelete, ImageManager.isImage(image));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800802 }
803
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800804 static void deleteImpl(
805 Activity activity, Runnable onDelete, boolean isImage) {
806 boolean needConfirm = PreferenceManager
807 .getDefaultSharedPreferences(activity)
808 .getBoolean("pref_gallery_confirm_delete_key", true);
809 if (!needConfirm) {
810 if (onDelete != null) onDelete.run();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800811 } else {
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800812 String title = activity.getString(R.string.confirm_delete_title);
813 String message = activity.getString(isImage
814 ? R.string.confirm_delete_message
815 : R.string.confirm_delete_video_message);
816 confirmAction(activity, title, message, onDelete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800817 }
818 }
819
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800820 public static void deleteMultiple(Context context, Runnable action) {
821 boolean needConfirm = PreferenceManager
822 .getDefaultSharedPreferences(context)
823 .getBoolean("pref_gallery_confirm_delete_key", true);
824 if (!needConfirm) {
825 if (action != null) action.run();
826 } else {
827 String title = context.getString(R.string.confirm_delete_title);
828 String message = context.getString(
829 R.string.confirm_delete_multiple_message);
830 confirmAction(context, title, message, action);
831 }
832 }
833
834 public static void confirmAction(Context context, String title,
835 String message, final Runnable action) {
836 OnClickListener listener = new OnClickListener() {
837 public void onClick(DialogInterface dialog, int which) {
838 switch (which) {
839 case DialogInterface.BUTTON_POSITIVE:
840 if (action != null) action.run();
841 }
842 }
843 };
844 new AlertDialog.Builder(context)
845 .setIcon(android.R.drawable.ic_dialog_alert)
846 .setTitle(title)
847 .setMessage(message)
848 .setPositiveButton(android.R.string.ok, listener)
849 .setNegativeButton(android.R.string.cancel, listener)
850 .create()
851 .show();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800852 }
853
854 static void addSwitchModeMenuItem(Menu menu, final Activity activity,
855 final boolean switchToVideo) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700856 int group = switchToVideo
857 ? MenuHelper.IMAGE_MODE_ITEM
858 : MenuHelper.VIDEO_MODE_ITEM;
859 int labelId = switchToVideo
860 ? R.string.switch_to_video_lable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800861 : R.string.switch_to_camera_lable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700862 int iconId = switchToVideo
863 ? R.drawable.ic_menu_camera_video_view
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800864 : android.R.drawable.ic_menu_camera;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700865 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
866 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
867 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700868 return onSwitchModeClicked(activity, switchToVideo);
869 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700870 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800871 item.setIcon(iconId);
872 }
873
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700874 private static boolean onSwitchModeClicked(Activity activity,
875 boolean switchToVideo) {
876 String action = switchToVideo
877 ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
878 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
879 Intent intent = new Intent(action);
880 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
881 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800882
883 // Keep the camera instance for a while.
884 // This avoids re-opening the camera and saves time.
885 CameraHolder.instance().keep();
886
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700887 activity.startActivity(intent);
888 return true;
889 }
890
Owen Lin059daa32009-05-18 15:31:17 -0700891 public static void gotoCameraMode(Activity activity) {
892 onSwitchModeClicked(activity, false);
893 }
894
895 public static void gotoVideoMode(Activity activity) {
896 onSwitchModeClicked(activity, true);
897 }
898
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800899 static void gotoStillImageCapture(Activity activity) {
900 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
901 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
902 try {
903 activity.startActivity(intent);
904 } catch (ActivityNotFoundException e) {
905 Log.e(TAG, "Could not start still image capture activity", e);
906 }
907 }
908
909 static void gotoCameraImageGallery(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700910 gotoGallery(activity, R.string.gallery_camera_bucket_name,
911 ImageManager.INCLUDE_IMAGES);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800912 }
913
914 static void gotoCameraVideoGallery(Activity activity) {
915 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
916 ImageManager.INCLUDE_VIDEOS);
917 }
918
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700919 private static void gotoGallery(Activity activity, int windowTitleId,
920 int mediaTypes) {
921 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
922 .appendQueryParameter("bucketId",
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800923 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
924 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700925 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800926 intent.putExtra("windowTitle", activity.getString(windowTitleId));
927 intent.putExtra("mediaTypes", mediaTypes);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700928
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800929 try {
930 activity.startActivity(intent);
931 } catch (ActivityNotFoundException e) {
932 Log.e(TAG, "Could not start gallery activity", e);
933 }
934 }
935
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700936 static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800937 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700938 .setOnMenuItemClickListener(
939 new MenuItem.OnMenuItemClickListener() {
940 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700941 return onCapturePictureClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700942 }
943 }).setIcon(android.R.drawable.ic_menu_camera);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700944 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800945
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700946 private static boolean onCapturePictureClicked(Activity activity) {
947 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
948 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
949 try {
950 activity.startActivity(intent);
951 } catch (android.content.ActivityNotFoundException e) {
952 // Ignore exception
953 }
954 return true;
955 }
956
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700957 static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800958 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700959 .setOnMenuItemClickListener(
960 new MenuItem.OnMenuItemClickListener() {
961 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700962 return onCaptureVideoClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700963 }
964 }).setIcon(R.drawable.ic_menu_camera_video_view);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800965 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700966
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700967 private static boolean onCaptureVideoClicked(Activity activity) {
968 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
969 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
970 try {
971 activity.startActivity(intent);
972 } catch (android.content.ActivityNotFoundException e) {
973 // Ignore exception
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700974 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700975 return true;
976 }
977
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700978 public static void addCaptureMenuItems(Menu menu, final Activity activity) {
979 addCapturePictureMenuItems(menu, activity);
980 addCaptureVideoMenuItems(menu, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800981 }
982
Owen Lin6795ff12009-06-09 13:39:00 -0700983 public static String formatDuration(final Context context,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700984 int durationMs) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800985 int duration = durationMs / 1000;
986 int h = duration / 3600;
987 int m = (duration - h * 3600) / 60;
988 int s = duration - (h * 3600 + m * 60);
989 String durationValue;
990 if (h == 0) {
991 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -0700992 context.getString(R.string.details_ms), m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800993 } else {
994 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -0700995 context.getString(R.string.details_hms), h, m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800996 }
997 return durationValue;
998 }
999
1000 public static void showStorageToast(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001001 showStorageToast(activity, calculatePicturesRemaining());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001002 }
1003
1004 public static void showStorageToast(Activity activity, int remaining) {
1005 String noStorageText = null;
1006
1007 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
1008 String state = Environment.getExternalStorageState();
1009 if (state == Environment.MEDIA_CHECKING) {
1010 noStorageText = activity.getString(R.string.preparing_sd);
1011 } else {
1012 noStorageText = activity.getString(R.string.no_storage);
1013 }
1014 } else if (remaining < 1) {
1015 noStorageText = activity.getString(R.string.not_enough_space);
1016 }
1017
1018 if (noStorageText != null) {
1019 Toast.makeText(activity, noStorageText, 5000).show();
1020 }
1021 }
1022
1023 public static int calculatePicturesRemaining() {
1024 try {
1025 if (!ImageManager.hasStorage()) {
1026 return NO_STORAGE_ERROR;
1027 } else {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001028 String storageDirectory =
1029 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001030 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001031 float remaining = ((float) stat.getAvailableBlocks()
1032 * (float) stat.getBlockSize()) / 400000F;
1033 return (int) remaining;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001034 }
1035 } catch (Exception ex) {
1036 // if we can't stat the filesystem then we don't know how many
1037 // pictures are remaining. it might be zero but just leave it
1038 // blank since we really don't know.
1039 return CANNOT_STAT_ERROR;
1040 }
1041 }
1042}