summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/camera_controls.xml13
-rw-r--r--res/layout/capture_module.xml25
-rw-r--r--res/values/camera2arrays.xml214
-rw-r--r--res/values/qcomstrings.xml14
-rw-r--r--res/xml/capture_preferences.xml68
-rw-r--r--src/com/android/camera/CameraActivity.java3
-rw-r--r--src/com/android/camera/CaptureModule.java526
-rw-r--r--src/com/android/camera/CaptureUI.java162
-rw-r--r--src/com/android/camera/SettingsManager.java94
-rw-r--r--src/com/android/camera/ui/CameraControls.java28
-rw-r--r--src/com/android/camera/util/CameraUtil.java59
-rw-r--r--src/com/android/camera/util/SettingTranslation.java117
12 files changed, 1287 insertions, 36 deletions
diff --git a/res/layout/camera_controls.xml b/res/layout/camera_controls.xml
index c1def502f..9d6ebf090 100644
--- a/res/layout/camera_controls.xml
+++ b/res/layout/camera_controls.xml
@@ -65,6 +65,19 @@
android:scaleType="fitCenter"
android:src="@drawable/btn_new_shutter" />
+ <ImageView
+ android:id="@+id/video_button"
+ android:visibility="invisible"
+ android:layout_width="@dimen/shutter_size"
+ android:layout_height="@dimen/shutter_size"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginBottom="@dimen/shutter_offset"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_shutter_button"
+ android:focusable="true"
+ android:scaleType="fitCenter"
+ android:src="@drawable/btn_new_shutter_video" />
+
<com.android.camera.ui.RotateImageView
android:id="@+id/preview_thumb"
android:layout_width="@dimen/capture_size"
diff --git a/res/layout/capture_module.xml b/res/layout/capture_module.xml
index d91b49a97..3b4f025bf 100644
--- a/res/layout/capture_module.xml
+++ b/res/layout/capture_module.xml
@@ -56,6 +56,31 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <com.android.camera.ui.RotateLayout
+ android:id="@+id/recording_time_rect"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <com.android.camera.PauseButton
+ android:id="@+id/video_pause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="70dp"
+ android:padding="23dp"
+ android:src="@drawable/btn_pause_recording"/>
+
+ <include
+ android:id="@+id/labels"
+ layout="@layout/viewfinder_labels_video"/>
+ </LinearLayout>
+ </com.android.camera.ui.RotateLayout>
+
<include
style="@style/CameraControls"
layout="@layout/camera_controls"
diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml
index 49f37e139..b2cb97958 100644
--- a/res/values/camera2arrays.xml
+++ b/res/values/camera2arrays.xml
@@ -571,4 +571,218 @@
<item>@drawable/ic_settings_filter_on</item>
</string-array>
+ <string-array name="pref_camera2_video_quality_entries" translatable="false">
+ <item>@string/pref_video_quality_entry_4kdci</item>
+ <item>@string/pref_video_quality_entry_2160p</item>
+ <item>@string/pref_video_quality_entry_qHD</item>
+ <item>@string/pref_video_quality_entry_2k</item>
+ <item>@string/pref_video_quality_entry_1080p</item>
+ <item>@string/pref_video_quality_entry_720p</item>
+ <item>@string/pref_video_quality_entry_480p</item>
+ <item>@string/pref_video_quality_entry_vga</item>
+ <item>@string/pref_video_quality_entry_cif</item>
+ <item>@string/pref_video_quality_entry_qvga</item>
+ <item>@string/pref_video_quality_entry_qcif</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_quality_entryvalues" translatable="false">
+ <item>4096x2160</item>
+ <item>3840x2160</item>
+ <item>2560x1440</item>
+ <item>2048x1080</item>
+ <item>1920x1080</item>
+ <item>1280x720</item>
+ <item>720x480</item>
+ <item>640x480</item>
+ <item>352x288</item>
+ <item>320x240</item>
+ <item>176x144</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_duration_entries" translatable="false">
+ <item>@string/pref_camera_video_duration_entry_mms</item>
+ <item>@string/pref_camera_video_duration_entry_10</item>
+ <item>@string/pref_camera_video_duration_entry_30</item>
+ <item>@string/pref_camera_video_duration_entry_nolimit</item>
+ </string-array>
+
+ <!-- The numbers are in minutes, except -1 means the duration suitable for mms. -->
+ <string-array name="pref_camera2_video_duration_entryvalues" translatable="false">
+ <item>-1</item>
+ <item>10</item>
+ <item>30</item>
+ <item>0</item>
+ </string-array>
+
+ <string-array name="pref_camera2_videoencoder_entries" translatable="false">
+ <item>@string/pref_camera_videoencoder_entry_0</item>
+ <item>@string/pref_camera_videoencoder_entry_1</item>
+ <item>@string/pref_camera_videoencoder_entry_2</item>
+ <item>@string/pref_camera_videoencoder_entry_3</item>
+ </string-array>
+
+ <string-array name="pref_camera2_videoencoder_entryvalues" translatable="false">
+ <item>mpeg-4-sp</item>
+ <item>h263</item>
+ <item>h264</item>
+ <item>h265</item>
+ </string-array>
+
+ <string-array name="pref_camera2_audioencoder_entries" translatable="false">
+ <item>@string/pref_camera_audioencoder_entry_0</item>
+ <item>@string/pref_camera_audioencoder_entry_1</item>
+ </string-array>
+
+ <string-array name="pref_camera2_audioencoder_entryvalues" translatable="false">
+ <item>amr-nb</item>
+ <item>aac</item>
+ </string-array>
+
+ <string-array name="pref_camera2_dis_entries" translatable="false">
+ <item>@string/pref_camera_dis_entry_off</item>
+ <item>@string/pref_camera_dis_entry_on</item>
+ </string-array>
+
+ <string-array name="pref_camera2_dis_entryvalues" translatable="false">
+ <item>@string/pref_camera_dis_value_disable</item>
+ <item>@string/pref_camera_dis_value_enable</item>
+ </string-array>
+
+ <string-array name="pref_camera2_noise_reduction_entries" translatable="false">
+ <item>@string/pref_camera2_noise_reduction_entry_off</item>
+ <item>@string/pref_camera2_noise_reduction_entry_fast</item>
+ <item>@string/pref_camera2_noise_reduction_entry_high_quality</item>
+ </string-array>
+
+ <string-array name="pref_camera2_noise_reduction_entryvalues" translatable="false">
+ <item>@string/pref_camera2_noise_reduction_value_off</item>
+ <item>@string/pref_camera2_noise_reduction_value_fast</item>
+ <item>@string/pref_camera2_noise_reduction_value_high_quality</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_flashmode_entries" translatable="false">
+ <item>@string/pref_camera_flashmode_entry_off</item>
+ <item>@string/pref_camera_flashmode_entry_on</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_flashmode_labels" translatable="false">
+ <item>@string/pref_camera_flashmode_label_off</item>
+ <item>@string/pref_camera_flashmode_label_on</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_flashmode_entryvalues" translatable="false">
+ <item>off</item>
+ <item>torch</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_rotation_entries" translatable="false">
+ <item>@string/pref_camera_video_rotation_entry_0</item>
+ <item>@string/pref_camera_video_rotation_entry_90</item>
+ <item>@string/pref_camera_video_rotation_entry_180</item>
+ <item>@string/pref_camera_video_rotation_entry_270</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_rotation_labels" translatable="false">
+ <item>@string/pref_camera_video_rotation_label_0</item>
+ <item>@string/pref_camera_video_rotation_label_90</item>
+ <item>@string/pref_camera_video_rotation_label_180</item>
+ <item>@string/pref_camera_video_rotation_label_270</item>
+ </string-array>
+
+ <string-array name="pref_camera2_video_rotation_entryvalues" translatable="false">
+ <item>0</item>
+ <item>90</item>
+ <item>180</item>
+ <item>270</item>
+ </string-array>
+
+ <!-- These values correspond to the time interval between frame capture in millseconds
+for time lapse recording -->
+ <string-array name="pref_camera2_video_time_lapse_frame_interval_entryvalues" translatable="false">
+ <item>0</item>
+ <item>500</item>
+ <item>1000</item>
+ <item>1500</item>
+ <item>2000</item>
+ <item>2500</item>
+ <item>3000</item>
+ <item>4000</item>
+ <item>5000</item>
+ <item>6000</item>
+ <item>10000</item>
+ <item>12000</item>
+ <item>15000</item>
+ <item>24000</item>
+ <item>30000</item>
+ <item>60000</item>
+ <item>90000</item>
+ <item>120000</item>
+ <item>150000</item>
+ <item>180000</item>
+ <item>240000</item>
+ <item>300000</item>
+ <item>360000</item>
+ <item>600000</item>
+ <item>720000</item>
+ <item>900000</item>
+ <item>1440000</item>
+ <item>1800000</item>
+ <item>3600000</item>
+ <item>5400000</item>
+ <item>7200000</item>
+ <item>9000000</item>
+ <item>10800000</item>
+ <item>14400000</item>
+ <item>18000000</item>
+ <item>21600000</item>
+ <item>36000000</item>
+ <item>43200000</item>
+ <item>54000000</item>
+ <item>86400000</item>
+ </string-array>
+
+ <!-- These values correspond to the time interval between frame capture in
+ different units (i.e. seconds, minutes, hours) for time lapse recording -->
+ <string-array name="pref_camera2_video_time_lapse_frame_interval_entries" translatable="true">
+ <item>@string/pref_video_time_lapse_frame_interval_off</item>
+ <item>@string/pref_video_time_lapse_frame_interval_500</item>
+ <item>@string/pref_video_time_lapse_frame_interval_1000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_1500</item>
+ <item>@string/pref_video_time_lapse_frame_interval_2000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_2500</item>
+ <item>@string/pref_video_time_lapse_frame_interval_3000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_4000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_5000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_6000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_10000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_12000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_15000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_24000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_30000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_60000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_90000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_120000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_150000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_180000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_240000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_300000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_360000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_600000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_720000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_900000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_1440000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_1800000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_3600000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_5400000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_7200000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_9000000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_10800000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_14400000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_18000000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_21600000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_36000000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_43200000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_54000000</item>
+ <item>@string/pref_video_time_lapse_frame_interval_86400000</item>
+ </string-array>
</resources>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index a808ba354..859803b23 100644
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved.
Not a Contribution.
@@ -981,6 +981,18 @@
<string name="pref_camera2_whitebalance_default" translatable="false">1</string>
<string name="pref_camera2_coloreffect_default" translatable="false">0</string>
<string name="pref_camera2_flashmode_default" translatable="false">2</string>
+
<string name="pref_camera2_makeup_title" translatable="true">Makeup</string>
+
+ <string name="pref_camera2_noise_reduction_default" translatable="false">off</string>
+ <string name="pref_camera2_noise_reduction_title" translatable="true">Noise Reduction</string>
+
+ <string name="pref_camera2_noise_reduction_entry_off" translatable="true">Off</string>
+ <string name="pref_camera2_noise_reduction_entry_fast" translatable="true">Fast</string>
+ <string name="pref_camera2_noise_reduction_entry_high_quality" translatable="true">High Quality</string>
+
+ <string name="pref_camera2_noise_reduction_value_off" translatable="false">off</string>
+ <string name="pref_camera2_noise_reduction_value_fast" translatable="false">fast</string>
+ <string name="pref_camera2_noise_reduction_value_high_quality" translatable="false">high-quality</string>
</resources>
diff --git a/res/xml/capture_preferences.xml b/res/xml/capture_preferences.xml
index 5e9235e34..697770b04 100644
--- a/res/xml/capture_preferences.xml
+++ b/res/xml/capture_preferences.xml
@@ -190,4 +190,72 @@
camera:entries="@array/pref_camera2_makeup_entries"
camera:entryValues="@array/pref_camera2_makeup_entryvalues"
camera:title="@string/pref_camera2_makeup_title"/>
+
+ <IconListPreference
+ camera:entries="@array/pref_camera2_video_quality_entries"
+ camera:entryValues="@array/pref_camera2_video_quality_entryvalues"
+ camera:key="pref_camera2_video_quality_key"
+ camera:singleIcon="@drawable/ic_settings_quality"
+ camera:title="@string/pref_video_quality_title"/>
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_camera_video_duration_default"
+ camera:entries="@array/pref_camera2_video_duration_entries"
+ camera:entryValues="@array/pref_camera2_video_duration_entryvalues"
+ camera:key="pref_camera2_video_duration_key"
+ camera:singleIcon="@drawable/ic_settings_duration"
+ camera:title="@string/pref_camera_video_duration_title"/>
+
+ <ListPreference
+ camera:defaultValue="@string/pref_camera_videoencoder_default"
+ camera:entries="@array/pref_camera2_videoencoder_entries"
+ camera:entryValues="@array/pref_camera2_videoencoder_entryvalues"
+ camera:key="pref_camera2_videoencoder_key"
+ camera:title="@string/pref_camera_videoencoder_title"/>
+ <ListPreference
+ camera:defaultValue="@string/pref_camera_audioencoder_default"
+ camera:entries="@array/pref_camera2_audioencoder_entries"
+ camera:entryValues="@array/pref_camera2_audioencoder_entryvalues"
+ camera:key="pref_camera2_audioencoder_key"
+ camera:title="@string/pref_camera_audioencoder_title"/>
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_camera_dis_default"
+ camera:entries="@array/pref_camera2_dis_entries"
+ camera:entryValues="@array/pref_camera2_dis_entryvalues"
+ camera:key="pref_camera2_dis_key"
+ camera:singleIcon="@drawable/ic_eis_menu"
+ camera:title="@string/pref_camera_dis_title"/>
+
+ <ListPreference
+ camera:defaultValue="@string/pref_camera_noise_reduction_default"
+ camera:entries="@array/pref_camera2_noise_reduction_entries"
+ camera:entryValues="@array/pref_camera2_noise_reduction_entryvalues"
+ camera:key="pref_camera2_noise_reduction_key"
+ camera:title="@string/pref_camera_noise_reduction_title"/>
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_camera_video_flashmode_default"
+ camera:entries="@array/pref_camera2_video_flashmode_entries"
+ camera:entryValues="@array/pref_camera2_video_flashmode_entryvalues"
+ camera:icons="@array/video_flashmode_icons"
+ camera:key="pref_camera2_video_flashmode_key"
+ camera:labelList="@array/pref_camera2_video_flashmode_labels"
+ camera:largeIcons="@array/video_flashmode_largeicons"
+ camera:singleIcon="@drawable/ic_settings_flash"
+ camera:title="@string/pref_camera_flashmode_title"/>
+
+ <ListPreference
+ camera:defaultValue="@string/pref_camera_video_rotation_default"
+ camera:entries="@array/pref_camera2_video_rotation_entries"
+ camera:entryValues="@array/pref_camera2_video_rotation_entryvalues"
+ camera:key="pref_camera2_video_rotation_key"
+ camera:title="@string/pref_camera_video_rotation_title"/>
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_video_time_lapse_frame_interval_default"
+ camera:entries="@array/pref_camera2_video_time_lapse_frame_interval_entries"
+ camera:entryValues="@array/pref_camera2_video_time_lapse_frame_interval_entryvalues"
+ camera:key="pref_camera2_video_time_lapse_frame_interval_key"
+ camera:title="@string/pref_video_time_lapse_frame_interval_title"/>
</PreferenceGroup>
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index d324776c3..e3b4573d1 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -733,7 +733,8 @@ public class CameraActivity extends Activity
public void updateThumbnail(boolean videoOnly) {
// Only handle OnDataInserted if it's video.
// Photo and Panorama have their own way of updating thumbnail.
- if (!videoOnly || (mCurrentModule instanceof VideoModule)) {
+ if (!videoOnly || (mCurrentModule instanceof VideoModule) ||
+ ((mCurrentModule instanceof CaptureModule) && videoOnly)) {
(new UpdateThumbnailTask(null, true)).execute();
}
}
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index ee4bcc724..336e7b410 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -22,6 +22,7 @@ package com.android.camera;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -45,15 +46,22 @@ import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
+import android.location.Location;
+import android.media.AudioManager;
+import android.media.CamcorderProfile;
import android.media.CameraProfile;
import android.media.Image;
import android.media.ImageReader;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Debug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
+import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
@@ -76,15 +84,20 @@ import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.PersistUtil;
+import com.android.camera.util.SettingTranslation;
import com.android.internal.util.MemInfoReader;
import org.codeaurora.snapcam.R;
import org.codeaurora.snapcam.filter.ClearSightImageProcessor;
+import java.io.File;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -109,10 +122,6 @@ public class CaptureModule implements CameraModule, PhotoController,
private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{
new MeteringRectangle(0, 0, 0, 0, 0)};
/**
- * Conversion from screen rotation to JPEG orientation.
- */
- private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
- /**
* Camera state: Showing camera preview.
*/
private static final int STATE_PREVIEW = 0;
@@ -143,12 +152,6 @@ public class CaptureModule implements CameraModule, PhotoController,
// we can change it based on memory status or other requirements.
private static final int LONGSHOT_CANCEL_THRESHOLD = 40 * 1024 * 1024;
- static {
- ORIENTATIONS.append(Surface.ROTATION_0, 90);
- ORIENTATIONS.append(Surface.ROTATION_90, 0);
- ORIENTATIONS.append(Surface.ROTATION_180, 270);
- ORIENTATIONS.append(Surface.ROTATION_270, 180);
- }
private static final int MAX_IMAGE_NUM = 8;
MeteringRectangle[][] mAFRegions = new MeteringRectangle[MAX_NUM_CAM][];
@@ -238,6 +241,28 @@ public class CaptureModule implements CameraModule, PhotoController,
private int[] mPrecaptureRequestHashCode = new int[MAX_NUM_CAM];
private int[] mLockRequestHashCode = new int[MAX_NUM_CAM];
private final Handler mHandler = new MainHandler();
+ private CameraCaptureSession mPreviewSession;
+ private Size mPreviewSize;
+ private Size mPictureSize;
+ private Size mVideoPreviewSize;
+ private Size mVideoSize;
+
+ private MediaRecorder mMediaRecorder;
+ private boolean mIsRecordingVideo;
+ // The video duration limit. 0 means no limit.
+ private int mMaxVideoDurationInMs;
+ private boolean mIsMute = false;
+ // Default 0. If it is larger than 0, the camcorder is in time lapse mode.
+ private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
+ private boolean mCaptureTimeLapse = false;
+ private CamcorderProfile mProfile;
+ private static final int UPDATE_RECORD_TIME = 5;
+ private ContentValues mCurrentVideoValues;
+ private String mVideoFilename;
+ private boolean mMediaRecorderPausing = false;
+ private long mRecordingStartTime;
+ private long mRecordingTotalTime;
+ private boolean mRecordingTimeCountsDown = false;
private class MediaSaveNotifyThread extends Thread {
private Uri uri;
@@ -274,6 +299,17 @@ public class CaptureModule implements CameraModule, PhotoController,
}
private MediaSaveNotifyThread mediaSaveNotifyThread;
+
+ private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener =
+ new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ }
+ }
+ };
+
private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
new MediaSaveService.OnMediaSavedListener() {
@Override
@@ -634,6 +670,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
// When the session is ready, we start displaying the preview.
mCaptureSession[id] = cameraCaptureSession;
+ mPreviewSession = cameraCaptureSession;
initializePreviewConfiguration(id);
try {
if (isBackCamera() && getCameraMode() == DUAL_MODE) {
@@ -1085,28 +1122,29 @@ public class CaptureModule implements CameraModule, PhotoController,
}
mCameraId[i] = cameraId;
- String pictureSize = mSettingsManager.getValue(SettingsManager
- .KEY_PICTURE_SIZE);
+ if (i == getMainCameraId()) {
+ String pictureSize = mSettingsManager.getValue(SettingsManager
+ .KEY_PICTURE_SIZE);
- Size size = parsePictureSize(pictureSize);
+ Size size = parsePictureSize(pictureSize);
- if (i == getMainCameraId()) {
Point screenSize = new Point();
mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
Size[] prevSizes = map.getOutputSizes(imageFormat);
mFrameProcPreviewOutputSize = getOptimalPreviewSize(size, prevSizes, screenSize.x,
screenSize.y);
- mUI.setPreviewSize(mFrameProcPreviewOutputSize.getWidth(), mFrameProcPreviewOutputSize.getHeight());
}
+
if (isClearSightOn()) {
if(i == getMainCameraId()) {
- ClearSightImageProcessor.getInstance().init(size.getWidth(), size.getHeight(),
- mActivity, mOnMediaSavedListener);
+ ClearSightImageProcessor.getInstance().init(mPictureSize.getWidth(),
+ mPictureSize.getHeight(), mActivity, mOnMediaSavedListener);
ClearSightImageProcessor.getInstance().setCallback(this);
}
} else {
// No Clearsight
- mImageReader[i] = ImageReader.newInstance(size.getWidth(), size.getHeight(), imageFormat, MAX_IMAGE_NUM);
+ mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(),
+ mPictureSize.getHeight(), imageFormat, MAX_IMAGE_NUM);
if(mPostProcessor.isFilterOn() && i == getMainCameraId()) {
mImageReader[i].setOnImageAvailableListener(mPostProcessor, mImageAvailableHandler);
// if(mFrameProcessor.isFrameFilterEnabled()) {
@@ -1138,8 +1176,8 @@ public class CaptureModule implements CameraModule, PhotoController,
}, mImageAvailableHandler);
}
}
-
}
+ mMediaRecorder = new MediaRecorder();
mAutoFocusRegionSupported = mSettingsManager.isAutoFocusRegionSupported(mCameraIdList);
mAutoExposureRegionSupported = mSettingsManager.isAutoExposureRegionSupported(mCameraIdList);
} catch (CameraAccessException e) {
@@ -1233,6 +1271,10 @@ public class CaptureModule implements CameraModule, PhotoController,
mCameraDevice[i] = null;
mCameraOpened[i] = false;
}
+ if (null != mMediaRecorder) {
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
}
} catch (InterruptedException e) {
mCameraOpenCloseLock.release();
@@ -1367,6 +1409,9 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onPauseBeforeSuper() {
mPaused = true;
+ if (mIsRecordingVideo) {
+ stopRecordingVideo(getMainCameraId());
+ }
}
@Override
@@ -1412,9 +1457,19 @@ public class CaptureModule implements CameraModule, PhotoController,
return PostProcessor.FILTER_NONE;
}
+ private void initializeValues() {
+ updatePictureSize();
+ updateVideoSize();
+ updateTimeLapseSetting();
+ estimateJpegFileSize();
+ updateMaxVideoDuration();
+ }
+
@Override
public void onResumeAfterSuper() {
Log.d(TAG, "onResume " + getCameraMode());
+ initializeValues();
+ mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());;
mUI.showSurfaceView();
mUI.setSwitcherIndex();
mCameraIdList = new ArrayList<>();
@@ -1470,7 +1525,6 @@ public class CaptureModule implements CameraModule, PhotoController,
mActivity.updateStorageSpaceAndHint();
}
});
- estimateJpegFileSize();
mUI.enableShutter(true);
}
@@ -1642,7 +1696,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
private boolean isTouchToFocusAllowed() {
- if (isTakingPicture() || isSceneModeOn()) return false;
+ if (isTakingPicture() || mIsRecordingVideo || isSceneModeOn()) return false;
return true;
}
@@ -1685,7 +1739,7 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onPreviewUIReady() {
- if (mPaused) {
+ if (mPaused || mIsRecordingVideo) {
return;
}
Log.d(TAG, "onPreviewUIReady");
@@ -1790,6 +1844,411 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void updatePictureSize() {
+ String pictureSize = mSettingsManager.getValue(SettingsManager.KEY_PICTURE_SIZE);
+ mPictureSize = parsePictureSize(pictureSize);
+ Point screenSize = new Point();
+ mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
+ Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),
+ SurfaceHolder.class);
+ mPreviewSize = getOptimalPreviewSize(mPictureSize, prevSizes, screenSize.x, screenSize.y);
+ }
+
+ public boolean isRecordingVideo() {
+ return mIsRecordingVideo;
+ }
+
+ public void setMute(boolean enable, boolean isValue) {
+ AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
+ am.setMicrophoneMute(enable);
+ if (isValue) {
+ mIsMute = enable;
+ }
+ }
+
+ public boolean isAudioMute() {
+ return mIsMute;
+ }
+
+ private void updateVideoSize() {
+ String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
+ mVideoSize = parsePictureSize(videoSize);
+ Point screenSize = new Point();
+ mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
+ Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),
+ MediaRecorder.class);
+ mVideoPreviewSize = getOptimalPreviewSize(mVideoSize, prevSizes, screenSize.x, screenSize.y);
+ }
+
+ private void updateMaxVideoDuration() {
+ String minutesStr = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_DURATION);
+ int minutes = Integer.parseInt(minutesStr);
+ if (minutes == -1) {
+ // User wants lowest, set 30s */
+ mMaxVideoDurationInMs = 30000;
+ } else {
+ // 1 minute = 60000ms
+ mMaxVideoDurationInMs = 60000 * minutes;
+ }
+ }
+
+ private void startRecordingVideo(int cameraId) {
+ if (null == mCameraDevice[cameraId]) {
+ return;
+ }
+ Log.d(TAG, "StartRecordingVideo " + cameraId);
+ mIsRecordingVideo = true;
+ mMediaRecorderPausing = false;
+ mUI.hideUIwhileRecording();
+ mUI.clearFocus();
+ mCameraHandler.removeMessages(CANCEL_TOUCH_FOCUS, cameraId);
+ mState[cameraId] = STATE_PREVIEW;
+ mControlAFMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+ closePreviewSession();
+ boolean changed = mUI.setPreviewSize(mVideoPreviewSize.getWidth(), mVideoPreviewSize
+ .getHeight());
+ if (changed) {
+ mUI.hideSurfaceView();
+ mUI.showSurfaceView();
+ }
+
+ try {
+ setUpMediaRecorder(cameraId);
+ final CaptureRequest.Builder mPreviewBuilder = mCameraDevice[cameraId]
+ .createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ List<Surface> surfaces = new ArrayList<>();
+
+ Surface previewSurface = getPreviewSurface(cameraId);
+ surfaces.add(previewSurface);
+ mPreviewBuilder.addTarget(previewSurface);
+ surfaces.add(mMediaRecorder.getSurface());
+ mPreviewBuilder.addTarget(mMediaRecorder.getSurface());
+
+ mCameraDevice[cameraId].createCaptureSession(surfaces, new CameraCaptureSession
+ .StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ Log.d(TAG, "StartRecordingVideo session onConfigured");
+ mPreviewSession = cameraCaptureSession;
+ try {
+ setUpVideoCaptureRequestBuilder(mPreviewBuilder);
+ mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ mMediaRecorder.start();
+ mUI.clearFocus();
+ mUI.resetPauseButton();
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mUI.showRecordingUI(true);
+ updateRecordingTime();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Video Failed", Toast.LENGTH_SHORT).show();
+ }
+ }, null);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void updateTimeLapseSetting() {
+ String value = mSettingsManager.getValue(SettingsManager
+ .KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL);
+ if (value == null) return;
+ int time = Integer.parseInt(value);
+ mTimeBetweenTimeLapseFrameCaptureMs = time;
+ mCaptureTimeLapse = mTimeBetweenTimeLapseFrameCaptureMs != 0;
+ mUI.showTimeLapseUI(mCaptureTimeLapse);
+ }
+
+ private void setUpVideoCaptureRequestBuilder(CaptureRequest.Builder builder) {
+ builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
+ builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest
+ .CONTROL_AF_MODE_CONTINUOUS_VIDEO);
+ builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
+ applyVideoStabilization(builder);
+ applyNoiseReduction(builder);
+ applyColorEffect(builder);
+ applyWhiteBalance(builder);
+ applyVideoFlash(builder);
+ }
+
+ private void applyVideoFlash(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_FLASH_MODE);
+ if (value == null) return;
+
+ if (value.equals("torch")) {
+ builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
+ } else {
+ builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
+ }
+ }
+
+ private void applyNoiseReduction(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_NOISE_REDUCTION);
+ if (value == null) return;
+ int noiseReduction = SettingTranslation.getNoiseReduction(value);
+ builder.set(CaptureRequest.NOISE_REDUCTION_MODE, noiseReduction);
+ }
+
+ private void applyVideoStabilization(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_DIS);
+ if (value == null) return;
+ if (value.equals("enable")) {
+ builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest
+ .CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ } else {
+ builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest
+ .CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+ }
+ }
+
+ private long getTimeLapseVideoLength(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;
+ return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
+ }
+
+ private void updateRecordingTime() {
+ if (!mIsRecordingVideo) {
+ return;
+ }
+ if (mMediaRecorderPausing) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ long delta = now - mRecordingStartTime + mRecordingTotalTime;
+
+ // Starting a minute before reaching the max duration
+ // limit, we'll countdown the remaining time instead.
+ boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
+ && delta >= mMaxVideoDurationInMs - 60000);
+
+ long deltaAdjusted = delta;
+ if (countdownRemainingTime) {
+ deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
+ }
+ String text;
+
+ long targetNextUpdateDelay;
+ if (!mCaptureTimeLapse) {
+ text = CameraUtil.millisecondToTimeString(deltaAdjusted, false);
+ targetNextUpdateDelay = 1000;
+ } else {
+ // The length of time lapse video is different from the length
+ // of the actual wall clock time elapsed. Display the video length
+ // only in format hh:mm:ss.dd, where dd are the centi seconds.
+ text = CameraUtil.millisecondToTimeString(getTimeLapseVideoLength(delta), true);
+ targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
+ }
+
+ mUI.setRecordingTime(text);
+
+ if (mRecordingTimeCountsDown != countdownRemainingTime) {
+ // Avoid setting the color on every update, do it only
+ // when it needs changing.
+ mRecordingTimeCountsDown = countdownRemainingTime;
+
+ int color = mActivity.getResources().getColor(countdownRemainingTime
+ ? R.color.recording_time_remaining_text
+ : R.color.recording_time_elapsed_text);
+
+ mUI.setRecordingTimeTextColor(color);
+ }
+
+ long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
+ mHandler.sendEmptyMessageDelayed(
+ UPDATE_RECORD_TIME, actualNextUpdateDelay);
+ }
+
+ private void pauseVideoRecording() {
+ Log.v(TAG, "pauseVideoRecording");
+ mMediaRecorderPausing = true;
+ mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
+ mMediaRecorder.pause();
+ }
+
+ private void resumeVideoRecording() {
+ Log.v(TAG, "resumeVideoRecording");
+ mMediaRecorderPausing = false;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ updateRecordingTime();
+ mMediaRecorder.start();
+ }
+
+ public void onButtonPause() {
+ pauseVideoRecording();
+ }
+
+ public void onButtonContinue() {
+ resumeVideoRecording();
+ }
+
+ private void stopRecordingVideo(int cameraId) {
+ Log.d(TAG, "stopRecordingVideo " + cameraId);
+
+ // Stop recording
+ closePreviewSession();
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+
+ saveVideo();
+
+ mUI.showRecordingUI(false);
+ mIsRecordingVideo = false;
+ boolean changed = mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ if (changed) {
+ mUI.hideSurfaceView();
+ mUI.showSurfaceView();
+ } else {
+ createSession(cameraId);
+ }
+ mUI.showUIafterRecording();
+ }
+
+ private void closePreviewSession() {
+ Log.d(TAG, "closePreviewSession");
+ if (mPreviewSession != null) {
+ mPreviewSession.close();
+ mPreviewSession = null;
+ }
+ }
+
+ private String createName(long dateTaken) {
+ Date date = new Date(dateTaken);
+ SimpleDateFormat dateFormat = new SimpleDateFormat(
+ mActivity.getString(R.string.video_file_name_format));
+
+ return dateFormat.format(date);
+ }
+
+ private String generateVideoFilename(int outputFileFormat) {
+ long dateTaken = System.currentTimeMillis();
+ String title = createName(dateTaken);
+ String filename = title + CameraUtil.convertOutputFormatToFileExt(outputFileFormat);
+ String mime = CameraUtil.convertOutputFormatToMimeType(outputFileFormat);
+ String path;
+ if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
+ path = SDCard.instance().getDirectory() + '/' + filename;
+ } else {
+ path = Storage.DIRECTORY + '/' + filename;
+ }
+ mCurrentVideoValues = new ContentValues(9);
+ mCurrentVideoValues.put(MediaStore.Video.Media.TITLE, title);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken);
+ mCurrentVideoValues.put(MediaStore.MediaColumns.DATE_MODIFIED, dateTaken / 1000);
+ mCurrentVideoValues.put(MediaStore.Video.Media.MIME_TYPE, mime);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DATA, path);
+ mCurrentVideoValues.put(MediaStore.Video.Media.RESOLUTION,
+ "" + mVideoSize.getWidth() + "x" + mVideoSize.getHeight());
+ Location loc = mLocationManager.getCurrentLocation();
+ if (loc != null) {
+ mCurrentVideoValues.put(MediaStore.Video.Media.LATITUDE, loc.getLatitude());
+ mCurrentVideoValues.put(MediaStore.Video.Media.LONGITUDE, loc.getLongitude());
+ }
+ mVideoFilename = path;
+ return path;
+ }
+
+ private void saveVideo() {
+ File origFile = new File(mVideoFilename);
+ if (!origFile.exists() || origFile.length() <= 0) {
+ Log.e(TAG, "Invalid file");
+ mCurrentVideoValues = null;
+ return;
+ }
+
+ long duration = 0L;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+
+ try {
+ retriever.setDataSource(mVideoFilename);
+ duration = Long.valueOf(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_DURATION));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "cannot access the file");
+ }
+ retriever.release();
+
+ mActivity.getMediaSaveService().addVideo(mVideoFilename,
+ duration, mCurrentVideoValues,
+ mOnVideoSavedListener, mContentResolver);
+ mCurrentVideoValues = null;
+ }
+
+ private void setUpMediaRecorder(int cameraId) throws IOException {
+ Log.d(TAG, "setUpMediaRecorder");
+ String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
+ int size = CameraSettings.VIDEO_QUALITY_TABLE.get(videoSize);
+ if (mCaptureTimeLapse)
+ size = CameraSettings.getTimeLapseQualityFor(size);
+ mProfile = CamcorderProfile.get(cameraId, size);
+
+ int videoEncoder = SettingTranslation
+ .getVideoEncoder(mSettingsManager.getValue(SettingsManager.KEY_VIDEO_ENCODER));
+ int audioEncoder = SettingTranslation
+ .getAudioEncoder(mSettingsManager.getValue(SettingsManager.KEY_AUDIO_ENCODER));
+
+ int outputFormat = MediaRecorder.OutputFormat.MPEG_4;
+
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+
+ mMediaRecorder.setOutputFormat(mProfile.fileFormat);
+ String fileName = generateVideoFilename(outputFormat);
+ Log.v(TAG, "New video filename: " + fileName);
+ mMediaRecorder.setOutputFile(fileName);
+ mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate);
+ mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(videoEncoder);
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
+ mMediaRecorder.setAudioChannels(mProfile.audioChannels);
+ mMediaRecorder.setAudioSamplingRate(mProfile.audioSampleRate);
+ mMediaRecorder.setAudioEncoder(audioEncoder);
+ }
+ mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
+ if (mCaptureTimeLapse) {
+ double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs;
+ mMediaRecorder.setCaptureRate(fps);
+ }
+ Location loc = mLocationManager.getCurrentLocation();
+ if (loc != null) {
+ mMediaRecorder.setLocation((float) loc.getLatitude(),
+ (float) loc.getLongitude());
+ }
+ int rotation = CameraUtil.getJpegRotation(cameraId, mOrientation);
+ String videoRotation = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_ROTATION);
+ if (videoRotation != null) {
+ rotation += Integer.parseInt(videoRotation);
+ rotation = rotation % 360;
+ }
+ mMediaRecorder.setOrientationHint(rotation);
+ mMediaRecorder.prepare();
+ }
+
+ public void onVideoButtonClick() {
+ if (getCameraMode() == DUAL_MODE) return;
+ if (mIsRecordingVideo) {
+ stopRecordingVideo(getMainCameraId());
+ } else {
+ startRecordingVideo(getMainCameraId());
+ }
+ }
+
@Override
public void onShutterButtonClick() {
if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
@@ -2226,13 +2685,25 @@ public class CaptureModule implements CameraModule, PhotoController,
case SettingsManager.KEY_JPEG_QUALITY:
estimateJpegFileSize();
continue;
+ case SettingsManager.KEY_VIDEO_DURATION:
+ updateMaxVideoDuration();
+ continue;
+ case SettingsManager.KEY_VIDEO_QUALITY:
+ updateVideoSize();
+ continue;
+ case SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL:
+ updateTimeLapseSetting();
+ continue;
case SettingsManager.KEY_CAMERA2:
switchCameraMode(value);
return;
+ case SettingsManager.KEY_PICTURE_SIZE:
+ updatePictureSize();
+ if (count == 0) restart();
+ return;
case SettingsManager.KEY_CAMERA_ID:
case SettingsManager.KEY_MONO_ONLY:
case SettingsManager.KEY_CLEARSIGHT:
- case SettingsManager.KEY_PICTURE_SIZE:
case SettingsManager.KEY_MONO_PREVIEW:
if (count == 0) restart();
return;
@@ -2414,5 +2885,14 @@ public class CaptureModule implements CameraModule, PhotoController,
public MainHandler() {
super(Looper.getMainLooper());
}
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case UPDATE_RECORD_TIME: {
+ updateRecordingTime();
+ break;
+ }
+ }
+ }
}
}
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index 71d39e067..f10be5703 100644
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -67,7 +67,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
CameraManager.CameraFaceDetectionCallback,
SettingsManager.Listener,
ListMenu.Listener,
- ListSubMenu.Listener {
+ ListSubMenu.Listener,
+ PauseButton.OnPauseButtonListener {
private static final int HIGHLIGHT_COLOR = 0xff33b5e5;
private static final String TAG = "SnapCam_CaptureUI";
private static final int SETTING_MENU_NONE = 0;
@@ -93,13 +94,22 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
SettingsManager.KEY_EXPOSURE,
SettingsManager.KEY_WHITE_BALANCE,
SettingsManager.KEY_CAMERA2,
- SettingsManager.KEY_MAKEUP
+ SettingsManager.KEY_MAKEUP,
+ SettingsManager.KEY_VIDEO_FLASH_MODE,
+ SettingsManager.KEY_VIDEO_DURATION,
+ SettingsManager.KEY_VIDEO_QUALITY
};
String[] mDeveloperKeys = new String[]{
SettingsManager.KEY_REDEYE_REDUCTION,
SettingsManager.KEY_MONO_ONLY,
SettingsManager.KEY_CLEARSIGHT,
- SettingsManager.KEY_MONO_PREVIEW
+ SettingsManager.KEY_MONO_PREVIEW,
+ SettingsManager.KEY_NOISE_REDUCTION,
+ SettingsManager.KEY_DIS,
+ SettingsManager.KEY_VIDEO_ENCODER,
+ SettingsManager.KEY_AUDIO_ENCODER,
+ SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
+ SettingsManager.KEY_VIDEO_ROTATION
};
private CameraActivity mActivity;
private View mRootView;
@@ -148,6 +158,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
};
private ShutterButton mShutterButton;
+ private ImageView mVideoButton;
private RenderOverlay mRenderOverlay;
private View mMenuButton;
private ModuleSwitcher mSwitcher;
@@ -165,6 +176,15 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private View mFilterModeSwitcher;
private View mSceneModeSwitcher;
private View mFrontBackSwitcher;
+ private TextView mRecordingTimeView;
+ private LinearLayout mLabelsLinearLayout;
+ private View mTimeLapseLabel;
+ private RotateLayout mRecordingTimeRect;
+ private PauseButton mPauseButton;
+ private RotateImageView mMuteButton;
+
+ int mPreviewWidth;
+ int mPreviewHeight;
private SurfaceHolder.Callback callback2 = new SurfaceHolder.Callback() {
@@ -224,6 +244,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
+ mVideoButton = (ImageView) mRootView.findViewById(R.id.video_button);
mFilterModeSwitcher = mRootView.findViewById(R.id.filter_mode_switcher);
mSceneModeSwitcher = mRootView.findViewById(R.id.scene_mode_switcher);
mFrontBackSwitcher = mRootView.findViewById(R.id.front_back_switcher);
@@ -246,6 +267,32 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
});
mMenuButton = mRootView.findViewById(R.id.menu);
+ mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
+ mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
+ mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
+ mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
+ mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause);
+ mPauseButton.setOnPauseButtonListener(this);
+
+ mMuteButton = (RotateImageView)mRootView.findViewById(R.id.mute_button);
+ mMuteButton.setVisibility(View.VISIBLE);
+ if(!mModule.isAudioMute()) {
+ mMuteButton.setImageResource(R.drawable.ic_unmuted_button);
+ } else {
+ mMuteButton.setImageResource(R.drawable.ic_muted_button);
+ }
+ mMuteButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean isEnabled = !mModule.isAudioMute();
+ mModule.setMute(isEnabled, true);
+ if (!isEnabled)
+ mMuteButton.setImageResource(R.drawable.ic_unmuted_button);
+ else
+ mMuteButton.setImageResource(R.drawable.ic_muted_button);
+ }
+ });
+
RotateImageView muteButton = (RotateImageView) mRootView.findViewById(R.id.mute_button);
muteButton.setVisibility(View.GONE);
@@ -283,6 +330,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mRenderOverlay.requestLayout();
mActivity.setPreviewGestures(mGestures);
+ ((ViewGroup)mRootView).removeView(mRecordingTimeRect);
+ mCameraControls.setPreviewRatio(0, true);
}
public void onCameraOpened(List<Integer> cameraIds) {
@@ -314,6 +363,14 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
});
mShutterButton.setOnShutterButtonListener(mModule);
mShutterButton.setVisibility(View.VISIBLE);
+ mVideoButton.setVisibility(View.VISIBLE);
+ mVideoButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mModule.onVideoButtonClick();
+ }
+ });
+ mCameraControls.setPreviewRatio(0, true);
}
public void initializeZoom(List<Integer> ids) {
@@ -421,6 +478,53 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
});
}
+ public void showTimeLapseUI(boolean enable) {
+ if (mTimeLapseLabel != null) {
+ mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void showRecordingUI(boolean recording) {
+ mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
+ if (recording) {
+ mVideoButton.setImageResource(R.drawable.shutter_button_video_stop);
+ hideSwitcher();
+ mRecordingTimeView.setText("");
+ ((ViewGroup)mRootView).addView(mRecordingTimeRect);
+ mMuteButton.setVisibility(View.VISIBLE);
+ } else {
+ mVideoButton.setImageResource(R.drawable.btn_new_shutter_video);
+ showSwitcher();
+ ((ViewGroup)mRootView).removeView(mRecordingTimeRect);
+ mMuteButton.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public void hideUIwhileRecording() {
+ mCameraControls.setWillNotDraw(true);
+ mFrontBackSwitcher.setVisibility(View.INVISIBLE);
+ mFilterModeSwitcher.setVisibility(View.INVISIBLE);
+ mSceneModeSwitcher.setVisibility(View.INVISIBLE);
+ mShutterButton.setVisibility(View.INVISIBLE);
+ }
+
+ public void showUIafterRecording() {
+ mCameraControls.setWillNotDraw(false);
+ mFrontBackSwitcher.setVisibility(View.VISIBLE);
+ mFilterModeSwitcher.setVisibility(View.VISIBLE);
+ mSceneModeSwitcher.setVisibility(View.VISIBLE);
+ mShutterButton.setVisibility(View.VISIBLE);
+ }
+
+ public void hideSwitcher() {
+ mSwitcher.closePopup();
+ mSwitcher.setVisibility(View.INVISIBLE);
+ }
+
+ public void showSwitcher() {
+ mSwitcher.setVisibility(View.VISIBLE);
+ }
+
public void setSwitcherIndex() {
mSwitcher.setCurrentIndex(ModuleSwitcher.PHOTO_MODULE_INDEX);
}
@@ -1015,7 +1119,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mThumbnail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (!CameraControls.isAnimating() && !mModule.isTakingPicture())
+ if (!CameraControls.isAnimating() && !mModule.isTakingPicture() &&
+ !mModule.isRecordingVideo())
mActivity.gotoGallery();
}
});
@@ -1301,6 +1406,15 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
}
}
+ if (mRecordingTimeRect != null) {
+ if (orientation == 180) {
+ mRecordingTimeRect.setOrientation(0, false);
+ mRecordingTimeView.setRotation(180);
+ } else {
+ mRecordingTimeView.setRotation(0);
+ mRecordingTimeRect.setOrientation(orientation, false);
+ }
+ }
if (mCountDownView != null)
mCountDownView.setOrientation(orientation);
RotateTextToast.setOrientation(orientation);
@@ -1364,6 +1478,34 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mShutterButton.setPressed(true);
}
+ public void setRecordingTime(String text) {
+ mRecordingTimeView.setText(text);
+ }
+
+ public void setRecordingTimeTextColor(int color) {
+ mRecordingTimeView.setTextColor(color);
+ }
+
+ public void resetPauseButton() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ mPauseButton.setPaused(false);
+ }
+
+ @Override
+ public void onButtonPause() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_pausing_indicator, 0, 0, 0);
+ mModule.onButtonPause();
+ }
+
+ @Override
+ public void onButtonContinue() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ mModule.onButtonContinue();
+ }
+
@Override
public void onSettingsChanged(List<SettingsManager.SettingState> settings) {
for (SettingsManager.SettingState setting : settings) {
@@ -1385,6 +1527,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
public void showSurfaceView() {
+ mSurfaceView.getHolder().setFixedSize(mPreviewWidth, mPreviewHeight);
+ mSurfaceView.setAspectRatio(mPreviewHeight, mPreviewWidth);
mSurfaceView.setVisibility(View.VISIBLE);
mSurfaceView2.setVisibility(View.VISIBLE);
}
@@ -1397,10 +1541,12 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
}
- public void setPreviewSize(int width, int height) {
- mSurfaceView.getHolder().setFixedSize(width, height);
- mCameraControls.setPreviewRatio(0, true);
- mSurfaceView.setAspectRatio(height, width);
+ public boolean setPreviewSize(int width, int height) {
+ Log.d(TAG, "setPreviewSize " + width + " " + height);
+ boolean changed = (width != mPreviewWidth) || (height != mPreviewHeight);
+ mPreviewWidth = width;
+ mPreviewHeight = height;
+ return changed;
}
@Override
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index a5b72488c..dbffb8401 100644
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -38,6 +38,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.MediaRecorder;
import android.util.Log;
import android.util.Range;
import android.util.Rational;
@@ -45,6 +46,7 @@ import android.util.Size;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
import com.android.camera.ui.ListMenu;
+import com.android.camera.util.SettingTranslation;
import org.codeaurora.snapcam.R;
@@ -87,6 +89,16 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final String KEY_EXPOSURE = "pref_camera2_exposure_key";
public static final String KEY_TIMER = "pref_camera2_timer_key";
public static final String KEY_LONGSHOT = "pref_camera2_longshot_key";
+ public static final String KEY_VIDEO_DURATION = "pref_camera2_video_duration_key";
+ public static final String KEY_VIDEO_QUALITY = "pref_camera2_video_quality_key";
+ public static final String KEY_VIDEO_ENCODER = "pref_camera2_videoencoder_key";
+ public static final String KEY_AUDIO_ENCODER = "pref_camera2_audioencoder_key";
+ public static final String KEY_DIS = "pref_camera2_dis_key";
+ public static final String KEY_NOISE_REDUCTION = "pref_camera2_noise_reduction_key";
+ public static final String KEY_VIDEO_FLASH_MODE = "pref_camera2_video_flashmode_key";
+ public static final String KEY_VIDEO_ROTATION = "pref_camera2_video_rotation_key";
+ public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL =
+ "pref_camera2_video_time_lapse_frame_interval_key";
private static final String TAG = "SnapCam_SettingsManager";
private static SettingsManager sInstance;
@@ -502,6 +514,11 @@ public class SettingsManager implements ListMenu.SettingsListener {
ListPreference monoPreview = mPreferenceGroup.findPreference(KEY_MONO_PREVIEW);
ListPreference monoOnly = mPreferenceGroup.findPreference(KEY_MONO_ONLY);
ListPreference redeyeReduction = mPreferenceGroup.findPreference(KEY_REDEYE_REDUCTION);
+ ListPreference videoQuality = mPreferenceGroup.findPreference(KEY_VIDEO_QUALITY);
+ ListPreference videoEncoder = mPreferenceGroup.findPreference(KEY_VIDEO_ENCODER);
+ ListPreference audioEncoder = mPreferenceGroup.findPreference(KEY_AUDIO_ENCODER);
+ ListPreference noiseReduction = mPreferenceGroup.findPreference(KEY_NOISE_REDUCTION);
+ ListPreference videoFlash = mPreferenceGroup.findPreference(KEY_VIDEO_FLASH_MODE);
if (whiteBalance != null) {
CameraSettings.filterUnsupportedOptions(mPreferenceGroup,
@@ -537,6 +554,11 @@ public class SettingsManager implements ListMenu.SettingsListener {
iso, getSupportedIso(cameraId));
}
+ if (iso != null) {
+ CameraSettings.filterUnsupportedOptions(mPreferenceGroup,
+ videoQuality, getSupportedVideoSize(cameraId));
+ }
+
if (!mIsMonoCameraPresent) {
if (clearsight != null) removePreference(mPreferenceGroup, KEY_CLEARSIGHT);
if (monoPreview != null) removePreference(mPreferenceGroup, KEY_MONO_PREVIEW);
@@ -547,6 +569,26 @@ public class SettingsManager implements ListMenu.SettingsListener {
CameraSettings.filterUnsupportedOptions(mPreferenceGroup,
redeyeReduction, getSupportedRedeyeReduction(cameraId));
}
+
+ if (videoEncoder != null) {
+ CameraSettings.filterUnsupportedOptions(mPreferenceGroup, videoEncoder,
+ getSupportedVideoEncoders(videoEncoder.getEntryValues()));
+ }
+
+ if (audioEncoder != null) {
+ CameraSettings.filterUnsupportedOptions(mPreferenceGroup, audioEncoder,
+ getSupportedAudioEncoders(audioEncoder.getEntryValues()));
+ }
+
+ if (noiseReduction != null) {
+ CameraSettings.filterUnsupportedOptions(mPreferenceGroup, noiseReduction,
+ getSupportedNoiseReductionModes(cameraId));
+ }
+
+ if (videoFlash != null) {
+ if (!isFlashAvailable(cameraId))
+ removePreference(mPreferenceGroup, KEY_VIDEO_FLASH_MODE);
+ }
}
private void buildExposureCompensation(int cameraId) {
@@ -721,6 +763,23 @@ public class SettingsManager implements ListMenu.SettingsListener {
return res;
}
+ public Size[] getSupportedOutputSize(int cameraId, Class cl) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ return map.getOutputSizes(cl);
+ }
+
+ private List<String> getSupportedVideoSize(int cameraId) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ Size[] sizes = map.getOutputSizes(MediaRecorder.class);
+ List<String> res = new ArrayList<>();
+ for (int i = 0; i < sizes.length; i++) {
+ res.add(sizes[i].toString());
+ }
+ return res;
+ }
+
private List<String> getSupportedRedeyeReduction(int cameraId) {
int[] flashModes = mCharacteristics.get(cameraId).get(CameraCharacteristics
.CONTROL_AE_AVAILABLE_MODES);
@@ -768,6 +827,10 @@ public class SettingsManager implements ListMenu.SettingsListener {
return modes;
}
+ private boolean isFlashAvailable(int cameraId) {
+ return mCharacteristics.get(cameraId).get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ }
+
public List<String> getSupportedColorEffects(int cameraId) {
int[] flashModes = mCharacteristics.get(cameraId).get(CameraCharacteristics
.CONTROL_AVAILABLE_EFFECTS);
@@ -794,6 +857,37 @@ public class SettingsManager implements ListMenu.SettingsListener {
return supportedIso;
}
+ private static List<String> getSupportedVideoEncoders(CharSequence[] strings) {
+ ArrayList<String> supported = new ArrayList<>();
+ for (CharSequence cs: strings) {
+ String s = cs.toString();
+ int value = SettingTranslation.getVideoEncoder(s.toString());
+ if (value != SettingTranslation.NOT_FOUND) supported.add(s.toString());
+ }
+ return supported;
+ }
+
+ private static List<String> getSupportedAudioEncoders(CharSequence[] strings) {
+ ArrayList<String> supported = new ArrayList<>();
+ for (CharSequence cs: strings) {
+ String s = cs.toString();
+ int value = SettingTranslation.getAudioEncoder(s);
+ if (value != SettingTranslation.NOT_FOUND) supported.add(s);
+ }
+ return supported;
+ }
+
+ public List<String> getSupportedNoiseReductionModes(int cameraId) {
+ int[] noiseReduction = mCharacteristics.get(cameraId).get(CameraCharacteristics
+ .NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES);
+ List<String> modes = new ArrayList<>();
+ for (int mode : noiseReduction) {
+ String str = SettingTranslation.getNoiseReduction(mode);
+ if (str != null) modes.add(str);
+ }
+ return modes;
+ }
+
private boolean specialDepedency(String key) {
return key.equals(KEY_SCENE_MODE);
}
diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java
index 9f2a5ebb8..5de05dca9 100644
--- a/src/com/android/camera/ui/CameraControls.java
+++ b/src/com/android/camera/ui/CameraControls.java
@@ -51,6 +51,7 @@ public class CameraControls extends RotatableLayout {
private View mBackgroundView;
private View mShutter;
+ private View mVideoShutter;
private View mSwitcher;
private View mMenu;
private View mMute;
@@ -82,10 +83,11 @@ public class CameraControls extends RotatableLayout {
private static final int PREVIEW_INDEX = 7;
private static final int INDICATOR_INDEX = 8;
private static final int MUTE_INDEX = 9;
+ private static final int VIDEO_SHUTTER_INDEX = 10;
private static final int ANIME_DURATION = 300;
- private float[][] mLocX = new float[4][10];
- private float[][] mLocY = new float[4][10];
- private boolean[] mTempEnabled = new boolean[10];
+ private float[][] mLocX = new float[4][11];
+ private float[][] mLocY = new float[4][11];
+ private boolean[] mTempEnabled = new boolean[11];
private boolean mLocSet = false;
private boolean mHideRemainingPhoto = false;
private LinearLayout mRemainingPhotos;
@@ -127,6 +129,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.setVisibility(View.INVISIBLE);
mShutter.setVisibility(View.INVISIBLE);
+ mVideoShutter.setVisibility(View.INVISIBLE);
mMenu.setVisibility(View.INVISIBLE);
mMute.setVisibility(View.INVISIBLE);
mIndicators.setVisibility(View.INVISIBLE);
@@ -150,6 +153,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.setVisibility(View.INVISIBLE);
mShutter.setVisibility(View.INVISIBLE);
+ mVideoShutter.setVisibility(View.INVISIBLE);
mMenu.setVisibility(View.INVISIBLE);
mMute.setVisibility(View.INVISIBLE);
mIndicators.setVisibility(View.INVISIBLE);
@@ -208,6 +212,7 @@ public class CameraControls extends RotatableLayout {
public void enableTouch(boolean enable) {
if (enable) {
((ShutterButton) mShutter).setPressed(false);
+ mVideoShutter.setPressed(false);
mSwitcher.setPressed(false);
mMenu.setPressed(false);
mMute.setPressed(false);
@@ -223,6 +228,7 @@ public class CameraControls extends RotatableLayout {
mTempEnabled[FILTER_MODE_INDEX] = mFilterModeSwitcher.isEnabled();
}
((ShutterButton) mShutter).enableTouch(enable);
+ mVideoShutter.setClickable(enable);
((ModuleSwitcher) mSwitcher).enableTouch(enable);
mMenu.setEnabled(enable);
mMute.setEnabled(enable);
@@ -254,6 +260,8 @@ public class CameraControls extends RotatableLayout {
mViewList.add(mFilterModeSwitcher);
if (mShutter.getVisibility() == View.VISIBLE)
mViewList.add(mShutter);
+ if (mVideoShutter.getVisibility() == View.VISIBLE)
+ mViewList.add(mVideoShutter);
if (mMenu.getVisibility() == View.VISIBLE)
mViewList.add(mMenu);
if (mMute.getVisibility() == View.VISIBLE)
@@ -276,6 +284,7 @@ public class CameraControls extends RotatableLayout {
mBackgroundView = findViewById(R.id.blocker);
mSwitcher = findViewById(R.id.camera_switcher);
mShutter = findViewById(R.id.shutter_button);
+ mVideoShutter = findViewById(R.id.video_button);
mFrontBackSwitcher = findViewById(R.id.front_back_switcher);
if(TsMakeupManager.HAS_TS_MAKEUP) {
mTsMakeupSwitcher = findViewById(R.id.ts_makeup_switcher);
@@ -361,6 +370,7 @@ public class CameraControls extends RotatableLayout {
private void setLocation(int w, int h) {
int rotation = getUnifiedRotation();
toIndex(mSwitcher, w, h, rotation, 4, 6, SWITCHER_INDEX);
+ toIndex(mVideoShutter, w, h, rotation, 3, 6, VIDEO_SHUTTER_INDEX);
toIndex(mMenu, w, h, rotation, 4, 0, MENU_INDEX);
toIndex(mMute, w, h, rotation, 3, 0, MUTE_INDEX);
toIndex(mIndicators, w, h, rotation, 0, 6, INDICATOR_INDEX);
@@ -475,6 +485,7 @@ public class CameraControls extends RotatableLayout {
mMute.setX(mLocX[idx1][MUTE_INDEX] + x);
mSwitcher.setX(mLocX[idx1][SWITCHER_INDEX] - x);
mShutter.setX(mLocX[idx1][SHUTTER_INDEX] - x);
+ mVideoShutter.setX(mLocX[idx1][VIDEO_SHUTTER_INDEX] - x);
mIndicators.setX(mLocX[idx1][INDICATOR_INDEX] - x);
mPreview.setX(mLocX[idx1][PREVIEW_INDEX] - x);
@@ -490,6 +501,7 @@ public class CameraControls extends RotatableLayout {
mMute.setY(mLocY[idx1][MUTE_INDEX] + y);
mSwitcher.setY(mLocY[idx1][SWITCHER_INDEX] - y);
mShutter.setY(mLocY[idx1][SHUTTER_INDEX] - y);
+ mVideoShutter.setY(mLocY[idx1][VIDEO_SHUTTER_INDEX] - y);
mIndicators.setY(mLocY[idx1][INDICATOR_INDEX] - y);
mPreview.setY(mLocY[idx1][PREVIEW_INDEX] - y);
}
@@ -521,6 +533,7 @@ public class CameraControls extends RotatableLayout {
mFilterModeSwitcher.animate().cancel();
mSwitcher.animate().cancel();
mShutter.animate().cancel();
+ mVideoShutter.animate().cancel();
mMenu.animate().cancel();
mMute.animate().cancel();
mIndicators.animate().cancel();
@@ -544,6 +557,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
break;
@@ -561,6 +575,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
break;
@@ -578,6 +593,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
break;
@@ -595,6 +611,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
break;
@@ -618,6 +635,7 @@ public class CameraControls extends RotatableLayout {
mFilterModeSwitcher.animate().cancel();
mSwitcher.animate().cancel();
mShutter.animate().cancel();
+ mVideoShutter.animate().cancel();
mMenu.animate().cancel();
mMute.animate().cancel();
mIndicators.animate().cancel();
@@ -653,6 +671,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationYBy(-mSize).setDuration(ANIME_DURATION);
break;
@@ -672,6 +691,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationXBy(-mSize).setDuration(ANIME_DURATION);
break;
@@ -691,6 +711,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationYBy(mSize).setDuration(ANIME_DURATION);
break;
@@ -710,6 +731,7 @@ public class CameraControls extends RotatableLayout {
mSwitcher.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mShutter.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
+ mVideoShutter.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mIndicators.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
mPreview.animate().translationXBy(mSize).setDuration(ANIME_DURATION);
break;
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index 812220c1a..172a54582 100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
@@ -36,6 +36,7 @@ import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.location.Location;
+import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
@@ -1168,4 +1169,62 @@ public class CameraUtil {
return retRatio;
}
+ public 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();
+ }
+
+ public static String convertOutputFormatToMimeType(int outputFileFormat) {
+ if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) {
+ return "video/mp4";
+ }
+ return "video/3gpp";
+ }
+
+ public static String convertOutputFormatToFileExt(int outputFileFormat) {
+ if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) {
+ return ".mp4";
+ }
+ return ".3gp";
+ }
}
diff --git a/src/com/android/camera/util/SettingTranslation.java b/src/com/android/camera/util/SettingTranslation.java
new file mode 100644
index 000000000..6aee0ede0
--- /dev/null
+++ b/src/com/android/camera/util/SettingTranslation.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera.util;
+
+import android.hardware.camera2.CameraMetadata;
+import android.media.MediaRecorder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SettingTranslation {
+ public static final int NOT_FOUND = -1;
+ private static final TwoWayMap VIDEO_ENCODER_TABLE = new TwoWayMap();
+ private static final TwoWayMap AUDIO_ENCODER_TABLE = new TwoWayMap();
+ private static final TwoWayMap NOISE_REDUCTION_TABLE = new TwoWayMap();
+
+ static {
+ VIDEO_ENCODER_TABLE.put("default", MediaRecorder.VideoEncoder.DEFAULT);
+ VIDEO_ENCODER_TABLE.put("h263", MediaRecorder.VideoEncoder.H263);
+ VIDEO_ENCODER_TABLE.put("h264", MediaRecorder.VideoEncoder.H264);
+ int h265 = ApiHelper.getIntFieldIfExists(MediaRecorder.VideoEncoder.class,
+ "HEVC", null, MediaRecorder.VideoEncoder.DEFAULT);
+ if (h265 == MediaRecorder.VideoEncoder.DEFAULT) {
+ h265 = ApiHelper.getIntFieldIfExists(MediaRecorder.VideoEncoder.class,
+ "H265", null, MediaRecorder.VideoEncoder.DEFAULT);
+ }
+ VIDEO_ENCODER_TABLE.put("h265", h265);
+ VIDEO_ENCODER_TABLE.put("mpeg-4-sp", MediaRecorder.VideoEncoder.MPEG_4_SP);
+ VIDEO_ENCODER_TABLE.put("vp8", MediaRecorder.VideoEncoder.VP8);
+
+ AUDIO_ENCODER_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC);
+ AUDIO_ENCODER_TABLE.put("aac-eld", MediaRecorder.AudioEncoder.AAC_ELD);
+ AUDIO_ENCODER_TABLE.put("amr-nb", MediaRecorder.AudioEncoder.AMR_NB);
+ AUDIO_ENCODER_TABLE.put("amr-wb", MediaRecorder.AudioEncoder.AMR_WB);
+ AUDIO_ENCODER_TABLE.put("default", MediaRecorder.AudioEncoder.DEFAULT);
+ AUDIO_ENCODER_TABLE.put("he-aac", MediaRecorder.AudioEncoder.HE_AAC);
+ AUDIO_ENCODER_TABLE.put("vorbis", MediaRecorder.AudioEncoder.VORBIS);
+
+ NOISE_REDUCTION_TABLE.put("off", CameraMetadata.NOISE_REDUCTION_MODE_OFF);
+ NOISE_REDUCTION_TABLE.put("fast", CameraMetadata.NOISE_REDUCTION_MODE_FAST);
+ NOISE_REDUCTION_TABLE.put("high-quality", CameraMetadata
+ .NOISE_REDUCTION_MODE_HIGH_QUALITY);
+ NOISE_REDUCTION_TABLE.put("minimal", CameraMetadata.NOISE_REDUCTION_MODE_MINIMAL);
+ NOISE_REDUCTION_TABLE.put("zero-shutter-lag", CameraMetadata
+ .NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
+ }
+
+ public static int getVideoEncoder(String key) {
+ return VIDEO_ENCODER_TABLE.get(key);
+ }
+
+ public static String getVideoEncoder(int key) {
+ return VIDEO_ENCODER_TABLE.get(key);
+ }
+
+ public static int getAudioEncoder(String key) {
+ return AUDIO_ENCODER_TABLE.get(key);
+ }
+
+ public static String getAudioEncoder(int key) {
+ return AUDIO_ENCODER_TABLE.get(key);
+ }
+
+ public static int getNoiseReduction(String key) {
+ return NOISE_REDUCTION_TABLE.get(key);
+ }
+
+ public static String getNoiseReduction(int key) {
+ return NOISE_REDUCTION_TABLE.get(key);
+ }
+
+ private static class TwoWayMap {
+ private Map<String, Integer> strToInt = new HashMap<>();
+ private Map<Integer, String> intToStr = new HashMap<>();
+
+ public void put(String key, int value) {
+ strToInt.put(key, value);
+ intToStr.put(value, key);
+ }
+
+ public int get(String key) {
+ Integer res = strToInt.get(key);
+ if (res != null) return res;
+ else return NOT_FOUND;
+ }
+
+ public String get(int key) {
+ return intToStr.get(key);
+ }
+ }
+}