summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/VideoCamera.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/VideoCamera.java')
-rw-r--r--src/com/android/camera/VideoCamera.java484
1 files changed, 361 insertions, 123 deletions
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index a92e33c..fddfdaf 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -19,6 +19,7 @@ package com.android.camera;
import com.android.camera.gallery.IImage;
import com.android.camera.gallery.IImageList;
import com.android.camera.ui.CamcorderHeadUpDisplay;
+import com.android.camera.ui.ControlPanel;
import com.android.camera.ui.GLRootView;
import com.android.camera.ui.GLView;
import com.android.camera.ui.HeadUpDisplay;
@@ -33,6 +34,7 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.hardware.Camera.Parameters;
@@ -50,9 +52,12 @@ import android.os.Message;
import android.os.StatFs;
import android.os.SystemClock;
import android.provider.MediaStore;
-import android.provider.Settings;
import android.provider.MediaStore.Video;
+import android.provider.MediaStore.Video.VideoColumns;
+import android.provider.MediaStore.Video.Media;
+import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -66,8 +71,13 @@ import android.view.WindowManager;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.CursorAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
@@ -130,13 +140,22 @@ public class VideoCamera extends NoSearchActivity
private ImageView mVideoFrame;
private GLRootView mGLRootView;
private CamcorderHeadUpDisplay mHeadUpDisplay;
+ private ControlPanel mControlPanel;
+ private MenuItem mSwitchTimeLapseMenuItem;
private boolean mIsVideoCaptureIntent;
private boolean mQuickCapture;
- // mLastPictureButton and mThumbController
- // are non-null only if mIsVideoCaptureIntent is true.
- private ImageView mLastPictureButton;
- private ThumbnailController mThumbController;
+
+ // The layout of small devices has a thumbnail button, which shows the last
+ // captured picture.
+ private RotateImageView mThumbnailButton;
+ // The layout of xlarge devices have a list of thumbnails, which show the
+ // last captured pictures.
+ private ListView mThumbnailList;
+ private OnItemClickListener mThumbnailItemClickListener =
+ new ThumbnailItemClickListener();
+ private ThumbnailAdapter mThumbnailAdapter;
+
private boolean mStartPreviewFail = false;
private int mStorageStatus = STORAGE_STATUS_OK;
@@ -160,13 +179,20 @@ public class VideoCamera extends NoSearchActivity
// The video duration limit. 0 menas no limit.
private int mMaxVideoDurationInMs;
+ // Time Lapse parameters.
+ private boolean mCaptureTimeLapse = false;
+ private int mTimeBetweenTimeLapseFrameCaptureMs = 2000;
+
+ private int mDesiredPreviewWidth;
+ private int mDesiredPreviewHeight;
+
boolean mPausing = false;
boolean mPreviewing = false; // True if preview is started.
private ContentResolver mContentResolver;
private ShutterButton mShutterButton;
- private TextView mRecordingTimeView;
+ private TextView mRecordingTimeView, mTimeLapseRecordingTimeView;
private Switcher mSwitcher;
private boolean mRecordingTimeCountsDown = false;
@@ -332,19 +358,13 @@ public class VideoCamera extends NoSearchActivity
mIsVideoCaptureIntent = isVideoCaptureIntent();
mQuickCapture = getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
- mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
ViewGroup rootView = (ViewGroup) findViewById(R.id.video_camera);
LayoutInflater inflater = this.getLayoutInflater();
if (!mIsVideoCaptureIntent) {
View controlBar = inflater.inflate(
R.layout.camera_control, rootView);
- mLastPictureButton =
- (ImageView) controlBar.findViewById(R.id.review_thumbnail);
- mThumbController = new ThumbnailController(
- getResources(), mLastPictureButton, mContentResolver);
- mLastPictureButton.setOnClickListener(this);
- mThumbController.loadData(ImageManager.getLastVideoThumbPath());
+ initThumbnailButton();
mSwitcher = ((Switcher) findViewById(R.id.camera_switch));
mSwitcher.setOnSwitchListener(this);
mSwitcher.addTouchView(findViewById(R.id.camera_switch_set));
@@ -365,6 +385,10 @@ public class VideoCamera extends NoSearchActivity
mShutterButton.setOnShutterButtonListener(this);
mShutterButton.requestFocus();
+ mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
+ mTimeLapseRecordingTimeView = (TextView) findViewById(
+ R.id.time_lapse_recording_time);
+
// Make sure preview is started.
try {
startPreviewThread.join();
@@ -381,6 +405,7 @@ public class VideoCamera extends NoSearchActivity
mHeadUpDisplay = new CamcorderHeadUpDisplay(this);
mHeadUpDisplay.setListener(new MyHeadUpDisplayListener());
initializeHeadUpDisplay();
+ initializeControlPanel();
}
private void changeHeadUpDisplayState() {
@@ -400,14 +425,13 @@ public class VideoCamera extends NoSearchActivity
private void initializeHeadUpDisplay() {
CameraSettings settings = new CameraSettings(this, mParameters,
- CameraHolder.instance().getCameraInfo());
+ mCameraId, CameraHolder.instance().getCameraInfo());
- PreferenceGroup group =
- settings.getPreferenceGroup(R.xml.video_preferences);
+ PreferenceGroup group = settings.getPreferenceGroup(R.xml.video_preferences);
if (mIsVideoCaptureIntent) {
group = filterPreferenceScreenByIntent(group);
}
- mHeadUpDisplay.initialize(this, group);
+ mHeadUpDisplay.initialize(this, group, mCaptureTimeLapse);
}
private void attachHeadUpDisplay() {
@@ -423,6 +447,20 @@ public class VideoCamera extends NoSearchActivity
mGLRootView = null;
}
+ private void initializeControlPanel() {
+ String[] keys = new String[]{CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE,
+ CameraSettings.KEY_WHITE_BALANCE,
+ CameraSettings.KEY_CAMERA_ID};
+ mControlPanel = (ControlPanel) findViewById(R.id.control_panel);
+ if (mControlPanel != null) {
+ CameraSettings settings = new CameraSettings(this, mParameters,
+ mCameraId, CameraHolder.instance().getCameraInfo());
+ mControlPanel.initialize(this,
+ settings.getPreferenceGroup(R.xml.video_preferences), keys);
+ mControlPanel.setListener(new MyControlPanelListener());
+ }
+ }
+
@Override
protected void onStart() {
super.onStart();
@@ -452,10 +490,14 @@ public class VideoCamera extends NoSearchActivity
doReturnToCaller(true);
break;
case R.id.btn_cancel:
- stopVideoRecordingAndReturn(false);
+ stopVideoRecording();
+ doReturnToCaller(false);
break;
case R.id.review_thumbnail:
- if (!mMediaRecorderRecording) viewLastVideo();
+ if (!mMediaRecorderRecording) viewVideo(mThumbnailButton);
+ break;
+ case R.id.btn_gallery:
+ gotoGallery();
break;
}
}
@@ -465,14 +507,15 @@ public class VideoCamera extends NoSearchActivity
}
private void onStopVideoRecording(boolean valid) {
+ stopVideoRecording();
if (mIsVideoCaptureIntent) {
if (mQuickCapture) {
- stopVideoRecordingAndReturn(valid);
+ doReturnToCaller(valid);
} else {
- stopVideoRecordingAndShowAlert();
+ showAlert();
}
} else {
- stopVideoRecordingAndGetThumbnail();
+ getThumbnail();
initializeRecorder();
}
}
@@ -481,6 +524,7 @@ public class VideoCamera extends NoSearchActivity
switch (button.getId()) {
case R.id.shutter_button:
if (mHeadUpDisplay.collapse()) return;
+ if (mControlPanel != null) mControlPanel.hideSettingPicker();
if (mMediaRecorderRecording) {
onStopVideoRecording(true);
@@ -500,7 +544,8 @@ public class VideoCamera extends NoSearchActivity
private void discardCurrentVideoAndInitRecorder() {
deleteCurrentVideo();
- hideAlertAndInitializeRecorder();
+ hideAlert();
+ mHandler.sendEmptyMessage(INIT_RECORDER);
}
private OnScreenHint mStorageHint;
@@ -548,7 +593,39 @@ public class VideoCamera extends NoSearchActivity
: STORAGE_STATUS_OK;
}
+ private void readTimeLapseVideoPreferences() {
+ // Read CamcorderProfile quality.
+ String qualityStr = mPreferences.getString(
+ CameraSettings.KEY_VIDEO_TIME_LAPSE_QUALITY,
+ getString(R.string.pref_video_time_lapse_quality_default));
+ mProfile = CamcorderProfile.get(mCameraId, Integer.parseInt(qualityStr));
+
+ // Read interval between frame capture.
+ String frameIntervalStr = mPreferences.getString(
+ CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
+ getString(R.string.pref_video_time_lapse_frame_interval_default));
+ mTimeBetweenTimeLapseFrameCaptureMs = Integer.parseInt(frameIntervalStr);
+
+ mMaxVideoDurationInMs = 0; // No limit
+
+ // Time lapse mode can capture video (using the still camera) at resolutions
+ // higher than the supported preview sizes. In that case
+ // mProfile.{videoFrameWidth,videoFrameHeight} will correspond to an unsupported
+ // preview size. So choose preview size optimally from the supported preview
+ // sizes.
+ List<Size> sizes = mParameters.getSupportedPreviewSizes();
+ Size optimalSize = Util.getOptimalPreviewSize(this,
+ sizes, (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight);
+ mDesiredPreviewWidth = optimalSize.width;
+ mDesiredPreviewHeight = optimalSize.height;
+ }
+
private void readVideoPreferences() {
+ if (mCaptureTimeLapse) {
+ readTimeLapseVideoPreferences();
+ return;
+ }
+
String quality = mPreferences.getString(
CameraSettings.KEY_VIDEO_QUALITY,
CameraSettings.DEFAULT_VIDEO_QUALITY_VALUE);
@@ -577,6 +654,9 @@ public class VideoCamera extends NoSearchActivity
videoQualityHigh
? CamcorderProfile.QUALITY_HIGH
: CamcorderProfile.QUALITY_LOW);
+
+ mDesiredPreviewWidth = mProfile.videoFrameWidth;
+ mDesiredPreviewHeight = mProfile.videoFrameHeight;
}
private void resizeForPreviewAspectRatio() {
@@ -620,6 +700,13 @@ public class VideoCamera extends NoSearchActivity
}
changeHeadUpDisplayState();
+ // Update the last video thumbnail.
+ if (!mIsVideoCaptureIntent) {
+ if (mThumbnailButton != null && !mThumbnailButton.isUriValid()) {
+ updateThumbnailButton();
+ }
+ updateThumbnailList();
+ }
}
private void setPreviewDisplay(SurfaceHolder holder) {
@@ -677,17 +764,7 @@ public class VideoCamera extends NoSearchActivity
mPreviewing = false;
}
- @Override
- protected void onPause() {
- super.onPause();
- mPausing = true;
-
- changeHeadUpDisplayState();
-
- // Hide the preview now. Otherwise, the preview may be rotated during
- // onPause and it is annoying to users.
- mVideoPreview.setVisibility(View.INVISIBLE);
-
+ private void finishRecorderAndCloseCamera() {
// This is similar to what mShutterButton.performClick() does,
// but not quite the same.
if (mMediaRecorderRecording) {
@@ -695,12 +772,28 @@ public class VideoCamera extends NoSearchActivity
stopVideoRecording();
showAlert();
} else {
- stopVideoRecordingAndGetThumbnail();
+ stopVideoRecording();
+ getThumbnail();
}
} else {
stopVideoRecording();
}
closeCamera();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mPausing = true;
+
+ changeHeadUpDisplayState();
+ if (mControlPanel != null) mControlPanel.hideSettingPicker();
+
+ // Hide the preview now. Otherwise, the preview may be rotated during
+ // onPause and it is annoying to users.
+ mVideoPreview.setVisibility(View.INVISIBLE);
+
+ finishRecorderAndCloseCamera();
if (mReceiver != null) {
unregisterReceiver(mReceiver);
@@ -708,8 +801,8 @@ public class VideoCamera extends NoSearchActivity
}
resetScreenOn();
- if (!mIsVideoCaptureIntent) {
- mThumbController.storeData(ImageManager.getLastVideoThumbPath());
+ if (!mIsVideoCaptureIntent && mThumbnailButton != null) {
+ mThumbnailButton.storeData(ImageManager.getLastVideoThumbPath());
}
if (mStorageHint != null) {
@@ -808,6 +901,7 @@ public class VideoCamera extends NoSearchActivity
setPreviewDisplay(holder);
mCameraDevice.unlock();
mHandler.sendEmptyMessage(INIT_RECORDER);
+ initThumbnailList();
} else {
stopVideoRecording();
// If video quality changes, the surface will change. But we need to
@@ -928,10 +1022,17 @@ public class VideoCamera extends NoSearchActivity
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCameraDevice);
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(mProfile);
- mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
+ if (mMaxVideoDurationInMs != 0) {
+ mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
+ }
+ if (mCaptureTimeLapse) {
+ mMediaRecorder.setCaptureRate((1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs));
+ }
// Set output file.
if (mStorageStatus != STORAGE_STATUS_OK) {
@@ -980,14 +1081,6 @@ public class VideoCamera extends NoSearchActivity
throw new RuntimeException(e);
}
mMediaRecorderRecording = false;
-
- // Update the last video thumbnail.
- if (!mIsVideoCaptureIntent) {
- if (!mThumbController.isUriValid()) {
- updateLastVideo();
- }
- mThumbController.updateDisplayIfNeeded();
- }
}
private void releaseMediaRecorder() {
@@ -1059,6 +1152,14 @@ public class VideoCamera extends NoSearchActivity
}
}
+ private void setTimeLapseSwitchTitle(boolean enableTimeLapse) {
+ int labelId = enableTimeLapse
+ ? R.string.enable_time_lapse_mode
+ : R.string.disable_time_lapse_mode;
+
+ mSwitchTimeLapseMenuItem.setTitle(labelId);
+ }
+
private void addBaseMenuItems(Menu menu) {
MenuHelper.addSwitchModeMenuItem(menu, false, new Runnable() {
public void run() {
@@ -1089,6 +1190,45 @@ public class VideoCamera extends NoSearchActivity
}
}).setIcon(android.R.drawable.ic_menu_camera);
}
+
+ mSwitchTimeLapseMenuItem = menu.add(Menu.NONE, Menu.NONE,
+ MenuHelper.POSITION_SWITCH_TIME_LAPSE_MODE,
+ R.string.enable_time_lapse_mode)
+ .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ switchTimeLapseMode();
+ return true;
+ }
+ }).setIcon(android.R.drawable.ic_menu_camera);
+ }
+
+ private void switchTimeLapseMode() {
+ mCaptureTimeLapse = !mCaptureTimeLapse;
+
+ finishRecorderAndCloseCamera();
+ mHandler.removeMessages(INIT_RECORDER);
+
+ // Read the video preferences
+ readVideoPreferences();
+ resetCameraParameters();
+
+ // Restart preview
+ try {
+ startPreview();
+ } catch (CameraHardwareException e) {
+ showCameraErrorAndFinish();
+ return;
+ }
+
+ // Reload the UI.
+ initializeHeadUpDisplay();
+
+ if (mSurfaceHolder != null) {
+ mHandler.sendEmptyMessage(INIT_RECORDER);
+ }
+
+ // Change menu
+ setTimeLapseSwitchTitle(!mCaptureTimeLapse);
}
private void switchCameraId(int cameraId) {
@@ -1096,19 +1236,7 @@ public class VideoCamera extends NoSearchActivity
mCameraId = cameraId;
CameraSettings.writePreferredCameraId(mPreferences, cameraId);
- // This is similar to what mShutterButton.performClick() does,
- // but not quite the same.
- if (mMediaRecorderRecording) {
- if (mIsVideoCaptureIntent) {
- stopVideoRecording();
- showAlert();
- } else {
- stopVideoRecordingAndGetThumbnail();
- }
- } else {
- stopVideoRecording();
- }
- closeCamera();
+ finishRecorderAndCloseCamera();
mHandler.removeMessages(INIT_RECORDER);
// Reload the preferences.
@@ -1208,6 +1336,10 @@ public class VideoCamera extends NoSearchActivity
updateRecordingIndicator(false);
mRecordingTimeView.setText("");
mRecordingTimeView.setVisibility(View.VISIBLE);
+ if (mTimeLapseRecordingTimeView != null) {
+ mTimeLapseRecordingTimeView.setText("");
+ mTimeLapseRecordingTimeView.setVisibility(View.VISIBLE);
+ }
updateRecordingTime();
keepScreenOn();
}
@@ -1221,19 +1353,9 @@ public class VideoCamera extends NoSearchActivity
mShutterButton.setImageDrawable(drawable);
}
- private void stopVideoRecordingAndGetThumbnail() {
- stopVideoRecording();
+ private void getThumbnail() {
acquireVideoThumb();
- }
-
- private void stopVideoRecordingAndReturn(boolean valid) {
- stopVideoRecording();
- doReturnToCaller(valid);
- }
-
- private void stopVideoRecordingAndShowAlert() {
- stopVideoRecording();
- showAlert();
+ updateThumbnailList();
}
private void showAlert() {
@@ -1279,22 +1401,21 @@ public class VideoCamera extends NoSearchActivity
return this.mVideoFrame.getVisibility() == View.VISIBLE;
}
- private void viewLastVideo() {
- Intent intent = null;
- if (mThumbController.isUriValid()) {
- intent = new Intent(Util.REVIEW_ACTION, mThumbController.getUri());
+ private void viewVideo(RotateImageView view) {
+ if(view.isUriValid()) {
+ Intent intent = new Intent(Util.REVIEW_ACTION, view.getUri());
try {
startActivity(intent);
} catch (ActivityNotFoundException ex) {
try {
- intent = new Intent(Intent.ACTION_VIEW, mThumbController.getUri());
+ intent = new Intent(Intent.ACTION_VIEW, view.getUri());
startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "review video fail", e);
+ Log.e(TAG, "review video fail. uri=" + view.getUri(), e);
}
}
} else {
- Log.e(TAG, "Can't view last video.");
+ Log.e(TAG, "Uri invalid. uri=" + view.getUri());
}
}
@@ -1321,6 +1442,9 @@ public class VideoCamera extends NoSearchActivity
releaseMediaRecorder();
updateRecordingIndicator(true);
mRecordingTimeView.setVisibility(View.GONE);
+ if (mTimeLapseRecordingTimeView != null) {
+ mTimeLapseRecordingTimeView.setVisibility(View.GONE);
+ }
keepScreenOnAwhile();
}
if (needToRegisterRecording && mStorageStatus == STORAGE_STATUS_OK) {
@@ -1347,22 +1471,23 @@ public class VideoCamera extends NoSearchActivity
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
- private void hideAlertAndInitializeRecorder() {
- hideAlert();
- mHandler.sendEmptyMessage(INIT_RECORDER);
- }
-
private void acquireVideoThumb() {
- Bitmap videoFrame = ThumbnailUtils.createVideoThumbnail(
- mCurrentVideoFilename, Video.Thumbnails.MINI_KIND);
- mThumbController.setData(mCurrentVideoUri, videoFrame);
+ if (mThumbnailButton != null) {
+ Bitmap videoFrame = ThumbnailUtils.createVideoThumbnail(
+ mCurrentVideoFilename, Video.Thumbnails.MINI_KIND);
+ mThumbnailButton.setData(mCurrentVideoUri, videoFrame);
+ }
}
- private static ImageManager.DataLocation dataLocation() {
- return ImageManager.DataLocation.EXTERNAL;
+ private void initThumbnailButton() {
+ mThumbnailButton = (RotateImageView)findViewById(R.id.review_thumbnail);
+ if (mThumbnailButton != null) {
+ mThumbnailButton.setOnClickListener(this);
+ mThumbnailButton.loadData(ImageManager.getLastVideoThumbPath());
+ }
}
- private void updateLastVideo() {
+ private void updateThumbnailButton() {
IImageList list = ImageManager.makeImageList(
mContentResolver,
dataLocation(),
@@ -1373,13 +1498,128 @@ public class VideoCamera extends NoSearchActivity
if (count > 0) {
IImage image = list.getImageAt(count - 1);
Uri uri = image.fullSizeImageUri();
- mThumbController.setData(uri, image.miniThumbBitmap());
+ mThumbnailButton.setData(uri, image.miniThumbBitmap());
} else {
- mThumbController.setData(null, null);
+ mThumbnailButton.setData(null, null);
}
list.close();
}
+ private Cursor getThumbnailsCursor(int thumbnailCount) {
+ Log.v(TAG, "thumbnailCount=" + thumbnailCount);
+ String[] projections = { MediaStore.Video.Thumbnails._ID };
+ Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+ .buildUpon()
+ .appendQueryParameter("limit", String.valueOf(thumbnailCount))
+ .build();
+ // TODO: managedQuery is deprecated. Use CursorLoader.
+ return managedQuery(uri, projections, Media.BUCKET_ID + " = ?",
+ new String[] {ImageManager.CAMERA_IMAGE_BUCKET_ID},
+ VideoColumns._ID + " DESC");
+ }
+
+ private void initThumbnailList() {
+ mThumbnailList = (ListView) findViewById(R.id.thumbnail_list);
+ if (mThumbnailList == null) return;
+
+ int width = mThumbnailList.getWidth();
+ int height = mThumbnailList.getHeight();
+
+ // Add gallery button to header view.
+ if (mThumbnailList.getHeaderViewsCount() == 0) {
+ LayoutInflater inflater = getLayoutInflater();
+ Button b = new Button(this);
+ ListView.LayoutParams params = new ListView.LayoutParams(width, width);
+ b.setId(R.id.btn_gallery);
+ b.setLayoutParams(params);
+ b.setOnClickListener(this);
+ b.setBackgroundResource(R.drawable.ic_menu_gallery);
+ mThumbnailList.addHeaderView(b);
+ }
+
+ // Set cursor adapter.
+ int thumbnailCount = (height + mThumbnailList.getDividerHeight())
+ / (width + mThumbnailList.getDividerHeight()) - 1;
+ Cursor cursor = getThumbnailsCursor(thumbnailCount);
+ mThumbnailAdapter = new ThumbnailAdapter(
+ getApplicationContext(), R.layout.thumbnail_item, cursor,
+ false);
+ mThumbnailList.setAdapter(mThumbnailAdapter);
+ mThumbnailList.setOnItemClickListener(mThumbnailItemClickListener);
+ }
+
+ private void updateThumbnailList() {
+ if (mThumbnailList == null) return;
+ mThumbnailAdapter.getCursor().requery();
+ mThumbnailAdapter.notifyDataSetChanged();
+ }
+
+ private class ThumbnailItemClickListener implements OnItemClickListener {
+ public void onItemClick(AdapterView<?> p, View v, int pos, long id) {
+ viewVideo((RotateImageView)v);
+ }
+ }
+
+ private static ImageManager.DataLocation dataLocation() {
+ return ImageManager.DataLocation.EXTERNAL;
+ }
+
+ private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) {
+ long seconds = milliSeconds / 1000; // round down to compute seconds
+ long minutes = seconds / 60;
+ long hours = minutes / 60;
+ long remainderMinutes = minutes - (hours * 60);
+ long remainderSeconds = seconds - (minutes * 60);
+
+ StringBuilder timeStringBuilder = new StringBuilder();
+
+ // Hours
+ if (hours > 0) {
+ if (hours < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(hours);
+
+ timeStringBuilder.append(':');
+ }
+
+ // Minutes
+ if (remainderMinutes < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderMinutes);
+ timeStringBuilder.append(':');
+
+ // Seconds
+ if (remainderSeconds < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderSeconds);
+
+ // Centi seconds
+ if (displayCentiSeconds) {
+ timeStringBuilder.append('.');
+ long remainderCentiSeconds = (milliSeconds - seconds * 1000) / 10;
+ if (remainderCentiSeconds < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderCentiSeconds);
+ }
+
+ return timeStringBuilder.toString();
+ }
+
+ // Calculates the time lapse video length till now and returns it in
+ // the format hh:mm:ss.dd, where dd are the centi seconds.
+ private String getTimeLapseVideoLengthString(long deltaMs) {
+ // For better approximation calculate fractional number of frames captured.
+ // This will update the video time at a higher resolution.
+ double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
+ long videoTimeMs =
+ (long) (numberOfFrames / (double) mProfile.videoFrameRate * 1000);
+ return millisecondToTimeString(videoTimeMs, true);
+ }
+
private void updateRecordingTime() {
if (!mMediaRecorderRecording) {
return;
@@ -1392,36 +1632,27 @@ public class VideoCamera extends NoSearchActivity
boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
&& delta >= mMaxVideoDurationInMs - 60000);
- long next_update_delay = 1000 - (delta % 1000);
- long seconds;
+ long deltaAdjusted = delta;
if (countdownRemainingTime) {
- delta = Math.max(0, mMaxVideoDurationInMs - delta);
- seconds = (delta + 999) / 1000;
- } else {
- seconds = delta / 1000; // round to nearest
- }
-
- long minutes = seconds / 60;
- long hours = minutes / 60;
- long remainderMinutes = minutes - (hours * 60);
- long remainderSeconds = seconds - (minutes * 60);
-
- String secondsString = Long.toString(remainderSeconds);
- if (secondsString.length() < 2) {
- secondsString = "0" + secondsString;
- }
- String minutesString = Long.toString(remainderMinutes);
- if (minutesString.length() < 2) {
- minutesString = "0" + minutesString;
- }
- String text = minutesString + ":" + secondsString;
- if (hours > 0) {
- String hoursString = Long.toString(hours);
- if (hoursString.length() < 2) {
- hoursString = "0" + hoursString;
+ deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
+ }
+ String text = millisecondToTimeString(deltaAdjusted, false);
+
+ if (mCaptureTimeLapse) {
+ // Since the length of time lapse video is different from the length
+ // of the actual wall clock time elapsed, we display the video length
+ // alongside the wall clock time.
+ String timeLapseText = "(" + getTimeLapseVideoLengthString(delta) + ")";
+ // In xlarge layout, recording time and time lapse recording time
+ // are separated in two lines. In other layouts, they are in one
+ // line.
+ if (mTimeLapseRecordingTimeView == null) {
+ text += " " + timeLapseText;
+ } else {
+ mTimeLapseRecordingTimeView.setText(timeLapseText);
}
- text = hoursString + ":" + text;
}
+
mRecordingTimeView.setText(text);
if (mRecordingTimeCountsDown != countdownRemainingTime) {
@@ -1436,8 +1667,9 @@ public class VideoCamera extends NoSearchActivity
mRecordingTimeView.setTextColor(color);
}
+ long nextUpdateDelay = 1000 - (delta % 1000);
mHandler.sendEmptyMessageDelayed(
- UPDATE_RECORD_TIME, next_update_delay);
+ UPDATE_RECORD_TIME, nextUpdateDelay);
}
private static boolean isSupported(String value, List<String> supported) {
@@ -1447,7 +1679,7 @@ public class VideoCamera extends NoSearchActivity
private void setCameraParameters() {
mParameters = mCameraDevice.getParameters();
- mParameters.setPreviewSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
mParameters.setPreviewFrameRate(mProfile.videoFrameRate);
// Set flash mode.
@@ -1520,8 +1752,8 @@ public class VideoCamera extends NoSearchActivity
private void resetCameraParameters() {
// We need to restart the preview if preview size is changed.
Size size = mParameters.getPreviewSize();
- if (size.width != mProfile.videoFrameWidth
- || size.height != mProfile.videoFrameHeight) {
+ if (size.width != mDesiredPreviewWidth
+ || size.height != mDesiredPreviewHeight) {
// It is assumed media recorder is released before
// onSharedPreferenceChanged, so we can close the camera here.
closeCamera();
@@ -1611,4 +1843,10 @@ public class VideoCamera extends NoSearchActivity
}
}
}
+
+ private class MyControlPanelListener implements ControlPanel.Listener {
+ public void onSharedPreferencesChanged() {
+ VideoCamera.this.onSharedPreferencesChanged();
+ }
+ }
}