blob: 568b3a650d7a70ab1217198fa868ef3b4f934b68 [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
19import java.io.Closeable;
20import java.util.ArrayList;
21
22import android.app.Activity;
23import android.app.AlertDialog;
24import android.content.ActivityNotFoundException;
25import android.content.DialogInterface;
26import android.content.Intent;
27import android.content.SharedPreferences;
28import android.content.res.Configuration;
29import 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;
36import android.util.Config;
37import android.util.Log;
38import android.view.Menu;
39import android.view.MenuItem;
40import android.view.SubMenu;
41import android.view.View;
42import android.view.MenuItem.OnMenuItemClickListener;
43import android.widget.ImageView;
44import android.widget.TextView;
45import android.widget.Toast;
46
47import com.android.camera.ImageManager.IImage;
48
49public class MenuHelper {
50 static private final String TAG = "MenuHelper";
51
52 static public final int GENERIC_ITEM = 1;
53 static public final int IMAGE_SAVING_ITEM = 2;
54 static public final int VIDEO_SAVING_ITEM = 3;
55 static public final int IMAGE_MODE_ITEM = 4;
56 static public final int VIDEO_MODE_ITEM = 5;
57 static public final int MENU_ITEM_MAX = 5;
58
59 static public final int INCLUDE_ALL = 0xFFFFFFFF;
60 static public final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
61 static public final int INCLUDE_SHARE_MENU = (1 << 1);
62 static public final int INCLUDE_SET_MENU = (1 << 2);
63 static public final int INCLUDE_CROP_MENU = (1 << 3);
64 static public final int INCLUDE_DELETE_MENU = (1 << 4);
65 static public final int INCLUDE_ROTATE_MENU = (1 << 5);
66 static public final int INCLUDE_DETAILS_MENU = (1 << 5);
67
68 static public final int MENU_SWITCH_CAMERA_MODE = 0;
69 static public final int MENU_CAPTURE_PICTURE = 1;
70 static public final int MENU_CAPTURE_VIDEO = 2;
71 static public final int MENU_IMAGE_SHARE = 10;
72 static public final int MENU_IMAGE_SET = 14;
73 static public final int MENU_IMAGE_SET_WALLPAPER = 15;
74 static public final int MENU_IMAGE_SET_CONTACT = 16;
75 static public final int MENU_IMAGE_SET_MYFAVE = 17;
76 static public final int MENU_IMAGE_CROP = 18;
77 static public final int MENU_IMAGE_ROTATE = 19;
78 static public final int MENU_IMAGE_ROTATE_LEFT = 20;
79 static public final int MENU_IMAGE_ROTATE_RIGHT = 21;
80 static public final int MENU_IMAGE_TOSS = 22;
81 static public final int MENU_VIDEO_PLAY = 23;
82 static public final int MENU_VIDEO_SHARE = 24;
83 static public final int MENU_VIDEO_TOSS = 27;
84
The Android Open Source Projecte3f45162009-03-11 12:11:58 -070085 static private final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L;
86
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080087 public static final int NO_STORAGE_ERROR = -1;
88 public static final int CANNOT_STAT_ERROR = -2;
89
90 /** Activity result code used to report crop results.
91 */
92 public static final int RESULT_COMMON_MENU_CROP = 490;
93
94 public interface MenuItemsResult {
95 public void gettingReadyToOpen(Menu menu, ImageManager.IImage image);
96 public void aboutToCall(MenuItem item, ImageManager.IImage image);
97 }
98
99 public interface MenuInvoker {
100 public void run(MenuCallback r);
101 }
102
103 public interface MenuCallback {
104 public void run(Uri uri, ImageManager.IImage image);
105 }
106
107 private static void closeSilently(Closeable target) {
108 try {
109 if (target != null) target.close();
110 } catch (Throwable t) {
111 // ignore all exceptions, that's what silently means
112 }
113 }
114
115 public static long getImageFileSize(ImageManager.IImage image) {
116 java.io.InputStream data = image.fullSizeImageData();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800117 if (data == null) return -1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800118 try {
119 return data.available();
120 } catch (java.io.IOException ex) {
121 return -1;
122 } finally {
123 closeSilently(data);
124 }
125 }
126
127 static MenuItemsResult addImageMenuItems(
128 Menu menu,
129 int inclusions,
130 final boolean isImage,
131 final Activity activity,
132 final Handler handler,
133 final Runnable onDelete,
134 final MenuInvoker onInvoke) {
135 final ArrayList<MenuItem> requiresWriteAccessItems = new ArrayList<MenuItem>();
136 final ArrayList<MenuItem> requiresNoDrmAccessItems = new ArrayList<MenuItem>();
137
138 if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
139 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM, MENU_IMAGE_ROTATE,
140 40, R.string.rotate).setIcon(android.R.drawable.ic_menu_rotate);
141 // Don't show the rotate submenu if the item at hand is read only
142 // since the items within the submenu won't be shown anyway. This is
143 // really a framework bug in that it shouldn't show the submenu if
144 // the submenu has no visible items.
145 requiresWriteAccessItems.add(rotateSubmenu.getItem());
146 if (rotateSubmenu != null) {
147 requiresWriteAccessItems.add(rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50, R.string.rotate_left).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
148 public boolean onMenuItemClick(MenuItem item) {
149 onInvoke.run(new MenuCallback() {
150 public void run(Uri u, ImageManager.IImage image) {
151 if (image == null || image.isReadonly())
152 return;
153 image.rotateImageBy(-90);
154 }
155 });
156 return true;
157 }
158 }).setAlphabeticShortcut('l'));
159 requiresWriteAccessItems.add(rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60, R.string.rotate_right).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
160 public boolean onMenuItemClick(MenuItem item) {
161 onInvoke.run(new MenuCallback() {
162 public void run(Uri u, ImageManager.IImage image) {
163 if (image == null || image.isReadonly())
164 return;
165
166 image.rotateImageBy(90);
167 }
168 });
169 return true;
170 }
171 }).setAlphabeticShortcut('r'));
172 }
173 }
174
175 if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
176 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
177 R.string.camera_crop).setOnMenuItemClickListener(
178 new MenuItem.OnMenuItemClickListener() {
179 public boolean onMenuItemClick(MenuItem item) {
180 onInvoke.run(new MenuCallback() {
181 public void run(Uri u, ImageManager.IImage image) {
182 if (u == null)
183 return;
184
185 Intent cropIntent = new Intent();
186 cropIntent.setClass(activity, CropImage.class);
187 cropIntent.setData(u);
188 activity.startActivityForResult(cropIntent, RESULT_COMMON_MENU_CROP);
189 }
190 });
191 return true;
192 }
193 });
194 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
195 requiresWriteAccessItems.add(autoCrop);
196 }
197
198 if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
199 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75, R.string.camera_set);
200 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
201
202 setMenu.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
203 public boolean onMenuItemClick(MenuItem item) {
204 onInvoke.run(new MenuCallback() {
205 public void run(Uri u, ImageManager.IImage image) {
206 if (u == null || image == null)
207 return;
208
209 if (Config.LOGV)
210 Log.v(TAG, "in callback u is " + u + "; mime type is " + image.getMimeType());
211 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
212 intent.setDataAndType(u, image.getMimeType());
213 intent.putExtra("mimeType", image.getMimeType());
214 activity.startActivity(Intent.createChooser(intent, activity.getText(R.string.setImage)));
215 }
216 });
217 return true;
218 }
219 });
220 }
221
222 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
223 if (Config.LOGV)
224 Log.v(TAG, ">>>>> add share");
225 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
226 R.string.camera_share).setOnMenuItemClickListener(
227 new MenuItem.OnMenuItemClickListener() {
228 public boolean onMenuItemClick(MenuItem item) {
229 onInvoke.run(new MenuCallback() {
230 public void run(Uri u, ImageManager.IImage image) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700231 if (image == null) return;
232 if (!isImage && getImageFileSize(image) > SHARE_FILE_LENGTH_LIMIT ) {
233 Toast.makeText(activity,
234 R.string.too_large_to_attach, Toast.LENGTH_LONG).show();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800235 return;
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700236 }
237
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800238 Intent intent = new Intent();
239 intent.setAction(Intent.ACTION_SEND);
240 String mimeType = image.getMimeType();
241 intent.setType(mimeType);
242 intent.putExtra(Intent.EXTRA_STREAM, u);
243 boolean isImage = ImageManager.isImageMimeType(mimeType);
244 try {
245 activity.startActivity(Intent.createChooser(intent,
246 activity.getText(
247 isImage ? R.string.sendImage : R.string.sendVideo)));
248 } catch (android.content.ActivityNotFoundException ex) {
249 Toast.makeText(activity,
250 isImage ? R.string.no_way_to_share_image
251 : R.string.no_way_to_share_video,
252 Toast.LENGTH_SHORT).show();
253 }
254 }
255 });
256 return true;
257 }
258 });
259 item1.setIcon(android.R.drawable.ic_menu_share);
260 MenuItem item = item1;
261 requiresNoDrmAccessItems.add(item);
262 }
263
264 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
265 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS, 70, R.string.camera_toss);
266 requiresWriteAccessItems.add(deleteItem);
267 deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
268 public boolean onMenuItemClick(MenuItem item) {
269 deleteImageImpl(activity, onDelete, isImage);
270 return true;
271 }
272 })
273 .setAlphabeticShortcut('d')
274 .setIcon(android.R.drawable.ic_menu_delete);
275 }
276
277 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
278 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
279 public boolean onMenuItemClick(MenuItem item) {
280 onInvoke.run(new MenuCallback() {
281 public void run(Uri u, ImageManager.IImage image) {
282 if (image == null)
283 return;
284
285 AlertDialog.Builder builder = new AlertDialog.Builder(activity);
286
287 final View d = View.inflate(activity, R.layout.detailsview, null);
288
289 ImageView imageView = (ImageView) d.findViewById(R.id.details_thumbnail_image);
290 imageView.setImageBitmap(image.miniThumbBitmap());
291
292 TextView textView = (TextView) d.findViewById(R.id.details_image_title);
293 textView.setText(image.getDisplayName());
294
295 long length = getImageFileSize(image);
296 String lengthString = lengthString = length < 0 ? ""
297 : android.text.format.Formatter.formatFileSize(activity, length);
298 ((TextView)d.findViewById(R.id.details_file_size_value))
299 .setText(lengthString);
300
301 int dimensionWidth = 0;
302 int dimensionHeight = 0;
303 if (isImage) {
304 dimensionWidth = image.getWidth();
305 dimensionHeight = image.getHeight();
306 d.findViewById(R.id.details_duration_row).setVisibility(View.GONE);
307 d.findViewById(R.id.details_frame_rate_row).setVisibility(View.GONE);
308 d.findViewById(R.id.details_bit_rate_row).setVisibility(View.GONE);
309 d.findViewById(R.id.details_format_row).setVisibility(View.GONE);
310 d.findViewById(R.id.details_codec_row).setVisibility(View.GONE);
311 } else {
312 MediaMetadataRetriever retriever = new MediaMetadataRetriever();
313 try {
314 retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
315 retriever.setDataSource(image.getDataPath());
316 try {
317 dimensionWidth = Integer.parseInt(
318 retriever.extractMetadata(
319 MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
320 dimensionHeight = Integer.parseInt(
321 retriever.extractMetadata(
322 MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
323 } catch (NumberFormatException e) {
324 dimensionWidth = 0;
325 dimensionHeight = 0;
326 }
327
328 try {
329 int durationMs = Integer.parseInt(retriever.extractMetadata(
330 MediaMetadataRetriever.METADATA_KEY_DURATION));
331 String durationValue = formatDuration(
332 activity, durationMs);
333 ((TextView)d.findViewById(R.id.details_duration_value))
334 .setText(durationValue);
335 } catch (NumberFormatException e) {
336 d.findViewById(R.id.details_frame_rate_row)
337 .setVisibility(View.GONE);
338 }
339
340 try {
341 String frame_rate = String.format(
342 activity.getString(R.string.details_fps),
343 Integer.parseInt(
344 retriever.extractMetadata(
345 MediaMetadataRetriever.METADATA_KEY_FRAME_RATE)));
346 ((TextView)d.findViewById(R.id.details_frame_rate_value))
347 .setText(frame_rate);
348 } catch (NumberFormatException e) {
349 d.findViewById(R.id.details_frame_rate_row)
350 .setVisibility(View.GONE);
351 }
352
353 try {
354 long bitRate = Long.parseLong(retriever.extractMetadata(
355 MediaMetadataRetriever.METADATA_KEY_BIT_RATE));
356 String bps;
357 if (bitRate < 1000000) {
358 bps = String.format(
359 activity.getString(R.string.details_kbps),
360 bitRate / 1000);
361 } else {
362 bps = String.format(
363 activity.getString(R.string.details_mbps),
364 ((double) bitRate) / 1000000.0);
365 }
366 ((TextView)d.findViewById(R.id.details_bit_rate_value))
367 .setText(bps);
368 } catch (NumberFormatException e) {
369 d.findViewById(R.id.details_bit_rate_row)
370 .setVisibility(View.GONE);
371 }
372
373 String format = retriever.extractMetadata(
374 MediaMetadataRetriever.METADATA_KEY_VIDEO_FORMAT);
375 ((TextView)d.findViewById(R.id.details_format_value))
376 .setText(format);
377
378 String codec = retriever.extractMetadata(
379 MediaMetadataRetriever.METADATA_KEY_CODEC);
380
381 if (codec == null) {
382 d.findViewById(R.id.details_codec_row).
383 setVisibility(View.GONE);
384 } else {
385 ((TextView)d.findViewById(R.id.details_codec_value))
386 .setText(codec);
387 }
388 } catch(RuntimeException ex) {
389 // Assume this is a corrupt video file.
390 } finally {
391 try {
392 retriever.release();
393 } catch (RuntimeException ex) {
394 // Ignore failures while cleaning up.
395 }
396 }
397 }
398
399 String dimensionsString = String.format(
400 activity.getString(R.string.details_dimension_x),
401 dimensionWidth, dimensionHeight);
402 ((TextView)d.findViewById(R.id.details_resolution_value))
403 .setText(dimensionsString);
404
405 String dateString = "";
406 long dateTaken = image.getDateTaken();
407 if (dateTaken != 0) {
408 java.util.Date date = new java.util.Date(image.getDateTaken());
409 java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat();
410 dateString = dateFormat.format(date);
411
412 ((TextView)d.findViewById(R.id.details_date_taken_value))
413 .setText(dateString);
414 } else {
415 d.findViewById(R.id.details_date_taken_row)
416 .setVisibility(View.GONE);
417 }
418
419 builder.setNeutralButton(R.string.details_ok,
420 new DialogInterface.OnClickListener() {
421 public void onClick(DialogInterface dialog, int which) {
422 dialog.dismiss();
423 }
424 });
425
426 builder.setIcon(android.R.drawable.ic_dialog_info)
427 .setTitle(R.string.details_panel_title)
428 .setView(d)
429 .show();
430
431 }
432 });
433 return true;
434 }
435 });
436 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
437 }
438
439 if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
440 menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
441 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
442 public boolean onMenuItemClick(MenuItem item) {
443 onInvoke.run(new MenuCallback() {
444 public void run(Uri uri, IImage image) {
445 if (image != null) {
446 Intent intent = new Intent(Intent.ACTION_VIEW,
447 image.fullSizeImageUri());
448 activity.startActivity(intent);
449 }
450 }});
451 return true;
452 }
453 });
454 }
455
456
457 return new MenuItemsResult() {
458 public void gettingReadyToOpen(Menu menu, ImageManager.IImage image) {
459 // protect against null here. this isn't strictly speaking required
460 // but if a client app isn't handling sdcard removal properly it
461 // could happen
462 if (image == null) {
463 return;
464 }
465 boolean readOnly = image.isReadonly();
466 boolean isDrm = image.isDrm();
467 if (Config.LOGV)
468 Log.v(TAG, "readOnly: " + readOnly + "; drm: " + isDrm);
469 for (MenuItem item: requiresWriteAccessItems) {
470 if (Config.LOGV)
471 Log.v(TAG, "item is " + item.toString());
472 item.setVisible(!readOnly);
473 item.setEnabled(!readOnly);
474 }
475 for (MenuItem item: requiresNoDrmAccessItems) {
476 if (Config.LOGV)
477 Log.v(TAG, "item is " + item.toString());
478 item.setVisible(!isDrm);
479 item.setEnabled(!isDrm);
480 }
481 }
482 public void aboutToCall(MenuItem menu, ImageManager.IImage image) {
483 }
484 };
485 }
486
487 static void deletePhoto(Activity activity, Runnable onDelete) {
488 deleteImageImpl(activity, onDelete, true);
489 }
490
491 static void deleteImage(Activity activity, Runnable onDelete, IImage image) {
492 if (image != null) {
493 deleteImageImpl(activity, onDelete, ImageManager.isImage(image));
494 }
495 }
496
497 private static void deleteImageImpl(Activity activity, final Runnable onDelete, boolean isPhoto) {
498 boolean confirm = android.preference.PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("pref_gallery_confirm_delete_key", true);
499 if (!confirm) {
500 if (onDelete != null)
501 onDelete.run();
502 } else {
503 displayDeleteDialog(activity, onDelete, isPhoto);
504 }
505 }
506
507 public static void displayDeleteDialog(Activity activity,
508 final Runnable onDelete, boolean isPhoto) {
509 android.app.AlertDialog.Builder b = new android.app.AlertDialog.Builder(activity);
510 b.setIcon(android.R.drawable.ic_dialog_alert);
511 b.setTitle(R.string.confirm_delete_title);
512 b.setMessage(isPhoto? R.string.confirm_delete_message
513 : R.string.confirm_delete_video_message);
514 b.setPositiveButton(android.R.string.ok, new android.content.DialogInterface.OnClickListener() {
515 public void onClick(android.content.DialogInterface v, int x) {
516 if (onDelete != null)
517 onDelete.run();
518 }
519 });
520 b.setNegativeButton(android.R.string.cancel, new android.content.DialogInterface.OnClickListener() {
521 public void onClick(android.content.DialogInterface v, int x) {
522
523 }
524 });
525 b.create().show();
526 }
527
528 static void addSwitchModeMenuItem(Menu menu, final Activity activity,
529 final boolean switchToVideo) {
530 int group = switchToVideo ? MenuHelper.IMAGE_MODE_ITEM : MenuHelper.VIDEO_MODE_ITEM;
531 int labelId = switchToVideo ? R.string.switch_to_video_lable
532 : R.string.switch_to_camera_lable;
533 int iconId = switchToVideo ? R.drawable.ic_menu_camera_video_view
534 : android.R.drawable.ic_menu_camera;
535 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0,
536 labelId).setOnMenuItemClickListener(
537 new OnMenuItemClickListener() {
538 public boolean onMenuItemClick(MenuItem item) {
539 String action = switchToVideo ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
540 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
541 Intent intent = new Intent(action);
542 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
543 activity.finish();
544 activity.startActivity(intent);
545 return true;
546 }
547 });
548 item.setIcon(iconId);
549 }
550
551 static void gotoStillImageCapture(Activity activity) {
552 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
553 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
554 try {
555 activity.startActivity(intent);
556 } catch (ActivityNotFoundException e) {
557 Log.e(TAG, "Could not start still image capture activity", e);
558 }
559 }
560
561 static void gotoCameraImageGallery(Activity activity) {
562 gotoGallery(activity, R.string.gallery_camera_bucket_name, ImageManager.INCLUDE_IMAGES);
563 }
564
565 static void gotoCameraVideoGallery(Activity activity) {
566 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
567 ImageManager.INCLUDE_VIDEOS);
568 }
569
570 static private void gotoGallery(Activity activity, int windowTitleId, int mediaTypes) {
571 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("bucketId",
572 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
573 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700574 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800575 intent.putExtra("windowTitle", activity.getString(windowTitleId));
576 intent.putExtra("mediaTypes", mediaTypes);
577 // Request unspecified so that we match the current camera orientation rather than
578 // matching the "flip orientation" preference.
579 // Disabled because people don't care for it. Also it's
580 // not as compelling now that we have implemented have quick orientation flipping.
581 // intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
582 // android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
583 try {
584 activity.startActivity(intent);
585 } catch (ActivityNotFoundException e) {
586 Log.e(TAG, "Could not start gallery activity", e);
587 }
588 }
589
590 static void addCaptureMenuItems(Menu menu, final Activity activity) {
591
592 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
593 .setOnMenuItemClickListener(
594 new MenuItem.OnMenuItemClickListener() {
595 public boolean onMenuItemClick(MenuItem item) {
596 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700597 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800598 try {
599 activity.startActivity(intent);
600 } catch (android.content.ActivityNotFoundException e) {
601 // Ignore exception
602 }
603 return true;
604 }
605 })
606 .setIcon(android.R.drawable.ic_menu_camera);
607
608 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
609 .setOnMenuItemClickListener(
610 new MenuItem.OnMenuItemClickListener() {
611 public boolean onMenuItemClick(MenuItem item) {
612 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700613 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800614 try {
615 activity.startActivity(intent);
616 } catch (android.content.ActivityNotFoundException e) {
617 // Ignore exception
618 }
619 return true;
620 }
621 })
622 .setIcon(R.drawable.ic_menu_camera_video_view);
623 }
624 static MenuItem addFlipOrientation(Menu menu, final Activity activity, final SharedPreferences prefs) {
625 // position 41 after rotate
626 // D
627 return menu
628 .add(Menu.CATEGORY_SECONDARY, 304, 41, R.string.flip_orientation)
629 .setOnMenuItemClickListener(
630 new MenuItem.OnMenuItemClickListener() {
631 public boolean onMenuItemClick(MenuItem item) {
632 // Check what our actual orientation is
633 int current = activity.getResources().getConfiguration().orientation;
634 int newOrientation = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
635 if (current == Configuration.ORIENTATION_LANDSCAPE) {
636 newOrientation = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
637 }
638 SharedPreferences.Editor editor = prefs.edit();
639 editor.putInt("nuorientation", newOrientation);
640 editor.commit();
641 requestOrientation(activity, prefs, true);
642 return true;
643 }
644 })
645 .setIcon(android.R.drawable.ic_menu_always_landscape_portrait);
646 }
647
648 static void requestOrientation(Activity activity, SharedPreferences prefs) {
649 requestOrientation(activity, prefs, false);
650 }
651
652 static private void requestOrientation(Activity activity, SharedPreferences prefs,
653 boolean ignoreIntentExtra) {
654 int req = prefs.getInt("nuorientation",
655 android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
656 // A little trick: use USER instead of UNSPECIFIED, so we ignore the
657 // orientation set by the activity below. It may have forced a landscape
658 // orientation, which the user has now cleared here.
659 if (req == android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
660 req = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
661 }
662 if (! ignoreIntentExtra) {
663 Intent intent = activity.getIntent();
664 req = intent.getIntExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, req);
665 }
666 activity.setRequestedOrientation(req);
667 }
668
669 static void setFlipOrientationEnabled(Activity activity, MenuItem flipItem) {
670 int keyboard = activity.getResources().getConfiguration().hardKeyboardHidden;
671 flipItem.setEnabled(keyboard != android.content.res.Configuration.HARDKEYBOARDHIDDEN_NO);
672 }
673
674 public static String formatDuration(final Activity activity, int durationMs) {
675 int duration = durationMs / 1000;
676 int h = duration / 3600;
677 int m = (duration - h * 3600) / 60;
678 int s = duration - (h * 3600 + m * 60);
679 String durationValue;
680 if (h == 0) {
681 durationValue = String.format(
682 activity.getString(R.string.details_ms), m, s);
683 } else {
684 durationValue = String.format(
685 activity.getString(R.string.details_hms), h, m, s);
686 }
687 return durationValue;
688 }
689
690 public static void showStorageToast(Activity activity) {
691 showStorageToast(activity, calculatePicturesRemaining());
692 }
693
694 public static void showStorageToast(Activity activity, int remaining) {
695 String noStorageText = null;
696
697 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
698 String state = Environment.getExternalStorageState();
699 if (state == Environment.MEDIA_CHECKING) {
700 noStorageText = activity.getString(R.string.preparing_sd);
701 } else {
702 noStorageText = activity.getString(R.string.no_storage);
703 }
704 } else if (remaining < 1) {
705 noStorageText = activity.getString(R.string.not_enough_space);
706 }
707
708 if (noStorageText != null) {
709 Toast.makeText(activity, noStorageText, 5000).show();
710 }
711 }
712
713 public static int calculatePicturesRemaining() {
714 try {
715 if (!ImageManager.hasStorage()) {
716 return NO_STORAGE_ERROR;
717 } else {
718 String storageDirectory = Environment.getExternalStorageDirectory().toString();
719 StatFs stat = new StatFs(storageDirectory);
720 float remaining = ((float)stat.getAvailableBlocks() * (float)stat.getBlockSize()) / 400000F;
721 return (int)remaining;
722 }
723 } catch (Exception ex) {
724 // if we can't stat the filesystem then we don't know how many
725 // pictures are remaining. it might be zero but just leave it
726 // blank since we really don't know.
727 return CANNOT_STAT_ERROR;
728 }
729 }
730}
731