blob: 7fcab9ac8776bc3db466a4538ca0a9792f40367c [file] [log] [blame]
The Android Open Source Project0eaec582008-12-17 18:05:54 -08001/*
2 * Copyright (C) 2007 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.File;
20import java.util.ArrayList;
21import java.io.IOException;
22
23import android.app.Activity;
24import android.app.ProgressDialog;
25import android.content.ActivityNotFoundException;
26import android.content.BroadcastReceiver;
27import android.content.ContentResolver;
28import android.content.ContentValues;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.SharedPreferences;
33import android.content.res.Resources;
34import android.graphics.Bitmap;
35import android.graphics.drawable.ColorDrawable;
36import android.location.LocationManager;
37import android.media.MediaMetadataRetriever;
38import android.media.MediaRecorder;
39import android.net.Uri;
40import android.os.Bundle;
41import android.os.Environment;
42import android.os.Handler;
43import android.os.Message;
44import android.os.StatFs;
45import android.os.SystemClock;
46import android.preference.PreferenceManager;
47import android.provider.MediaStore.Images;
48import android.provider.MediaStore.Video;
49import android.text.format.DateFormat;
50import android.util.Log;
51import android.view.KeyEvent;
52import android.view.Menu;
53import android.view.MenuItem;
54import android.view.MotionEvent;
55import android.view.SurfaceHolder;
56import android.view.SurfaceView;
57import android.view.View;
58import android.view.Window;
59import android.view.WindowManager;
60import android.view.MenuItem.OnMenuItemClickListener;
61import android.view.animation.Animation;
62import android.widget.ImageView;
63import android.widget.TextView;
64import android.widget.Toast;
65import android.widget.RelativeLayout.LayoutParams;
66
67public class VideoCamera extends Activity implements View.OnClickListener, SurfaceHolder.Callback {
68
69 private static final String TAG = "videocamera";
70
71 private static final boolean DEBUG = true;
72 private static final boolean DEBUG_SUPPRESS_AUDIO_RECORDING = DEBUG && true;
73 private static final boolean DEBUG_DO_NOT_REUSE_MEDIA_RECORDER = DEBUG && true;
74
75 private static final int KEEP = 2;
76 private static final int CLEAR_SCREEN_DELAY = 4;
77 private static final int UPDATE_RECORD_TIME = 5;
78 private static final int RESTART_PREVIEW = 6;
79
80 private static final int SCREEN_DELAY = 2 * 60 * 1000;
81 private static final int POST_PICTURE_ALERT_TIMEOUT = 6 * 1000;
82
83 private static final int NO_STORAGE_ERROR = -1;
84 private static final int CANNOT_STAT_ERROR = -2;
85
86 public static final int MENU_SWITCH_TO_VIDEO = 0;
87 public static final int MENU_SWITCH_TO_CAMERA = 1;
88 public static final int MENU_SETTINGS = 6;
89 public static final int MENU_GALLERY_PHOTOS = 7;
90 public static final int MENU_GALLERY_VIDEOS = 8;
91 public static final int MENU_SAVE_SELECT_PHOTOS = 30;
92 public static final int MENU_SAVE_NEW_PHOTO = 31;
93 public static final int MENU_SAVE_SELECTVIDEO = 32;
94 public static final int MENU_SAVE_TAKE_NEW_VIDEO = 33;
95 public static final int MENU_SAVE_GALLERY_PHOTO = 34;
96 public static final int MENU_SAVE_GALLERY_VIDEO_PHOTO = 35;
97 public static final int MENU_SAVE_CAMERA_DONE = 36;
98 public static final int MENU_SAVE_CAMERA_VIDEO_DONE = 37;
99
100 Toast mToast;
101 SharedPreferences mPreferences;
102
103 private static final float VIDEO_ASPECT_RATIO = 176.0f / 144.0f;
104 VideoPreview mVideoPreview;
105 SurfaceHolder mSurfaceHolder = null;
106 ImageView mBlackout = null;
107 ImageView mVideoFrame;
108 Bitmap mVideoFrameBitmap;
109
110 private MediaRecorder mMediaRecorder;
111 private boolean mMediaRecorderRecording = false;
112 private long mRecordingStartTime;
113 private String mCurrentVideoFilename;
114 private Uri mCurrentVideoUri;
115
116 boolean mPausing = false;
117
118 static ContentResolver mContentResolver;
119 boolean mDidRegister = false;
120
121 int mCurrentZoomIndex = 0;
122
123 private ImageView mModeIndicatorView;
124 private ImageView mRecordingIndicatorView;
125 private TextView mRecordingTimeView;
126
127 ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
128
129 View mPostPictureAlert;
130 LocationManager mLocationManager = null;
131
132 private int mPicturesRemaining;
133
134 private Handler mHandler = new MainHandler();
135
136 private void cancelSavingNotification() {
137 if (mToast != null) {
138 mToast.cancel();
139 mToast = null;
140 }
141 }
142
143 /** This Handler is used to post message back onto the main thread of the application */
144 private class MainHandler extends Handler {
145 @Override
146 public void handleMessage(Message msg) {
147 switch (msg.what) {
148 case KEEP: {
149 keep();
150
151 if (msg.obj != null) {
152 mHandler.post((Runnable)msg.obj);
153 }
154 break;
155 }
156
157 case CLEAR_SCREEN_DELAY: {
158 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
159 break;
160 }
161
162 case UPDATE_RECORD_TIME: {
163 if (mMediaRecorderRecording) {
164 long now = SystemClock.uptimeMillis();
165 long delta = now - mRecordingStartTime;
166 long seconds = delta / 1000;
167 long minutes = seconds / 60;
168 long remainderSeconds = seconds - (minutes * 60);
169
170 String secondsString = Long.toString(remainderSeconds);
171 if (secondsString.length() < 2) {
172 secondsString = "0" + secondsString;
173 }
174 String minutesString = Long.toString(minutes);
175 if (minutesString.length() < 2) {
176 minutesString = "0" + minutesString;
177 }
178 String text = minutesString + ":" + secondsString;
179 mRecordingTimeView.setText(text);
180 mHandler.sendEmptyMessageDelayed(UPDATE_RECORD_TIME, 1000);
181 }
182 break;
183 }
184
185 case RESTART_PREVIEW:
186 hideVideoFrameAndStartPreview();
187 break;
188
189 default:
190 Log.v(TAG, "Unhandled message: " + msg.what);
191 break;
192 }
193 }
194 };
195
196 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
197 @Override
198 public void onReceive(Context context, Intent intent) {
199 String action = intent.getAction();
200 if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
201 // SD card available
202 // TODO put up a "please wait" message
203 // TODO also listen for the media scanner finished message
204 showStorageToast();
205 } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
206 // SD card unavailable
207 showStorageToast();
208 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
209 Toast.makeText(VideoCamera.this, getResources().getString(R.string.wait), 5000);
210 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
211 showStorageToast();
212 }
213 }
214 };
215
216 static private String createName(long dateTaken) {
217 return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
218 }
219
220 private void postAfterKeep(final Runnable r) {
221 Message msg = mHandler.obtainMessage(KEEP);
222 msg.obj = r;
223 msg.sendToTarget();
224 }
225
226 /** Called with the activity is first created. */
227 @Override
228 public void onCreate(Bundle icicle) {
229 super.onCreate(icicle);
230
231 mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
232
233 mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
234 mContentResolver = getContentResolver();
235
236 //setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
237 requestWindowFeature(Window.FEATURE_PROGRESS);
238
239 Window win = getWindow();
240 win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
241 setContentView(R.layout.video_camera);
242
243 mVideoPreview = (VideoPreview) findViewById(R.id.camera_preview);
244 mVideoPreview.setAspectRatio(VIDEO_ASPECT_RATIO);
245
246 // don't set mSurfaceHolder here. We have it set ONLY within
247 // surfaceCreated / surfaceDestroyed, other parts of the code
248 // assume that when it is set, the surface is also set.
249 SurfaceHolder holder = mVideoPreview.getHolder();
250 holder.addCallback(this);
251 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
252
253 mBlackout = (ImageView) findViewById(R.id.blackout);
254 mBlackout.setBackgroundDrawable(new ColorDrawable(0xFF000000));
255
256 mPostPictureAlert = findViewById(R.id.post_picture_panel);
257 View b;
258
259 b = findViewById(R.id.play);
260 b.setOnClickListener(this);
261
262 b = findViewById(R.id.share);
263 b.setOnClickListener(this);
264
265 b = findViewById(R.id.discard);
266 b.setOnClickListener(this);
267
268 mModeIndicatorView = (ImageView) findViewById(R.id.mode_indicator);
269 mRecordingIndicatorView = (ImageView) findViewById(R.id.recording_indicator);
270 mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
271 mVideoFrame = (ImageView) findViewById(R.id.video_frame);
272 }
273
274 @Override
275 public void onStart() {
276 super.onStart();
277
278 final View hintView = findViewById(R.id.hint_toast);
279 if (hintView != null)
280 hintView.setVisibility(View.GONE);
281
282 Thread t = new Thread(new Runnable() {
283 public void run() {
284 final boolean storageOK = calculatePicturesRemaining() > 0;
285 if (hintView == null)
286 return;
287
288 if (storageOK) {
289 mHandler.post(new Runnable() {
290 public void run() {
291 hintView.setVisibility(View.VISIBLE);
292 }
293 });
294 mHandler.postDelayed(new Runnable() {
295 public void run() {
296 Animation a = new android.view.animation.AlphaAnimation(1F, 0F);
297 a.setDuration(500);
298 a.startNow();
299 hintView.setAnimation(a);
300 hintView.setVisibility(View.GONE);
301 }
302 }, 3000);
303 } else {
304 mHandler.post(new Runnable() {
305 public void run() {
306 hintView.setVisibility(View.GONE);
307 showStorageToast();
308 }
309 });
310 }
311 }
312 });
313 t.start();
314 }
315
316 public void onClick(View v) {
317 switch (v.getId()) {
318 case R.id.discard: {
319 File f = new File(mCurrentVideoFilename);
320 f.delete();
321 mContentResolver.delete(mCurrentVideoUri, null, null);
322
323 hideVideoFrameAndStartPreview();
324 break;
325 }
326
327 case R.id.share: {
328 Intent intent = new Intent();
329 intent.setAction(Intent.ACTION_SEND);
330 intent.setType("video/3gpp");
331 intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri);
332 try {
333 startActivity(Intent.createChooser(intent, getText(R.string.sendVideo)));
334 } catch (android.content.ActivityNotFoundException ex) {
335 Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show();
336 }
337
338 break;
339 }
340
341 case R.id.play: {
342 Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri);
343 try {
344 startActivity(intent);
345 } catch (android.content.ActivityNotFoundException ex) {
346 Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
347 }
348 break;
349 }
350 }
351 }
352
353 private void showStorageToast() {
354 String noStorageText = null;
355 int remaining = calculatePicturesRemaining();
356
357 if (remaining == NO_STORAGE_ERROR) {
358 noStorageText = getString(R.string.no_storage);
359 } else if (remaining < 1) {
360 noStorageText = getString(R.string.not_enough_space);
361 }
362
363 if (noStorageText != null) {
364 Toast.makeText(this, noStorageText, 5000).show();
365 }
366 }
367
368 @Override
369 public void onResume() {
370 super.onResume();
371 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
372
373 mPausing = false;
374
375 // install an intent filter to receive SD card related events.
376 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
377 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
378 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
379 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
380 intentFilter.addDataScheme("file");
381 registerReceiver(mReceiver, intentFilter);
382 mDidRegister = true;
383
384 mBlackout.setVisibility(View.INVISIBLE);
385 if (mVideoFrameBitmap == null) {
386 initializeVideo();
387 } else {
388 showPostRecordingAlert();
389 }
390 }
391
392 @Override
393 public void onStop() {
394 Log.v(TAG, "onStop");
395 stopVideoRecording();
396 keep();
397 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
398 super.onStop();
399 }
400
401 @Override
402 protected void onPause() {
403 Log.v(TAG, "onPause");
404 stopVideoRecording();
405 keep();
406 hidePostPictureAlert();
407
408 mPausing = true;
409
410 if (mDidRegister) {
411 unregisterReceiver(mReceiver);
412 mDidRegister = false;
413 }
414
415 super.onPause();
416 }
417
418 @Override
419 public boolean onKeyDown(int keyCode, KeyEvent event) {
420 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
421 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
422
423 switch (keyCode) {
424 case KeyEvent.KEYCODE_BACK:
425 if (mMediaRecorderRecording) {
426 Log.v(TAG, "onKeyBack");
427 stopVideoRecordingAndDisplayDialog();
428 return true;
429 } else if(isPostRecordingAlertVisible()) {
430 hideVideoFrameAndStartPreview();
431 return true;
432 }
433 break;
434 case KeyEvent.KEYCODE_FOCUS:
435 return true;
436 case KeyEvent.KEYCODE_CAMERA:
437 case KeyEvent.KEYCODE_DPAD_CENTER:
438 if (event.getRepeatCount() == 0) {
439 if (!mMediaRecorderRecording) {
440 startVideoRecording();
441 } else {
442 stopVideoRecordingAndDisplayDialog();
443 }
444 return true;
445 }
446 return true;
447 case KeyEvent.KEYCODE_MENU:
448 if (mMediaRecorderRecording) {
449 stopVideoRecordingAndDisplayDialog();
450 return true;
451 }
452 hideVideoFrameAndStartPreview();
453 break;
454 }
455
456 return super.onKeyDown(keyCode, event);
457 }
458
459 @Override
460 public boolean onTrackballEvent(MotionEvent event) {
461 cancelRestartPreviewTimeout();
462 return super.onTrackballEvent(event);
463 }
464
465 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
466 stopVideoRecording();
467 initializeVideo();
468 }
469
470 public void surfaceCreated(SurfaceHolder holder) {
471 mSurfaceHolder = holder;
472 }
473
474 public void surfaceDestroyed(SurfaceHolder holder) {
475 mSurfaceHolder = null;
476 }
477
478 void gotoGallery() {
479 Uri target = Video.Media.INTERNAL_CONTENT_URI;
480 Intent intent = new Intent(Intent.ACTION_VIEW, target);
481 try {
482 startActivity(intent);
483 } catch (ActivityNotFoundException e) {
484 Log.e(TAG, "Could not start gallery activity", e);
485 }
486 }
487
488 void keep() {
489 cancelSavingNotification();
490 };
491
492 void toss() {
493 cancelSavingNotification();
494 };
495
496 @Override
497 public boolean onPrepareOptionsMenu(Menu menu) {
498 super.onPrepareOptionsMenu(menu);
499
500 for (int i = 1; i <= MenuHelper.MENU_ITEM_MAX; i++) {
501 if (i != MenuHelper.GENERIC_ITEM) {
502 menu.setGroupVisible(i, false);
503 }
504 }
505
506 menu.setGroupVisible(MenuHelper.VIDEO_MODE_ITEM, true);
507
508 return true;
509 }
510
511 @Override
512 public boolean onCreateOptionsMenu(Menu menu) {
513 super.onCreateOptionsMenu(menu);
514
515 addBaseMenuItems(menu);
516 MenuHelper.addImageMenuItems(
517 menu,
518 MenuHelper.INCLUDE_ALL & ~MenuHelper.INCLUDE_ROTATE_MENU,
519 false,
520 VideoCamera.this,
521 mHandler,
522
523 // Handler for deletion
524 new Runnable() {
525 public void run() {
526 // What do we do here?
527 // mContentResolver.delete(uri, null, null);
528 }
529 },
530 new MenuHelper.MenuInvoker() {
531 public void run(final MenuHelper.MenuCallback cb) {
532 }
533 });
534
535 MenuItem gallery = menu.add(MenuHelper.IMAGE_SAVING_ITEM, MENU_SAVE_GALLERY_PHOTO, 0,
536 R.string.camera_gallery_photos_text).setOnMenuItemClickListener(
537 new MenuItem.OnMenuItemClickListener() {
538 public boolean onMenuItemClick(MenuItem item) {
539 postAfterKeep(new Runnable() {
540 public void run() {
541 gotoGallery();
542 }
543 });
544 return true;
545 }
546 });
547 gallery.setIcon(android.R.drawable.ic_menu_gallery);
548 return true;
549 }
550
551 private int calculatePicturesRemaining() {
552 try {
553 if (!ImageManager.hasStorage()) {
554 mPicturesRemaining = NO_STORAGE_ERROR;
555 } else {
556 String storageDirectory = Environment.getExternalStorageDirectory().toString();
557 StatFs stat = new StatFs(storageDirectory);
558 float remaining = ((float)stat.getAvailableBlocks() * (float)stat.getBlockSize()) / 400000F;
559 mPicturesRemaining = (int)remaining;
560 }
561 } catch (Exception ex) {
562 // if we can't stat the filesystem then we don't know how many
563 // pictures are remaining. it might be zero but just leave it
564 // blank since we really don't know.
565 mPicturesRemaining = CANNOT_STAT_ERROR;
566 }
567 return mPicturesRemaining;
568 }
569
570 private void initializeVideo() {
571 Log.v(TAG, "initializeVideo");
572 releaseMediaRecorder();
573
574 if (mSurfaceHolder == null) {
575 Log.v(TAG, "SurfaceHolder is null");
576 return;
577 }
578
579 mMediaRecorder = new MediaRecorder();
580
581 if (DEBUG_SUPPRESS_AUDIO_RECORDING) {
582 Log.v(TAG, "DEBUG_SUPPRESS_AUDIO_RECORDING is true.");
583 } else {
584 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
585 }
586 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
587 mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
588 Log.v(TAG, "before setOutputFile");
589 createVideoPath();
590 mMediaRecorder.setOutputFile(mCurrentVideoFilename);
591 Boolean videoQualityLow = getIntPreference("pref_camera_videoquality_key") == 0;
592
593 // Use the same frame rate for both, since internally
594 // if the frame rate is too large, it can cause camera to become
595 // unstable. We need to fix the MediaRecorder to disable the support
596 // of setting frame rate for now.
597 mMediaRecorder.setVideoFrameRate(20);
598 if (videoQualityLow) {
599 mMediaRecorder.setVideoSize(176,144);
600 } else {
601 mMediaRecorder.setVideoSize(352,288);
602 }
603 mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
604 if (!DEBUG_SUPPRESS_AUDIO_RECORDING) {
605 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
606 }
607 Log.v(TAG, "before setPreviewDisplay");
608 mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
609 try {
610 mMediaRecorder.prepare();
611 } catch (IOException exception) {
612 Log.e(TAG, "prepare failed for " + mCurrentVideoFilename);
613 releaseMediaRecorder();
614 // TODO: add more exception handling logic here
615 return;
616 }
617 mMediaRecorderRecording = false;
618 }
619
620 private void releaseMediaRecorder() {
621 Log.v(TAG, "Releasing media recorder.");
622 if (mMediaRecorder != null) {
623 mMediaRecorder.reset();
624 mMediaRecorder.release();
625 mMediaRecorder = null;
626 }
627 }
628
629 private void restartPreview() {
630 if (DEBUG_DO_NOT_REUSE_MEDIA_RECORDER) {
631 Log.v(TAG, "DEBUG_DO_NOT_REUSE_MEDIA_RECORDER recreating mMediaRecorder.");
632 initializeVideo();
633 } else {
634 try {
635 mMediaRecorder.prepare();
636 } catch (IOException exception) {
637 Log.e(TAG, "prepare failed for " + mCurrentVideoFilename);
638 releaseMediaRecorder();
639 // TODO: add more exception handling logic here
640 }
641 }
642 }
643
644 private int getIntPreference(String key) {
645 String s = mPreferences.getString(key, "0");
646 return Integer.parseInt(s);
647 }
648
649 private void createVideoPath() {
650 long dateTaken = System.currentTimeMillis();
651 String title = createName(dateTaken);
652 String displayName = title + ".3gp"; // Used when emailing.
653 String filename = ImageManager.CAMERA_IMAGE_BUCKET_NAME + "/"
654 + Long.toString(dateTaken) + ".3gp";
655 ContentValues values = new ContentValues(7);
656 values.put(Video.Media.TITLE, title);
657 values.put(Video.Media.DISPLAY_NAME, displayName);
658 values.put(Video.Media.DESCRIPTION, "");
659 values.put(Video.Media.DATE_TAKEN, dateTaken);
660 values.put(Video.Media.MIME_TYPE, "video/3gpp");
661 values.put(Video.Media.DATA, filename);
662 Uri videoTable = Uri.parse("content://media/external/video/media");
663 Uri item = mContentResolver.insert(videoTable, values);
664 mCurrentVideoFilename = filename;
665 mCurrentVideoUri = item;
666 }
667
668 private void addBaseMenuItems(Menu menu) {
669 MenuHelper.addSwitchModeMenuItem(menu, this, false);
670 {
671 MenuItem gallery = menu.add(MenuHelper.IMAGE_MODE_ITEM, MENU_GALLERY_PHOTOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
672 public boolean onMenuItemClick(MenuItem item) {
673 gotoGallery();
674 return true;
675 }
676 });
677 gallery.setIcon(android.R.drawable.ic_menu_gallery);
678 mGalleryItems.add(gallery);
679 }
680 {
681 MenuItem gallery = menu.add(MenuHelper.VIDEO_MODE_ITEM, MENU_GALLERY_VIDEOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
682 public boolean onMenuItemClick(MenuItem item) {
683 gotoGallery();
684 return true;
685 }
686 });
687 gallery.setIcon(android.R.drawable.ic_menu_gallery);
688 mGalleryItems.add(gallery);
689 }
690
691 MenuItem item = menu.add(MenuHelper.GENERIC_ITEM, MENU_SETTINGS, 0, R.string.settings).setOnMenuItemClickListener(new OnMenuItemClickListener() {
692 public boolean onMenuItemClick(MenuItem item) {
693 Intent intent = new Intent();
694 intent.setClass(VideoCamera.this, CameraSettings.class);
695 startActivity(intent);
696 return true;
697 }
698 });
699 item.setIcon(android.R.drawable.ic_menu_preferences);
700 }
701
702 private void startVideoRecording() {
703 Log.v(TAG, "startVideoRecording");
704 if (!mMediaRecorderRecording) {
705
706 // Check mMediaRecorder to see whether it is initialized or not.
707 if (mMediaRecorder == null) {
708 initializeVideo();
709 }
710 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
711 try {
712 mMediaRecorder.start(); // Recording is now started
713 } catch (RuntimeException e) {
714 Log.e(TAG, "Could not start media recorder. ", e);
715 return;
716 }
717 mMediaRecorderRecording = true;
718 mRecordingStartTime = SystemClock.uptimeMillis();
719 mModeIndicatorView.setVisibility(View.GONE);
720 mRecordingIndicatorView.setVisibility(View.VISIBLE);
721 mRecordingTimeView.setText("");
722 mRecordingTimeView.setVisibility(View.VISIBLE);
723 mHandler.sendEmptyMessage(UPDATE_RECORD_TIME);
724 }
725 }
726
727 private void stopVideoRecordingAndDisplayDialog() {
728 Log.v(TAG, "stopVideoRecordingAndDisplayDialog");
729 if (mMediaRecorderRecording) {
730 stopVideoRecording();
731 acquireAndShowVideoFrame();
732 showPostRecordingAlert();
733 }
734 }
735
736 private void showPostRecordingAlert() {
737 cancelRestartPreviewTimeout();
738 mPostPictureAlert.setVisibility(View.VISIBLE);
739 mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, POST_PICTURE_ALERT_TIMEOUT);
740 }
741
742 private void hidePostPictureAlert() {
743 cancelRestartPreviewTimeout();
744 mPostPictureAlert.setVisibility(View.INVISIBLE);
745 }
746
747 private void cancelRestartPreviewTimeout() {
748 mHandler.removeMessages(RESTART_PREVIEW);
749 }
750
751 private boolean isPostRecordingAlertVisible() {
752 return mPostPictureAlert.getVisibility() == View.VISIBLE;
753 }
754
755 private void stopVideoRecording() {
756 Log.v(TAG, "stopVideoRecording");
757 if (mMediaRecorderRecording || mMediaRecorder != null) {
758 if (mMediaRecorderRecording) {
759 mMediaRecorder.stop();
760 }
761 releaseMediaRecorder();
762 mMediaRecorderRecording = false;
763 mModeIndicatorView.setVisibility(View.VISIBLE);
764 mRecordingIndicatorView.setVisibility(View.GONE);
765 mRecordingTimeView.setVisibility(View.GONE);
766 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
767 }
768 }
769
770 private void hideVideoFrameAndStartPreview() {
771 hidePostPictureAlert();
772 hideVideoFrame();
773 restartPreview();
774 }
775
776 private void acquireAndShowVideoFrame() {
777 recycleVideoFrameBitmap();
778 mVideoFrameBitmap = createVideoThumbnail(mCurrentVideoFilename);
779 mVideoFrame.setImageBitmap(mVideoFrameBitmap);
780 mVideoFrame.setVisibility(View.VISIBLE);
781 }
782
783 private void hideVideoFrame() {
784 recycleVideoFrameBitmap();
785 mVideoFrame.setVisibility(View.GONE);
786 }
787
788 private void recycleVideoFrameBitmap() {
789 if (mVideoFrameBitmap != null) {
790 mVideoFrame.setImageDrawable(null);
791 mVideoFrameBitmap.recycle();
792 mVideoFrameBitmap = null;
793 }
794 }
795
796 private Bitmap createVideoThumbnail(String filePath) {
797 Bitmap bitmap = null;
798 MediaMetadataRetriever retriever = new MediaMetadataRetriever();
799 try {
800 retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
801 retriever.setDataSource(filePath);
802 bitmap = retriever.captureFrame();
803 } finally {
804 retriever.release();
805 }
806 return bitmap;
807 }
808
809}
810