blob: 0e3658c27cdae6440fa1cd6bae37bc15f2d4e642 [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;
Ray Chen0f0af522009-04-22 13:26:07 +080020import com.android.camera.gallery.Image;
Owen Lin101d5282009-04-03 16:20:08 -070021
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080022import android.app.Activity;
23import android.app.AlertDialog;
24import android.content.ActivityNotFoundException;
25import 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;
Ray Chen0f0af522009-04-22 13:26:07 +080040import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080041import android.view.SubMenu;
42import android.view.View;
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 Chen0f0af522009-04-22 13:26:07 +080052import java.util.Iterator;
53import java.util.List;
54import java.util.Locale;
55import java.util.StringTokenizer;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080056
57public 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
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070091 private static final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L;
The Android Open Source Projecte3f45162009-03-11 12:11:58 -070092
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080093 public static final int NO_STORAGE_ERROR = -1;
94 public static final int CANNOT_STAT_ERROR = -2;
Ray Chen0f0af522009-04-22 13:26:07 +080095 public static final String EMPTY_STRING = "";
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 Chen0a5a78c2009-04-24 14:13:01 +0800163 private static float getLatLng(Image img, String tag) {
Ray Chen0f0af522009-04-22 13:26:07 +0800164 String value = img.getExifTag(tag);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800165 String ref;
166
167 if (tag == ExifInterface.TAG_GPS_LATITUDE) {
168 ref = img.getExifTag(ExifInterface.TAG_GPS_LATITUDE_REF);
169 } else {
170 ref = img.getExifTag(ExifInterface.TAG_GPS_LONGITUDE_REF);
171 }
172
173 float f = INVALID_LATLNG;
Ray Chen0f0af522009-04-22 13:26:07 +0800174 if (value != null && ref != null) {
175 f = ExifInterface.convertRationalLatLonToFloat(
176 value, ref);
Ray Chen0f0af522009-04-22 13:26:07 +0800177 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800178 return f;
179 }
180
181 private static float setLatLngDetails(View d, Image img,
182 String tag, String refTag) {
Ray Chen0f0af522009-04-22 13:26:07 +0800183 int valueId = R.id.details_latitude_value;
184 int rowId = R.id.details_latitude_row;
Ray Chen0a5a78c2009-04-24 14:13:01 +0800185 float latlng = getLatLng(img, tag);
Ray Chen0f0af522009-04-22 13:26:07 +0800186
187 if (tag == ExifInterface.TAG_GPS_LONGITUDE) {
188 valueId = R.id.details_longitude_value;
189 rowId = R.id.details_longitude_row;
190 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800191
192 if (latlng == INVALID_LATLNG) {
Ray Chen0f0af522009-04-22 13:26:07 +0800193 hideDetailsRow(d, rowId);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800194 return INVALID_LATLNG;
Ray Chen0f0af522009-04-22 13:26:07 +0800195 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800196
197 setDetailsValue(d, String.valueOf(latlng), valueId);
198 return latlng;
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);
212 List<Address> address = geocoder.getFromLocation(
213 lat, lng, 1);
214 Iterator<Address> iterator = address.iterator();
215
216 while (iterator.hasNext()) {
217 Address addr = iterator.next();
218 value += addr.getAddressLine(
219 addr.getMaxAddressLineIndex());
220 Log.v(TAG, addr.toString());
221 }
222 } 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 Chen0a5a78c2009-04-24 14:13:01 +0800238 // Called when "Show on Maps" is clicked.
239 // Displays image location on Google Maps for further operations.
240 private static boolean onShowMapClicked(MenuInvoker onInvoke,
241 final Handler handler,
242 final Activity activity) {
243 onInvoke.run(new MenuCallback() {
244 public void run(Uri u, IImage image) {
245 if (image == null) {
246 return;
247 }
248 float lat = getLatLng((Image) image,
249 ExifInterface.TAG_GPS_LATITUDE);
250 float lng = getLatLng((Image) image,
251 ExifInterface.TAG_GPS_LONGITUDE);
252 if (lat == INVALID_LATLNG || lng == INVALID_LATLNG) {
253 handler.post(new Runnable() {
254 public void run() {
255 Toast.makeText(activity,
256 R.string.no_location_image,
257 Toast.LENGTH_SHORT).show();
258 }
259 });
260 return;
261 }
262
263 // Can't use geo:latitude,longitude because it only centers
264 // the MapView to specified location, but we need a bubble
265 // for further operations (routing to/from).
266 // The q=(lat, lng) syntax is suggested by geo-team.
267 String uri = "http://maps.google.com/maps?f=q&" +
268 "q=(" + lat + "," + lng + ")";
269 activity.startActivity(new Intent(
270 android.content.Intent.ACTION_VIEW,
271 Uri.parse(uri)));
272 }
273 });
274 return true;
275 }
276
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700277 // Called when "Details" is clicked.
278 // Displays detailed information about the image/video.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700279 private static boolean onDetailsClicked(MenuInvoker onInvoke,
Ray Chen0a5a78c2009-04-24 14:13:01 +0800280 final Handler handler,
281 final Activity activity,
282 final boolean isImage) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700283 onInvoke.run(new MenuCallback() {
284 public void run(Uri u, IImage image) {
285 if (image == null) {
286 return;
287 }
288
Ray Chen993105a2009-04-10 02:11:35 -0700289 final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700290
291 final View d = View.inflate(activity, R.layout.detailsview,
292 null);
293
294 ImageView imageView = (ImageView) d.findViewById(
295 R.id.details_thumbnail_image);
296 imageView.setImageBitmap(image.miniThumbBitmap());
297
298 TextView textView = (TextView) d.findViewById(
299 R.id.details_image_title);
300 textView.setText(image.getDisplayName());
301
302 long length = getImageFileSize(image);
Owen Lin937fc482009-04-14 02:02:51 -0700303 String lengthString = length < 0
Ray Chen0f0af522009-04-22 13:26:07 +0800304 ? EMPTY_STRING
Owen Lin937fc482009-04-14 02:02:51 -0700305 : Formatter.formatFileSize(activity, length);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700306 ((TextView) d
307 .findViewById(R.id.details_file_size_value))
308 .setText(lengthString);
309
310 int dimensionWidth = 0;
311 int dimensionHeight = 0;
312 if (isImage) {
Ray Chen0f0af522009-04-22 13:26:07 +0800313 // getWidth is much slower than reading from EXIF
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700314 dimensionWidth = image.getWidth();
315 dimensionHeight = image.getHeight();
316 d.findViewById(R.id.details_duration_row)
317 .setVisibility(View.GONE);
318 d.findViewById(R.id.details_frame_rate_row)
319 .setVisibility(View.GONE);
320 d.findViewById(R.id.details_bit_rate_row)
321 .setVisibility(View.GONE);
322 d.findViewById(R.id.details_format_row)
323 .setVisibility(View.GONE);
324 d.findViewById(R.id.details_codec_row)
325 .setVisibility(View.GONE);
326 } else {
327 MediaMetadataRetriever retriever
328 = new MediaMetadataRetriever();
329 try {
330 retriever.setMode(MediaMetadataRetriever
331 .MODE_GET_METADATA_ONLY);
332 retriever.setDataSource(image.getDataPath());
333 try {
334 dimensionWidth = Integer.parseInt(
335 retriever.extractMetadata(
336 MediaMetadataRetriever
337 .METADATA_KEY_VIDEO_WIDTH));
338 dimensionHeight = Integer.parseInt(
339 retriever.extractMetadata(
340 MediaMetadataRetriever
341 .METADATA_KEY_VIDEO_HEIGHT));
342 } catch (NumberFormatException e) {
343 dimensionWidth = 0;
344 dimensionHeight = 0;
345 }
346
347 try {
348 int durationMs = Integer.parseInt(
349 retriever.extractMetadata(
350 MediaMetadataRetriever
351 .METADATA_KEY_DURATION));
352 String durationValue = formatDuration(
353 activity, durationMs);
354 ((TextView) d.findViewById(
355 R.id.details_duration_value))
356 .setText(durationValue);
357 } catch (NumberFormatException e) {
358 d.findViewById(
359 R.id.details_frame_rate_row)
360 .setVisibility(View.GONE);
361 }
362
363 try {
364 String frameRate = String.format(
365 activity.getString(R.string.details_fps),
366 Integer.parseInt(
367 retriever.extractMetadata(
368 MediaMetadataRetriever
369 .METADATA_KEY_FRAME_RATE)));
370 ((TextView) d.findViewById(
371 R.id.details_frame_rate_value))
372 .setText(frameRate);
373 } catch (NumberFormatException e) {
374 d.findViewById(
375 R.id.details_frame_rate_row)
376 .setVisibility(View.GONE);
377 }
378
379 try {
380 long bitRate = Long.parseLong(
381 retriever.extractMetadata(
382 MediaMetadataRetriever
383 .METADATA_KEY_BIT_RATE));
384 String bps;
385 if (bitRate < 1000000) {
386 bps = String.format(
387 activity.getString(
388 R.string.details_kbps),
389 bitRate / 1000);
390 } else {
391 bps = String.format(
392 activity.getString(
393 R.string.details_mbps),
Owen Lin937fc482009-04-14 02:02:51 -0700394 (bitRate) / 1000000.0);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700395 }
396 ((TextView) d.findViewById(
397 R.id.details_bit_rate_value))
398 .setText(bps);
399 } catch (NumberFormatException e) {
400 d.findViewById(R.id.details_bit_rate_row)
401 .setVisibility(View.GONE);
402 }
403
404 String format = retriever.extractMetadata(
405 MediaMetadataRetriever
406 .METADATA_KEY_VIDEO_FORMAT);
407 ((TextView) d.findViewById(
408 R.id.details_format_value))
409 .setText(format);
410
411 String codec = retriever.extractMetadata(
412 MediaMetadataRetriever.METADATA_KEY_CODEC);
Ray Chen0f0af522009-04-22 13:26:07 +0800413 if (codec != null) {
414 setDetailsValue(d, codec, R.id.details_codec_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700415 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800416 hideDetailsRow(d, R.id.details_codec_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700417 }
Ray Chen0f0af522009-04-22 13:26:07 +0800418
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700419 } catch (RuntimeException ex) {
420 // Assume this is a corrupt video file.
421 } finally {
422 try {
423 retriever.release();
424 } catch (RuntimeException ex) {
425 // Ignore failures while cleaning up.
426 }
427 }
428 }
429
Ray Chen0f0af522009-04-22 13:26:07 +0800430 Image img = (Image) image;
431 String value = null;
432 if (dimensionWidth > 0 && dimensionHeight > 0) {
433 value = String.format(
434 activity.getString(R.string.details_dimension_x),
435 dimensionWidth, dimensionHeight);
436 } else {
437 String width = img.getExifTag(ExifInterface.TAG_IMAGE_WIDTH);
438 String height = img.getExifTag(ExifInterface.TAG_IMAGE_LENGTH);
439 if (width != null && height != null) {
440 value = EMPTY_STRING + width + " x " + height;
441 }
442 }
443 if (value != null) {
444 setDetailsValue(d, value, R.id.details_resolution_value);
445 } else {
446 hideDetailsRow(d, R.id.details_resolution_row);
447 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700448
Ray Chen0f0af522009-04-22 13:26:07 +0800449 value = img.getExifTag(ExifInterface.TAG_MAKE);
450 if (value != null) {
451 setDetailsValue(d, value, R.id.details_make_value);
452 } else {
453 hideDetailsRow(d, R.id.details_make_row);
454 }
455
456 value = img.getExifTag(ExifInterface.TAG_MODEL);
457 if (value != null) {
458 setDetailsValue(d, value, R.id.details_model_value);
459 } else {
460 hideDetailsRow(d, R.id.details_model_row);
461 }
462
463 value = img.getExifTag(ExifInterface.TAG_WHITE_BALANCE);
464 if (value != null) {
465 value = ExifInterface.whiteBalanceToString(
466 Integer.parseInt(value));
467 }
468 if (value != null) {
469 setDetailsValue(d, value, R.id.details_whitebalance_value);
470 } else {
471 hideDetailsRow(d, R.id.details_whitebalance_row);
472 }
473
474 float lat = setLatLngDetails(d, img,
475 ExifInterface.TAG_GPS_LATITUDE,
476 ExifInterface.TAG_GPS_LATITUDE_REF);
477 float lng = setLatLngDetails(d, img,
478 ExifInterface.TAG_GPS_LONGITUDE,
479 ExifInterface.TAG_GPS_LONGITUDE_REF);
480 setReverseGeocodingDetails(d, activity, lat, lng);
481
482 value = EMPTY_STRING;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700483 long dateTaken = image.getDateTaken();
484 if (dateTaken != 0) {
485 Date date = new Date(image.getDateTaken());
486 SimpleDateFormat dateFormat = new SimpleDateFormat();
Ray Chen0f0af522009-04-22 13:26:07 +0800487 value = dateFormat.format(date);
488 }
489 if (value != EMPTY_STRING) {
490 setDetailsValue(d, value, R.id.details_date_taken_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700491 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800492 hideDetailsRow(d, R.id.details_date_taken_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700493 }
494
495 builder.setNeutralButton(R.string.details_ok,
496 new DialogInterface.OnClickListener() {
497 public void onClick(DialogInterface dialog,
498 int which) {
499 dialog.dismiss();
500 }
501 });
502
Ray Chen993105a2009-04-10 02:11:35 -0700503 handler.post(
504 new Runnable() {
505 public void run() {
506 builder.setIcon(android.R.drawable.ic_dialog_info)
507 .setTitle(R.string.details_panel_title)
508 .setView(d)
509 .show();
510 }
511 });
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700512 }
513 });
514 return true;
515 }
516
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700517 // Called when "Rotate left" or "Rotate right" is clicked.
518 private static boolean onRotateClicked(MenuInvoker onInvoke,
519 final int degree) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700520 onInvoke.run(new MenuCallback() {
521 public void run(Uri u, IImage image) {
522 if (image == null || image.isReadonly()) {
523 return;
524 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700525 image.rotateImageBy(degree);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700526 }
527 });
528 return true;
529 }
530
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700531 // Called when "Crop" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700532 private static boolean onCropClicked(MenuInvoker onInvoke,
533 final Activity activity) {
534 onInvoke.run(new MenuCallback() {
535 public void run(Uri u, IImage image) {
536 if (u == null) {
537 return;
538 }
539
540 Intent cropIntent = new Intent();
541 cropIntent.setClass(activity, CropImage.class);
542 cropIntent.setData(u);
543 activity.startActivityForResult(cropIntent,
544 RESULT_COMMON_MENU_CROP);
545 }
546 });
547 return true;
548 }
549
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700550 // Called when "Set as" is clicked.
551 private static boolean onSetAsClicked(MenuInvoker onInvoke,
552 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700553 onInvoke.run(new MenuCallback() {
554 public void run(Uri u, IImage image) {
555 if (u == null || image == null) {
556 return;
557 }
558
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700559 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
560 intent.setDataAndType(u, image.getMimeType());
561 intent.putExtra("mimeType", image.getMimeType());
562 activity.startActivity(Intent.createChooser(intent,
563 activity.getText(R.string.setImage)));
564 }
565 });
566 return true;
567 }
568
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700569 // Called when "Share" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700570 private static boolean onImageShareClicked(MenuInvoker onInvoke,
571 final Activity activity, final boolean isImage) {
572 onInvoke.run(new MenuCallback() {
573 public void run(Uri u, IImage image) {
574 if (image == null) return;
575 if (!isImage && getImageFileSize(image)
576 > SHARE_FILE_LENGTH_LIMIT) {
577 Toast.makeText(activity,
578 R.string.too_large_to_attach,
579 Toast.LENGTH_LONG).show();
580 return;
581 }
582
583 Intent intent = new Intent();
584 intent.setAction(Intent.ACTION_SEND);
585 String mimeType = image.getMimeType();
586 intent.setType(mimeType);
587 intent.putExtra(Intent.EXTRA_STREAM, u);
588 boolean isImage = ImageManager.isImageMimeType(mimeType);
589 try {
590 activity.startActivity(Intent.createChooser(intent,
591 activity.getText(isImage
592 ? R.string.sendImage
593 : R.string.sendVideo)));
594 } catch (android.content.ActivityNotFoundException ex) {
595 Toast.makeText(activity, isImage
596 ? R.string.no_way_to_share_image
597 : R.string.no_way_to_share_video,
598 Toast.LENGTH_SHORT).show();
599 }
600 }
601 });
602 return true;
603 }
604
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700605 // Called when "Play" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700606 private static boolean onViewPlayClicked(MenuInvoker onInvoke,
607 final Activity activity) {
608 onInvoke.run(new MenuCallback() {
609 public void run(Uri uri, IImage image) {
610 if (image != null) {
611 Intent intent = new Intent(Intent.ACTION_VIEW,
612 image.fullSizeImageUri());
613 activity.startActivity(intent);
614 }
615 }});
616 return true;
617 }
618
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800619 static MenuItemsResult addImageMenuItems(
620 Menu menu,
621 int inclusions,
622 final boolean isImage,
623 final Activity activity,
Ray Chen993105a2009-04-10 02:11:35 -0700624 final Handler handler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800625 final Runnable onDelete,
626 final MenuInvoker onInvoke) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700627 final ArrayList<MenuItem> requiresWriteAccessItems =
628 new ArrayList<MenuItem>();
629 final ArrayList<MenuItem> requiresNoDrmAccessItems =
630 new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800631
632 if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700633 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
634 MENU_IMAGE_ROTATE, 40, R.string.rotate)
635 .setIcon(android.R.drawable.ic_menu_rotate);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800636 // Don't show the rotate submenu if the item at hand is read only
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700637 // since the items within the submenu won't be shown anyway. This
638 // is really a framework bug in that it shouldn't show the submenu
639 // if the submenu has no visible items.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800640 requiresWriteAccessItems.add(rotateSubmenu.getItem());
641 if (rotateSubmenu != null) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700642 requiresWriteAccessItems.add(
643 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50,
644 R.string.rotate_left)
645 .setOnMenuItemClickListener(
646 new MenuItem.OnMenuItemClickListener() {
647 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700648 return onRotateClicked(onInvoke, -90);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800649 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700650 }).setAlphabeticShortcut('l'));
651 requiresWriteAccessItems.add(
652 rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60,
653 R.string.rotate_right)
654 .setOnMenuItemClickListener(
655 new MenuItem.OnMenuItemClickListener() {
656 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700657 return onRotateClicked(onInvoke, 90);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800658 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700659 }).setAlphabeticShortcut('r'));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800660 }
661 }
662
663 if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
664 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700665 R.string.camera_crop);
666 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
667 autoCrop.setOnMenuItemClickListener(
668 new MenuItem.OnMenuItemClickListener() {
669 public boolean onMenuItemClick(MenuItem item) {
670 return onCropClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800671 }
672 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800673 requiresWriteAccessItems.add(autoCrop);
674 }
675
676 if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700677 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
678 R.string.camera_set);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800679 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700680 setMenu.setOnMenuItemClickListener(
681 new MenuItem.OnMenuItemClickListener() {
682 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700683 return onSetAsClicked(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 }
687
688 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800689 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
690 R.string.camera_share).setOnMenuItemClickListener(
691 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700692 public boolean onMenuItemClick(MenuItem item) {
693 return onImageShareClicked(onInvoke, activity,
694 isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800695 }
696 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800697 item1.setIcon(android.R.drawable.ic_menu_share);
698 MenuItem item = item1;
699 requiresNoDrmAccessItems.add(item);
700 }
701
702 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700703 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
704 70, R.string.camera_toss);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800705 requiresWriteAccessItems.add(deleteItem);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700706 deleteItem.setOnMenuItemClickListener(
707 new MenuItem.OnMenuItemClickListener() {
708 public boolean onMenuItemClick(MenuItem item) {
709 deleteImpl(activity, onDelete, isImage);
710 return true;
711 }
712 })
713 .setAlphabeticShortcut('d')
714 .setIcon(android.R.drawable.ic_menu_delete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800715 }
716
717 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700718 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
719 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800720 public boolean onMenuItemClick(MenuItem item) {
Ray Chen993105a2009-04-10 02:11:35 -0700721 return onDetailsClicked(onInvoke, handler, activity, isImage);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800722 }
723 });
724 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
725 }
726
Ray Chen0a5a78c2009-04-24 14:13:01 +0800727 if ((isImage) && ((inclusions & INCLUDE_SHOWMAP_MENU) != 0)) {
728 menu.add(0, 0, 80, R.string.show_on_map)
729 .setOnMenuItemClickListener(
730 new MenuItem.OnMenuItemClickListener() {
731 public boolean onMenuItemClick(MenuItem item) {
732 return onShowMapClicked(onInvoke,
733 handler, activity);
734 }
735 });
736 }
737
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800738 if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
739 menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700740 .setOnMenuItemClickListener(
741 new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800742 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700743 return onViewPlayClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800744 }
745 });
746 }
747
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800748 return new MenuItemsResult() {
Owen Lin101d5282009-04-03 16:20:08 -0700749 public void gettingReadyToOpen(Menu menu, IImage image) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700750 // protect against null here. this isn't strictly speaking
751 // required but if a client app isn't handling sdcard removal
752 // properly it could happen
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800753 if (image == null) {
754 return;
755 }
756 boolean readOnly = image.isReadonly();
757 boolean isDrm = image.isDrm();
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800758
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700759 for (MenuItem item : requiresWriteAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700760 item.setVisible(!readOnly);
761 item.setEnabled(!readOnly);
762 }
763 for (MenuItem item : requiresNoDrmAccessItems) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700764 item.setVisible(!isDrm);
765 item.setEnabled(!isDrm);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800766 }
767 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700768
769 // must override abstract method
Owen Lin101d5282009-04-03 16:20:08 -0700770 public void aboutToCall(MenuItem menu, IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800771 }
772 };
773 }
774
775 static void deletePhoto(Activity activity, Runnable onDelete) {
Ray Chen7638a542009-03-24 20:37:45 -0700776 deleteImpl(activity, onDelete, true);
777 }
Owen Lin095afa12009-03-24 23:41:27 -0700778
Ray Chen7638a542009-03-24 20:37:45 -0700779 static void deleteVideo(Activity activity, Runnable onDelete) {
780 deleteImpl(activity, onDelete, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800781 }
782
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700783 static void deleteImage(Activity activity, Runnable onDelete,
784 IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800785 if (image != null) {
Ray Chen7638a542009-03-24 20:37:45 -0700786 deleteImpl(activity, onDelete, ImageManager.isImage(image));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800787 }
788 }
789
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700790 private static void deleteImpl(Activity activity, final Runnable onDelete,
791 boolean isPhoto) {
792 boolean confirm = android.preference.PreferenceManager
793 .getDefaultSharedPreferences(activity)
794 .getBoolean("pref_gallery_confirm_delete_key", true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800795 if (!confirm) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700796 if (onDelete != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800797 onDelete.run();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700798 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800799 } else {
800 displayDeleteDialog(activity, onDelete, isPhoto);
801 }
802 }
803
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700804 private static void displayDeleteDialog(Activity activity,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800805 final Runnable onDelete, boolean isPhoto) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700806 android.app.AlertDialog.Builder b =
807 new android.app.AlertDialog.Builder(activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800808 b.setIcon(android.R.drawable.ic_dialog_alert);
809 b.setTitle(R.string.confirm_delete_title);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700810 b.setMessage(isPhoto
811 ? R.string.confirm_delete_message
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800812 : R.string.confirm_delete_video_message);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700813 b.setPositiveButton(android.R.string.ok,
814 new android.content.DialogInterface.OnClickListener() {
815 public void onClick(android.content.DialogInterface v,
816 int x) {
817 if (onDelete != null) {
818 onDelete.run();
819 }
820 }
821 });
822 b.setNegativeButton(android.R.string.cancel,
823 new android.content.DialogInterface.OnClickListener() {
824 public void onClick(android.content.DialogInterface v,
825 int x) {
826 }
827 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800828 b.create().show();
829 }
830
831 static void addSwitchModeMenuItem(Menu menu, final Activity activity,
832 final boolean switchToVideo) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700833 int group = switchToVideo
834 ? MenuHelper.IMAGE_MODE_ITEM
835 : MenuHelper.VIDEO_MODE_ITEM;
836 int labelId = switchToVideo
837 ? R.string.switch_to_video_lable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800838 : R.string.switch_to_camera_lable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700839 int iconId = switchToVideo
840 ? R.drawable.ic_menu_camera_video_view
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800841 : android.R.drawable.ic_menu_camera;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700842 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
843 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
844 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700845 return onSwitchModeClicked(activity, switchToVideo);
846 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700847 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800848 item.setIcon(iconId);
849 }
850
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700851 private static boolean onSwitchModeClicked(Activity activity,
852 boolean switchToVideo) {
853 String action = switchToVideo
854 ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
855 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
856 Intent intent = new Intent(action);
857 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
858 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
859 activity.startActivity(intent);
860 return true;
861 }
862
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800863 static void gotoStillImageCapture(Activity activity) {
864 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
865 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
866 try {
867 activity.startActivity(intent);
868 } catch (ActivityNotFoundException e) {
869 Log.e(TAG, "Could not start still image capture activity", e);
870 }
871 }
872
873 static void gotoCameraImageGallery(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700874 gotoGallery(activity, R.string.gallery_camera_bucket_name,
875 ImageManager.INCLUDE_IMAGES);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800876 }
877
878 static void gotoCameraVideoGallery(Activity activity) {
879 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
880 ImageManager.INCLUDE_VIDEOS);
881 }
882
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700883 private static void gotoGallery(Activity activity, int windowTitleId,
884 int mediaTypes) {
885 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
886 .appendQueryParameter("bucketId",
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800887 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
888 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700889 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800890 intent.putExtra("windowTitle", activity.getString(windowTitleId));
891 intent.putExtra("mediaTypes", mediaTypes);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700892
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800893 try {
894 activity.startActivity(intent);
895 } catch (ActivityNotFoundException e) {
896 Log.e(TAG, "Could not start gallery activity", e);
897 }
898 }
899
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700900 static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800901 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700902 .setOnMenuItemClickListener(
903 new MenuItem.OnMenuItemClickListener() {
904 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700905 return onCapturePictureClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700906 }
907 }).setIcon(android.R.drawable.ic_menu_camera);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700908 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800909
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700910 private static boolean onCapturePictureClicked(Activity activity) {
911 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
912 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
913 try {
914 activity.startActivity(intent);
915 } catch (android.content.ActivityNotFoundException e) {
916 // Ignore exception
917 }
918 return true;
919 }
920
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700921 static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800922 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700923 .setOnMenuItemClickListener(
924 new MenuItem.OnMenuItemClickListener() {
925 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700926 return onCaptureVideoClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700927 }
928 }).setIcon(R.drawable.ic_menu_camera_video_view);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800929 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700930
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700931 private static boolean onCaptureVideoClicked(Activity activity) {
932 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
933 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
934 try {
935 activity.startActivity(intent);
936 } catch (android.content.ActivityNotFoundException e) {
937 // Ignore exception
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700938 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700939 return true;
940 }
941
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700942 public static void addCaptureMenuItems(Menu menu, final Activity activity) {
943 addCapturePictureMenuItems(menu, activity);
944 addCaptureVideoMenuItems(menu, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800945 }
946
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700947 public static String formatDuration(final Activity activity,
948 int durationMs) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800949 int duration = durationMs / 1000;
950 int h = duration / 3600;
951 int m = (duration - h * 3600) / 60;
952 int s = duration - (h * 3600 + m * 60);
953 String durationValue;
954 if (h == 0) {
955 durationValue = String.format(
956 activity.getString(R.string.details_ms), m, s);
957 } else {
958 durationValue = String.format(
959 activity.getString(R.string.details_hms), h, m, s);
960 }
961 return durationValue;
962 }
963
964 public static void showStorageToast(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700965 showStorageToast(activity, calculatePicturesRemaining());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800966 }
967
968 public static void showStorageToast(Activity activity, int remaining) {
969 String noStorageText = null;
970
971 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
972 String state = Environment.getExternalStorageState();
973 if (state == Environment.MEDIA_CHECKING) {
974 noStorageText = activity.getString(R.string.preparing_sd);
975 } else {
976 noStorageText = activity.getString(R.string.no_storage);
977 }
978 } else if (remaining < 1) {
979 noStorageText = activity.getString(R.string.not_enough_space);
980 }
981
982 if (noStorageText != null) {
983 Toast.makeText(activity, noStorageText, 5000).show();
984 }
985 }
986
987 public static int calculatePicturesRemaining() {
988 try {
989 if (!ImageManager.hasStorage()) {
990 return NO_STORAGE_ERROR;
991 } else {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700992 String storageDirectory =
993 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800994 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700995 float remaining = ((float) stat.getAvailableBlocks()
996 * (float) stat.getBlockSize()) / 400000F;
997 return (int) remaining;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800998 }
999 } catch (Exception ex) {
1000 // if we can't stat the filesystem then we don't know how many
1001 // pictures are remaining. it might be zero but just leave it
1002 // blank since we really don't know.
1003 return CANNOT_STAT_ERROR;
1004 }
1005 }
1006}