blob: 1a92057783d2aa627a07288e0cc4f6e861b33358 [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;
24import android.content.DialogInterface;
25import android.content.Intent;
Ray Chen0f0af522009-04-22 13:26:07 +080026import android.location.Address;
27import android.location.Geocoder;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080028import android.media.MediaMetadataRetriever;
29import android.net.Uri;
30import android.os.Environment;
31import android.os.Handler;
32import android.os.StatFs;
33import android.provider.MediaStore;
34import android.provider.MediaStore.Images;
Owen Lin937fc482009-04-14 02:02:51 -070035import android.text.format.Formatter;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080036import android.util.Log;
37import android.view.Menu;
38import android.view.MenuItem;
39import android.view.SubMenu;
40import android.view.View;
Owen Lin059daa32009-05-18 15:31:17 -070041import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080042import android.widget.ImageView;
43import android.widget.TextView;
44import android.widget.Toast;
45
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070046import java.io.Closeable;
Ray Chen0f0af522009-04-22 13:26:07 +080047import java.io.IOException;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070048import java.text.SimpleDateFormat;
49import java.util.ArrayList;
50import java.util.Date;
Ray Chend5142de2009-05-07 15:24:48 +080051import java.util.HashMap;
Ray Chen0f0af522009-04-22 13:26:07 +080052import java.util.List;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080053
Ray Chend5142de2009-05-07 15:24:48 +080054/**
55 * A utility class to handle various kinds of menu operations.
56 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080057public class MenuHelper {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070058 private static final String TAG = "MenuHelper";
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080059
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070060 public static final int GENERIC_ITEM = 1;
61 public static final int IMAGE_SAVING_ITEM = 2;
62 public static final int VIDEO_SAVING_ITEM = 3;
63 public static final int IMAGE_MODE_ITEM = 4;
64 public static final int VIDEO_MODE_ITEM = 5;
65 public static final int MENU_ITEM_MAX = 5;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080066
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070067 public static final int INCLUDE_ALL = 0xFFFFFFFF;
68 public static final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
69 public static final int INCLUDE_SHARE_MENU = (1 << 1);
70 public static final int INCLUDE_SET_MENU = (1 << 2);
71 public static final int INCLUDE_CROP_MENU = (1 << 3);
72 public static final int INCLUDE_DELETE_MENU = (1 << 4);
73 public static final int INCLUDE_ROTATE_MENU = (1 << 5);
74 public static final int INCLUDE_DETAILS_MENU = (1 << 6);
Ray Chen0a5a78c2009-04-24 14:13:01 +080075 public static final int INCLUDE_SHOWMAP_MENU = (1 << 7);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080076
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070077 public static final int MENU_SWITCH_CAMERA_MODE = 0;
78 public static final int MENU_CAPTURE_PICTURE = 1;
79 public static final int MENU_CAPTURE_VIDEO = 2;
80 public static final int MENU_IMAGE_SHARE = 10;
81 public static final int MENU_IMAGE_SET = 14;
82 public static final int MENU_IMAGE_SET_WALLPAPER = 15;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070083 public static final int MENU_IMAGE_CROP = 18;
84 public static final int MENU_IMAGE_ROTATE = 19;
85 public static final int MENU_IMAGE_ROTATE_LEFT = 20;
86 public static final int MENU_IMAGE_ROTATE_RIGHT = 21;
87 public static final int MENU_IMAGE_TOSS = 22;
88 public static final int MENU_VIDEO_PLAY = 23;
89 public static final int MENU_VIDEO_SHARE = 24;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080090
91 public static final int NO_STORAGE_ERROR = -1;
92 public static final int CANNOT_STAT_ERROR = -2;
Ray Chen0f0af522009-04-22 13:26:07 +080093 public static final String EMPTY_STRING = "";
Ray Chend5142de2009-05-07 15:24:48 +080094 public static final String JPEG_MIME_TYPE = "image/jpeg";
Ray Chen0a5a78c2009-04-24 14:13:01 +080095 // valid range is -180f to +180f
96 public static final float INVALID_LATLNG = 255f;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080097
98 /** Activity result code used to report crop results.
99 */
100 public static final int RESULT_COMMON_MENU_CROP = 490;
101
102 public interface MenuItemsResult {
Owen Lin101d5282009-04-03 16:20:08 -0700103 public void gettingReadyToOpen(Menu menu, IImage image);
104 public void aboutToCall(MenuItem item, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800105 }
106
107 public interface MenuInvoker {
108 public void run(MenuCallback r);
109 }
110
111 public interface MenuCallback {
Owen Lin101d5282009-04-03 16:20:08 -0700112 public void run(Uri uri, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800113 }
114
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700115 public static void closeSilently(Closeable c) {
116 if (c != null) {
117 try {
118 c.close();
119 } catch (Throwable e) {
120 // ignore
121 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800122 }
123 }
124
Owen Lin101d5282009-04-03 16:20:08 -0700125 public static long getImageFileSize(IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800126 java.io.InputStream data = image.fullSizeImageData();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800127 if (data == null) return -1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800128 try {
129 return data.available();
130 } catch (java.io.IOException ex) {
131 return -1;
132 } finally {
133 closeSilently(data);
134 }
135 }
136
Chih-Chung Chang47bf4ce2009-03-25 01:51:03 -0700137 // This is a hack before we find a solution to pass a permission to other
138 // applications. See bug #1735149.
139 // Checks if the URI starts with "content://mms".
140 public static boolean isMMSUri(Uri uri) {
141 return (uri != null) &&
142 uri.getScheme().equals("content") &&
143 uri.getAuthority().equals("mms");
144 }
Owen Lin937fc482009-04-14 02:02:51 -0700145
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700146 public static void enableShareMenuItem(Menu menu, boolean enabled) {
147 MenuItem item = menu.findItem(MENU_IMAGE_SHARE);
148 if (item != null) {
149 item.setVisible(enabled);
150 item.setEnabled(enabled);
151 }
152 }
153
Ray Chen0f0af522009-04-22 13:26:07 +0800154 private static void setDetailsValue(View d, String text, int valueId) {
155 ((TextView) d.findViewById(valueId)).setText(text);
156 }
157
158 private static void hideDetailsRow(View d, int rowId) {
159 d.findViewById(rowId).setVisibility(View.GONE);
160 }
161
Ray Chend5142de2009-05-07 15:24:48 +0800162 private static float[] getLatLng(HashMap<String, String> exifData) {
163 if (exifData == null) {
164 return null;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800165 }
166
Ray Chend5142de2009-05-07 15:24:48 +0800167 String latValue = exifData.get(ExifInterface.TAG_GPS_LATITUDE);
168 String latRef = exifData.get(ExifInterface.TAG_GPS_LATITUDE_REF);
169 String lngValue = exifData.get(ExifInterface.TAG_GPS_LONGITUDE);
170 String lngRef = exifData.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
171 float[] latlng = null;
172
173 if (latValue != null && latRef != null
174 && lngValue != null && lngRef != null) {
175 latlng = new float[2];
176 latlng[0] = ExifInterface.convertRationalLatLonToFloat(
177 latValue, latRef);
178 latlng[1] = ExifInterface.convertRationalLatLonToFloat(
179 lngValue, lngRef);
Ray Chen0f0af522009-04-22 13:26:07 +0800180 }
Ray Chend5142de2009-05-07 15:24:48 +0800181
182 return latlng;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800183 }
184
Ray Chend5142de2009-05-07 15:24:48 +0800185 private static void setLatLngDetails(View d, Activity context,
186 HashMap<String, String> exifData) {
187 float[] latlng = getLatLng(exifData);
188 if (latlng != null) {
189 setDetailsValue(d, String.valueOf(latlng[0]),
190 R.id.details_latitude_value);
191 setDetailsValue(d, String.valueOf(latlng[1]),
192 R.id.details_longitude_value);
193 setReverseGeocodingDetails(d, context, latlng[0], latlng[1]);
194 } else {
195 hideDetailsRow(d, R.id.details_latitude_row);
196 hideDetailsRow(d, R.id.details_longitude_row);
197 hideDetailsRow(d, R.id.details_location_row);
Ray Chen0f0af522009-04-22 13:26:07 +0800198 }
Ray Chen0f0af522009-04-22 13:26:07 +0800199 }
200
201 private static void setReverseGeocodingDetails(View d, Activity context,
202 float lat, float lng) {
203 // Fill in reverse-geocoded address
204 String value = EMPTY_STRING;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800205 if (lat == INVALID_LATLNG || lng == INVALID_LATLNG) {
206 hideDetailsRow(d, R.id.details_location_row);
207 return;
208 }
209
Ray Chen0f0af522009-04-22 13:26:07 +0800210 try {
211 Geocoder geocoder = new Geocoder(context);
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800212 List<Address> address = geocoder.getFromLocation(lat, lng, 1);
213 StringBuilder sb = new StringBuilder();
214 for (Address addr : address) {
215 int index = addr.getMaxAddressLineIndex();
216 sb.append(addr.getAddressLine(index));
Ray Chen0f0af522009-04-22 13:26:07 +0800217 }
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800218 value = sb.toString();
Ray Chen0f0af522009-04-22 13:26:07 +0800219 } catch (IOException ex) {
220 // Ignore this exception.
221 value = EMPTY_STRING;
222 Log.e(TAG, "Geocoder exception: ", ex);
223 } catch (RuntimeException ex) {
224 // Ignore this exception.
225 value = EMPTY_STRING;
226 Log.e(TAG, "Geocoder exception: ", ex);
227 }
228 if (value != EMPTY_STRING) {
229 setDetailsValue(d, value, R.id.details_location_value);
230 } else {
231 hideDetailsRow(d, R.id.details_location_row);
232 }
233 }
234
Ray Chend5142de2009-05-07 15:24:48 +0800235 private static HashMap<String, String> getExifData(IImage image) {
236 if (!JPEG_MIME_TYPE.equals(image.getMimeType())) {
237 return null;
238 }
239
240 ExifInterface exif = new ExifInterface(image.getDataPath());
241 HashMap<String, String> exifData = null;
242 if (exif != null) {
243 exifData = exif.getAttributes();
244 }
245 return exifData;
246 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800247 // Called when "Show on Maps" is clicked.
248 // Displays image location on Google Maps for further operations.
249 private static boolean onShowMapClicked(MenuInvoker onInvoke,
250 final Handler handler,
251 final Activity activity) {
252 onInvoke.run(new MenuCallback() {
253 public void run(Uri u, IImage image) {
254 if (image == null) {
255 return;
256 }
Ray Chend5142de2009-05-07 15:24:48 +0800257 float[] latlng = getLatLng(getExifData(image));
258 if (latlng == null) {
Ray Chen0a5a78c2009-04-24 14:13:01 +0800259 handler.post(new Runnable() {
260 public void run() {
261 Toast.makeText(activity,
262 R.string.no_location_image,
263 Toast.LENGTH_SHORT).show();
264 }
265 });
266 return;
267 }
268
269 // Can't use geo:latitude,longitude because it only centers
270 // the MapView to specified location, but we need a bubble
271 // for further operations (routing to/from).
272 // The q=(lat, lng) syntax is suggested by geo-team.
273 String uri = "http://maps.google.com/maps?f=q&" +
Ray Chend5142de2009-05-07 15:24:48 +0800274 "q=(" + latlng[0] + "," + latlng[1] + ")";
Ray Chen0a5a78c2009-04-24 14:13:01 +0800275 activity.startActivity(new Intent(
276 android.content.Intent.ACTION_VIEW,
277 Uri.parse(uri)));
278 }
279 });
280 return true;
281 }
282
Ray Chend5142de2009-05-07 15:24:48 +0800283 private static void hideExifInformation(View d) {
284 hideDetailsRow(d, R.id.details_resolution_row);
285 hideDetailsRow(d, R.id.details_make_row);
286 hideDetailsRow(d, R.id.details_model_row);
287 hideDetailsRow(d, R.id.details_whitebalance_row);
288 hideDetailsRow(d, R.id.details_latitude_row);
289 hideDetailsRow(d, R.id.details_longitude_row);
290 hideDetailsRow(d, R.id.details_location_row);
291 }
292
293 private static void showExifInformation(IImage image, View d, Activity activity) {
294 HashMap<String, String> exifData = getExifData(image);
295 if (exifData == null) {
296 hideExifInformation(d);
297 return;
298 }
299
300 String value = exifData.get(ExifInterface.TAG_MAKE);
301 if (value != null) {
302 setDetailsValue(d, value, R.id.details_make_value);
303 } else {
304 hideDetailsRow(d, R.id.details_make_row);
305 }
306
307 value = exifData.get(ExifInterface.TAG_MODEL);
308 if (value != null) {
309 setDetailsValue(d, value, R.id.details_model_value);
310 } else {
311 hideDetailsRow(d, R.id.details_model_row);
312 }
313
314 value = exifData.get(ExifInterface.TAG_WHITE_BALANCE);
315 if (value != null) {
316 value = ExifInterface.whiteBalanceToString(
317 Integer.parseInt(value));
318 }
319 if (value != null && value != EMPTY_STRING) {
320 setDetailsValue(d, value, R.id.details_whitebalance_value);
321 } else {
322 hideDetailsRow(d, R.id.details_whitebalance_row);
323 }
324
325 setLatLngDetails(d, activity, exifData);
326 }
327
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700328 // Called when "Details" is clicked.
329 // Displays detailed information about the image/video.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700330 private static boolean onDetailsClicked(MenuInvoker onInvoke,
Ray Chen0a5a78c2009-04-24 14:13:01 +0800331 final Handler handler,
332 final Activity activity,
333 final boolean isImage) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700334 onInvoke.run(new MenuCallback() {
335 public void run(Uri u, IImage image) {
336 if (image == null) {
337 return;
338 }
339
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800340 final AlertDialog.Builder builder =
341 new AlertDialog.Builder(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700342
343 final View d = View.inflate(activity, R.layout.detailsview,
344 null);
345
346 ImageView imageView = (ImageView) d.findViewById(
347 R.id.details_thumbnail_image);
348 imageView.setImageBitmap(image.miniThumbBitmap());
349
350 TextView textView = (TextView) d.findViewById(
351 R.id.details_image_title);
352 textView.setText(image.getDisplayName());
353
354 long length = getImageFileSize(image);
Owen Lin937fc482009-04-14 02:02:51 -0700355 String lengthString = length < 0
Ray Chen0f0af522009-04-22 13:26:07 +0800356 ? EMPTY_STRING
Owen Lin937fc482009-04-14 02:02:51 -0700357 : Formatter.formatFileSize(activity, length);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700358 ((TextView) d
359 .findViewById(R.id.details_file_size_value))
360 .setText(lengthString);
361
362 int dimensionWidth = 0;
363 int dimensionHeight = 0;
364 if (isImage) {
Ray Chen0f0af522009-04-22 13:26:07 +0800365 // getWidth is much slower than reading from EXIF
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700366 dimensionWidth = image.getWidth();
367 dimensionHeight = image.getHeight();
368 d.findViewById(R.id.details_duration_row)
369 .setVisibility(View.GONE);
370 d.findViewById(R.id.details_frame_rate_row)
371 .setVisibility(View.GONE);
372 d.findViewById(R.id.details_bit_rate_row)
373 .setVisibility(View.GONE);
374 d.findViewById(R.id.details_format_row)
375 .setVisibility(View.GONE);
376 d.findViewById(R.id.details_codec_row)
377 .setVisibility(View.GONE);
378 } else {
379 MediaMetadataRetriever retriever
380 = new MediaMetadataRetriever();
381 try {
382 retriever.setMode(MediaMetadataRetriever
383 .MODE_GET_METADATA_ONLY);
384 retriever.setDataSource(image.getDataPath());
385 try {
386 dimensionWidth = Integer.parseInt(
387 retriever.extractMetadata(
388 MediaMetadataRetriever
389 .METADATA_KEY_VIDEO_WIDTH));
390 dimensionHeight = Integer.parseInt(
391 retriever.extractMetadata(
392 MediaMetadataRetriever
393 .METADATA_KEY_VIDEO_HEIGHT));
394 } catch (NumberFormatException e) {
395 dimensionWidth = 0;
396 dimensionHeight = 0;
397 }
398
399 try {
400 int durationMs = Integer.parseInt(
401 retriever.extractMetadata(
402 MediaMetadataRetriever
403 .METADATA_KEY_DURATION));
404 String durationValue = formatDuration(
405 activity, durationMs);
406 ((TextView) d.findViewById(
407 R.id.details_duration_value))
408 .setText(durationValue);
409 } catch (NumberFormatException e) {
410 d.findViewById(
411 R.id.details_frame_rate_row)
412 .setVisibility(View.GONE);
413 }
414
415 try {
416 String frameRate = String.format(
417 activity.getString(R.string.details_fps),
418 Integer.parseInt(
419 retriever.extractMetadata(
420 MediaMetadataRetriever
421 .METADATA_KEY_FRAME_RATE)));
422 ((TextView) d.findViewById(
423 R.id.details_frame_rate_value))
424 .setText(frameRate);
425 } catch (NumberFormatException e) {
426 d.findViewById(
427 R.id.details_frame_rate_row)
428 .setVisibility(View.GONE);
429 }
430
431 try {
432 long bitRate = Long.parseLong(
433 retriever.extractMetadata(
434 MediaMetadataRetriever
435 .METADATA_KEY_BIT_RATE));
436 String bps;
437 if (bitRate < 1000000) {
438 bps = String.format(
439 activity.getString(
440 R.string.details_kbps),
441 bitRate / 1000);
442 } else {
443 bps = String.format(
444 activity.getString(
445 R.string.details_mbps),
Owen Lin937fc482009-04-14 02:02:51 -0700446 (bitRate) / 1000000.0);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700447 }
448 ((TextView) d.findViewById(
449 R.id.details_bit_rate_value))
450 .setText(bps);
451 } catch (NumberFormatException e) {
452 d.findViewById(R.id.details_bit_rate_row)
453 .setVisibility(View.GONE);
454 }
455
456 String format = retriever.extractMetadata(
457 MediaMetadataRetriever
458 .METADATA_KEY_VIDEO_FORMAT);
459 ((TextView) d.findViewById(
460 R.id.details_format_value))
461 .setText(format);
462
463 String codec = retriever.extractMetadata(
464 MediaMetadataRetriever.METADATA_KEY_CODEC);
Ray Chen0f0af522009-04-22 13:26:07 +0800465 if (codec != null) {
466 setDetailsValue(d, codec, R.id.details_codec_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700467 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800468 hideDetailsRow(d, R.id.details_codec_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700469 }
Ray Chen0f0af522009-04-22 13:26:07 +0800470
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700471 } catch (RuntimeException ex) {
472 // Assume this is a corrupt video file.
473 } finally {
474 try {
475 retriever.release();
476 } catch (RuntimeException ex) {
477 // Ignore failures while cleaning up.
478 }
479 }
480 }
481
Ray Chen0f0af522009-04-22 13:26:07 +0800482 String value = null;
483 if (dimensionWidth > 0 && dimensionHeight > 0) {
484 value = String.format(
485 activity.getString(R.string.details_dimension_x),
486 dimensionWidth, dimensionHeight);
Ray Chen0f0af522009-04-22 13:26:07 +0800487 }
Ray Chend5142de2009-05-07 15:24:48 +0800488
Ray Chen0f0af522009-04-22 13:26:07 +0800489 if (value != null) {
490 setDetailsValue(d, value, R.id.details_resolution_value);
491 } else {
492 hideDetailsRow(d, R.id.details_resolution_row);
493 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700494
Ray Chen0f0af522009-04-22 13:26:07 +0800495 value = EMPTY_STRING;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700496 long dateTaken = image.getDateTaken();
497 if (dateTaken != 0) {
498 Date date = new Date(image.getDateTaken());
499 SimpleDateFormat dateFormat = new SimpleDateFormat();
Ray Chen0f0af522009-04-22 13:26:07 +0800500 value = dateFormat.format(date);
501 }
502 if (value != EMPTY_STRING) {
503 setDetailsValue(d, value, R.id.details_date_taken_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700504 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800505 hideDetailsRow(d, R.id.details_date_taken_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700506 }
507
Ray Chend5142de2009-05-07 15:24:48 +0800508 // Show more EXIF header details for JPEG images.
509 if (JPEG_MIME_TYPE.equals(image.getMimeType())) {
510 showExifInformation(image, d, activity);
511 } else {
512 hideExifInformation(d);
513 }
514
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700515 builder.setNeutralButton(R.string.details_ok,
516 new DialogInterface.OnClickListener() {
517 public void onClick(DialogInterface dialog,
518 int which) {
519 dialog.dismiss();
520 }
521 });
522
Ray Chen993105a2009-04-10 02:11:35 -0700523 handler.post(
524 new Runnable() {
525 public void run() {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800526 builder.setIcon(
527 android.R.drawable.ic_dialog_info)
Ray Chen993105a2009-04-10 02:11:35 -0700528 .setTitle(R.string.details_panel_title)
529 .setView(d)
530 .show();
531 }
532 });
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700533 }
534 });
535 return true;
536 }
537
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700538 // Called when "Rotate left" or "Rotate right" is clicked.
539 private static boolean onRotateClicked(MenuInvoker onInvoke,
540 final int degree) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700541 onInvoke.run(new MenuCallback() {
542 public void run(Uri u, IImage image) {
543 if (image == null || image.isReadonly()) {
544 return;
545 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700546 image.rotateImageBy(degree);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700547 }
548 });
549 return true;
550 }
551
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700552 // Called when "Crop" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700553 private static boolean onCropClicked(MenuInvoker onInvoke,
554 final Activity activity) {
555 onInvoke.run(new MenuCallback() {
556 public void run(Uri u, IImage image) {
557 if (u == null) {
558 return;
559 }
560
561 Intent cropIntent = new Intent();
562 cropIntent.setClass(activity, CropImage.class);
563 cropIntent.setData(u);
564 activity.startActivityForResult(cropIntent,
565 RESULT_COMMON_MENU_CROP);
566 }
567 });
568 return true;
569 }
570
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700571 // Called when "Set as" is clicked.
572 private static boolean onSetAsClicked(MenuInvoker onInvoke,
573 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700574 onInvoke.run(new MenuCallback() {
575 public void run(Uri u, IImage image) {
576 if (u == null || image == null) {
577 return;
578 }
579
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700580 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
581 intent.setDataAndType(u, image.getMimeType());
582 intent.putExtra("mimeType", image.getMimeType());
583 activity.startActivity(Intent.createChooser(intent,
584 activity.getText(R.string.setImage)));
585 }
586 });
587 return true;
588 }
589
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700590 // Called when "Share" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700591 private static boolean onImageShareClicked(MenuInvoker onInvoke,
592 final Activity activity, final boolean isImage) {
593 onInvoke.run(new MenuCallback() {
594 public void run(Uri u, IImage image) {
595 if (image == null) return;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700596
597 Intent intent = new Intent();
598 intent.setAction(Intent.ACTION_SEND);
599 String mimeType = image.getMimeType();
600 intent.setType(mimeType);
601 intent.putExtra(Intent.EXTRA_STREAM, u);
602 boolean isImage = ImageManager.isImageMimeType(mimeType);
603 try {
604 activity.startActivity(Intent.createChooser(intent,
605 activity.getText(isImage
606 ? R.string.sendImage
607 : R.string.sendVideo)));
608 } catch (android.content.ActivityNotFoundException ex) {
609 Toast.makeText(activity, isImage
610 ? R.string.no_way_to_share_image
611 : R.string.no_way_to_share_video,
612 Toast.LENGTH_SHORT).show();
613 }
614 }
615 });
616 return true;
617 }
618
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700619 // Called when "Play" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700620 private static boolean onViewPlayClicked(MenuInvoker onInvoke,
621 final Activity activity) {
622 onInvoke.run(new MenuCallback() {
623 public void run(Uri uri, IImage image) {
624 if (image != null) {
625 Intent intent = new Intent(Intent.ACTION_VIEW,
626 image.fullSizeImageUri());
627 activity.startActivity(intent);
628 }
629 }});
630 return true;
631 }
632
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800633 static MenuItemsResult addImageMenuItems(
634 Menu menu,
635 int inclusions,
636 final boolean isImage,
637 final Activity activity,
Ray Chen993105a2009-04-10 02:11:35 -0700638 final Handler handler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800639 final Runnable onDelete,
640 final MenuInvoker onInvoke) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700641 final ArrayList<MenuItem> requiresWriteAccessItems =
642 new ArrayList<MenuItem>();
643 final ArrayList<MenuItem> requiresNoDrmAccessItems =
644 new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800645
646 if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700647 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
648 MENU_IMAGE_ROTATE, 40, R.string.rotate)
649 .setIcon(android.R.drawable.ic_menu_rotate);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800650 // Don't show the rotate submenu if the item at hand is read only
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700651 // since the items within the submenu won't be shown anyway. This
652 // is really a framework bug in that it shouldn't show the submenu
653 // if the submenu has no visible items.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800654 requiresWriteAccessItems.add(rotateSubmenu.getItem());
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800655 requiresWriteAccessItems.add(
656 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50,
657 R.string.rotate_left)
658 .setOnMenuItemClickListener(
659 new MenuItem.OnMenuItemClickListener() {
660 public boolean onMenuItemClick(MenuItem item) {
661 return onRotateClicked(onInvoke, -90);
662 }
663 }).setAlphabeticShortcut('l'));
664 requiresWriteAccessItems.add(
665 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60,
666 R.string.rotate_right)
667 .setOnMenuItemClickListener(
668 new MenuItem.OnMenuItemClickListener() {
669 public boolean onMenuItemClick(MenuItem item) {
670 return onRotateClicked(onInvoke, 90);
671 }
672 }).setAlphabeticShortcut('r'));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800673 }
674
675 if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
676 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700677 R.string.camera_crop);
678 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
679 autoCrop.setOnMenuItemClickListener(
680 new MenuItem.OnMenuItemClickListener() {
681 public boolean onMenuItemClick(MenuItem item) {
682 return onCropClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800683 }
684 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800685 requiresWriteAccessItems.add(autoCrop);
686 }
687
688 if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700689 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
690 R.string.camera_set);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800691 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700692 setMenu.setOnMenuItemClickListener(
693 new MenuItem.OnMenuItemClickListener() {
694 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700695 return onSetAsClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800696 }
697 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800698 }
699
700 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800701 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
702 R.string.camera_share).setOnMenuItemClickListener(
703 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700704 public boolean onMenuItemClick(MenuItem item) {
705 return onImageShareClicked(onInvoke, activity,
706 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800707 }
708 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800709 item1.setIcon(android.R.drawable.ic_menu_share);
710 MenuItem item = item1;
711 requiresNoDrmAccessItems.add(item);
712 }
713
714 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700715 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
716 70, R.string.camera_toss);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800717 requiresWriteAccessItems.add(deleteItem);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700718 deleteItem.setOnMenuItemClickListener(
719 new MenuItem.OnMenuItemClickListener() {
720 public boolean onMenuItemClick(MenuItem item) {
721 deleteImpl(activity, onDelete, isImage);
722 return true;
723 }
724 })
725 .setAlphabeticShortcut('d')
726 .setIcon(android.R.drawable.ic_menu_delete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800727 }
728
729 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700730 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
731 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800732 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800733 return onDetailsClicked(onInvoke, handler, activity,
734 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800735 }
736 });
737 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
738 }
739
Ray Chen0a5a78c2009-04-24 14:13:01 +0800740 if ((isImage) && ((inclusions & INCLUDE_SHOWMAP_MENU) != 0)) {
741 menu.add(0, 0, 80, R.string.show_on_map)
742 .setOnMenuItemClickListener(
743 new MenuItem.OnMenuItemClickListener() {
744 public boolean onMenuItemClick(MenuItem item) {
745 return onShowMapClicked(onInvoke,
746 handler, activity);
747 }
Ray Chen1e99d7c2009-05-13 13:55:29 +0800748 }).setIcon(R.drawable.ic_menu_3d_globe);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800749 }
750
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800751 if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
752 menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700753 .setOnMenuItemClickListener(
754 new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800755 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700756 return onViewPlayClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800757 }
758 });
759 }
760
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800761 return new MenuItemsResult() {
Owen Lin101d5282009-04-03 16:20:08 -0700762 public void gettingReadyToOpen(Menu menu, IImage image) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700763 // protect against null here. this isn't strictly speaking
764 // required but if a client app isn't handling sdcard removal
765 // properly it could happen
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800766 if (image == null) {
767 return;
768 }
769 boolean readOnly = image.isReadonly();
770 boolean isDrm = image.isDrm();
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800771
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700772 for (MenuItem item : requiresWriteAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700773 item.setVisible(!readOnly);
774 item.setEnabled(!readOnly);
775 }
776 for (MenuItem item : requiresNoDrmAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700777 item.setVisible(!isDrm);
778 item.setEnabled(!isDrm);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800779 }
780 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700781
782 // must override abstract method
Owen Lin101d5282009-04-03 16:20:08 -0700783 public void aboutToCall(MenuItem menu, IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800784 }
785 };
786 }
787
788 static void deletePhoto(Activity activity, Runnable onDelete) {
Ray Chen7638a542009-03-24 20:37:45 -0700789 deleteImpl(activity, onDelete, true);
790 }
Owen Lin095afa12009-03-24 23:41:27 -0700791
Ray Chen7638a542009-03-24 20:37:45 -0700792 static void deleteVideo(Activity activity, Runnable onDelete) {
793 deleteImpl(activity, onDelete, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800794 }
795
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700796 static void deleteImage(Activity activity, Runnable onDelete,
797 IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800798 if (image != null) {
Ray Chen7638a542009-03-24 20:37:45 -0700799 deleteImpl(activity, onDelete, ImageManager.isImage(image));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800800 }
801 }
802
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700803 private static void deleteImpl(Activity activity, final Runnable onDelete,
804 boolean isPhoto) {
805 boolean confirm = android.preference.PreferenceManager
806 .getDefaultSharedPreferences(activity)
807 .getBoolean("pref_gallery_confirm_delete_key", true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800808 if (!confirm) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700809 if (onDelete != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800810 onDelete.run();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700811 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800812 } else {
813 displayDeleteDialog(activity, onDelete, isPhoto);
814 }
815 }
816
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700817 private static void displayDeleteDialog(Activity activity,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800818 final Runnable onDelete, boolean isPhoto) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700819 android.app.AlertDialog.Builder b =
820 new android.app.AlertDialog.Builder(activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800821 b.setIcon(android.R.drawable.ic_dialog_alert);
822 b.setTitle(R.string.confirm_delete_title);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700823 b.setMessage(isPhoto
824 ? R.string.confirm_delete_message
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800825 : R.string.confirm_delete_video_message);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700826 b.setPositiveButton(android.R.string.ok,
827 new android.content.DialogInterface.OnClickListener() {
828 public void onClick(android.content.DialogInterface v,
829 int x) {
830 if (onDelete != null) {
831 onDelete.run();
832 }
833 }
834 });
835 b.setNegativeButton(android.R.string.cancel,
836 new android.content.DialogInterface.OnClickListener() {
837 public void onClick(android.content.DialogInterface v,
838 int x) {
839 }
840 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800841 b.create().show();
842 }
843
844 static void addSwitchModeMenuItem(Menu menu, final Activity activity,
845 final boolean switchToVideo) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700846 int group = switchToVideo
847 ? MenuHelper.IMAGE_MODE_ITEM
848 : MenuHelper.VIDEO_MODE_ITEM;
849 int labelId = switchToVideo
850 ? R.string.switch_to_video_lable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800851 : R.string.switch_to_camera_lable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700852 int iconId = switchToVideo
853 ? R.drawable.ic_menu_camera_video_view
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800854 : android.R.drawable.ic_menu_camera;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700855 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
856 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
857 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700858 return onSwitchModeClicked(activity, switchToVideo);
859 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700860 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800861 item.setIcon(iconId);
862 }
863
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700864 private static boolean onSwitchModeClicked(Activity activity,
865 boolean switchToVideo) {
866 String action = switchToVideo
867 ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
868 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
869 Intent intent = new Intent(action);
870 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
871 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800872
873 // Keep the camera instance for a while.
874 // This avoids re-opening the camera and saves time.
875 CameraHolder.instance().keep();
876
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700877 activity.startActivity(intent);
878 return true;
879 }
880
Owen Lin059daa32009-05-18 15:31:17 -0700881 public static void gotoCameraMode(Activity activity) {
882 onSwitchModeClicked(activity, false);
883 }
884
885 public static void gotoVideoMode(Activity activity) {
886 onSwitchModeClicked(activity, true);
887 }
888
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800889 static void gotoStillImageCapture(Activity activity) {
890 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
891 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
892 try {
893 activity.startActivity(intent);
894 } catch (ActivityNotFoundException e) {
895 Log.e(TAG, "Could not start still image capture activity", e);
896 }
897 }
898
899 static void gotoCameraImageGallery(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700900 gotoGallery(activity, R.string.gallery_camera_bucket_name,
901 ImageManager.INCLUDE_IMAGES);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800902 }
903
904 static void gotoCameraVideoGallery(Activity activity) {
905 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
906 ImageManager.INCLUDE_VIDEOS);
907 }
908
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700909 private static void gotoGallery(Activity activity, int windowTitleId,
910 int mediaTypes) {
911 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
912 .appendQueryParameter("bucketId",
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800913 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
914 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700915 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800916 intent.putExtra("windowTitle", activity.getString(windowTitleId));
917 intent.putExtra("mediaTypes", mediaTypes);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700918
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800919 try {
920 activity.startActivity(intent);
921 } catch (ActivityNotFoundException e) {
922 Log.e(TAG, "Could not start gallery activity", e);
923 }
924 }
925
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700926 static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800927 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700928 .setOnMenuItemClickListener(
929 new MenuItem.OnMenuItemClickListener() {
930 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700931 return onCapturePictureClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700932 }
933 }).setIcon(android.R.drawable.ic_menu_camera);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700934 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800935
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700936 private static boolean onCapturePictureClicked(Activity activity) {
937 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
938 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
939 try {
940 activity.startActivity(intent);
941 } catch (android.content.ActivityNotFoundException e) {
942 // Ignore exception
943 }
944 return true;
945 }
946
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700947 static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800948 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700949 .setOnMenuItemClickListener(
950 new MenuItem.OnMenuItemClickListener() {
951 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700952 return onCaptureVideoClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700953 }
954 }).setIcon(R.drawable.ic_menu_camera_video_view);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800955 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700956
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700957 private static boolean onCaptureVideoClicked(Activity activity) {
958 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
959 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
960 try {
961 activity.startActivity(intent);
962 } catch (android.content.ActivityNotFoundException e) {
963 // Ignore exception
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700964 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700965 return true;
966 }
967
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700968 public static void addCaptureMenuItems(Menu menu, final Activity activity) {
969 addCapturePictureMenuItems(menu, activity);
970 addCaptureVideoMenuItems(menu, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800971 }
972
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700973 public static String formatDuration(final Activity activity,
974 int durationMs) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800975 int duration = durationMs / 1000;
976 int h = duration / 3600;
977 int m = (duration - h * 3600) / 60;
978 int s = duration - (h * 3600 + m * 60);
979 String durationValue;
980 if (h == 0) {
981 durationValue = String.format(
982 activity.getString(R.string.details_ms), m, s);
983 } else {
984 durationValue = String.format(
985 activity.getString(R.string.details_hms), h, m, s);
986 }
987 return durationValue;
988 }
989
990 public static void showStorageToast(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700991 showStorageToast(activity, calculatePicturesRemaining());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800992 }
993
994 public static void showStorageToast(Activity activity, int remaining) {
995 String noStorageText = null;
996
997 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
998 String state = Environment.getExternalStorageState();
999 if (state == Environment.MEDIA_CHECKING) {
1000 noStorageText = activity.getString(R.string.preparing_sd);
1001 } else {
1002 noStorageText = activity.getString(R.string.no_storage);
1003 }
1004 } else if (remaining < 1) {
1005 noStorageText = activity.getString(R.string.not_enough_space);
1006 }
1007
1008 if (noStorageText != null) {
1009 Toast.makeText(activity, noStorageText, 5000).show();
1010 }
1011 }
1012
1013 public static int calculatePicturesRemaining() {
1014 try {
1015 if (!ImageManager.hasStorage()) {
1016 return NO_STORAGE_ERROR;
1017 } else {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001018 String storageDirectory =
1019 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001020 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001021 float remaining = ((float) stat.getAvailableBlocks()
1022 * (float) stat.getBlockSize()) / 400000F;
1023 return (int) remaining;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001024 }
1025 } catch (Exception ex) {
1026 // if we can't stat the filesystem then we don't know how many
1027 // pictures are remaining. it might be zero but just leave it
1028 // blank since we really don't know.
1029 return CANNOT_STAT_ERROR;
1030 }
1031 }
1032}