diff options
Diffstat (limited to 'src/com/android/camera/VideoCamera.java')
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 484 |
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(); + } + } } |