blob: 4f22804ec23f77ec0a93e0fac45233b92b974a63 [file] [log] [blame]
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
Owen Lin61b98312009-06-19 00:21:10 -07004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08007 *
Owen Lin61b98312009-06-19 00:21:10 -07008 * http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08009 *
10 * Unless required by applicable law or agreed to in writing, software
Owen Lin61b98312009-06-19 00:21:10 -070011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080015 */
16
17package com.android.camera;
18
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080019import android.app.Activity;
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +080020import android.content.ActivityNotFoundException;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080021import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.SharedPreferences;
Owen Lin50c60042009-09-10 14:43:42 +080028import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
Owen Lin3f3c8572009-08-18 13:33:49 +080029import android.content.res.Resources;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080030import android.graphics.Bitmap;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080031import android.graphics.drawable.Drawable;
Owen Lin50c60042009-09-10 14:43:42 +080032import android.hardware.Camera.Parameters;
Wei-Ta Chen7e4655b2009-09-25 17:23:22 -070033import android.hardware.Camera.Size;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080034import android.media.MediaRecorder;
Ray Chen9f1480b2009-08-27 17:59:29 -070035import android.media.ThumbnailUtil;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080036import android.net.Uri;
Owen Linf6ef7b92009-09-14 18:48:12 +080037import android.os.Build;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080038import android.os.Bundle;
39import android.os.Environment;
40import android.os.Handler;
41import android.os.Message;
42import android.os.StatFs;
43import android.os.SystemClock;
Chih-Chung Chang97601c72009-07-27 19:19:10 +080044import android.os.SystemProperties;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080045import android.preference.PreferenceManager;
Wei-Ta Chen7e4655b2009-09-25 17:23:22 -070046import android.preference.PreferenceScreen;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080047import android.provider.MediaStore;
48import android.provider.MediaStore.Video;
49import android.text.format.DateFormat;
50import android.util.Log;
51import android.view.KeyEvent;
Owen Lin61b98312009-06-19 00:21:10 -070052import android.view.LayoutInflater;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080053import android.view.Menu;
54import android.view.MenuItem;
Owen Linc1f2e302009-09-14 19:04:37 +080055import android.view.MotionEvent;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080056import android.view.SurfaceHolder;
Cheng-Ru Linffcca742009-09-28 03:21:25 +080057import android.view.SurfaceView;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080058import android.view.View;
Owen Lin61b98312009-06-19 00:21:10 -070059import android.view.ViewGroup;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080060import android.view.Window;
61import android.view.WindowManager;
Owen Lin059daa32009-05-18 15:31:17 -070062import android.view.MenuItem.OnMenuItemClickListener;
Wu-cheng Li84f96462009-06-19 20:11:44 +080063import android.view.animation.AlphaAnimation;
64import android.view.animation.Animation;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080065import android.widget.ImageView;
66import android.widget.TextView;
67import android.widget.Toast;
68
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -070069import com.android.camera.PreviewFrameLayout.OnSizeChangedListener;
Owen Lin2e768c12009-07-01 15:51:45 -070070import com.android.camera.gallery.IImage;
71import com.android.camera.gallery.IImageList;
72
Chih-Chung Changd8209aa2009-04-07 11:45:12 -070073import java.io.File;
74import java.io.FileDescriptor;
75import java.io.IOException;
76import java.text.SimpleDateFormat;
77import java.util.ArrayList;
78import java.util.Date;
Chih-Chung Chang97601c72009-07-27 19:19:10 +080079import java.util.HashMap;
Chih-Chung Changd8209aa2009-04-07 11:45:12 -070080
Ray Chen23c51b72009-04-10 03:41:00 -070081/**
82 * The Camcorder activity.
83 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080084public class VideoCamera extends Activity implements View.OnClickListener,
Chih-Chung Changd8209aa2009-04-07 11:45:12 -070085 ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback,
Owen Line239acc2009-06-23 22:18:20 -070086 MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener,
Owen Lin3e737c22009-09-11 11:31:59 +080087 Switcher.OnSwitchListener, OnSharedPreferenceChangeListener,
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -070088 OnScreenSettings.OnVisibilityChangedListener,
89 PreviewFrameLayout.OnSizeChangedListener {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080090
91 private static final String TAG = "videocamera";
92
Wu-cheng Lib1284462009-06-05 14:35:42 +080093 private static final int INIT_RECORDER = 3;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080094 private static final int CLEAR_SCREEN_DELAY = 4;
95 private static final int UPDATE_RECORD_TIME = 5;
96
97 private static final int SCREEN_DELAY = 2 * 60 * 1000;
98
99 private static final long NO_STORAGE_ERROR = -1L;
100 private static final long CANNOT_STAT_ERROR = -2L;
101 private static final long LOW_STORAGE_THRESHOLD = 512L * 1024L;
102
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700103 private static final int STORAGE_STATUS_OK = 0;
104 private static final int STORAGE_STATUS_LOW = 1;
105 private static final int STORAGE_STATUS_NONE = 2;
106
Owen Line239acc2009-06-23 22:18:20 -0700107 private static final boolean SWITCH_CAMERA = true;
108 private static final boolean SWITCH_VIDEO = false;
109
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800110 private SharedPreferences mPreferences;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800111
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -0700112 private PreviewFrameLayout mPreviewFrameLayout;
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800113 private SurfaceView mVideoPreview;
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800114 private SurfaceHolder mSurfaceHolder = null;
115 private ImageView mVideoFrame;
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700116
117 private boolean mIsVideoCaptureIntent;
118 // mLastPictureButton and mThumbController
Chih-Chung Chang0a475e12009-04-16 11:42:12 +0800119 // are non-null only if mIsVideoCaptureIntent is true.
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700120 private ImageView mLastPictureButton;
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700121 private ThumbnailController mThumbController;
Owen Lin3f3c8572009-08-18 13:33:49 +0800122 private boolean mStartPreviewFail = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800123
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700124 private int mStorageStatus = STORAGE_STATUS_OK;
125
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800126 private MediaRecorder mMediaRecorder;
127 private boolean mMediaRecorderRecording = false;
128 private long mRecordingStartTime;
129 // The video file that the hardware camera is about to record into
130 // (or is recording into.)
131 private String mCameraVideoFilename;
132 private FileDescriptor mCameraVideoFileDescriptor;
133
134 // The video file that has already been recorded, and that is being
135 // examined by the user.
136 private String mCurrentVideoFilename;
137 private Uri mCurrentVideoUri;
138 private ContentValues mCurrentVideoValues;
139
Chih-Chung Chang97601c72009-07-27 19:19:10 +0800140 private MediaRecorderProfile mProfile;
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800141
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800142 // The video duration limit. 0 menas no limit.
Chih-Chung Chang82ded202009-05-20 14:24:25 +0800143 private int mMaxVideoDurationInMs;
144
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800145 boolean mPausing = false;
Owen Lin61b98312009-06-19 00:21:10 -0700146 boolean mPreviewing = false; // True if preview is started.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800147
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700148 private ContentResolver mContentResolver;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800149
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800150 private ShutterButton mShutterButton;
151 private TextView mRecordingTimeView;
Chih-Chung Changfae0daa2009-09-21 05:36:24 +0800152 private View mGripper;
Owen Lin2e768c12009-07-01 15:51:45 -0700153 private Switcher mSwitcher;
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -0700154 private boolean mRecordingTimeCountsDown = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800155
Wei-Ta Chen7e4655b2009-09-25 17:23:22 -0700156 private final ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800157
Owen Lin059daa32009-05-18 15:31:17 -0700158 private final Handler mHandler = new MainHandler();
Owen Lin50c60042009-09-10 14:43:42 +0800159 private Parameters mParameters;
160 private OnScreenSettings mSettings;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800161
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700162 // This Handler is used to post message back onto the main thread of the
163 // application
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800164 private class MainHandler extends Handler {
165 @Override
166 public void handleMessage(Message msg) {
167 switch (msg.what) {
168
169 case CLEAR_SCREEN_DELAY: {
Owen Lincc8d7562009-09-16 14:43:09 +0800170 getWindow().clearFlags(
171 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800172 break;
173 }
174
175 case UPDATE_RECORD_TIME: {
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700176 updateRecordingTime();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800177 break;
178 }
179
Wu-cheng Lib1284462009-06-05 14:35:42 +0800180 case INIT_RECORDER: {
181 initializeRecorder();
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800182 break;
183 }
184
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800185 default:
186 Log.v(TAG, "Unhandled message: " + msg.what);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +0800187 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800188 }
189 }
Owen Lin937fc482009-04-14 02:02:51 -0700190 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800191
Owen Lin3f3c8572009-08-18 13:33:49 +0800192 private BroadcastReceiver mReceiver = null;
193
194 private class MyBroadcastReceiver extends BroadcastReceiver {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800195 @Override
196 public void onReceive(Context context, Intent intent) {
197 String action = intent.getAction();
198 if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700199 updateAndShowStorageHint(false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800200 stopVideoRecording();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800201 } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700202 updateAndShowStorageHint(true);
Wu-cheng Lib1284462009-06-05 14:35:42 +0800203 initializeRecorder();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800204 } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
205 // SD card unavailable
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700206 // handled in ACTION_MEDIA_EJECT
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800207 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800208 Toast.makeText(VideoCamera.this,
209 getResources().getString(R.string.wait), 5000);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800210 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700211 updateAndShowStorageHint(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800212 }
213 }
Owen Lin3f3c8572009-08-18 13:33:49 +0800214 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800215
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700216 private static String createName(long dateTaken) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800217 return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
218 }
219
Owen Lin3f3c8572009-08-18 13:33:49 +0800220 private void showCameraBusyAndFinish() {
221 Resources ress = getResources();
222 Util.showFatalErrorAndFinish(VideoCamera.this,
223 ress.getString(R.string.camera_error_title),
224 ress.getString(R.string.cannot_connect_camera));
225 }
226
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800227 /** Called with the activity is first created. */
228 @Override
229 public void onCreate(Bundle icicle) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800230 super.onCreate(icicle);
231
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800232 mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
Chih-Chung Chang6f2c5302009-08-31 20:02:55 +0800233 CameraSettings.upgradePreferences(mPreferences);
Owen Lin50c60042009-09-10 14:43:42 +0800234
Owen Lin50c60042009-09-10 14:43:42 +0800235 readVideoPreferences();
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800236
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800237 /*
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800238 * To reduce startup time, we start the preview in another thread.
239 * We make sure the preview is started at the end of onCreate.
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800240 */
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800241 Thread startPreviewThread = new Thread(new Runnable() {
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800242 public void run() {
Owen Lin3f3c8572009-08-18 13:33:49 +0800243 try {
244 mStartPreviewFail = false;
245 startPreview();
246 } catch (CameraHardwareException e) {
Owen Linf6ef7b92009-09-14 18:48:12 +0800247 // In eng build, we throw the exception so that test tool
248 // can detect it and report it
249 if ("eng".equals(Build.TYPE)) {
250 throw new RuntimeException(e);
251 }
Owen Lin3f3c8572009-08-18 13:33:49 +0800252 mStartPreviewFail = true;
253 }
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800254 }
255 });
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800256 startPreviewThread.start();
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800257
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800258 mContentResolver = getContentResolver();
259
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800260 requestWindowFeature(Window.FEATURE_PROGRESS);
261 setContentView(R.layout.video_camera);
262
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -0700263 mPreviewFrameLayout = (PreviewFrameLayout)
264 findViewById(R.id.frame_layout);
265 mPreviewFrameLayout.setOnSizeChangedListener(this);
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800266 resizeForPreviewAspectRatio();
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -0700267
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800268 mVideoPreview = (SurfaceView) findViewById(R.id.camera_preview);
Chih-Chung Chang54dd1d32009-09-01 13:26:14 +0800269 mVideoFrame = (ImageView) findViewById(R.id.video_frame);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800270
271 // don't set mSurfaceHolder here. We have it set ONLY within
272 // surfaceCreated / surfaceDestroyed, other parts of the code
273 // assume that when it is set, the surface is also set.
274 SurfaceHolder holder = mVideoPreview.getHolder();
275 holder.addCallback(this);
276 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
277
Owen Lin61b98312009-06-19 00:21:10 -0700278 mIsVideoCaptureIntent = isVideoCaptureIntent();
279 mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
Wu-cheng Li84f96462009-06-19 20:11:44 +0800280
Owen Lin61b98312009-06-19 00:21:10 -0700281 ViewGroup rootView = (ViewGroup) findViewById(R.id.video_camera);
282 LayoutInflater inflater = this.getLayoutInflater();
283 if (!mIsVideoCaptureIntent) {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800284 View controlBar = inflater.inflate(
285 R.layout.camera_control, rootView);
286 mLastPictureButton =
287 (ImageView) controlBar.findViewById(R.id.review_thumbnail);
Owen Line594b192009-08-13 18:04:45 +0800288 mThumbController = new ThumbnailController(
289 getResources(), mLastPictureButton, mContentResolver);
Owen Lin61b98312009-06-19 00:21:10 -0700290 mLastPictureButton.setOnClickListener(this);
291 mThumbController.loadData(ImageManager.getLastVideoThumbPath());
Owen Lin2e768c12009-07-01 15:51:45 -0700292 mSwitcher = ((Switcher) findViewById(R.id.camera_switch));
293 mSwitcher.setOnSwitchListener(this);
Chih-Chung Chang781f55b2009-08-10 17:00:52 +0800294 mSwitcher.addTouchView(findViewById(R.id.camera_switch_set));
Owen Lin61b98312009-06-19 00:21:10 -0700295 } else {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800296 View controlBar = inflater.inflate(
297 R.layout.attach_camera_control, rootView);
Owen Lin61b98312009-06-19 00:21:10 -0700298 controlBar.findViewById(R.id.btn_cancel).setOnClickListener(this);
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800299 ImageView retake =
300 (ImageView) controlBar.findViewById(R.id.btn_retake);
Owen Lin1af86ab2009-06-22 17:19:56 -0700301 retake.setOnClickListener(this);
302 retake.setImageResource(R.drawable.btn_ic_review_retake_video);
Owen Lin61b98312009-06-19 00:21:10 -0700303 controlBar.findViewById(R.id.btn_play).setOnClickListener(this);
304 controlBar.findViewById(R.id.btn_done).setOnClickListener(this);
Wu-cheng Li84f96462009-06-19 20:11:44 +0800305 }
306
Owen Lindad4b182009-06-11 16:02:29 -0700307 mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
308 mShutterButton.setImageResource(R.drawable.btn_ic_video_record);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800309 mShutterButton.setOnShutterButtonListener(this);
Owen Lin059daa32009-05-18 15:31:17 -0700310 mShutterButton.requestFocus();
Chih-Chung Changfae0daa2009-09-21 05:36:24 +0800311 mGripper = findViewById(R.id.btn_gripper);
312 mGripper.setOnTouchListener(new GripperTouchListener());
Owen Lin059daa32009-05-18 15:31:17 -0700313
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800314 // Make sure preview is started.
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800315 try {
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800316 startPreviewThread.join();
Owen Linf6ef7b92009-09-14 18:48:12 +0800317 if (mStartPreviewFail) {
318 showCameraBusyAndFinish();
319 return;
320 }
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800321 } catch (InterruptedException ex) {
322 // ignore
323 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800324 }
325
Owen Lin2e768c12009-07-01 15:51:45 -0700326 @Override
327 protected void onStart() {
328 super.onStart();
329 if (!mIsVideoCaptureIntent) {
330 mSwitcher.setSwitch(SWITCH_VIDEO);
331 }
332 }
333
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700334 private void startShareVideoActivity() {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700335 Intent intent = new Intent();
336 intent.setAction(Intent.ACTION_SEND);
337 intent.setType("video/3gpp");
338 intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri);
339 try {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800340 startActivity(Intent.createChooser(intent,
341 getText(R.string.sendVideo)));
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700342 } catch (android.content.ActivityNotFoundException ex) {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800343 Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video,
344 Toast.LENGTH_SHORT).show();
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700345 }
346 }
347
Owen Lin61b98312009-06-19 00:21:10 -0700348 private void startPlayVideoActivity() {
349 Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri);
350 try {
351 startActivity(intent);
352 } catch (android.content.ActivityNotFoundException ex) {
353 Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
354 }
355 }
356
357
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800358 public void onClick(View v) {
359 switch (v.getId()) {
Owen Lin61b98312009-06-19 00:21:10 -0700360 case R.id.btn_retake:
361 discardCurrentVideoAndInitRecorder();
362 break;
Owen Lin61b98312009-06-19 00:21:10 -0700363 case R.id.btn_play:
364 startPlayVideoActivity();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800365 break;
Owen Lin61b98312009-06-19 00:21:10 -0700366 case R.id.btn_done:
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800367 doReturnToCaller(true);
368 break;
Owen Lin61b98312009-06-19 00:21:10 -0700369 case R.id.btn_cancel:
370 stopVideoRecording();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800371 doReturnToCaller(false);
372 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800373 case R.id.discard: {
Ray Chen7638a542009-03-24 20:37:45 -0700374 Runnable deleteCallback = new Runnable() {
375 public void run() {
Wu-cheng Lib1284462009-06-05 14:35:42 +0800376 discardCurrentVideoAndInitRecorder();
Ray Chen7638a542009-03-24 20:37:45 -0700377 }
378 };
379 MenuHelper.deleteVideo(this, deleteCallback);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800380 break;
381 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800382 case R.id.share: {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700383 startShareVideoActivity();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800384 break;
385 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800386 case R.id.play: {
387 doPlayCurrentVideo();
388 break;
389 }
Owen Lindad4b182009-06-11 16:02:29 -0700390 case R.id.review_thumbnail: {
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +0800391 stopVideoRecordingAndShowReview();
Chih-Chung Chang22b5c552009-10-02 15:27:55 -0700392 initializeRecorder();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700393 break;
394 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800395 }
396 }
397
398 public void onShutterButtonFocus(ShutterButton button, boolean pressed) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700399 // Do nothing (everything happens in onShutterButtonClick).
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800400 }
401
402 public void onShutterButtonClick(ShutterButton button) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700403 switch (button.getId()) {
Owen Lindad4b182009-06-11 16:02:29 -0700404 case R.id.shutter_button:
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700405 if (mMediaRecorderRecording) {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700406 if (mIsVideoCaptureIntent) {
Wu-cheng Li84f96462009-06-19 20:11:44 +0800407 stopVideoRecordingAndShowAlert();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700408 } else {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700409 stopVideoRecordingAndGetThumbnail();
Wu-cheng Lib1284462009-06-05 14:35:42 +0800410 initializeRecorder();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700411 }
Owen Lin0dd23412009-09-11 16:03:42 +0800412 } else if (mMediaRecorder != null) {
Wu-cheng Lib1284462009-06-05 14:35:42 +0800413 // If the click comes before recorder initialization, it is
414 // ignored. If users click the button during initialization,
415 // the event is put in the queue and record will be started
416 // eventually.
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700417 startVideoRecording();
418 }
419 break;
420 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800421 }
422
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800423 private void doPlayCurrentVideo() {
Chih-Chung Chang0a475e12009-04-16 11:42:12 +0800424 Log.v(TAG, "Playing current video: " + mCurrentVideoUri);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800425 Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri);
426 try {
427 startActivity(intent);
428 } catch (android.content.ActivityNotFoundException ex) {
429 Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
430 }
431 }
432
Wu-cheng Lib1284462009-06-05 14:35:42 +0800433 private void discardCurrentVideoAndInitRecorder() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800434 deleteCurrentVideo();
Wu-cheng Lib1284462009-06-05 14:35:42 +0800435 hideAlertAndInitializeRecorder();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800436 }
437
438 private OnScreenHint mStorageHint;
439
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700440 private void updateAndShowStorageHint(boolean mayHaveSd) {
441 mStorageStatus = getStorageStatus(mayHaveSd);
442 showStorageHint();
443 }
444
445 private void showStorageHint() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800446 String errorMessage = null;
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700447 switch (mStorageStatus) {
Owen Lin61b98312009-06-19 00:21:10 -0700448 case STORAGE_STATUS_NONE:
449 errorMessage = getString(R.string.no_storage);
450 break;
451 case STORAGE_STATUS_LOW:
452 errorMessage = getString(R.string.spaceIsLow_content);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800453 }
454 if (errorMessage != null) {
455 if (mStorageHint == null) {
456 mStorageHint = OnScreenHint.makeText(this, errorMessage);
457 } else {
458 mStorageHint.setText(errorMessage);
459 }
460 mStorageHint.show();
461 } else if (mStorageHint != null) {
462 mStorageHint.cancel();
463 mStorageHint = null;
464 }
465 }
466
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700467 private int getStorageStatus(boolean mayHaveSd) {
468 long remaining = mayHaveSd ? getAvailableStorage() : NO_STORAGE_ERROR;
469 if (remaining == NO_STORAGE_ERROR) {
470 return STORAGE_STATUS_NONE;
471 }
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800472 return remaining < LOW_STORAGE_THRESHOLD
473 ? STORAGE_STATUS_LOW
474 : STORAGE_STATUS_OK;
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700475 }
476
Owen Lin50c60042009-09-10 14:43:42 +0800477 private void readVideoPreferences() {
Owen Lin61b98312009-06-19 00:21:10 -0700478 boolean videoQualityHigh =
479 getBooleanPreference(CameraSettings.KEY_VIDEO_QUALITY,
Owen Lin50c60042009-09-10 14:43:42 +0800480 CameraSettings.DEFAULT_VIDEO_QUALITY_VALUE);
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800481
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800482 // Set video quality.
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800483 Intent intent = getIntent();
484 if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800485 int extraVideoQuality =
486 intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800487 videoQualityHigh = (extraVideoQuality > 0);
488 }
489
Chih-Chung Chang232b70a2009-08-25 13:42:04 +0800490 // Set video duration limit. The limit is read from the preference,
491 // unless it is specified in the intent.
492 if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) {
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800493 int seconds =
494 intent.getIntExtra(MediaStore.EXTRA_DURATION_LIMIT, 0);
Chih-Chung Chang232b70a2009-08-25 13:42:04 +0800495 mMaxVideoDurationInMs = 1000 * seconds;
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800496 } else {
Chih-Chung Chang232b70a2009-08-25 13:42:04 +0800497 int minutes = getIntPreference(CameraSettings.KEY_VIDEO_DURATION,
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800498 CameraSettings.DEFAULT_VIDEO_DURATION_VALUE);
Chih-Chung Chang6f2c5302009-08-31 20:02:55 +0800499 if (minutes == -1) {
500 // This is a special case: the value -1 means we want to use the
Chih-Chung Chang232b70a2009-08-25 13:42:04 +0800501 // device-dependent duration for MMS messages. The value is
502 // represented in seconds.
Chih-Chung Chang9b93bcb2009-09-04 19:46:14 +0800503 mMaxVideoDurationInMs =
504 1000 * CameraSettings.MMS_VIDEO_DURATION;
Chih-Chung Chang232b70a2009-08-25 13:42:04 +0800505 } else {
506 // 1 minute = 60000ms
507 mMaxVideoDurationInMs = 60000 * minutes;
508 }
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800509 }
510
Chih-Chung Chang97601c72009-07-27 19:19:10 +0800511 mProfile = new MediaRecorderProfile(videoQualityHigh);
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800512 }
513
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800514 private void resizeForPreviewAspectRatio() {
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -0700515 mPreviewFrameLayout.setAspectRatio(
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800516 (double) mProfile.mVideoWidth / mProfile.mVideoHeight);
Chih-Chung Chang54dd1d32009-09-01 13:26:14 +0800517 }
518
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800519 @Override
520 public void onResume() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800521 super.onResume();
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800522 mPausing = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800523
Owen Lin50c60042009-09-10 14:43:42 +0800524 readVideoPreferences();
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800525 resizeForPreviewAspectRatio();
Owen Lin3f3c8572009-08-18 13:33:49 +0800526 if (!mPreviewing && !mStartPreviewFail) {
527 try {
528 startPreview();
529 } catch (CameraHardwareException e) {
530 showCameraBusyAndFinish();
531 return;
532 }
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800533 }
Owen Lincc8d7562009-09-16 14:43:09 +0800534 keepScreenOnAwhile();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800535
536 // install an intent filter to receive SD card related events.
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800537 IntentFilter intentFilter =
538 new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800539 intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
540 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
541 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
542 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
543 intentFilter.addDataScheme("file");
Owen Lin3f3c8572009-08-18 13:33:49 +0800544 mReceiver = new MyBroadcastReceiver();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800545 registerReceiver(mReceiver, intentFilter);
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700546 mStorageStatus = getStorageStatus(true);
547
548 mHandler.postDelayed(new Runnable() {
549 public void run() {
550 showStorageHint();
551 }
552 }, 200);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800553
Wu-cheng Lib1284462009-06-05 14:35:42 +0800554 if (mSurfaceHolder != null) {
Wu-cheng Lib1284462009-06-05 14:35:42 +0800555 mHandler.sendEmptyMessage(INIT_RECORDER);
556 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800557 }
558
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800559 private void setPreviewDisplay(SurfaceHolder holder) {
560 try {
561 mCameraDevice.setPreviewDisplay(holder);
562 } catch (Throwable ex) {
563 closeCamera();
564 throw new RuntimeException("setPreviewDisplay failed", ex);
565 }
566 }
567
Owen Lin3f3c8572009-08-18 13:33:49 +0800568 private void startPreview() throws CameraHardwareException {
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800569 Log.v(TAG, "startPreview");
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800570 if (mPreviewing) {
Chih-Chung Chang1fb8ac42009-06-05 17:32:54 +0800571 // After recording a video, preview is not stopped. So just return.
Wu-cheng Lifa1dfa22009-06-10 14:44:43 +0800572 return;
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800573 }
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800574
575 if (mCameraDevice == null) {
576 // If the activity is paused and resumed, camera device has been
577 // released and we need to open the camera.
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800578 mCameraDevice = CameraHolder.instance().open();
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800579 }
580
Owen Lin50c60042009-09-10 14:43:42 +0800581 mCameraDevice.lock();
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800582 setCameraParameters();
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800583 setPreviewDisplay(mSurfaceHolder);
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800584
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800585 try {
586 mCameraDevice.startPreview();
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800587 mPreviewing = true;
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800588 } catch (Throwable ex) {
Wu-cheng Lifa1dfa22009-06-10 14:44:43 +0800589 closeCamera();
590 throw new RuntimeException("startPreview failed", ex);
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800591 }
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800592
593 // If setPreviewDisplay has been set with a valid surface, unlock now.
594 // If surface is null, unlock later. Otherwise, setPreviewDisplay in
595 // surfaceChanged will fail.
596 if (mSurfaceHolder != null) {
597 mCameraDevice.unlock();
598 }
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800599 }
600
Chih-Chung Changd55a5e92009-05-14 11:49:34 +0800601 private void closeCamera() {
602 Log.v(TAG, "closeCamera");
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800603 if (mCameraDevice == null) {
604 Log.d(TAG, "already stopped.");
605 return;
606 }
Wu-cheng Lifbdbae62009-06-02 15:46:20 +0800607 // If we don't lock the camera, release() will fail.
608 mCameraDevice.lock();
Chih-Chung Changcd65be32009-06-09 13:51:29 +0800609 CameraHolder.instance().release();
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800610 mCameraDevice = null;
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800611 mPreviewing = false;
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800612 }
613
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800614 @Override
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800615 protected void onPause() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800616 super.onPause();
617
Wu-cheng Lifbdbae62009-06-02 15:46:20 +0800618 mPausing = true;
619
Owen Lin50c60042009-09-10 14:43:42 +0800620 if (mSettings != null && mSettings.isVisible()) {
621 mSettings.setVisible(false);
622 }
623
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700624 // This is similar to what mShutterButton.performClick() does,
625 // but not quite the same.
626 if (mMediaRecorderRecording) {
627 if (mIsVideoCaptureIntent) {
Owen Lin61b98312009-06-19 00:21:10 -0700628 stopVideoRecording();
629 showAlert();
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700630 } else {
631 stopVideoRecordingAndGetThumbnail();
632 }
633 } else {
634 stopVideoRecording();
635 }
Wu-cheng Lifbdbae62009-06-02 15:46:20 +0800636 closeCamera();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800637
Owen Lin3f3c8572009-08-18 13:33:49 +0800638 if (mReceiver != null) {
639 unregisterReceiver(mReceiver);
640 mReceiver = null;
641 }
Owen Lincc8d7562009-09-16 14:43:09 +0800642 resetScreenOn();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800643
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700644 if (!mIsVideoCaptureIntent) {
645 mThumbController.storeData(ImageManager.getLastVideoThumbPath());
646 }
Owen Lin095afa12009-03-24 23:41:27 -0700647
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800648 if (mStorageHint != null) {
649 mStorageHint.cancel();
650 mStorageHint = null;
651 }
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800652
Wu-cheng Lib1284462009-06-05 14:35:42 +0800653 mHandler.removeMessages(INIT_RECORDER);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800654 }
655
656 @Override
Owen Lincc8d7562009-09-16 14:43:09 +0800657 public void onUserInteraction() {
658 super.onUserInteraction();
659 if (!mMediaRecorderRecording) keepScreenOnAwhile();
660 }
661
662 @Override
Chih-Chung Chang0b8028e2009-09-25 15:12:14 -0700663 public void onBackPressed() {
664 if (mPausing) return;
665 if (mMediaRecorderRecording) {
666 mShutterButton.performClick();
667 return;
668 }
669 super.onBackPressed();
670 }
671
672 @Override
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800673 public boolean onKeyDown(int keyCode, KeyEvent event) {
Wu-cheng Lifbdbae62009-06-02 15:46:20 +0800674 // Do not handle any key if the activity is paused.
675 if (mPausing) {
676 return true;
677 }
678
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800679 switch (keyCode) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800680 case KeyEvent.KEYCODE_CAMERA:
681 if (event.getRepeatCount() == 0) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700682 mShutterButton.performClick();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800683 return true;
684 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700685 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800686 case KeyEvent.KEYCODE_DPAD_CENTER:
687 if (event.getRepeatCount() == 0) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700688 mShutterButton.performClick();
689 return true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800690 }
691 break;
692 case KeyEvent.KEYCODE_MENU:
693 if (mMediaRecorderRecording) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700694 mShutterButton.performClick();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800695 return true;
696 }
697 break;
698 }
699
700 return super.onKeyDown(keyCode, event);
701 }
702
703 @Override
704 public boolean onKeyUp(int keyCode, KeyEvent event) {
Owen Lin61b98312009-06-19 00:21:10 -0700705 switch (keyCode) {
706 case KeyEvent.KEYCODE_CAMERA:
707 mShutterButton.setPressed(false);
708 return true;
Wei-Ta Chenbf45b962009-09-27 16:20:23 -0700709 case KeyEvent.KEYCODE_MENU:
710 if (this.mIsVideoCaptureIntent) {
711 showOnScreenSettings();
712 return true;
713 }
714 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800715 }
716 return super.onKeyUp(keyCode, event);
717 }
718
719 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Wu-cheng Li37dcfbb2009-06-23 15:34:19 +0800720 // Make sure we have a surface in the holder before proceeding.
721 if (holder.getSurface() == null) {
722 Log.d(TAG, "holder.getSurface() == null");
723 return;
724 }
725
Andreas Huber314f9a72009-03-24 20:12:48 -0700726 if (mPausing) {
727 // We're pausing, the screen is off and we already stopped
728 // video recording. We don't want to start the camera again
729 // in this case in order to conserve power.
730 // The fact that surfaceChanged is called _after_ an onPause appears
731 // to be legitimate since in that case the lockscreen always returns
732 // to portrait orientation possibly triggering the notification.
733 return;
734 }
735
Owen Lin3665f922009-09-02 18:03:42 +0800736 // The mCameraDevice will be null if it is fail to connect to the
737 // camera hardware. In this case we will show a dialog and then
Owen Lin3f3c8572009-08-18 13:33:49 +0800738 // finish the activity, so it's OK to ignore it.
739 if (mCameraDevice == null) return;
740
Wu-cheng Lib1284462009-06-05 14:35:42 +0800741 if (mMediaRecorderRecording) {
742 stopVideoRecording();
743 }
744
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800745 // Set preview display if the surface is being created. Preview was
746 // already started.
747 if (holder.isCreating()) {
748 setPreviewDisplay(holder);
749 mCameraDevice.unlock();
Wu-cheng Lib1284462009-06-05 14:35:42 +0800750 mHandler.sendEmptyMessage(INIT_RECORDER);
751 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800752 }
753
754 public void surfaceCreated(SurfaceHolder holder) {
755 mSurfaceHolder = holder;
756 }
757
758 public void surfaceDestroyed(SurfaceHolder holder) {
759 mSurfaceHolder = null;
760 }
761
Chih-Chung Chang0a475e12009-04-16 11:42:12 +0800762 private void gotoGallery() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800763 MenuHelper.gotoCameraVideoGallery(this);
764 }
765
766 @Override
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800767 public boolean onCreateOptionsMenu(Menu menu) {
768 super.onCreateOptionsMenu(menu);
769
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700770 if (mIsVideoCaptureIntent) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800771 // No options menu for attach mode.
772 return false;
773 } else {
774 addBaseMenuItems(menu);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800775 }
776 return true;
777 }
778
779 private boolean isVideoCaptureIntent() {
780 String action = getIntent().getAction();
781 return (MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
782 }
783
784 private void doReturnToCaller(boolean success) {
785 Intent resultIntent = new Intent();
786 int resultCode;
787 if (success) {
788 resultCode = RESULT_OK;
789 resultIntent.setData(mCurrentVideoUri);
790 } else {
791 resultCode = RESULT_CANCELED;
792 }
793 setResult(resultCode, resultIntent);
794 finish();
795 }
796
797 /**
798 * Returns
Owen Lin61b98312009-06-19 00:21:10 -0700799 *
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800800 * @return number of bytes available, or an ERROR code.
801 */
802 private static long getAvailableStorage() {
803 try {
804 if (!ImageManager.hasStorage()) {
805 return NO_STORAGE_ERROR;
806 } else {
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800807 String storageDirectory =
808 Environment.getExternalStorageDirectory().toString();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800809 StatFs stat = new StatFs(storageDirectory);
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800810 return (long) stat.getAvailableBlocks()
811 * (long) stat.getBlockSize();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800812 }
Ray Chen23c51b72009-04-10 03:41:00 -0700813 } catch (RuntimeException ex) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800814 // if we can't stat the filesystem then we don't know how many
Owen Lin61b98312009-06-19 00:21:10 -0700815 // free bytes exist. It might be zero but just leave it
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800816 // blank since we really don't know.
817 return CANNOT_STAT_ERROR;
818 }
819 }
820
821 private void cleanupEmptyFile() {
822 if (mCameraVideoFilename != null) {
823 File f = new File(mCameraVideoFilename);
824 if (f.length() == 0 && f.delete()) {
Owen Lin61b98312009-06-19 00:21:10 -0700825 Log.v(TAG, "Empty video file deleted: " + mCameraVideoFilename);
826 mCameraVideoFilename = null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800827 }
828 }
829 }
830
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800831 private android.hardware.Camera mCameraDevice;
Owen Lin61b98312009-06-19 00:21:10 -0700832
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700833 // Prepares media recorder.
834 private void initializeRecorder() {
Wu-cheng Lib1284462009-06-05 14:35:42 +0800835 Log.v(TAG, "initializeRecorder");
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700836 if (mMediaRecorder != null) return;
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700837
Wu-cheng Li84f96462009-06-19 20:11:44 +0800838 // We will call initializeRecorder() again when the alert is hidden.
Owen Lin3f3c8572009-08-18 13:33:49 +0800839 // If the mCameraDevice is null, then this activity is going to finish
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700840 if (isAlertVisible() || mCameraDevice == null) return;
Wu-cheng Li84f96462009-06-19 20:11:44 +0800841
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800842 Intent intent = getIntent();
843 Bundle myExtras = intent.getExtras();
844
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800845 long requestedSizeLimit = 0;
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700846 if (mIsVideoCaptureIntent && myExtras != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800847 Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
848 if (saveUri != null) {
849 try {
Owen Lin61b98312009-06-19 00:21:10 -0700850 mCameraVideoFileDescriptor =
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800851 mContentResolver.openFileDescriptor(saveUri, "rw")
852 .getFileDescriptor();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800853 mCurrentVideoUri = saveUri;
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700854 } catch (java.io.FileNotFoundException ex) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800855 // invalid uri
856 Log.e(TAG, ex.toString());
857 }
858 }
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800859 requestedSizeLimit = myExtras.getLong(MediaStore.EXTRA_SIZE_LIMIT);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800860 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800861 mMediaRecorder = new MediaRecorder();
862
Chih-Chung Chang845accc2009-04-23 14:14:37 +0800863 mMediaRecorder.setCamera(mCameraDevice);
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700864 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800865 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
Chih-Chung Chang97601c72009-07-27 19:19:10 +0800866 mMediaRecorder.setOutputFormat(mProfile.mOutputFormat);
Chih-Chung Chang82ded202009-05-20 14:24:25 +0800867 mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -0700868
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700869 // Set output file.
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700870 if (mStorageStatus != STORAGE_STATUS_OK) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800871 mMediaRecorder.setOutputFile("/dev/null");
872 } else {
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700873 // Try Uri in the intent first. If it doesn't exist, use our own
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700874 // instead.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800875 if (mCameraVideoFileDescriptor != null) {
876 mMediaRecorder.setOutputFile(mCameraVideoFileDescriptor);
877 } else {
878 createVideoPath();
879 mMediaRecorder.setOutputFile(mCameraVideoFilename);
880 }
881 }
882
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800883 // Use the same frame rate for both, since internally
884 // if the frame rate is too large, it can cause camera to become
885 // unstable. We need to fix the MediaRecorder to disable the support
886 // of setting frame rate for now.
Chih-Chung Chang947455a2009-07-29 14:50:07 +0800887 mMediaRecorder.setVideoFrameRate(mProfile.mVideoFps);
Chih-Chung Chang97601c72009-07-27 19:19:10 +0800888 mMediaRecorder.setVideoSize(
889 mProfile.mVideoWidth, mProfile.mVideoHeight);
Chih-Chung Chang947455a2009-07-29 14:50:07 +0800890 mMediaRecorder.setParameters(String.format(
891 "video-param-encoding-bitrate=%d", mProfile.mVideoBitrate));
892 mMediaRecorder.setParameters(String.format(
893 "audio-param-encoding-bitrate=%d", mProfile.mAudioBitrate));
894 mMediaRecorder.setParameters(String.format(
895 "audio-param-number-of-channels=%d", mProfile.mAudioChannels));
896 mMediaRecorder.setParameters(String.format(
897 "audio-param-sampling-rate=%d", mProfile.mAudioSamplingRate));
Chih-Chung Chang97601c72009-07-27 19:19:10 +0800898 mMediaRecorder.setVideoEncoder(mProfile.mVideoEncoder);
899 mMediaRecorder.setAudioEncoder(mProfile.mAudioEncoder);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800900 mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700901
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800902 // Set maximum file size.
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700903 // remaining >= LOW_STORAGE_THRESHOLD at this point, reserve a quarter
Chih-Chung Changd8209aa2009-04-07 11:45:12 -0700904 // of that to make it more likely that recording can complete
905 // successfully.
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800906 long maxFileSize = getAvailableStorage() - LOW_STORAGE_THRESHOLD / 4;
907 if (requestedSizeLimit > 0 && requestedSizeLimit < maxFileSize) {
908 maxFileSize = requestedSizeLimit;
909 }
910
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700911 try {
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +0800912 mMediaRecorder.setMaxFileSize(maxFileSize);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700913 } catch (RuntimeException exception) {
914 // We are going to ignore failure of setMaxFileSize here, as
915 // a) The composer selected may simply not support it, or
916 // b) The underlying media framework may not handle 64-bit range
Owen Lin61b98312009-06-19 00:21:10 -0700917 // on the size restriction.
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700918 }
919
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800920 try {
921 mMediaRecorder.prepare();
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700922 } catch (IOException e) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800923 Log.e(TAG, "prepare failed for " + mCameraVideoFilename);
924 releaseMediaRecorder();
Wu-cheng Li80b7c5b2009-09-27 18:03:50 -0700925 throw new RuntimeException(e);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800926 }
927 mMediaRecorderRecording = false;
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700928
Wu-cheng Liac3a8c82009-05-12 13:00:10 +0800929 // Update the last video thumbnail.
Wu-cheng Lib1284462009-06-05 14:35:42 +0800930 if (!mIsVideoCaptureIntent) {
931 if (!mThumbController.isUriValid()) {
932 updateLastVideo();
933 }
934 mThumbController.updateDisplayIfNeeded();
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700935 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800936 }
937
938 private void releaseMediaRecorder() {
939 Log.v(TAG, "Releasing media recorder.");
940 if (mMediaRecorder != null) {
941 cleanupEmptyFile();
942 mMediaRecorder.reset();
943 mMediaRecorder.release();
944 mMediaRecorder = null;
945 }
946 }
947
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800948 private int getIntPreference(String key, int defaultValue) {
949 String s = mPreferences.getString(key, "");
950 int result = defaultValue;
951 try {
952 result = Integer.parseInt(s);
953 } catch (NumberFormatException e) {
954 // Ignore, result is already the default value.
955 }
956 return result;
957 }
958
959 private boolean getBooleanPreference(String key, boolean defaultValue) {
960 return getIntPreference(key, defaultValue ? 1 : 0) != 0;
961 }
962
963 private void createVideoPath() {
964 long dateTaken = System.currentTimeMillis();
965 String title = createName(dateTaken);
966 String displayName = title + ".3gp"; // Used when emailing.
967 String cameraDirPath = ImageManager.CAMERA_IMAGE_BUCKET_NAME;
968 File cameraDir = new File(cameraDirPath);
969 cameraDir.mkdirs();
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800970 SimpleDateFormat dateFormat = new SimpleDateFormat(
971 getString(R.string.video_file_name_format));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800972 Date date = new Date(dateTaken);
973 String filepart = dateFormat.format(date);
974 String filename = cameraDirPath + "/" + filepart + ".3gp";
975 ContentValues values = new ContentValues(7);
976 values.put(Video.Media.TITLE, title);
977 values.put(Video.Media.DISPLAY_NAME, displayName);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800978 values.put(Video.Media.DATE_TAKEN, dateTaken);
979 values.put(Video.Media.MIME_TYPE, "video/3gpp");
980 values.put(Video.Media.DATA, filename);
981 mCameraVideoFilename = filename;
982 Log.v(TAG, "Current camera video filename: " + mCameraVideoFilename);
983 mCurrentVideoValues = values;
984 }
985
986 private void registerVideo() {
987 if (mCameraVideoFileDescriptor == null) {
988 Uri videoTable = Uri.parse("content://media/external/video/media");
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800989 mCurrentVideoValues.put(Video.Media.SIZE,
990 new File(mCurrentVideoFilename).length());
991 mCurrentVideoUri = mContentResolver.insert(videoTable,
992 mCurrentVideoValues);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800993 Log.v(TAG, "Current video URI: " + mCurrentVideoUri);
994 }
995 mCurrentVideoValues = null;
996 }
997
998 private void deleteCurrentVideo() {
999 if (mCurrentVideoFilename != null) {
1000 deleteVideoFile(mCurrentVideoFilename);
1001 mCurrentVideoFilename = null;
1002 }
1003 if (mCurrentVideoUri != null) {
1004 mContentResolver.delete(mCurrentVideoUri, null, null);
1005 mCurrentVideoUri = null;
1006 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001007 updateAndShowStorageHint(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001008 }
1009
1010 private void deleteVideoFile(String fileName) {
1011 Log.v(TAG, "Deleting video " + fileName);
1012 File f = new File(fileName);
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001013 if (!f.delete()) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001014 Log.v(TAG, "Could not delete " + fileName);
1015 }
1016 }
1017
1018 private void addBaseMenuItems(Menu menu) {
Chih-Chung Changd1890832009-09-08 13:32:52 +08001019 MenuItem gallery = menu.add(Menu.NONE, Menu.NONE,
1020 MenuHelper.POSITION_GOTO_GALLERY,
Chih-Chung Changb5946542009-09-07 20:17:12 +08001021 R.string.camera_gallery_photos_text)
1022 .setOnMenuItemClickListener(
1023 new OnMenuItemClickListener() {
1024 public boolean onMenuItemClick(MenuItem item) {
1025 gotoGallery();
1026 return true;
1027 }
1028 });
1029 gallery.setIcon(android.R.drawable.ic_menu_gallery);
1030 mGalleryItems.add(gallery);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001031
Chih-Chung Changd1890832009-09-08 13:32:52 +08001032 MenuItem item = menu.add(Menu.NONE, Menu.NONE,
Owen Lin50c60042009-09-10 14:43:42 +08001033 MenuHelper.POSITION_CAMERA_SETTING, R.string.settings)
1034 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1035 public boolean onMenuItemClick(MenuItem item) {
Owen Linc1f2e302009-09-14 19:04:37 +08001036 showOnScreenSettings();
Owen Lin50c60042009-09-10 14:43:42 +08001037 return true;
1038 }});
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001039 item.setIcon(android.R.drawable.ic_menu_preferences);
1040 }
1041
Owen Linc1f2e302009-09-14 19:04:37 +08001042 private void showOnScreenSettings() {
1043 if (mSettings == null) {
1044 mSettings = new OnScreenSettings(
1045 findViewById(R.id.camera_preview));
1046 CameraSettings helper = new CameraSettings(this, mParameters);
Wei-Ta Chen7e4655b2009-09-25 17:23:22 -07001047 PreferenceScreen screen = helper
1048 .getPreferenceScreen(R.xml.video_preferences);
1049 if (mIsVideoCaptureIntent) {
1050 screen = filterPreferenceScreenByIntent(screen);
1051 }
1052
1053 mSettings.setPreferenceScreen(screen);
Owen Linc1f2e302009-09-14 19:04:37 +08001054 mSettings.setOnVisibilityChangedListener(this);
1055 }
Cheng-Ru Linabdd8a12009-09-30 15:35:43 +08001056 mSettings.setVisible(true);
Owen Linc1f2e302009-09-14 19:04:37 +08001057 }
1058
Wei-Ta Chen7e4655b2009-09-25 17:23:22 -07001059 private PreferenceScreen filterPreferenceScreenByIntent(
1060 PreferenceScreen screen) {
1061 Intent intent = getIntent();
1062 if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
1063 CameraSettings.removePreferenceFromScreen(screen,
1064 CameraSettings.KEY_VIDEO_QUALITY);
1065 }
1066
1067 if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) {
1068 CameraSettings.removePreferenceFromScreen(screen,
1069 CameraSettings.KEY_VIDEO_DURATION);
1070 }
1071 return screen;
1072 }
1073
Owen Linc1f2e302009-09-14 19:04:37 +08001074 private class GripperTouchListener implements View.OnTouchListener {
1075 public boolean onTouch(View view, MotionEvent event) {
1076 switch (event.getAction()) {
1077 case MotionEvent.ACTION_DOWN:
1078 return true;
1079 case MotionEvent.ACTION_UP:
1080 showOnScreenSettings();
1081 return true;
1082 }
1083 return false;
1084 }
1085 }
1086
Owen Lin3e737c22009-09-11 11:31:59 +08001087 public void onVisibilityChanged(boolean visible) {
Chih-Chung Changfae0daa2009-09-21 05:36:24 +08001088 // At this point, we are not recording.
1089 mGripper.setVisibility(visible ? View.INVISIBLE : View.VISIBLE);
Owen Lin3e737c22009-09-11 11:31:59 +08001090 if (visible) {
1091 releaseMediaRecorder();
Wei-Ta Chend18f3802009-09-30 20:27:42 -07001092 mPreferences.registerOnSharedPreferenceChangeListener(this);
Owen Lin3e737c22009-09-11 11:31:59 +08001093 } else {
1094 initializeRecorder();
Wei-Ta Chend18f3802009-09-30 20:27:42 -07001095 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
Owen Lin3e737c22009-09-11 11:31:59 +08001096 }
1097 }
1098
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001099 // from MediaRecorder.OnErrorListener
1100 public void onError(MediaRecorder mr, int what, int extra) {
1101 if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
1102 // We may have run out of space on the sdcard.
1103 stopVideoRecording();
The Android Open Source Project9a379bd2009-03-09 11:52:14 -07001104 updateAndShowStorageHint(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001105 }
1106 }
1107
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001108 // from MediaRecorder.OnInfoListener
1109 public void onInfo(MediaRecorder mr, int what, int extra) {
1110 if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001111 mShutterButton.performClick();
Chih-Chung Chang91acfc92009-07-06 15:37:24 +08001112 } else if (what
1113 == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001114 mShutterButton.performClick();
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +08001115 // Show the toast.
1116 Toast.makeText(VideoCamera.this, R.string.video_reach_size_limit,
1117 Toast.LENGTH_LONG).show();
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001118 }
1119 }
1120
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001121 /*
Owen Lin61b98312009-06-19 00:21:10 -07001122 * Make sure we're not recording music playing in the background, ask the
1123 * MediaPlaybackService to pause playback.
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001124 */
1125 private void pauseAudioPlayback() {
1126 // Shamelessly copied from MediaPlaybackService.java, which
1127 // should be public, but isn't.
1128 Intent i = new Intent("com.android.music.musicservicecommand");
1129 i.putExtra("command", "pause");
1130
1131 sendBroadcast(i);
1132 }
1133
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001134 private void startVideoRecording() {
1135 Log.v(TAG, "startVideoRecording");
1136 if (!mMediaRecorderRecording) {
1137
The Android Open Source Project9a379bd2009-03-09 11:52:14 -07001138 if (mStorageStatus != STORAGE_STATUS_OK) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001139 Log.v(TAG, "Storage issue, ignore the start request");
1140 return;
1141 }
1142
1143 // Check mMediaRecorder to see whether it is initialized or not.
Wu-cheng Lib1284462009-06-05 14:35:42 +08001144 if (mMediaRecorder == null) {
1145 Log.e(TAG, "MediaRecorder is not initialized.");
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001146 return;
1147 }
1148
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001149 pauseAudioPlayback();
1150
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001151 try {
1152 mMediaRecorder.setOnErrorListener(this);
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001153 mMediaRecorder.setOnInfoListener(this);
Owen Lin61b98312009-06-19 00:21:10 -07001154 mMediaRecorder.start(); // Recording is now started
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001155 } catch (RuntimeException e) {
1156 Log.e(TAG, "Could not start media recorder. ", e);
1157 return;
1158 }
1159 mMediaRecorderRecording = true;
1160 mRecordingStartTime = SystemClock.uptimeMillis();
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +08001161 updateRecordingIndicator(false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001162 mRecordingTimeView.setText("");
1163 mRecordingTimeView.setVisibility(View.VISIBLE);
Wu-cheng Li5f3fe872009-09-29 20:29:49 -07001164 updateRecordingTime();
Owen Lincc8d7562009-09-16 14:43:09 +08001165 keepScreenOn();
Chih-Chung Changfae0daa2009-09-21 05:36:24 +08001166 mGripper.setVisibility(View.INVISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001167 }
1168 }
1169
1170 private void updateRecordingIndicator(boolean showRecording) {
Owen Lin61b98312009-06-19 00:21:10 -07001171 int drawableId =
1172 showRecording ? R.drawable.btn_ic_video_record
1173 : R.drawable.btn_ic_video_record_stop;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001174 Drawable drawable = getResources().getDrawable(drawableId);
1175 mShutterButton.setImageDrawable(drawable);
1176 }
1177
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001178 private void stopVideoRecordingAndGetThumbnail() {
1179 stopVideoRecording();
1180 acquireVideoThumb();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001181 }
1182
Wu-cheng Li84f96462009-06-19 20:11:44 +08001183 private void stopVideoRecordingAndShowAlert() {
1184 stopVideoRecording();
1185 showAlert();
1186 }
1187
1188 private void showAlert() {
Owen Lin61b98312009-06-19 00:21:10 -07001189 fadeOut(findViewById(R.id.shutter_button));
1190 if (mCurrentVideoFilename != null) {
1191 mVideoFrame.setImageBitmap(
Ray Chen9f1480b2009-08-27 17:59:29 -07001192 ThumbnailUtil.createVideoThumbnail(mCurrentVideoFilename));
Wu-cheng Li84f96462009-06-19 20:11:44 +08001193 mVideoFrame.setVisibility(View.VISIBLE);
1194 }
Owen Lin61b98312009-06-19 00:21:10 -07001195 int[] pickIds = {R.id.btn_retake, R.id.btn_done, R.id.btn_play};
1196 for (int id : pickIds) {
1197 View button = findViewById(id);
1198 fadeIn(((View) button.getParent()));
1199 }
Wu-cheng Li84f96462009-06-19 20:11:44 +08001200 }
1201
1202 private void hideAlert() {
Wu-cheng Li84f96462009-06-19 20:11:44 +08001203 mVideoFrame.setVisibility(View.INVISIBLE);
Owen Lin61b98312009-06-19 00:21:10 -07001204 fadeIn(findViewById(R.id.shutter_button));
1205 int[] pickIds = {R.id.btn_retake, R.id.btn_done, R.id.btn_play};
1206 for (int id : pickIds) {
1207 View button = findViewById(id);
1208 fadeOut(((View) button.getParent()));
Wu-cheng Li84f96462009-06-19 20:11:44 +08001209 }
1210 }
1211
Owen Lin61b98312009-06-19 00:21:10 -07001212 private static void fadeIn(View view) {
1213 view.setVisibility(View.VISIBLE);
1214 Animation animation = new AlphaAnimation(0F, 1F);
1215 animation.setDuration(500);
1216 view.startAnimation(animation);
1217 }
1218
1219 private static void fadeOut(View view) {
1220 view.setVisibility(View.INVISIBLE);
1221 Animation animation = new AlphaAnimation(1F, 0F);
1222 animation.setDuration(500);
1223 view.startAnimation(animation);
1224 }
1225
Wu-cheng Li84f96462009-06-19 20:11:44 +08001226 private boolean isAlertVisible() {
Owen Lin61b98312009-06-19 00:21:10 -07001227 return this.mVideoFrame.getVisibility() == View.VISIBLE;
Wu-cheng Li84f96462009-06-19 20:11:44 +08001228 }
1229
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +08001230 private void stopVideoRecordingAndShowReview() {
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001231 stopVideoRecording();
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +08001232 if (mThumbController.isUriValid()) {
1233 Uri targetUri = mThumbController.getUri();
1234 Intent intent = new Intent(this, ReviewImage.class);
1235 intent.setData(targetUri);
1236 intent.putExtra(MediaStore.EXTRA_FULL_SCREEN, true);
1237 intent.putExtra(MediaStore.EXTRA_SHOW_ACTION_ICONS, true);
1238 intent.putExtra("com.android.camera.ReviewMode", true);
1239 try {
1240 startActivity(intent);
1241 } catch (ActivityNotFoundException ex) {
1242 Log.e(TAG, "review video fail", ex);
1243 }
1244 } else {
1245 Log.e(TAG, "Can't view last video.");
1246 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001247 }
1248
1249 private void stopVideoRecording() {
1250 Log.v(TAG, "stopVideoRecording");
1251 boolean needToRegisterRecording = false;
1252 if (mMediaRecorderRecording || mMediaRecorder != null) {
1253 if (mMediaRecorderRecording && mMediaRecorder != null) {
1254 try {
1255 mMediaRecorder.setOnErrorListener(null);
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001256 mMediaRecorder.setOnInfoListener(null);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001257 mMediaRecorder.stop();
1258 } catch (RuntimeException e) {
1259 Log.e(TAG, "stop fail: " + e.getMessage());
1260 }
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001261
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001262 mCurrentVideoFilename = mCameraVideoFilename;
Chih-Chung Chang91acfc92009-07-06 15:37:24 +08001263 Log.v(TAG, "Setting current video filename: "
1264 + mCurrentVideoFilename);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001265 needToRegisterRecording = true;
1266 mMediaRecorderRecording = false;
1267 }
1268 releaseMediaRecorder();
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +08001269 updateRecordingIndicator(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001270 mRecordingTimeView.setVisibility(View.GONE);
Owen Lincc8d7562009-09-16 14:43:09 +08001271 keepScreenOnAwhile();
Chih-Chung Changfae0daa2009-09-21 05:36:24 +08001272 mGripper.setVisibility(View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001273 }
The Android Open Source Project9a379bd2009-03-09 11:52:14 -07001274 if (needToRegisterRecording && mStorageStatus == STORAGE_STATUS_OK) {
1275 registerVideo();
1276 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001277
1278 mCameraVideoFilename = null;
1279 mCameraVideoFileDescriptor = null;
1280 }
1281
Owen Lincc8d7562009-09-16 14:43:09 +08001282 private void resetScreenOn() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001283 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
Owen Lincc8d7562009-09-16 14:43:09 +08001284 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001285 }
1286
Owen Lincc8d7562009-09-16 14:43:09 +08001287 private void keepScreenOnAwhile() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001288 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
Owen Lincc8d7562009-09-16 14:43:09 +08001289 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001290 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1291 }
1292
Owen Lincc8d7562009-09-16 14:43:09 +08001293 private void keepScreenOn() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001294 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
Owen Lincc8d7562009-09-16 14:43:09 +08001295 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001296 }
1297
Wu-cheng Lib1284462009-06-05 14:35:42 +08001298 private void hideAlertAndInitializeRecorder() {
Wu-cheng Li84f96462009-06-19 20:11:44 +08001299 hideAlert();
Wu-cheng Lib1284462009-06-05 14:35:42 +08001300 mHandler.sendEmptyMessage(INIT_RECORDER);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001301 }
1302
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001303 private void acquireVideoThumb() {
Ray Chen9f1480b2009-08-27 17:59:29 -07001304 Bitmap videoFrame = ThumbnailUtil.createVideoThumbnail(mCurrentVideoFilename);
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001305 mThumbController.setData(mCurrentVideoUri, videoFrame);
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001306 }
1307
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001308 private static ImageManager.DataLocation dataLocation() {
1309 return ImageManager.DataLocation.EXTERNAL;
1310 }
1311
1312 private void updateLastVideo() {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +08001313 IImageList list = ImageManager.makeImageList(
1314 mContentResolver,
1315 dataLocation(),
Chih-Chung Chang91acfc92009-07-06 15:37:24 +08001316 ImageManager.INCLUDE_VIDEOS,
1317 ImageManager.SORT_ASCENDING,
Owen Lin61b98312009-06-19 00:21:10 -07001318 ImageManager.CAMERA_IMAGE_BUCKET_ID);
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001319 int count = list.getCount();
1320 if (count > 0) {
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001321 IImage image = list.getImageAt(count - 1);
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001322 Uri uri = image.fullSizeImageUri();
1323 mThumbController.setData(uri, image.miniThumbBitmap());
1324 } else {
1325 mThumbController.setData(null, null);
1326 }
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +08001327 list.close();
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001328 }
1329
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001330 private void updateRecordingTime() {
Ray Chen23c51b72009-04-10 03:41:00 -07001331 if (!mMediaRecorderRecording) {
1332 return;
1333 }
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001334 long now = SystemClock.uptimeMillis();
1335 long delta = now - mRecordingStartTime;
1336
1337 // Starting a minute before reaching the max duration
1338 // limit, we'll countdown the remaining time instead.
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001339 boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
Wu-cheng Lib6ed73e2009-07-08 13:55:06 +08001340 && delta >= mMaxVideoDurationInMs - 60000);
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001341
Wu-cheng Li5f3fe872009-09-29 20:29:49 -07001342 long next_update_delay = 1000 - (delta % 1000);
1343 long seconds;
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001344 if (countdownRemainingTime) {
Chih-Chung Chang82ded202009-05-20 14:24:25 +08001345 delta = Math.max(0, mMaxVideoDurationInMs - delta);
Wu-cheng Li5f3fe872009-09-29 20:29:49 -07001346 seconds = (delta + 999) / 1000;
1347 } else {
1348 seconds = delta / 1000; // round to nearest
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001349 }
1350
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001351 long minutes = seconds / 60;
1352 long hours = minutes / 60;
1353 long remainderMinutes = minutes - (hours * 60);
1354 long remainderSeconds = seconds - (minutes * 60);
1355
1356 String secondsString = Long.toString(remainderSeconds);
1357 if (secondsString.length() < 2) {
1358 secondsString = "0" + secondsString;
1359 }
1360 String minutesString = Long.toString(remainderMinutes);
1361 if (minutesString.length() < 2) {
1362 minutesString = "0" + minutesString;
1363 }
1364 String text = minutesString + ":" + secondsString;
1365 if (hours > 0) {
1366 String hoursString = Long.toString(hours);
1367 if (hoursString.length() < 2) {
1368 hoursString = "0" + hoursString;
1369 }
1370 text = hoursString + ":" + text;
1371 }
1372 mRecordingTimeView.setText(text);
1373
1374 if (mRecordingTimeCountsDown != countdownRemainingTime) {
1375 // Avoid setting the color on every update, do it only
1376 // when it needs changing.
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001377 mRecordingTimeCountsDown = countdownRemainingTime;
1378
Owen Lin482a3a52009-06-26 15:47:39 -07001379 int color = getResources().getColor(countdownRemainingTime
1380 ? R.color.recording_time_remaining_text
1381 : R.color.recording_time_elapsed_text);
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001382
1383 mRecordingTimeView.setTextColor(color);
1384 }
1385
Wu-cheng Li13874d72009-10-05 15:23:01 -07001386 mHandler.sendEmptyMessageDelayed(
1387 UPDATE_RECORD_TIME, next_update_delay);
Chih-Chung Changd8209aa2009-04-07 11:45:12 -07001388 }
Owen Line239acc2009-06-23 22:18:20 -07001389
Owen Lin50c60042009-09-10 14:43:42 +08001390 private void setCameraParameters() {
1391 mParameters = mCameraDevice.getParameters();
1392
1393 mParameters.setPreviewSize(mProfile.mVideoWidth, mProfile.mVideoHeight);
Chih-Chung Chang207ad852009-09-28 14:36:37 -07001394 mParameters.setPreviewFrameRate(mProfile.mVideoFps);
Owen Lin50c60042009-09-10 14:43:42 +08001395
1396 // Set white balance parameter.
1397 if (mParameters.getSupportedWhiteBalance() != null) {
1398 String whiteBalance = mPreferences.getString(
1399 CameraSettings.KEY_WHITE_BALANCE,
1400 getString(R.string.pref_camera_whitebalance_default));
1401 mParameters.setWhiteBalance(whiteBalance);
1402 }
1403
1404 // Set color effect parameter.
1405 if (mParameters.getSupportedColorEffects() != null) {
1406 String colorEffect = mPreferences.getString(
1407 CameraSettings.KEY_COLOR_EFFECT,
1408 getString(R.string.pref_camera_coloreffect_default));
1409 mParameters.setColorEffect(colorEffect);
1410 }
Wu-cheng Liffde05c2009-09-15 18:52:25 +08001411
Owen Lin50c60042009-09-10 14:43:42 +08001412 mCameraDevice.setParameters(mParameters);
1413 }
1414
Chih-Chung Changd918cfa2009-07-13 13:11:52 +08001415 public boolean onSwitchChanged(Switcher source, boolean onOff) {
Owen Line239acc2009-06-23 22:18:20 -07001416 if (onOff == SWITCH_CAMERA) {
1417 MenuHelper.gotoCameraMode(this);
Owen Lin3283e042009-06-26 11:59:58 -07001418 finish();
Owen Line239acc2009-06-23 22:18:20 -07001419 }
Chih-Chung Changd918cfa2009-07-13 13:11:52 +08001420 return true;
Owen Line239acc2009-06-23 22:18:20 -07001421 }
Owen Lin50c60042009-09-10 14:43:42 +08001422
1423 public void onSharedPreferenceChanged(
1424 SharedPreferences preferences, String key) {
1425 // ignore the events after "onPause()" or preview has not started yet
1426 if (mPausing) return;
1427
1428 if (CameraSettings.KEY_VIDEO_DURATION.equals(key)
1429 || CameraSettings.KEY_VIDEO_QUALITY.equals(key)) {
1430 readVideoPreferences();
1431 }
1432
1433 // If mCameraDevice is not ready then we can set the parameter in
1434 // startPreview().
1435 if (mCameraDevice == null) return;
1436
Wu-cheng Liffde05c2009-09-15 18:52:25 +08001437 // We need to restart the preview if preview size is changed.
1438 Size size = mParameters.getPreviewSize();
1439 if (size.width != mProfile.mVideoWidth
1440 || size.height != mProfile.mVideoHeight) {
1441 // It is assumed media recorder is released before
1442 // onSharedPreferenceChanged, so we can close the camera here.
1443 closeCamera();
1444 try {
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -07001445 resizeForPreviewAspectRatio();
Wu-cheng Liffde05c2009-09-15 18:52:25 +08001446 startPreview(); // Parameters will be set in startPreview().
1447 } catch (CameraHardwareException e) {
1448 showCameraBusyAndFinish();
1449 }
Owen Lin50c60042009-09-10 14:43:42 +08001450 } else {
Wu-cheng Lid0759fe2009-09-18 14:10:47 +08001451 try {
1452 // We need to lock the camera before writing parameters.
1453 mCameraDevice.lock();
1454 } catch (RuntimeException e) {
1455 // When preferences are added for the first time, this method
1456 // will be called. But OnScreenSetting is not displayed yet and
1457 // media recorder still owns the camera. Lock will fail and we
1458 // just ignore it.
1459 return;
Wu-cheng Liffde05c2009-09-15 18:52:25 +08001460 }
Wu-cheng Lid0759fe2009-09-18 14:10:47 +08001461 setCameraParameters();
1462 mCameraDevice.unlock();
Owen Lin50c60042009-09-10 14:43:42 +08001463 }
Owen Lin50c60042009-09-10 14:43:42 +08001464 }
Wei-Ta Chen1f0564e2009-09-28 18:38:05 -07001465
1466 public void onSizeChanged() {
1467 if (mSettings != null) {
1468 mSettings.updateLayout();
1469 }
1470
1471 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001472}
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001473
1474//
1475// DefaultHashMap is a HashMap which returns a default value if the specified
1476// key is not found.
1477//
Owen Lin71d56e22009-09-23 22:27:04 +08001478@SuppressWarnings("serial")
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001479class DefaultHashMap<K, V> extends HashMap<K, V> {
1480 private V mDefaultValue;
1481
1482 public void putDefault(V defaultValue) {
1483 mDefaultValue = defaultValue;
1484 }
1485
1486 @Override
1487 public V get(Object key) {
1488 V value = super.get(key);
1489 return (value == null) ? mDefaultValue : value;
1490 }
1491}
1492
1493//
1494// MediaRecorderProfile reads from system properties to determine the proper
1495// values for various parameters for MediaRecorder.
1496//
1497class MediaRecorderProfile {
Owen Line594b192009-08-13 18:04:45 +08001498
1499 @SuppressWarnings("unused")
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001500 private static final String TAG = "MediaRecorderProfile";
1501 public final boolean mHiQuality;
1502 public final int mOutputFormat;
1503 public final int mVideoEncoder;
1504 public final int mAudioEncoder;
1505 public final int mVideoWidth;
1506 public final int mVideoHeight;
Chih-Chung Chang947455a2009-07-29 14:50:07 +08001507 public final int mVideoFps;
1508 public final int mVideoBitrate;
1509 public final int mAudioBitrate;
1510 public final int mAudioChannels;
1511 public final int mAudioSamplingRate;
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001512
1513 MediaRecorderProfile(boolean hiQuality) {
1514 mHiQuality = hiQuality;
1515
1516 mOutputFormat = getFromTable("ro.media.enc.hprof.file.format",
1517 "ro.media.enc.lprof.file.format",
1518 OUTPUT_FORMAT_TABLE);
1519
1520 mVideoEncoder = getFromTable("ro.media.enc.hprof.codec.vid",
1521 "ro.media.enc.lprof.codec.vid",
1522 VIDEO_ENCODER_TABLE);
1523
1524 mAudioEncoder = getFromTable("ro.media.enc.hprof.codec.aud",
1525 "ro.media.enc.lprof.codec.aud",
1526 AUDIO_ENCODER_TABLE);
1527
1528 mVideoWidth = getInt("ro.media.enc.hprof.vid.width",
1529 "ro.media.enc.lprof.vid.width",
1530 352, 176);
1531
1532 mVideoHeight = getInt("ro.media.enc.hprof.vid.height",
1533 "ro.media.enc.lprof.vid.height",
1534 288, 144);
1535
Chih-Chung Chang947455a2009-07-29 14:50:07 +08001536 mVideoFps = getInt("ro.media.enc.hprof.vid.fps",
1537 "ro.media.enc.lprof.vid.fps",
1538 20, 20);
1539
1540 mVideoBitrate = getInt("ro.media.enc.hprof.vid.bps",
1541 "ro.media.enc.lprof.vid.bps",
1542 360000, 192000);
1543
1544 mAudioBitrate = getInt("ro.media.enc.hprof.aud.bps",
1545 "ro.media.enc.lprof.aud.bps",
1546 23450, 23450);
1547
1548 mAudioChannels = getInt("ro.media.enc.hprof.aud.ch",
1549 "ro.media.enc.lprof.aud.ch",
1550 1, 1);
1551
1552 mAudioSamplingRate = getInt("ro.media.enc.hprof.aud.hz",
1553 "ro.media.enc.lprof.aud.hz",
1554 8000, 8000);
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001555 }
1556
1557 private int getFromTable(String highKey, String lowKey,
1558 DefaultHashMap<String, Integer> table) {
1559 String s;
1560 s = SystemProperties.get(mHiQuality ? highKey : lowKey);
1561 return table.get(s);
1562 }
1563
1564 private int getInt(String highKey, String lowKey, int highDefault,
1565 int lowDefault) {
1566 String key = mHiQuality ? highKey : lowKey;
1567 int defaultValue = mHiQuality ? highDefault : lowDefault;
1568 return SystemProperties.getInt(key, defaultValue);
1569 }
1570
1571 private static final DefaultHashMap<String, Integer>
1572 OUTPUT_FORMAT_TABLE = new DefaultHashMap<String, Integer>();
1573 private static final DefaultHashMap<String, Integer>
1574 VIDEO_ENCODER_TABLE = new DefaultHashMap<String, Integer>();
1575 private static final DefaultHashMap<String, Integer>
1576 AUDIO_ENCODER_TABLE = new DefaultHashMap<String, Integer>();
1577
1578 static {
1579 OUTPUT_FORMAT_TABLE.put("3gp", MediaRecorder.OutputFormat.THREE_GPP);
1580 OUTPUT_FORMAT_TABLE.put("mp4", MediaRecorder.OutputFormat.MPEG_4);
1581 OUTPUT_FORMAT_TABLE.putDefault(MediaRecorder.OutputFormat.DEFAULT);
1582
1583 VIDEO_ENCODER_TABLE.put("h263", MediaRecorder.VideoEncoder.H263);
1584 VIDEO_ENCODER_TABLE.put("h264", MediaRecorder.VideoEncoder.H264);
Snigdhaeb6a5532009-08-06 15:06:00 -05001585 VIDEO_ENCODER_TABLE.put("m4v", MediaRecorder.VideoEncoder.MPEG_4_SP);
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001586 VIDEO_ENCODER_TABLE.putDefault(MediaRecorder.VideoEncoder.DEFAULT);
1587
1588 AUDIO_ENCODER_TABLE.put("amrnb", MediaRecorder.AudioEncoder.AMR_NB);
1589 AUDIO_ENCODER_TABLE.put("amrwb", MediaRecorder.AudioEncoder.AMR_WB);
1590 AUDIO_ENCODER_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC);
1591 AUDIO_ENCODER_TABLE.put("aacplus", MediaRecorder.AudioEncoder.AAC_PLUS);
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001592 AUDIO_ENCODER_TABLE.put("eaacplus",
1593 MediaRecorder.AudioEncoder.EAAC_PLUS);
Chih-Chung Chang97601c72009-07-27 19:19:10 +08001594 AUDIO_ENCODER_TABLE.putDefault(MediaRecorder.AudioEncoder.DEFAULT);
1595 }
1596}