blob: ed208a619ad1068c9d47b12cee5137f5fff2c301 [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
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080019import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.ActivityNotFoundException;
Owen Lin6795ff12009-06-09 13:39:00 -070022import android.content.Context;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080023import android.content.DialogInterface;
24import android.content.Intent;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080025import android.content.DialogInterface.OnClickListener;
Ray Chen0f0af522009-04-22 13:26:07 +080026import android.location.Geocoder;
repo synca274cf12009-07-06 15:05:23 +080027import android.media.ExifInterface;
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;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080033import android.preference.PreferenceManager;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080034import android.provider.MediaStore;
35import android.provider.MediaStore.Images;
Owen Lin937fc482009-04-14 02:02:51 -070036import android.text.format.Formatter;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080037import android.util.Log;
38import android.view.Menu;
39import android.view.MenuItem;
40import android.view.SubMenu;
41import android.view.View;
Owen Lin059daa32009-05-18 15:31:17 -070042import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080043import android.widget.ImageView;
44import android.widget.TextView;
45import android.widget.Toast;
46
Owen Line594b192009-08-13 18:04:45 +080047import com.android.camera.gallery.IImage;
48
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070049import java.io.Closeable;
repo syncaa7075c2009-06-24 14:59:48 +080050import java.lang.ref.WeakReference;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070051import java.text.SimpleDateFormat;
52import java.util.ArrayList;
53import java.util.Date;
Ray Chend5142de2009-05-07 15:24:48 +080054import java.util.HashMap;
Ray Chen0f0af522009-04-22 13:26:07 +080055import java.util.List;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080056
Ray Chend5142de2009-05-07 15:24:48 +080057/**
58 * A utility class to handle various kinds of menu operations.
59 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080060public class MenuHelper {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070061 private static final String TAG = "MenuHelper";
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080062
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070063 public static final int GENERIC_ITEM = 1;
64 public static final int IMAGE_SAVING_ITEM = 2;
65 public static final int VIDEO_SAVING_ITEM = 3;
66 public static final int IMAGE_MODE_ITEM = 4;
67 public static final int VIDEO_MODE_ITEM = 5;
68 public static final int MENU_ITEM_MAX = 5;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080069
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070070 public static final int INCLUDE_ALL = 0xFFFFFFFF;
71 public static final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
72 public static final int INCLUDE_SHARE_MENU = (1 << 1);
73 public static final int INCLUDE_SET_MENU = (1 << 2);
74 public static final int INCLUDE_CROP_MENU = (1 << 3);
75 public static final int INCLUDE_DELETE_MENU = (1 << 4);
76 public static final int INCLUDE_ROTATE_MENU = (1 << 5);
77 public static final int INCLUDE_DETAILS_MENU = (1 << 6);
Ray Chen0a5a78c2009-04-24 14:13:01 +080078 public static final int INCLUDE_SHOWMAP_MENU = (1 << 7);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080079
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070080 public static final int MENU_SWITCH_CAMERA_MODE = 0;
81 public static final int MENU_CAPTURE_PICTURE = 1;
82 public static final int MENU_CAPTURE_VIDEO = 2;
83 public static final int MENU_IMAGE_SHARE = 10;
84 public static final int MENU_IMAGE_SET = 14;
85 public static final int MENU_IMAGE_SET_WALLPAPER = 15;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070086 public static final int MENU_IMAGE_CROP = 18;
87 public static final int MENU_IMAGE_ROTATE = 19;
88 public static final int MENU_IMAGE_ROTATE_LEFT = 20;
89 public static final int MENU_IMAGE_ROTATE_RIGHT = 21;
90 public static final int MENU_IMAGE_TOSS = 22;
91 public static final int MENU_VIDEO_PLAY = 23;
92 public static final int MENU_VIDEO_SHARE = 24;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080093
94 public static final int NO_STORAGE_ERROR = -1;
95 public static final int CANNOT_STAT_ERROR = -2;
Ray Chen0f0af522009-04-22 13:26:07 +080096 public static final String EMPTY_STRING = "";
Ray Chend5142de2009-05-07 15:24:48 +080097 public static final String JPEG_MIME_TYPE = "image/jpeg";
Ray Chen0a5a78c2009-04-24 14:13:01 +080098 // valid range is -180f to +180f
99 public static final float INVALID_LATLNG = 255f;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800100
101 /** Activity result code used to report crop results.
102 */
103 public static final int RESULT_COMMON_MENU_CROP = 490;
104
105 public interface MenuItemsResult {
Owen Lin101d5282009-04-03 16:20:08 -0700106 public void gettingReadyToOpen(Menu menu, IImage image);
107 public void aboutToCall(MenuItem item, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800108 }
109
110 public interface MenuInvoker {
111 public void run(MenuCallback r);
112 }
113
114 public interface MenuCallback {
Owen Lin101d5282009-04-03 16:20:08 -0700115 public void run(Uri uri, IImage image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800116 }
117
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700118 public static void closeSilently(Closeable c) {
119 if (c != null) {
120 try {
121 c.close();
122 } catch (Throwable e) {
123 // ignore
124 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800125 }
126 }
127
Owen Lin101d5282009-04-03 16:20:08 -0700128 public static long getImageFileSize(IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800129 java.io.InputStream data = image.fullSizeImageData();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800130 if (data == null) return -1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800131 try {
132 return data.available();
133 } catch (java.io.IOException ex) {
134 return -1;
135 } finally {
136 closeSilently(data);
137 }
138 }
139
Chih-Chung Chang47bf4ce2009-03-25 01:51:03 -0700140 // This is a hack before we find a solution to pass a permission to other
Chih-Chung Changb2a97652009-07-10 18:39:49 +0800141 // applications. See bug #1735149, #1836138.
142 // Checks if the URI is on our whitelist:
143 // content://media/... (MediaProvider)
144 // file:///sdcard/... (Browser download)
145 public static boolean isWhiteListUri(Uri uri) {
146 if (uri == null) return false;
147
148 String scheme = uri.getScheme();
149 String authority = uri.getAuthority();
150
151 if (scheme.equals("content") && authority.equals("media")) {
152 return true;
153 }
154
155 if (scheme.equals("file")) {
156 List<String> p = uri.getPathSegments();
157
158 if (p.size() >= 1 && p.get(0).equals("sdcard")) {
159 return true;
160 }
161 }
162
163 return false;
Chih-Chung Chang47bf4ce2009-03-25 01:51:03 -0700164 }
Owen Lin937fc482009-04-14 02:02:51 -0700165
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700166 public static void enableShareMenuItem(Menu menu, boolean enabled) {
167 MenuItem item = menu.findItem(MENU_IMAGE_SHARE);
168 if (item != null) {
169 item.setVisible(enabled);
170 item.setEnabled(enabled);
171 }
172 }
173
Ray Chen0f0af522009-04-22 13:26:07 +0800174 private static void setDetailsValue(View d, String text, int valueId) {
175 ((TextView) d.findViewById(valueId)).setText(text);
176 }
177
178 private static void hideDetailsRow(View d, int rowId) {
179 d.findViewById(rowId).setVisibility(View.GONE);
180 }
181
repo syncaa7075c2009-06-24 14:59:48 +0800182 private static class UpdateLocationCallback implements
183 ReverseGeocoderTask.Callback {
184 WeakReference<View> mView;
185
186 public UpdateLocationCallback(WeakReference<View> view) {
187 mView = view;
188 }
189
190 public void onComplete(String location) {
191 // View d is per-thread data, so when setDetailsValue is
192 // executed by UI thread, it doesn't matter whether the
193 // details dialog is dismissed or not.
194 View view = mView.get();
195 if (view == null) return;
196 if (location != MenuHelper.EMPTY_STRING) {
197 MenuHelper.setDetailsValue(view, location,
198 R.id.details_location_value);
199 } else {
200 MenuHelper.hideDetailsRow(view, R.id.details_location_row);
201 }
202 }
203 }
204
205 private static void setLatLngDetails(final View d, Activity context,
Ray Chend5142de2009-05-07 15:24:48 +0800206 HashMap<String, String> exifData) {
repo synca274cf12009-07-06 15:05:23 +0800207 float[] latlng = ExifInterface.getLatLng(exifData);
Ray Chend5142de2009-05-07 15:24:48 +0800208 if (latlng != null) {
209 setDetailsValue(d, String.valueOf(latlng[0]),
210 R.id.details_latitude_value);
211 setDetailsValue(d, String.valueOf(latlng[1]),
repo syncaa7075c2009-06-24 14:59:48 +0800212 R.id.details_longitude_value);
213
214 if (latlng[0] == INVALID_LATLNG || latlng[1] == INVALID_LATLNG) {
215 hideDetailsRow(d, R.id.details_latitude_row);
216 hideDetailsRow(d, R.id.details_longitude_row);
217 hideDetailsRow(d, R.id.details_location_row);
218 return;
219 }
220
221 UpdateLocationCallback cb = new UpdateLocationCallback(
222 new WeakReference<View>(d));
223 Geocoder geocoder = new Geocoder(context);
224 new ReverseGeocoderTask(geocoder, latlng, cb).execute();
Ray Chend5142de2009-05-07 15:24:48 +0800225 } else {
226 hideDetailsRow(d, R.id.details_latitude_row);
227 hideDetailsRow(d, R.id.details_longitude_row);
228 hideDetailsRow(d, R.id.details_location_row);
Ray Chen0f0af522009-04-22 13:26:07 +0800229 }
Ray Chen0f0af522009-04-22 13:26:07 +0800230 }
231
Ray Chend5142de2009-05-07 15:24:48 +0800232 private static HashMap<String, String> getExifData(IImage image) {
233 if (!JPEG_MIME_TYPE.equals(image.getMimeType())) {
234 return null;
235 }
236
repo synca274cf12009-07-06 15:05:23 +0800237 return ExifInterface.loadExifData(image.getDataPath());
Ray Chend5142de2009-05-07 15:24:48 +0800238 }
Ray Chen0a5a78c2009-04-24 14:13:01 +0800239 // Called when "Show on Maps" is clicked.
240 // Displays image location on Google Maps for further operations.
241 private static boolean onShowMapClicked(MenuInvoker onInvoke,
242 final Handler handler,
243 final Activity activity) {
244 onInvoke.run(new MenuCallback() {
245 public void run(Uri u, IImage image) {
246 if (image == null) {
247 return;
248 }
repo synca274cf12009-07-06 15:05:23 +0800249 float[] latlng = ExifInterface.getLatLng(getExifData(image));
Ray Chend5142de2009-05-07 15:24:48 +0800250 if (latlng == null) {
Ray Chen0a5a78c2009-04-24 14:13:01 +0800251 handler.post(new Runnable() {
252 public void run() {
253 Toast.makeText(activity,
254 R.string.no_location_image,
255 Toast.LENGTH_SHORT).show();
256 }
257 });
258 return;
259 }
260
261 // Can't use geo:latitude,longitude because it only centers
262 // the MapView to specified location, but we need a bubble
263 // for further operations (routing to/from).
264 // The q=(lat, lng) syntax is suggested by geo-team.
265 String uri = "http://maps.google.com/maps?f=q&" +
Ray Chend5142de2009-05-07 15:24:48 +0800266 "q=(" + latlng[0] + "," + latlng[1] + ")";
Ray Chen0a5a78c2009-04-24 14:13:01 +0800267 activity.startActivity(new Intent(
268 android.content.Intent.ACTION_VIEW,
269 Uri.parse(uri)));
270 }
271 });
272 return true;
273 }
274
Ray Chend5142de2009-05-07 15:24:48 +0800275 private static void hideExifInformation(View d) {
276 hideDetailsRow(d, R.id.details_resolution_row);
277 hideDetailsRow(d, R.id.details_make_row);
278 hideDetailsRow(d, R.id.details_model_row);
279 hideDetailsRow(d, R.id.details_whitebalance_row);
280 hideDetailsRow(d, R.id.details_latitude_row);
281 hideDetailsRow(d, R.id.details_longitude_row);
282 hideDetailsRow(d, R.id.details_location_row);
283 }
284
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800285 private static void showExifInformation(IImage image, View d,
286 Activity activity) {
Ray Chend5142de2009-05-07 15:24:48 +0800287 HashMap<String, String> exifData = getExifData(image);
288 if (exifData == null) {
289 hideExifInformation(d);
290 return;
291 }
292
293 String value = exifData.get(ExifInterface.TAG_MAKE);
294 if (value != null) {
295 setDetailsValue(d, value, R.id.details_make_value);
296 } else {
297 hideDetailsRow(d, R.id.details_make_row);
298 }
299
300 value = exifData.get(ExifInterface.TAG_MODEL);
301 if (value != null) {
302 setDetailsValue(d, value, R.id.details_model_value);
303 } else {
304 hideDetailsRow(d, R.id.details_model_row);
305 }
306
307 value = exifData.get(ExifInterface.TAG_WHITE_BALANCE);
308 if (value != null) {
309 value = ExifInterface.whiteBalanceToString(
310 Integer.parseInt(value));
311 }
312 if (value != null && value != EMPTY_STRING) {
313 setDetailsValue(d, value, R.id.details_whitebalance_value);
314 } else {
315 hideDetailsRow(d, R.id.details_whitebalance_row);
316 }
317
318 setLatLngDetails(d, activity, exifData);
319 }
320
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700321 // Called when "Details" is clicked.
322 // Displays detailed information about the image/video.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700323 private static boolean onDetailsClicked(MenuInvoker onInvoke,
Ray Chen0a5a78c2009-04-24 14:13:01 +0800324 final Handler handler,
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800325 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700326 onInvoke.run(new MenuCallback() {
327 public void run(Uri u, IImage image) {
328 if (image == null) {
329 return;
330 }
331
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800332 final AlertDialog.Builder builder =
333 new AlertDialog.Builder(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700334
335 final View d = View.inflate(activity, R.layout.detailsview,
336 null);
337
338 ImageView imageView = (ImageView) d.findViewById(
339 R.id.details_thumbnail_image);
340 imageView.setImageBitmap(image.miniThumbBitmap());
341
342 TextView textView = (TextView) d.findViewById(
343 R.id.details_image_title);
344 textView.setText(image.getDisplayName());
345
346 long length = getImageFileSize(image);
Owen Lin937fc482009-04-14 02:02:51 -0700347 String lengthString = length < 0
Ray Chen0f0af522009-04-22 13:26:07 +0800348 ? EMPTY_STRING
Owen Lin937fc482009-04-14 02:02:51 -0700349 : Formatter.formatFileSize(activity, length);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700350 ((TextView) d
351 .findViewById(R.id.details_file_size_value))
352 .setText(lengthString);
353
354 int dimensionWidth = 0;
355 int dimensionHeight = 0;
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800356 if (ImageManager.isImage(image)) {
Ray Chen0f0af522009-04-22 13:26:07 +0800357 // getWidth is much slower than reading from EXIF
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700358 dimensionWidth = image.getWidth();
359 dimensionHeight = image.getHeight();
360 d.findViewById(R.id.details_duration_row)
361 .setVisibility(View.GONE);
362 d.findViewById(R.id.details_frame_rate_row)
363 .setVisibility(View.GONE);
364 d.findViewById(R.id.details_bit_rate_row)
365 .setVisibility(View.GONE);
366 d.findViewById(R.id.details_format_row)
367 .setVisibility(View.GONE);
368 d.findViewById(R.id.details_codec_row)
369 .setVisibility(View.GONE);
370 } else {
371 MediaMetadataRetriever retriever
372 = new MediaMetadataRetriever();
373 try {
374 retriever.setMode(MediaMetadataRetriever
375 .MODE_GET_METADATA_ONLY);
376 retriever.setDataSource(image.getDataPath());
377 try {
378 dimensionWidth = Integer.parseInt(
379 retriever.extractMetadata(
380 MediaMetadataRetriever
381 .METADATA_KEY_VIDEO_WIDTH));
382 dimensionHeight = Integer.parseInt(
383 retriever.extractMetadata(
384 MediaMetadataRetriever
385 .METADATA_KEY_VIDEO_HEIGHT));
386 } catch (NumberFormatException e) {
387 dimensionWidth = 0;
388 dimensionHeight = 0;
389 }
390
391 try {
392 int durationMs = Integer.parseInt(
393 retriever.extractMetadata(
394 MediaMetadataRetriever
395 .METADATA_KEY_DURATION));
396 String durationValue = formatDuration(
397 activity, durationMs);
398 ((TextView) d.findViewById(
399 R.id.details_duration_value))
400 .setText(durationValue);
401 } catch (NumberFormatException e) {
402 d.findViewById(
403 R.id.details_frame_rate_row)
404 .setVisibility(View.GONE);
405 }
406
407 try {
408 String frameRate = String.format(
409 activity.getString(R.string.details_fps),
410 Integer.parseInt(
411 retriever.extractMetadata(
412 MediaMetadataRetriever
413 .METADATA_KEY_FRAME_RATE)));
414 ((TextView) d.findViewById(
415 R.id.details_frame_rate_value))
416 .setText(frameRate);
417 } catch (NumberFormatException e) {
418 d.findViewById(
419 R.id.details_frame_rate_row)
420 .setVisibility(View.GONE);
421 }
422
423 try {
424 long bitRate = Long.parseLong(
425 retriever.extractMetadata(
426 MediaMetadataRetriever
427 .METADATA_KEY_BIT_RATE));
428 String bps;
429 if (bitRate < 1000000) {
430 bps = String.format(
431 activity.getString(
432 R.string.details_kbps),
433 bitRate / 1000);
434 } else {
435 bps = String.format(
436 activity.getString(
437 R.string.details_mbps),
Owen Lin937fc482009-04-14 02:02:51 -0700438 (bitRate) / 1000000.0);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700439 }
440 ((TextView) d.findViewById(
441 R.id.details_bit_rate_value))
442 .setText(bps);
443 } catch (NumberFormatException e) {
444 d.findViewById(R.id.details_bit_rate_row)
445 .setVisibility(View.GONE);
446 }
447
448 String format = retriever.extractMetadata(
449 MediaMetadataRetriever
450 .METADATA_KEY_VIDEO_FORMAT);
451 ((TextView) d.findViewById(
452 R.id.details_format_value))
453 .setText(format);
454
455 String codec = retriever.extractMetadata(
456 MediaMetadataRetriever.METADATA_KEY_CODEC);
Ray Chen0f0af522009-04-22 13:26:07 +0800457 if (codec != null) {
458 setDetailsValue(d, codec, R.id.details_codec_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700459 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800460 hideDetailsRow(d, R.id.details_codec_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700461 }
Ray Chen0f0af522009-04-22 13:26:07 +0800462
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700463 } catch (RuntimeException ex) {
464 // Assume this is a corrupt video file.
465 } finally {
466 try {
467 retriever.release();
468 } catch (RuntimeException ex) {
469 // Ignore failures while cleaning up.
470 }
471 }
472 }
473
Ray Chen0f0af522009-04-22 13:26:07 +0800474 String value = null;
475 if (dimensionWidth > 0 && dimensionHeight > 0) {
476 value = String.format(
477 activity.getString(R.string.details_dimension_x),
478 dimensionWidth, dimensionHeight);
Ray Chen0f0af522009-04-22 13:26:07 +0800479 }
Ray Chend5142de2009-05-07 15:24:48 +0800480
Ray Chen0f0af522009-04-22 13:26:07 +0800481 if (value != null) {
482 setDetailsValue(d, value, R.id.details_resolution_value);
483 } else {
484 hideDetailsRow(d, R.id.details_resolution_row);
485 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700486
Ray Chen0f0af522009-04-22 13:26:07 +0800487 value = EMPTY_STRING;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700488 long dateTaken = image.getDateTaken();
489 if (dateTaken != 0) {
490 Date date = new Date(image.getDateTaken());
491 SimpleDateFormat dateFormat = new SimpleDateFormat();
Ray Chen0f0af522009-04-22 13:26:07 +0800492 value = dateFormat.format(date);
493 }
494 if (value != EMPTY_STRING) {
495 setDetailsValue(d, value, R.id.details_date_taken_value);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700496 } else {
Ray Chen0f0af522009-04-22 13:26:07 +0800497 hideDetailsRow(d, R.id.details_date_taken_row);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700498 }
499
Ray Chend5142de2009-05-07 15:24:48 +0800500 // Show more EXIF header details for JPEG images.
501 if (JPEG_MIME_TYPE.equals(image.getMimeType())) {
502 showExifInformation(image, d, activity);
503 } else {
504 hideExifInformation(d);
505 }
506
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700507 builder.setNeutralButton(R.string.details_ok,
508 new DialogInterface.OnClickListener() {
509 public void onClick(DialogInterface dialog,
510 int which) {
511 dialog.dismiss();
512 }
513 });
514
Ray Chen993105a2009-04-10 02:11:35 -0700515 handler.post(
516 new Runnable() {
517 public void run() {
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800518 builder.setIcon(
519 android.R.drawable.ic_dialog_info)
Ray Chen993105a2009-04-10 02:11:35 -0700520 .setTitle(R.string.details_panel_title)
521 .setView(d)
522 .show();
523 }
524 });
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700525 }
526 });
527 return true;
528 }
529
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700530 // Called when "Rotate left" or "Rotate right" is clicked.
531 private static boolean onRotateClicked(MenuInvoker onInvoke,
532 final int degree) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700533 onInvoke.run(new MenuCallback() {
534 public void run(Uri u, IImage image) {
535 if (image == null || image.isReadonly()) {
536 return;
537 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700538 image.rotateImageBy(degree);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700539 }
540 });
541 return true;
542 }
543
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700544 // Called when "Crop" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700545 private static boolean onCropClicked(MenuInvoker onInvoke,
546 final Activity activity) {
547 onInvoke.run(new MenuCallback() {
548 public void run(Uri u, IImage image) {
549 if (u == null) {
550 return;
551 }
552
553 Intent cropIntent = new Intent();
554 cropIntent.setClass(activity, CropImage.class);
555 cropIntent.setData(u);
556 activity.startActivityForResult(cropIntent,
557 RESULT_COMMON_MENU_CROP);
558 }
559 });
560 return true;
561 }
562
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700563 // Called when "Set as" is clicked.
564 private static boolean onSetAsClicked(MenuInvoker onInvoke,
565 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700566 onInvoke.run(new MenuCallback() {
567 public void run(Uri u, IImage image) {
568 if (u == null || image == null) {
569 return;
570 }
571
Chih-Chung Changbb187782009-07-02 16:46:30 +0800572 Intent intent = Util.createSetAsIntent(image);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700573 activity.startActivity(Intent.createChooser(intent,
574 activity.getText(R.string.setImage)));
575 }
576 });
577 return true;
578 }
579
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700580 // Called when "Share" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700581 private static boolean onImageShareClicked(MenuInvoker onInvoke,
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800582 final Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700583 onInvoke.run(new MenuCallback() {
584 public void run(Uri u, IImage image) {
585 if (image == null) return;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700586
587 Intent intent = new Intent();
588 intent.setAction(Intent.ACTION_SEND);
589 String mimeType = image.getMimeType();
590 intent.setType(mimeType);
591 intent.putExtra(Intent.EXTRA_STREAM, u);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800592 boolean isImage = ImageManager.isImage(image);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700593 try {
594 activity.startActivity(Intent.createChooser(intent,
595 activity.getText(isImage
596 ? R.string.sendImage
597 : R.string.sendVideo)));
598 } catch (android.content.ActivityNotFoundException ex) {
599 Toast.makeText(activity, isImage
600 ? R.string.no_way_to_share_image
601 : R.string.no_way_to_share_video,
602 Toast.LENGTH_SHORT).show();
603 }
604 }
605 });
606 return true;
607 }
608
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700609 // Called when "Play" is clicked.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700610 private static boolean onViewPlayClicked(MenuInvoker onInvoke,
611 final Activity activity) {
612 onInvoke.run(new MenuCallback() {
613 public void run(Uri uri, IImage image) {
614 if (image != null) {
615 Intent intent = new Intent(Intent.ACTION_VIEW,
616 image.fullSizeImageUri());
617 activity.startActivity(intent);
618 }
619 }});
620 return true;
621 }
622
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800623 // Called when "Delete" is clicked.
624 private static boolean onDeleteClicked(MenuInvoker onInvoke,
625 final Activity activity, final Runnable onDelete) {
626 onInvoke.run(new MenuCallback() {
627 public void run(Uri uri, IImage image) {
628 if (image != null) {
629 deleteImage(activity, onDelete, image);
630 }
631 }});
632 return true;
633 }
634
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800635 static MenuItemsResult addImageMenuItems(
636 Menu menu,
637 int inclusions,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800638 final Activity activity,
Ray Chen993105a2009-04-10 02:11:35 -0700639 final Handler handler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800640 final Runnable onDelete,
641 final MenuInvoker onInvoke) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700642 final ArrayList<MenuItem> requiresWriteAccessItems =
643 new ArrayList<MenuItem>();
644 final ArrayList<MenuItem> requiresNoDrmAccessItems =
645 new ArrayList<MenuItem>();
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800646 final ArrayList<MenuItem> requiresImageItems =
647 new ArrayList<MenuItem>();
648 final ArrayList<MenuItem> requiresVideoItems =
649 new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800650
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800651 if ((inclusions & INCLUDE_ROTATE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700652 SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
653 MENU_IMAGE_ROTATE, 40, R.string.rotate)
654 .setIcon(android.R.drawable.ic_menu_rotate);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800655 // Don't show the rotate submenu if the item at hand is read only
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700656 // since the items within the submenu won't be shown anyway. This
657 // is really a framework bug in that it shouldn't show the submenu
658 // if the submenu has no visible items.
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800659 MenuItem rotateLeft = rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT,
660 50, R.string.rotate_left)
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800661 .setOnMenuItemClickListener(
662 new MenuItem.OnMenuItemClickListener() {
663 public boolean onMenuItemClick(MenuItem item) {
664 return onRotateClicked(onInvoke, -90);
665 }
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800666 }).setAlphabeticShortcut('l');
667
668 MenuItem rotateRight = rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT,
669 60, R.string.rotate_right)
Chih-Chung Changf6e6d2b2009-05-14 19:19:17 +0800670 .setOnMenuItemClickListener(
671 new MenuItem.OnMenuItemClickListener() {
672 public boolean onMenuItemClick(MenuItem item) {
673 return onRotateClicked(onInvoke, 90);
674 }
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800675 }).setAlphabeticShortcut('r');
676
677 requiresWriteAccessItems.add(rotateSubmenu.getItem());
678 requiresWriteAccessItems.add(rotateLeft);
679 requiresWriteAccessItems.add(rotateRight);
680
681 requiresImageItems.add(rotateSubmenu.getItem());
682 requiresImageItems.add(rotateLeft);
683 requiresImageItems.add(rotateRight);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800684 }
685
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800686 if ((inclusions & INCLUDE_CROP_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800687 MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700688 R.string.camera_crop);
689 autoCrop.setIcon(android.R.drawable.ic_menu_crop);
690 autoCrop.setOnMenuItemClickListener(
691 new MenuItem.OnMenuItemClickListener() {
692 public boolean onMenuItemClick(MenuItem item) {
693 return onCropClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800694 }
695 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800696 requiresWriteAccessItems.add(autoCrop);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800697 requiresImageItems.add(autoCrop);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800698 }
699
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800700 if ((inclusions & INCLUDE_SET_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700701 MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
702 R.string.camera_set);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800703 setMenu.setIcon(android.R.drawable.ic_menu_set_as);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700704 setMenu.setOnMenuItemClickListener(
705 new MenuItem.OnMenuItemClickListener() {
706 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700707 return onSetAsClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800708 }
709 });
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800710 requiresImageItems.add(setMenu);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800711 }
712
713 if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800714 MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
715 R.string.camera_share).setOnMenuItemClickListener(
716 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700717 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800718 return onImageShareClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800719 }
720 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800721 item1.setIcon(android.R.drawable.ic_menu_share);
722 MenuItem item = item1;
723 requiresNoDrmAccessItems.add(item);
724 }
725
726 if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700727 MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
728 70, R.string.camera_toss);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800729 requiresWriteAccessItems.add(deleteItem);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700730 deleteItem.setOnMenuItemClickListener(
731 new MenuItem.OnMenuItemClickListener() {
732 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800733 return onDeleteClicked(onInvoke, activity,
734 onDelete);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700735 }
736 })
737 .setAlphabeticShortcut('d')
738 .setIcon(android.R.drawable.ic_menu_delete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800739 }
740
741 if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700742 MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
743 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800744 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800745 return onDetailsClicked(onInvoke, handler, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800746 }
747 });
748 detailsMenu.setIcon(R.drawable.ic_menu_view_details);
749 }
750
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800751 if ((inclusions & INCLUDE_SHOWMAP_MENU) != 0) {
752 MenuItem showOnMapItem = menu.add(0, 0, 80, R.string.show_on_map)
Ray Chen0a5a78c2009-04-24 14:13:01 +0800753 .setOnMenuItemClickListener(
754 new MenuItem.OnMenuItemClickListener() {
755 public boolean onMenuItemClick(MenuItem item) {
756 return onShowMapClicked(onInvoke,
757 handler, activity);
758 }
Ray Chen1e99d7c2009-05-13 13:55:29 +0800759 }).setIcon(R.drawable.ic_menu_3d_globe);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800760 requiresImageItems.add(showOnMapItem);
Ray Chen0a5a78c2009-04-24 14:13:01 +0800761 }
762
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800763 if ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0) {
764 MenuItem videoPlayItem = menu.add(VIDEO_SAVING_ITEM,
765 MENU_VIDEO_PLAY, 0, R.string.video_play)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700766 .setOnMenuItemClickListener(
767 new MenuItem.OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800768 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700769 return onViewPlayClicked(onInvoke, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800770 }
771 });
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800772 videoPlayItem.setIcon(
773 com.android.internal.R.drawable.ic_menu_play_clip);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800774 requiresVideoItems.add(videoPlayItem);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800775 }
776
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800777 return new MenuItemsResult() {
Owen Lin101d5282009-04-03 16:20:08 -0700778 public void gettingReadyToOpen(Menu menu, IImage image) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700779 // protect against null here. this isn't strictly speaking
780 // required but if a client app isn't handling sdcard removal
781 // properly it could happen
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800782 if (image == null) {
783 return;
784 }
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800785
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800786 ArrayList<MenuItem> enableList = new ArrayList<MenuItem>();
787 ArrayList<MenuItem> disableList = new ArrayList<MenuItem>();
788 ArrayList<MenuItem> list;
789
790 list = image.isReadonly() ? disableList : enableList;
791 list.addAll(requiresWriteAccessItems);
792
793 list = image.isDrm() ? disableList : enableList;
794 list.addAll(requiresNoDrmAccessItems);
795
796 list = ImageManager.isImage(image) ? enableList : disableList;
797 list.addAll(requiresImageItems);
798
799 list = ImageManager.isVideo(image) ? enableList : disableList;
800 list.addAll(requiresVideoItems);
repo synca274cf12009-07-06 15:05:23 +0800801
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800802 for (MenuItem item : enableList) {
803 item.setVisible(true);
804 item.setEnabled(true);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700805 }
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800806
807 for (MenuItem item : disableList) {
808 item.setVisible(false);
809 item.setEnabled(false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800810 }
811 }
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700812
813 // must override abstract method
Owen Lin101d5282009-04-03 16:20:08 -0700814 public void aboutToCall(MenuItem menu, IImage image) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800815 }
816 };
817 }
818
819 static void deletePhoto(Activity activity, Runnable onDelete) {
Ray Chen7638a542009-03-24 20:37:45 -0700820 deleteImpl(activity, onDelete, true);
821 }
Owen Lin095afa12009-03-24 23:41:27 -0700822
Ray Chen7638a542009-03-24 20:37:45 -0700823 static void deleteVideo(Activity activity, Runnable onDelete) {
824 deleteImpl(activity, onDelete, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800825 }
826
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800827 static void deleteImage(
828 Activity activity, Runnable onDelete, IImage image) {
829 deleteImpl(activity, onDelete, ImageManager.isImage(image));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800830 }
831
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800832 static void deleteImpl(
833 Activity activity, Runnable onDelete, boolean isImage) {
834 boolean needConfirm = PreferenceManager
835 .getDefaultSharedPreferences(activity)
836 .getBoolean("pref_gallery_confirm_delete_key", true);
837 if (!needConfirm) {
838 if (onDelete != null) onDelete.run();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800839 } else {
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800840 String title = activity.getString(R.string.confirm_delete_title);
841 String message = activity.getString(isImage
842 ? R.string.confirm_delete_message
843 : R.string.confirm_delete_video_message);
844 confirmAction(activity, title, message, onDelete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800845 }
846 }
847
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800848 public static void deleteMultiple(Context context, Runnable action) {
849 boolean needConfirm = PreferenceManager
850 .getDefaultSharedPreferences(context)
851 .getBoolean("pref_gallery_confirm_delete_key", true);
852 if (!needConfirm) {
853 if (action != null) action.run();
854 } else {
855 String title = context.getString(R.string.confirm_delete_title);
856 String message = context.getString(
857 R.string.confirm_delete_multiple_message);
858 confirmAction(context, title, message, action);
859 }
860 }
861
862 public static void confirmAction(Context context, String title,
863 String message, final Runnable action) {
864 OnClickListener listener = new OnClickListener() {
865 public void onClick(DialogInterface dialog, int which) {
866 switch (which) {
867 case DialogInterface.BUTTON_POSITIVE:
868 if (action != null) action.run();
869 }
870 }
871 };
872 new AlertDialog.Builder(context)
873 .setIcon(android.R.drawable.ic_dialog_alert)
874 .setTitle(title)
875 .setMessage(message)
876 .setPositiveButton(android.R.string.ok, listener)
877 .setNegativeButton(android.R.string.cancel, listener)
878 .create()
879 .show();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800880 }
881
Owen Lin3283e042009-06-26 11:59:58 -0700882 static void addSwitchModeMenuItem(
883 Menu menu, final Activity activity, boolean switchToVideo) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700884 int group = switchToVideo
885 ? MenuHelper.IMAGE_MODE_ITEM
886 : MenuHelper.VIDEO_MODE_ITEM;
887 int labelId = switchToVideo
888 ? R.string.switch_to_video_lable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800889 : R.string.switch_to_camera_lable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700890 int iconId = switchToVideo
891 ? R.drawable.ic_menu_camera_video_view
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800892 : android.R.drawable.ic_menu_camera;
Owen Lin3283e042009-06-26 11:59:58 -0700893 final String action = switchToVideo
894 ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
895 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700896 MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
897 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
Owen Lin3283e042009-06-26 11:59:58 -0700898 public boolean onMenuItemClick(MenuItem item) {
899 startCameraActivity(activity, action);
900 return true;
901 }
902 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800903 item.setIcon(iconId);
904 }
905
Owen Lin3283e042009-06-26 11:59:58 -0700906 private static void startCameraActivity(Activity activity, String action) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700907 Intent intent = new Intent(action);
908 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
909 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800910
911 // Keep the camera instance for a while.
912 // This avoids re-opening the camera and saves time.
913 CameraHolder.instance().keep();
914
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700915 activity.startActivity(intent);
Owen Lin059daa32009-05-18 15:31:17 -0700916 }
917
918 public static void gotoVideoMode(Activity activity) {
Owen Lin3283e042009-06-26 11:59:58 -0700919 startCameraActivity(activity, MediaStore.INTENT_ACTION_VIDEO_CAMERA);
Owen Lin059daa32009-05-18 15:31:17 -0700920 }
921
Owen Lin3283e042009-06-26 11:59:58 -0700922 public static void gotoCameraMode(Activity activity) {
923 startCameraActivity(
924 activity, MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800925 }
926
Owen Lin3283e042009-06-26 11:59:58 -0700927 public static void gotoCameraImageGallery(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700928 gotoGallery(activity, R.string.gallery_camera_bucket_name,
929 ImageManager.INCLUDE_IMAGES);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800930 }
931
Owen Lin3283e042009-06-26 11:59:58 -0700932 public static void gotoCameraVideoGallery(Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800933 gotoGallery(activity, R.string.gallery_camera_videos_bucket_name,
934 ImageManager.INCLUDE_VIDEOS);
935 }
936
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700937 private static void gotoGallery(Activity activity, int windowTitleId,
938 int mediaTypes) {
939 Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
940 .appendQueryParameter("bucketId",
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800941 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
942 Intent intent = new Intent(Intent.ACTION_VIEW, target);
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700943 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800944 intent.putExtra("windowTitle", activity.getString(windowTitleId));
945 intent.putExtra("mediaTypes", mediaTypes);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700946
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800947 try {
948 activity.startActivity(intent);
949 } catch (ActivityNotFoundException e) {
950 Log.e(TAG, "Could not start gallery activity", e);
951 }
952 }
953
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700954 static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800955 menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700956 .setOnMenuItemClickListener(
957 new MenuItem.OnMenuItemClickListener() {
958 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700959 return onCapturePictureClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700960 }
961 }).setIcon(android.R.drawable.ic_menu_camera);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700962 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800963
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700964 private static boolean onCapturePictureClicked(Activity activity) {
965 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
966 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
967 try {
968 activity.startActivity(intent);
969 } catch (android.content.ActivityNotFoundException e) {
970 // Ignore exception
971 }
972 return true;
973 }
974
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700975 static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800976 menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700977 .setOnMenuItemClickListener(
978 new MenuItem.OnMenuItemClickListener() {
979 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700980 return onCaptureVideoClicked(activity);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700981 }
982 }).setIcon(R.drawable.ic_menu_camera_video_view);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800983 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700984
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700985 private static boolean onCaptureVideoClicked(Activity activity) {
986 Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
987 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
988 try {
989 activity.startActivity(intent);
990 } catch (android.content.ActivityNotFoundException e) {
991 // Ignore exception
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700992 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700993 return true;
994 }
995
Chih-Chung Chang272c3fd2009-04-08 05:14:37 -0700996 public static void addCaptureMenuItems(Menu menu, final Activity activity) {
997 addCapturePictureMenuItems(menu, activity);
998 addCaptureVideoMenuItems(menu, activity);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800999 }
1000
Owen Lin6795ff12009-06-09 13:39:00 -07001001 public static String formatDuration(final Context context,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001002 int durationMs) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001003 int duration = durationMs / 1000;
1004 int h = duration / 3600;
1005 int m = (duration - h * 3600) / 60;
1006 int s = duration - (h * 3600 + m * 60);
1007 String durationValue;
1008 if (h == 0) {
1009 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -07001010 context.getString(R.string.details_ms), m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001011 } else {
1012 durationValue = String.format(
Owen Lin6795ff12009-06-09 13:39:00 -07001013 context.getString(R.string.details_hms), h, m, s);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001014 }
1015 return durationValue;
1016 }
1017
1018 public static void showStorageToast(Activity activity) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001019 showStorageToast(activity, calculatePicturesRemaining());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001020 }
1021
1022 public static void showStorageToast(Activity activity, int remaining) {
1023 String noStorageText = null;
1024
1025 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
1026 String state = Environment.getExternalStorageState();
1027 if (state == Environment.MEDIA_CHECKING) {
1028 noStorageText = activity.getString(R.string.preparing_sd);
1029 } else {
1030 noStorageText = activity.getString(R.string.no_storage);
1031 }
1032 } else if (remaining < 1) {
1033 noStorageText = activity.getString(R.string.not_enough_space);
1034 }
1035
1036 if (noStorageText != null) {
1037 Toast.makeText(activity, noStorageText, 5000).show();
1038 }
1039 }
1040
1041 public static int calculatePicturesRemaining() {
1042 try {
1043 if (!ImageManager.hasStorage()) {
1044 return NO_STORAGE_ERROR;
1045 } else {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001046 String storageDirectory =
1047 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001048 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001049 float remaining = ((float) stat.getAvailableBlocks()
1050 * (float) stat.getBlockSize()) / 400000F;
1051 return (int) remaining;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001052 }
1053 } catch (Exception ex) {
1054 // if we can't stat the filesystem then we don't know how many
1055 // pictures are remaining. it might be zero but just leave it
1056 // blank since we really don't know.
1057 return CANNOT_STAT_ERROR;
1058 }
1059 }
1060}