VideoCamera.java revision 46fc7aeec04021dfc2f4c947649888dbc7408f53
1b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project/*
2b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project *
4b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * you may not use this file except in compliance with the License.
6b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * You may obtain a copy of the License at
7b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project *
8b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project *
10b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * See the License for the specific language governing permissions and
14b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * limitations under the License.
15b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */
16b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
17b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectpackage com.android.camera;
18b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
19101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport com.android.camera.gallery.IImage;
20101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport com.android.camera.gallery.IImageList;
21101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin
22b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.app.Activity;
2346fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Liimport android.content.ActivityNotFoundException;
24b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.BroadcastReceiver;
25b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.ContentResolver;
26b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.ContentValues;
27b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.Context;
28b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.Intent;
29b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.IntentFilter;
30b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.SharedPreferences;
31b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.graphics.Bitmap;
32b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.graphics.drawable.Drawable;
33b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.media.MediaRecorder;
34b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.net.Uri;
35b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.Bundle;
36b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.Environment;
37b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.Handler;
38b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.Message;
39b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.StatFs;
40b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.os.SystemClock;
41b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.preference.PreferenceManager;
42b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.provider.MediaStore;
43b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.provider.MediaStore.Video;
44b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.text.format.DateFormat;
45b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.util.Log;
46b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.KeyEvent;
47b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.Menu;
48b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.MenuItem;
49b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.SurfaceHolder;
50b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.View;
51b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.Window;
52b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.view.WindowManager;
53059daa36dc6e83ca24a16d9b99925e71010bccebOwen Linimport android.view.MenuItem.OnMenuItemClickListener;
54b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.widget.ImageView;
55b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.widget.TextView;
56b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.widget.Toast;
57b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
58d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.io.File;
59d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.io.FileDescriptor;
60d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.io.IOException;
61d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.text.SimpleDateFormat;
62d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.util.ArrayList;
63d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Changimport java.util.Date;
64d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
6523c51b794e95c201290e36737f379c4bb8eefeaeRay Chen/**
6623c51b794e95c201290e36737f379c4bb8eefeaeRay Chen * The Camcorder activity.
6723c51b794e95c201290e36737f379c4bb8eefeaeRay Chen */
68b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectpublic class VideoCamera extends Activity implements View.OnClickListener,
69d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback,
70d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
71b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
72b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final String TAG = "videocamera";
73b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
74b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    private static final int INIT_RECORDER = 3;
75b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final int CLEAR_SCREEN_DELAY = 4;
76b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final int UPDATE_RECORD_TIME = 5;
77b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
78b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final int SCREEN_DELAY = 2 * 60 * 1000;
79b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
80b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final long NO_STORAGE_ERROR = -1L;
81b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final long CANNOT_STAT_ERROR = -2L;
82b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final long LOW_STORAGE_THRESHOLD = 512L * 1024L;
83b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
849a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private static final int STORAGE_STATUS_OK = 0;
859a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private static final int STORAGE_STATUS_LOW = 1;
869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private static final int STORAGE_STATUS_NONE = 2;
879a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project
88b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_SETTINGS = 6;
89b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_GALLERY_PHOTOS = 7;
90b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_GALLERY_VIDEOS = 8;
91b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_SAVE_GALLERY_PHOTO = 34;
92b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_SAVE_PLAY_VIDEO = 35;
93b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_SAVE_SELECT_VIDEO = 36;
94b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public static final int MENU_SAVE_NEW_VIDEO = 37;
95b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
96b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    SharedPreferences mPreferences;
97b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
98b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static final float VIDEO_ASPECT_RATIO = 176.0f / 144.0f;
99b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    VideoPreview mVideoPreview;
100b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    SurfaceHolder mSurfaceHolder = null;
1019bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang
1029bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private boolean mIsVideoCaptureIntent;
1039bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    // mLastPictureButton and mThumbController
1040a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang    // are non-null only if mIsVideoCaptureIntent is true.
105de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project    private ImageView mLastPictureButton;
1069bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private ThumbnailController mThumbController;
107b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1089a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private int mStorageStatus = STORAGE_STATUS_OK;
1099a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project
110b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private MediaRecorder mMediaRecorder;
111b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private boolean mMediaRecorderRecording = false;
112b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private long mRecordingStartTime;
113b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    // The video file that the hardware camera is about to record into
114b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    // (or is recording into.)
115b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private String mCameraVideoFilename;
116b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private FileDescriptor mCameraVideoFileDescriptor;
117b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
118b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    // The video file that has already been recorded, and that is being
119b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    // examined by the user.
120b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private String mCurrentVideoFilename;
121b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private Uri mCurrentVideoUri;
122b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private ContentValues mCurrentVideoValues;
123b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
124845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    // The video frame size we will record (like 352x288).
125845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    private int mVideoWidth, mVideoHeight;
126845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
12782ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang    // The video duration limit.
12882ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang    private int mMaxVideoDurationInMs;
12982ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang
130b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    boolean mPausing = false;
131ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li    boolean mPreviewing = false;  // True if preview is started.
132b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    boolean mRecorderInitialized = false;
133b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
134d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    private ContentResolver mContentResolver;
135b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
136b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private ShutterButton mShutterButton;
137b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private TextView mRecordingTimeView;
1388d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project    private boolean mRecordingTimeCountsDown = false;
139b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
140b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
141b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
142059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin    private final Handler mHandler = new MainHandler();
143b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
144d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    // This Handler is used to post message back onto the main thread of the
145d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    // application
146b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private class MainHandler extends Handler {
147b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        @Override
148b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        public void handleMessage(Message msg) {
149b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            switch (msg.what) {
150b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
151b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                case CLEAR_SCREEN_DELAY: {
152b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    clearScreenOnFlag();
153b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    break;
154b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
155b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
156b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                case UPDATE_RECORD_TIME: {
157d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    updateRecordingTime();
158b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    break;
159b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
160b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
161b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                case INIT_RECORDER: {
162b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                    initializeRecorder();
163ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li                    break;
164ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li                }
165ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
166b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                default:
167b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    Log.v(TAG, "Unhandled message: " + msg.what);
1680a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                    break;
169b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
170b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
171937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin    }
172b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
173b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
174b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        @Override
175b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        public void onReceive(Context context, Intent intent) {
176b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            String action = intent.getAction();
177b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
1789a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                updateAndShowStorageHint(false);
179b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                stopVideoRecording();
180b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
1819a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                updateAndShowStorageHint(true);
182b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                mRecorderInitialized = false;
183b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                initializeRecorder();
184b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
185b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                // SD card unavailable
1869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                // handled in ACTION_MEDIA_EJECT
187b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
188d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                Toast.makeText(VideoCamera.this,
189d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        getResources().getString(R.string.wait), 5000);
190b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
1919a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                updateAndShowStorageHint(true);
192b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
193b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
194b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    };
195b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
196d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    private static String createName(long dateTaken) {
197b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
198b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
199b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
200b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    /** Called with the activity is first created. */
201b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
202b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onCreate(Bundle icicle) {
203b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onCreate(icicle);
204b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
205ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        /*
206ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li         * To reduce startup time, we open camera device in another thread.
207ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li         * Camera is opened in onCreate instead of onResume because there are
208ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li         * lots of things to do here and camera open can be done in parallel.
209ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li         * We will make sure the camera is opened at the end of onCreate.
210ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li         */
211ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        Thread openCameraThread = new Thread(new Runnable() {
212ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            public void run() {
213cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang                mCameraDevice = CameraHolder.instance().open();
214ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            }
215ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        });
216ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        openCameraThread.start();
217ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
218b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
219b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mContentResolver = getContentResolver();
220b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
221b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        requestWindowFeature(Window.FEATURE_PROGRESS);
222b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setContentView(R.layout.video_camera);
223b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
224b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mVideoPreview = (VideoPreview) findViewById(R.id.camera_preview);
225b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mVideoPreview.setAspectRatio(VIDEO_ASPECT_RATIO);
226b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
227b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // don't set mSurfaceHolder here. We have it set ONLY within
228b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // surfaceCreated / surfaceDestroyed, other parts of the code
229b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // assume that when it is set, the surface is also set.
230b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        SurfaceHolder holder = mVideoPreview.getHolder();
231b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        holder.addCallback(this);
232b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
233b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
234dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin        mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
235dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin        mShutterButton.setImageResource(R.drawable.btn_ic_video_record);
236b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mShutterButton.setOnShutterButtonListener(this);
237059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin        mShutterButton.requestFocus();
238059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin
239b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
2409bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        mIsVideoCaptureIntent = isVideoCaptureIntent();
2419bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (!mIsVideoCaptureIntent) {
242dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            mLastPictureButton = (ImageView) findViewById(R.id.review_thumbnail);
2439bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mLastPictureButton.setOnClickListener(this);
244059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin            mThumbController = new ThumbnailController(
245059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin                    mLastPictureButton, mContentResolver);
2469bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mThumbController.loadData(ImageManager.getLastVideoThumbPath());
247dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            findViewById(R.id.camera_switch).setOnClickListener(this);
248059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin        } else {
249dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            findViewById(R.id.review_thumbnail).setVisibility(View.INVISIBLE);
2509bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        }
251ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
252ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        // Make sure the camera is opened.
253ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        try {
254ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            openCameraThread.join();
255ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        } catch (InterruptedException ex) {
256ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            // ignore
257ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        }
258b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
259b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
260e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project    private void startShareVideoActivity() {
261e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        Intent intent = new Intent();
262e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        intent.setAction(Intent.ACTION_SEND);
263e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        intent.setType("video/3gpp");
264e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri);
265e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        try {
266d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            startActivity(Intent.createChooser(
267d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    intent, getText(R.string.sendVideo)));
268e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        } catch (android.content.ActivityNotFoundException ex) {
269d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video,
270d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    Toast.LENGTH_SHORT).show();
271e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project        }
272e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project    }
273e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project
274b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onClick(View v) {
275b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        switch (v.getId()) {
276dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            case R.id.camera_switch:
277059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin                MenuHelper.gotoCameraMode(this);
278059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin                break;
279b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.gallery:
2800a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang                gotoGallery();
281b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
282b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.attach:
283b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                doReturnToCaller(true);
284b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
285b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.cancel:
286b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                doReturnToCaller(false);
287b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
288b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.discard: {
2897638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen                Runnable deleteCallback = new Runnable() {
2907638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen                    public void run() {
291b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                        discardCurrentVideoAndInitRecorder();
2927638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen                    }
2937638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen                };
2947638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen                MenuHelper.deleteVideo(this, deleteCallback);
295b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
296b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
297b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.share: {
298e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project                startShareVideoActivity();
299b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
300b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
301b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case R.id.play: {
302b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                doPlayCurrentVideo();
303b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
304b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
305dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            case R.id.review_thumbnail: {
30646fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li                stopVideoRecordingAndShowReview();
307de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                break;
308de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            }
309b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
310b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
311b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
312b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onShutterButtonFocus(ShutterButton button, boolean pressed) {
313de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        // Do nothing (everything happens in onShutterButtonClick).
314de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project    }
315de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project
316de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project    public void onShutterButtonClick(ShutterButton button) {
317b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        switch (button.getId()) {
318dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin            case R.id.shutter_button:
319de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                if (mMediaRecorderRecording) {
3209bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang                    if (mIsVideoCaptureIntent) {
32146fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li                        stopVideoRecordingAndShowReview();
322b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    } else {
3239bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang                        stopVideoRecordingAndGetThumbnail();
324b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                        mRecorderInitialized = false;
325b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                        initializeRecorder();
3269bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang                    }
327b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                } else if (mRecorderInitialized) {
328b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                    // If the click comes before recorder initialization, it is
329b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                    // ignored. If users click the button during initialization,
330b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                    // the event is put in the queue and record will be started
331b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                    // eventually.
332de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    startVideoRecording();
333b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
334b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
335b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
336b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
337b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
338b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void doPlayCurrentVideo() {
3390a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang        Log.v(TAG, "Playing current video: " + mCurrentVideoUri);
340b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri);
341b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        try {
342b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            startActivity(intent);
343b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } catch (android.content.ActivityNotFoundException ex) {
344b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
345b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
346b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
347b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
348b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    private void discardCurrentVideoAndInitRecorder() {
349b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        deleteCurrentVideo();
350b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        hideAlertAndInitializeRecorder();
351b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
352b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
353b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private OnScreenHint mStorageHint;
354b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
3559a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private void updateAndShowStorageHint(boolean mayHaveSd) {
3569a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        mStorageStatus = getStorageStatus(mayHaveSd);
3579a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        showStorageHint();
3589a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    }
3599a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project
3609a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private void showStorageHint() {
361b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String errorMessage = null;
3629a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        switch (mStorageStatus) {
3639a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        case STORAGE_STATUS_NONE:
364b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            errorMessage = getString(R.string.no_storage);
3659a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            break;
3669a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        case STORAGE_STATUS_LOW:
367b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            errorMessage = getString(R.string.spaceIsLow_content);
368b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
369b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (errorMessage != null) {
370b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (mStorageHint == null) {
371b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mStorageHint = OnScreenHint.makeText(this, errorMessage);
372b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else {
373b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mStorageHint.setText(errorMessage);
374b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
375b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mStorageHint.show();
376b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } else if (mStorageHint != null) {
377b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mStorageHint.cancel();
378b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mStorageHint = null;
379b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
380b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
381b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
3829a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    private int getStorageStatus(boolean mayHaveSd) {
3839a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        long remaining = mayHaveSd ? getAvailableStorage() : NO_STORAGE_ERROR;
3849a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        if (remaining == NO_STORAGE_ERROR) {
3859a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            return STORAGE_STATUS_NONE;
3869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        }
3879a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        return remaining < LOW_STORAGE_THRESHOLD
3889a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                ? STORAGE_STATUS_LOW : STORAGE_STATUS_OK;
3899a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project    }
3909a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project
391845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    private void readVideoSizePreference() {
392845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        boolean videoQualityHigh = getBooleanPreference(
393845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang                CameraSettings.KEY_VIDEO_QUALITY,
394845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang                CameraSettings.DEFAULT_VIDEO_QUALITY_VALUE);
395845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
39682ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang        // 1 minute = 60000ms
39782ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang        mMaxVideoDurationInMs = 60000 * getIntPreference(
39882ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang                CameraSettings.KEY_VIDEO_DURATION,
39982ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang                CameraSettings.DEFAULT_VIDEO_DURATION_VALUE);
40082ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang
401845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        Intent intent = getIntent();
402845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
403845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            int extraVideoQuality = intent.getIntExtra(
404845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang                    MediaStore.EXTRA_VIDEO_QUALITY, 0);
405845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            videoQualityHigh = (extraVideoQuality > 0);
406845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
407845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
408845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        if (videoQualityHigh) {
409845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            // CIF size
410845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mVideoWidth = 352;
411845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mVideoHeight = 288;
412845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        } else {
413845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            // QCIF size
414845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mVideoWidth = 176;
415845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mVideoHeight = 144;
416845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
417845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    }
418845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
419b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
420b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onResume() {
421b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onResume();
422845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mPausing = false;
423b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
424b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenTimeoutLong();
425845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        readVideoSizePreference();
426b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
427b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // install an intent filter to receive SD card related events.
428d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        IntentFilter intentFilter =
429d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
430b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
431b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
432b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
433b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
434b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        intentFilter.addDataScheme("file");
435b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        registerReceiver(mReceiver, intentFilter);
4369a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        mStorageStatus = getStorageStatus(true);
4379a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project
4389a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        mHandler.postDelayed(new Runnable() {
4399a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            public void run() {
4409a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project                showStorageHint();
4419a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            }
4429a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        }, 200);
443b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
444b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        if (mSurfaceHolder != null) {
445b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            startPreview();
446b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            mRecorderInitialized = false;
447b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            mHandler.sendEmptyMessage(INIT_RECORDER);
448b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        }
449b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
450b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
451845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    private void setCameraParameters() {
452845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        android.hardware.Camera.Parameters param;
453845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        param = mCameraDevice.getParameters();
454845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        param.setPreviewSize(mVideoWidth, mVideoHeight);
455845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mCameraDevice.setParameters(param);
456845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    }
457845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
458845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    // Precondition: mSurfaceHolder != null
459fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li    private void startPreview() {
460845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        Log.v(TAG, "startPreview");
461ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        if (mPreviewing) {
4621fb8ac4e3e03f31e6e099776d1026b9cadf57610Chih-Chung Chang            // After recording a video, preview is not stopped. So just return.
463fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li            return;
464845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
465ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
466ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        if (mCameraDevice == null) {
467ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            // If the activity is paused and resumed, camera device has been
468ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            // released and we need to open the camera.
469cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang            mCameraDevice = CameraHolder.instance().open();
470ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        }
471ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
472845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        setCameraParameters();
473845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        try {
474845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mCameraDevice.setPreviewDisplay(mSurfaceHolder);
475fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li        } catch (Throwable ex) {
476fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li            closeCamera();
477fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li            throw new RuntimeException("setPreviewDisplay failed", ex);
478845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
479ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li
480845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        try {
481845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            mCameraDevice.startPreview();
482ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li            mPreviewing = true;
483845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        } catch (Throwable ex) {
484fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li            closeCamera();
485fa1dfa2f3f1385e98cf8bdac5c48f8d13a400a8aWu-cheng Li            throw new RuntimeException("startPreview failed", ex);
486845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
487845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mCameraDevice.unlock();
488845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    }
489845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
490d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang    private void closeCamera() {
491d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang        Log.v(TAG, "closeCamera");
492845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        if (mCameraDevice == null) {
493845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            Log.d(TAG, "already stopped.");
494845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang            return;
495845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        }
496fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        // If we don't lock the camera, release() will fail.
497fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        mCameraDevice.lock();
498cd65be31531717fb032b7423f8d5a77df465cfcaChih-Chung Chang        CameraHolder.instance().release();
499845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mCameraDevice = null;
500ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        mPreviewing = false;
501845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    }
502845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
503b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
504b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onStop() {
505b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenTimeoutSystemDefault();
506b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onStop();
507b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
508b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
509b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
510b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    protected void onPause() {
511b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onPause();
512b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
513fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        mPausing = true;
514fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li
5159bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        // This is similar to what mShutterButton.performClick() does,
5169bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        // but not quite the same.
5179bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (mMediaRecorderRecording) {
5189bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            if (mIsVideoCaptureIntent) {
51946fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li                stopVideoRecordingAndShowReview();
5209bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            } else {
5219bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang                stopVideoRecordingAndGetThumbnail();
5229bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            }
5239bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        } else {
5249bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            stopVideoRecording();
5259bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        }
526fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        closeCamera();
527b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
5289c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        unregisterReceiver(mReceiver);
529b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenTimeoutSystemDefault();
530b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
5319bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (!mIsVideoCaptureIntent) {
5329bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mThumbController.storeData(ImageManager.getLastVideoThumbPath());
5339bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        }
534095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin
535b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mStorageHint != null) {
536b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mStorageHint.cancel();
537b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mStorageHint = null;
538b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
539845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang
540b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        mHandler.removeMessages(INIT_RECORDER);
541b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
542b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
543b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
544b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
545fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        // Do not handle any key if the activity is paused.
546fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        if (mPausing) {
547fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li            return true;
548fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li        }
549fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li
550b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenTimeoutLong();
551b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
552b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        switch (keyCode) {
553b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case KeyEvent.KEYCODE_BACK:
554b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                if (mMediaRecorderRecording) {
555de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    mShutterButton.performClick();
556b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    return true;
557b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
558b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
559b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case KeyEvent.KEYCODE_CAMERA:
560b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                if (event.getRepeatCount() == 0) {
561de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    mShutterButton.performClick();
562b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    return true;
563b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
564de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                break;
565b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_CENTER:
566b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                if (event.getRepeatCount() == 0) {
567de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    mShutterButton.performClick();
568de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    return true;
569b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
570b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
571b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            case KeyEvent.KEYCODE_MENU:
572b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                if (mMediaRecorderRecording) {
573de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project                    mShutterButton.performClick();
574b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    return true;
575b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
576b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                break;
577b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
578b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
579b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return super.onKeyDown(keyCode, event);
580b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
581b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
582b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
583b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
584b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        switch(keyCode) {
585b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        case KeyEvent.KEYCODE_CAMERA:
586b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mShutterButton.setPressed(false);
587b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            return true;
588b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
589b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return super.onKeyUp(keyCode, event);
590b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
591b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
592b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
593314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber        if (mPausing) {
594314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // We're pausing, the screen is off and we already stopped
595314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // video recording. We don't want to start the camera again
596314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // in this case in order to conserve power.
597314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // The fact that surfaceChanged is called _after_ an onPause appears
598314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // to be legitimate since in that case the lockscreen always returns
599314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            // to portrait orientation possibly triggering the notification.
600314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber            return;
601314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber        }
602314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber
603b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        if (mMediaRecorderRecording) {
604b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            stopVideoRecording();
605b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        }
606b128446b7ef264c33e91e119391045156a19439bWu-cheng Li
607b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        // Start the preview if it is not started yet. Preview may be already
608b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        // started in onResume and then surfaceChanged is called due to
609b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        // orientation change.
610b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        if (!mPreviewing) {
611b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            startPreview();
612b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            mRecorderInitialized = false;
613b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            mHandler.sendEmptyMessage(INIT_RECORDER);
614b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        }
615b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
616b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
617b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void surfaceCreated(SurfaceHolder holder) {
618b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mSurfaceHolder = holder;
619b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
620b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
621b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void surfaceDestroyed(SurfaceHolder holder) {
622b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mSurfaceHolder = null;
623b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
624b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
6250a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang    private void gotoGallery() {
626b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        MenuHelper.gotoCameraVideoGallery(this);
627b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
628b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
629b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
630b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public boolean onPrepareOptionsMenu(Menu menu) {
631b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onPrepareOptionsMenu(menu);
632b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
633b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        for (int i = 1; i <= MenuHelper.MENU_ITEM_MAX; i++) {
634b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (i != MenuHelper.GENERIC_ITEM) {
635b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                menu.setGroupVisible(i, false);
636b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
637b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
638b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
639b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        menu.setGroupVisible(MenuHelper.VIDEO_MODE_ITEM, true);
640b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return true;
641b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
642b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
643b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    @Override
644b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public boolean onCreateOptionsMenu(Menu menu) {
645b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        super.onCreateOptionsMenu(menu);
646b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
6479bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (mIsVideoCaptureIntent) {
648b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // No options menu for attach mode.
649b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            return false;
650b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } else {
651b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            addBaseMenuItems(menu);
652d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            int menuFlags = MenuHelper.INCLUDE_ALL
653d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    & ~MenuHelper.INCLUDE_ROTATE_MENU
654095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin                    & ~MenuHelper.INCLUDE_DETAILS_MENU;
655b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            MenuHelper.addImageMenuItems(
656b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    menu,
657095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin                    menuFlags,
658b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    false,
659b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    VideoCamera.this,
66023c51b794e95c201290e36737f379c4bb8eefeaeRay Chen                    mHandler,
661b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    // Handler for deletion
662b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    new Runnable() {
663b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                        public void run() {
664b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                            // What do we do here?
665b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                            // mContentResolver.delete(uri, null, null);
666b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                        }
667b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    },
668b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    new MenuHelper.MenuInvoker() {
669b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                        public void run(final MenuHelper.MenuCallback cb) {
670b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                        }
671b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    });
672b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
673d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            MenuItem gallery = menu.add(MenuHelper.IMAGE_SAVING_ITEM,
674d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    MENU_SAVE_GALLERY_PHOTO, 0,
675d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    R.string.camera_gallery_photos_text)
676d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    .setOnMenuItemClickListener(
677d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    new MenuItem.OnMenuItemClickListener() {
678d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        public boolean onMenuItemClick(MenuItem item) {
679d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            gotoGallery();
680d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            return true;
681d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        }
682d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    });
683b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            gallery.setIcon(android.R.drawable.ic_menu_gallery);
684b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
685b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return true;
686b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
687b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
688b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private boolean isVideoCaptureIntent() {
689b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String action = getIntent().getAction();
690b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return (MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
691b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
692b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
693b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void doReturnToCaller(boolean success) {
694b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Intent resultIntent = new Intent();
695b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        int resultCode;
696b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (success) {
697b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            resultCode = RESULT_OK;
698b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            resultIntent.setData(mCurrentVideoUri);
699b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } else {
700b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            resultCode = RESULT_CANCELED;
701b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
702b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setResult(resultCode, resultIntent);
703b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        finish();
704b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
705b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
706b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    /**
707b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project     * Returns
708b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project     * @return number of bytes available, or an ERROR code.
709b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project     */
710b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private static long getAvailableStorage() {
711b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        try {
712b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (!ImageManager.hasStorage()) {
713b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                return NO_STORAGE_ERROR;
714b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else {
715d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                String storageDirectory = Environment
716d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        .getExternalStorageDirectory().toString();
717b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                StatFs stat = new StatFs(storageDirectory);
718d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                return ((long) stat.getAvailableBlocks()
719d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        * (long) stat.getBlockSize());
720b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
72123c51b794e95c201290e36737f379c4bb8eefeaeRay Chen        } catch (RuntimeException ex) {
722b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // if we can't stat the filesystem then we don't know how many
723b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // free bytes exist.  It might be zero but just leave it
724b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // blank since we really don't know.
725b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            return CANNOT_STAT_ERROR;
726b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
727b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
728b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
729b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void cleanupEmptyFile() {
730b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mCameraVideoFilename != null) {
731b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            File f = new File(mCameraVideoFilename);
732b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (f.length() == 0 && f.delete()) {
733b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project              Log.v(TAG, "Empty video file deleted: " + mCameraVideoFilename);
734b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project              mCameraVideoFilename = null;
735b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
736b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
737b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
738b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
739845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang    private android.hardware.Camera mCameraDevice;
740b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    // initializeRecorder() prepares media recorder. Return false if fails.
741b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    private boolean initializeRecorder() {
742b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        Log.v(TAG, "initializeRecorder");
743b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        if (mRecorderInitialized) return true;
7449bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang
745b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Intent intent = getIntent();
746b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Bundle myExtras = intent.getExtras();
747b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
7489bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (mIsVideoCaptureIntent && myExtras != null) {
749b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
750b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (saveUri != null) {
751b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                try {
752b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    mCameraVideoFileDescriptor = mContentResolver.
753b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                        openFileDescriptor(saveUri, "rw").getFileDescriptor();
754b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    mCurrentVideoUri = saveUri;
755d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                } catch (java.io.FileNotFoundException ex) {
756b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    // invalid uri
757b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    Log.e(TAG, ex.toString());
758b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
759b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
760b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
761b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        releaseMediaRecorder();
762b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
763b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder = new MediaRecorder();
764b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
765845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mMediaRecorder.setCamera(mCameraDevice);
766d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
767b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
768b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
76982ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang        mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
7708d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project
7719a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        if (mStorageStatus != STORAGE_STATUS_OK) {
772b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorder.setOutputFile("/dev/null");
773b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } else {
774d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            // We try Uri in intent first. If it doesn't work, use our own
775d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            // instead.
776b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (mCameraVideoFileDescriptor != null) {
777b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mMediaRecorder.setOutputFile(mCameraVideoFileDescriptor);
778b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } else {
779b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                createVideoPath();
780b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mMediaRecorder.setOutputFile(mCameraVideoFilename);
781b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
782b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
783b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
784b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // Use the same frame rate for both, since internally
785b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // if the frame rate is too large, it can cause camera to become
786b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // unstable. We need to fix the MediaRecorder to disable the support
787b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        // of setting frame rate for now.
788b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder.setVideoFrameRate(20);
789845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang        mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
790b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
791d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
792b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
793de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project
794de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        long remaining = getAvailableStorage();
795de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        // remaining >= LOW_STORAGE_THRESHOLD at this point, reserve a quarter
796d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // of that to make it more likely that recording can complete
797d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // successfully.
798de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        try {
799d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            mMediaRecorder.setMaxFileSize(remaining -
800d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    LOW_STORAGE_THRESHOLD / 4);
801de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        } catch (RuntimeException exception) {
802de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            // We are going to ignore failure of setMaxFileSize here, as
803de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            // a) The composer selected may simply not support it, or
804de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            // b) The underlying media framework may not handle 64-bit range
805de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            //    on the size restriction.
806de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        }
807de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project
808b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        try {
809b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorder.prepare();
810b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } catch (IOException exception) {
811b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Log.e(TAG, "prepare failed for " + mCameraVideoFilename);
812b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            releaseMediaRecorder();
813b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // TODO: add more exception handling logic here
814b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            return false;
815b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
816b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mMediaRecorderRecording = false;
8179bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang
818ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li        // Update the last video thumbnail.
819b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        if (!mIsVideoCaptureIntent) {
820b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            if (!mThumbController.isUriValid()) {
821b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                updateLastVideo();
822b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            }
823b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            mThumbController.updateDisplayIfNeeded();
8249bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        }
825b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        mRecorderInitialized = true;
826b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return true;
827b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
828b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
829b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void releaseMediaRecorder() {
830b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Log.v(TAG, "Releasing media recorder.");
831b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mMediaRecorder != null) {
832b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            cleanupEmptyFile();
833b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorder.reset();
834b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorder.release();
835b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorder = null;
836b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
837b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
838b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
839b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private int getIntPreference(String key, int defaultValue) {
840b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String s = mPreferences.getString(key, "");
841b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        int result = defaultValue;
842b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        try {
843b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            result = Integer.parseInt(s);
844b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        } catch (NumberFormatException e) {
845b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // Ignore, result is already the default value.
846b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
847b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return result;
848b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
849b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
850b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private boolean getBooleanPreference(String key, boolean defaultValue) {
851b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        return getIntPreference(key, defaultValue ? 1 : 0) != 0;
852b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
853b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
854b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void createVideoPath() {
855b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        long dateTaken = System.currentTimeMillis();
856b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String title = createName(dateTaken);
857b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String displayName = title + ".3gp"; // Used when emailing.
858b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String cameraDirPath = ImageManager.CAMERA_IMAGE_BUCKET_NAME;
859b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        File cameraDir = new File(cameraDirPath);
860b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        cameraDir.mkdirs();
861b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        SimpleDateFormat dateFormat = new SimpleDateFormat(
862b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                getString(R.string.video_file_name_format));
863b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Date date = new Date(dateTaken);
864b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String filepart = dateFormat.format(date);
865b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        String filename = cameraDirPath + "/" + filepart + ".3gp";
866b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        ContentValues values = new ContentValues(7);
867b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        values.put(Video.Media.TITLE, title);
868b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        values.put(Video.Media.DISPLAY_NAME, displayName);
869b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        values.put(Video.Media.DATE_TAKEN, dateTaken);
870b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        values.put(Video.Media.MIME_TYPE, "video/3gpp");
871b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        values.put(Video.Media.DATA, filename);
872b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mCameraVideoFilename = filename;
873b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Log.v(TAG, "Current camera video filename: " + mCameraVideoFilename);
874b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mCurrentVideoValues = values;
875b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
876b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
877b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void registerVideo() {
878b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mCameraVideoFileDescriptor == null) {
879b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Uri videoTable = Uri.parse("content://media/external/video/media");
88084eaae7fbd51fe915c4a5e1daffe444b02352cdbOwen Lin            mCurrentVideoValues.put(Video.Media.SIZE,
88184eaae7fbd51fe915c4a5e1daffe444b02352cdbOwen Lin                    new File(mCurrentVideoFilename).length());
882b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mCurrentVideoUri = mContentResolver.insert(videoTable,
883b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    mCurrentVideoValues);
884b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Log.v(TAG, "Current video URI: " + mCurrentVideoUri);
885b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
886b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mCurrentVideoValues = null;
887b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
888b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
889b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void deleteCurrentVideo() {
890b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mCurrentVideoFilename != null) {
891b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            deleteVideoFile(mCurrentVideoFilename);
892b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mCurrentVideoFilename = null;
893b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
894b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mCurrentVideoUri != null) {
895b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mContentResolver.delete(mCurrentVideoUri, null, null);
896b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mCurrentVideoUri = null;
897b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
898de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        updateAndShowStorageHint(true);
899b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
900b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
901b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void deleteVideoFile(String fileName) {
902b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Log.v(TAG, "Deleting video " + fileName);
903b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        File f = new File(fileName);
904d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (!f.delete()) {
905b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            Log.v(TAG, "Could not delete " + fileName);
906b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
907b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
908b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
909b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void addBaseMenuItems(Menu menu) {
910b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        MenuHelper.addSwitchModeMenuItem(menu, this, false);
911b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        {
912d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            MenuItem gallery = menu.add(MenuHelper.IMAGE_MODE_ITEM,
913d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    MENU_GALLERY_PHOTOS, 0, R.string.camera_gallery_photos_text)
914d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    .setOnMenuItemClickListener(new OnMenuItemClickListener() {
915d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        public boolean onMenuItemClick(MenuItem item) {
916d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            gotoGallery();
917d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            return true;
918d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        }
919d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    });
920b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            gallery.setIcon(android.R.drawable.ic_menu_gallery);
921b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mGalleryItems.add(gallery);
922b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
923b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        {
924d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            MenuItem gallery = menu.add(MenuHelper.VIDEO_MODE_ITEM,
925d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    MENU_GALLERY_VIDEOS, 0, R.string.camera_gallery_photos_text)
926d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    .setOnMenuItemClickListener(new OnMenuItemClickListener() {
927d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        public boolean onMenuItemClick(MenuItem item) {
928d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            gotoGallery();
929d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                            return true;
930d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        }
931d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    });
932b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            gallery.setIcon(android.R.drawable.ic_menu_gallery);
933b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mGalleryItems.add(gallery);
934b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
935b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
936d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        MenuItem item = menu.add(MenuHelper.GENERIC_ITEM, MENU_SETTINGS, 0,
937d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                R.string.settings)
938d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                .setOnMenuItemClickListener(new OnMenuItemClickListener() {
939d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    public boolean onMenuItemClick(MenuItem item) {
94055319ceeef829274a95e2a41e7e365228acf5ccdWu-cheng Li                        // Keep the camera instance for a while.
94155319ceeef829274a95e2a41e7e365228acf5ccdWu-cheng Li                        // This avoids re-opening the camera and saves time.
94255319ceeef829274a95e2a41e7e365228acf5ccdWu-cheng Li                        CameraHolder.instance().keep();
94355319ceeef829274a95e2a41e7e365228acf5ccdWu-cheng Li
944d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        Intent intent = new Intent();
945d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        intent.setClass(VideoCamera.this, CameraSettings.class);
946d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        startActivity(intent);
947d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        return true;
948d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    }
949d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                });
950b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        item.setIcon(android.R.drawable.ic_menu_preferences);
951b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
952b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
953b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    // from MediaRecorder.OnErrorListener
954b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    public void onError(MediaRecorder mr, int what, int extra) {
955b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
956b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // We may have run out of space on the sdcard.
957b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            stopVideoRecording();
9589a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            updateAndShowStorageHint(true);
959b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
960b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
961b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
9628d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project    // from MediaRecorder.OnInfoListener
9638d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project    public void onInfo(MediaRecorder mr, int what, int extra) {
9648d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project        if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
965de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            mShutterButton.performClick();
966d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        } else if (what
967d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
968de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            mShutterButton.performClick();
969de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project            updateAndShowStorageHint(true);
9708d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project        }
9718d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project    }
9728d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project
9739c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project    /*
9749c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project     * Make sure we're not recording music playing in the background, ask
9759c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project     * the MediaPlaybackService to pause playback.
9769c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project     */
9779c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project    private void pauseAudioPlayback() {
9789c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        // Shamelessly copied from MediaPlaybackService.java, which
9799c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        // should be public, but isn't.
9809c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        Intent i = new Intent("com.android.music.musicservicecommand");
9819c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        i.putExtra("command", "pause");
9829c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project
9839c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project        sendBroadcast(i);
9849c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project    }
9859c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project
986b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void startVideoRecording() {
987b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Log.v(TAG, "startVideoRecording");
988b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (!mMediaRecorderRecording) {
989b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
9909a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            if (mStorageStatus != STORAGE_STATUS_OK) {
991b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                Log.v(TAG, "Storage issue, ignore the start request");
992b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                return;
993b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
994b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
995b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            // Check mMediaRecorder to see whether it is initialized or not.
996b128446b7ef264c33e91e119391045156a19439bWu-cheng Li            if (mMediaRecorder == null) {
997b128446b7ef264c33e91e119391045156a19439bWu-cheng Li                Log.e(TAG, "MediaRecorder is not initialized.");
998b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                return;
999b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
1000b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
10019c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project            pauseAudioPlayback();
10029c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project
1003b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            try {
1004b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mMediaRecorder.setOnErrorListener(this);
10058d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project                mMediaRecorder.setOnInfoListener(this);
1006b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mMediaRecorder.start();   // Recording is now started
1007b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            } catch (RuntimeException e) {
1008b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                Log.e(TAG, "Could not start media recorder. ", e);
1009b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                return;
1010b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
1011b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mMediaRecorderRecording = true;
1012b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mRecordingStartTime = SystemClock.uptimeMillis();
101346fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            updateRecordingIndicator(false);
1014b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mRecordingTimeView.setText("");
1015b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mRecordingTimeView.setVisibility(View.VISIBLE);
1016b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mHandler.sendEmptyMessage(UPDATE_RECORD_TIME);
1017b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            setScreenTimeoutInfinite();
1018b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
1019b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1020b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1021b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void updateRecordingIndicator(boolean showRecording) {
1022d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        int drawableId = showRecording
1023dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin                ? R.drawable.btn_ic_video_record
1024dad4b187eec436a2716aca5af31f23ce5de95f39Owen Lin                : R.drawable.btn_ic_video_record_stop;
1025b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Drawable drawable = getResources().getDrawable(drawableId);
1026b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mShutterButton.setImageDrawable(drawable);
1027b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1028b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
10299bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private void stopVideoRecordingAndGetThumbnail() {
10309bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        stopVideoRecording();
10319bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        acquireVideoThumb();
1032b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1033b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
103446fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li    private void stopVideoRecordingAndShowReview() {
1035de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project        stopVideoRecording();
103646fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li        if (mThumbController.isUriValid()) {
103746fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            Uri targetUri = mThumbController.getUri();
103846fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            Intent intent = new Intent(this, ReviewImage.class);
103946fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            intent.setData(targetUri);
104046fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            intent.putExtra(MediaStore.EXTRA_FULL_SCREEN, true);
104146fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            intent.putExtra(MediaStore.EXTRA_SHOW_ACTION_ICONS, true);
104246fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            intent.putExtra("com.android.camera.ReviewMode", true);
104346fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            try {
104446fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li                startActivity(intent);
104546fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            } catch (ActivityNotFoundException ex) {
104646fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li                Log.e(TAG, "review video fail", ex);
104746fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            }
104846fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li        } else {
104946fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            Log.e(TAG, "Can't view last video.");
105046fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li        }
1051b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1052b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1053b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void stopVideoRecording() {
1054b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Log.v(TAG, "stopVideoRecording");
1055b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        boolean needToRegisterRecording = false;
1056b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        if (mMediaRecorderRecording || mMediaRecorder != null) {
1057b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            if (mMediaRecorderRecording && mMediaRecorder != null) {
1058b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                try {
1059b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    mMediaRecorder.setOnErrorListener(null);
10608d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project                    mMediaRecorder.setOnInfoListener(null);
1061b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    mMediaRecorder.stop();
1062b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                } catch (RuntimeException e) {
1063b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                    Log.e(TAG, "stop fail: " + e.getMessage());
1064b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                }
10658d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project
1066b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mCurrentVideoFilename = mCameraVideoFilename;
1067d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                Log.v(TAG, "Setting current video filename: "
1068d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                        + mCurrentVideoFilename);
1069b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                needToRegisterRecording = true;
1070b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project                mMediaRecorderRecording = false;
1071b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            }
1072b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            releaseMediaRecorder();
107346fc7aeec04021dfc2f4c947649888dbc7408f53Wu-cheng Li            updateRecordingIndicator(true);
1074b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            mRecordingTimeView.setVisibility(View.GONE);
1075b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project            setScreenTimeoutLong();
1076b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
10779a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        if (needToRegisterRecording && mStorageStatus == STORAGE_STATUS_OK) {
10789a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project            registerVideo();
10799a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project        }
1080b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1081b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mCameraVideoFilename = null;
1082b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mCameraVideoFileDescriptor = null;
1083b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1084b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1085b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void setScreenTimeoutSystemDefault() {
1086b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1087b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        clearScreenOnFlag();
1088b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1089b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1090b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void setScreenTimeoutLong() {
1091b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1092b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenOnFlag();
1093b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1094b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1095b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1096b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void setScreenTimeoutInfinite() {
1097b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1098b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        setScreenOnFlag();
1099b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1100b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1101b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void clearScreenOnFlag() {
1102b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Window w = getWindow();
1103d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        final int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1104d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if ((w.getAttributes().flags & flag) != 0) {
1105d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            w.clearFlags(flag);
1106b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
1107b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1108b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1109b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    private void setScreenOnFlag() {
1110b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        Window w = getWindow();
1111d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        final int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1112d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if ((w.getAttributes().flags & flag) == 0) {
1113d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            w.addFlags(flag);
1114b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project        }
1115b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1116b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1117b128446b7ef264c33e91e119391045156a19439bWu-cheng Li    private void hideAlertAndInitializeRecorder() {
1118b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        mRecorderInitialized = false;
1119b128446b7ef264c33e91e119391045156a19439bWu-cheng Li        mHandler.sendEmptyMessage(INIT_RECORDER);
1120b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1121b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
11229bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private void acquireVideoThumb() {
1123101d528d59f447847d5c6b7578642132c2b76f4fOwen Lin        Bitmap videoFrame = Util.createVideoThumbnail(mCurrentVideoFilename);
11249bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        mThumbController.setData(mCurrentVideoUri, videoFrame);
1125de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project    }
1126de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project
11279bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private static ImageManager.DataLocation dataLocation() {
11289bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        return ImageManager.DataLocation.EXTERNAL;
1129de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project    }
1130de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project
11319bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang    private void updateLastVideo() {
113258e94eddd371a9bb7c04936dbeb99615fd1a0c2cChih-Chung Chang        IImageList list = ImageManager.allImages(
11339bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mContentResolver,
11349bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            dataLocation(),
11359bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            ImageManager.INCLUDE_VIDEOS,
11369bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            ImageManager.SORT_ASCENDING,
11379bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            ImageManager.CAMERA_IMAGE_BUCKET_ID);
11389bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        int count = list.getCount();
11399bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        if (count > 0) {
1140d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            IImage image = list.getImageAt(count - 1);
11419bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            Uri uri = image.fullSizeImageUri();
11429bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mThumbController.setData(uri, image.miniThumbBitmap());
11439bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        } else {
11449bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang            mThumbController.setData(null, null);
11459bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        }
11469bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang        list.deactivate();
1147b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project    }
1148b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project
1149d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    private void updateRecordingTime() {
115023c51b794e95c201290e36737f379c4bb8eefeaeRay Chen        if (!mMediaRecorderRecording) {
115123c51b794e95c201290e36737f379c4bb8eefeaeRay Chen            return;
115223c51b794e95c201290e36737f379c4bb8eefeaeRay Chen        }
1153d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long now = SystemClock.uptimeMillis();
1154d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long delta = now - mRecordingStartTime;
1155d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1156d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // Starting a minute before reaching the max duration
1157d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // limit, we'll countdown the remaining time instead.
1158d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        boolean countdownRemainingTime =
115982ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang            (delta >= mMaxVideoDurationInMs - 60000);
1160d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1161d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (countdownRemainingTime) {
116282ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang            delta = Math.max(0, mMaxVideoDurationInMs - delta);
1163d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        }
1164d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1165d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long seconds = (delta + 500) / 1000;  // round to nearest
1166d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long minutes = seconds / 60;
1167d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long hours = minutes / 60;
1168d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long remainderMinutes = minutes - (hours * 60);
1169d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        long remainderSeconds = seconds - (minutes * 60);
1170d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1171d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        String secondsString = Long.toString(remainderSeconds);
1172d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (secondsString.length() < 2) {
1173d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            secondsString = "0" + secondsString;
1174d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        }
1175d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        String minutesString = Long.toString(remainderMinutes);
1176d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (minutesString.length() < 2) {
1177d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            minutesString = "0" + minutesString;
1178d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        }
1179d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        String text = minutesString + ":" + secondsString;
1180d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (hours > 0) {
1181d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            String hoursString = Long.toString(hours);
1182d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            if (hoursString.length() < 2) {
1183d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                hoursString = "0" + hoursString;
1184d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            }
1185d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            text = hoursString + ":" + text;
1186d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        }
1187d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        mRecordingTimeView.setText(text);
1188d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1189d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        if (mRecordingTimeCountsDown != countdownRemainingTime) {
1190d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            // Avoid setting the color on every update, do it only
1191d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            // when it needs changing.
1192d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1193d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            mRecordingTimeCountsDown = countdownRemainingTime;
1194d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1195d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            int color = getResources().getColor(
1196d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    countdownRemainingTime
1197d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    ? R.color.recording_time_remaining_text
1198d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang                    : R.color.recording_time_elapsed_text);
1199d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1200d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang            mRecordingTimeView.setTextColor(color);
1201d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        }
1202d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang
1203d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // Work around a limitation of the T-Mobile G1: The T-Mobile
1204d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // hardware blitter can't pixel-accurately scale and clip at the
1205d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // same time, and the SurfaceFlinger doesn't attempt to work around
1206d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // this limitation. In order to avoid visual corruption we must
1207d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // manually refresh the entire surface view when changing any
1208d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        // overlapping view's contents.
1209d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        mVideoPreview.invalidate();
1210d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang        mHandler.sendEmptyMessageDelayed(UPDATE_RECORD_TIME, 1000);
1211d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang    }
1212b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project}
1213