diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2012-08-06 17:34:47 -0700 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2012-08-10 10:28:23 -0700 |
commit | abe36163445fb3fe458252fd8d21c3e1ac14ed6d (patch) | |
tree | 28ec5ee8e9554da10297b2153b7685c6b6dabfbc /apps/TestingCamera | |
parent | bc88c6ed6508927ad72eefba3f6f63c6436f06d3 (diff) | |
download | pdk-abe36163445fb3fe458252fd8d21c3e1ac14ed6d.tar.gz |
TestingCamera: Autofocus, recording, logging, code cleanup
- Add logging into onscreen textview
- Clean up code (whitespace, refactor some long methods)
- Add AF mode selection, AF trigger, AF cancel
- Add recording support
Bug: 6243944
Change-Id: I799a99e24009677b558875a2d980bb980dd8d004
Diffstat (limited to 'apps/TestingCamera')
7 files changed, 487 insertions, 139 deletions
diff --git a/apps/TestingCamera/AndroidManifest.xml b/apps/TestingCamera/AndroidManifest.xml index bb48524..cfed74b 100644 --- a/apps/TestingCamera/AndroidManifest.xml +++ b/apps/TestingCamera/AndroidManifest.xml @@ -22,8 +22,11 @@ <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="16"/> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/> <uses-feature android:name="android.hardware.camera.front" android:required="false"/> + <uses-permission android:name="android.permission.RECORD_AUDIO"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <application android:icon="@mipmap/launcher_testingcamera" android:label="@string/app_name" diff --git a/apps/TestingCamera/project.properties b/apps/TestingCamera/project.properties index e484b3c..9b84a6b 100644 --- a/apps/TestingCamera/project.properties +++ b/apps/TestingCamera/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=Google Inc.:Google APIs:16 +target=android-16 diff --git a/apps/TestingCamera/res/layout/main.xml b/apps/TestingCamera/res/layout/main.xml index 06f3628..4478379 100644 --- a/apps/TestingCamera/res/layout/main.xml +++ b/apps/TestingCamera/res/layout/main.xml @@ -32,12 +32,14 @@ android:layout_height="0px" android:layout_weight="6" /> + <TextView - android:id="@+id/log" - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:layout_weight="1" - /> + android:id="@+id/log" + android:layout_width="fill_parent" + android:layout_height="0px" + android:layout_weight="1.5" + android:freezesText="true" /> + </LinearLayout> <ScrollView @@ -74,8 +76,10 @@ <Button android:id="@+id/info_button" + style="?android:attr/buttonStyleSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" + android:layout_gravity="center" android:layout_weight="1" android:text="@string/show_info" /> @@ -106,6 +110,7 @@ android:id="@+id/start_preview" android:layout_width="fill_parent" android:layout_height="wrap_content" + android:layout_gravity="center" android:layout_weight="1" android:textColorLink="@android:color/holo_blue_light" android:textOff="@string/preview_off_label" @@ -121,6 +126,47 @@ android:background="@color/horiz_rule_color" /> <TextView + android:id="@+id/af_mode_spinner_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/af_mode_prompt" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + <Spinner + android:id="@+id/af_mode_spinner" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" /> + + <Button + android:id="@+id/af_button" + style="?android:attr/buttonStyleSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="1" + android:text="@string/trigger_autofocus" /> + + <Button + android:id="@+id/af_cancel_button" + style="?android:attr/buttonStyleSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="1" + android:text="@string/cancel_autofocus" /> + + <View + android:id="@+id/horizontal_rule_3" + android:layout_width="fill_parent" + android:layout_height="1dip" + android:layout_marginBottom="@dimen/horiz_rule_btm_margin" + android:layout_marginTop="@dimen/horiz_rule_top_margin" + android:layout_weight="1" + android:background="@color/horiz_rule_color" /> + + <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -136,13 +182,14 @@ <Button android:id="@+id/take_picture" + style="?android:attr/buttonStyleSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/take_picture_label" /> <View - android:id="@+id/horizontal_rule_3" + android:id="@+id/horizontal_rule_4" android:layout_width="fill_parent" android:layout_height="1dip" android:layout_marginBottom="@dimen/horiz_rule_btm_margin" diff --git a/apps/TestingCamera/res/values/strings.xml b/apps/TestingCamera/res/values/strings.xml index 69c57da..5ce8262 100644 --- a/apps/TestingCamera/res/values/strings.xml +++ b/apps/TestingCamera/res/values/strings.xml @@ -22,7 +22,7 @@ <string name="preview_off_label">Preview Off</string> <string name="take_picture_label">Take picture</string> <string name="preview_resolution_prompt">Preview size</string> - <string name="camera_selection_prompt">Camera ID</string> + <string name="camera_selection_prompt">Active camera</string> <string name="default_camera_entry">No cameras found</string> <string name="snapshot_text_default">Snapshot text</string> <string name="snapshot_size_spinner_label">Still capture size</string> @@ -34,4 +34,7 @@ <string name="info_ok_button_label">OK</string> <string name="snapshot_ok_label">OK</string> <string name="still_image_description">Captured still image</string> + <string name="af_mode_prompt">Autofocus mode</string> + <string name="trigger_autofocus">Trigger autofocus</string> + <string name="cancel_autofocus">Cancel Autofocus</string> </resources> diff --git a/apps/TestingCamera/src/com/android/testingcamera/InfoDialogFragment.java b/apps/TestingCamera/src/com/android/testingcamera/InfoDialogFragment.java index 9499778..da5496a 100644 --- a/apps/TestingCamera/src/com/android/testingcamera/InfoDialogFragment.java +++ b/apps/TestingCamera/src/com/android/testingcamera/InfoDialogFragment.java @@ -37,7 +37,6 @@ public class InfoDialogFragment extends DialogFragment implements View.OnClickLi return view; } - @Override public void onClick(View v) { this.dismiss(); } diff --git a/apps/TestingCamera/src/com/android/testingcamera/SnapshotDialogFragment.java b/apps/TestingCamera/src/com/android/testingcamera/SnapshotDialogFragment.java index 28ba3aa..9b13b95 100644 --- a/apps/TestingCamera/src/com/android/testingcamera/SnapshotDialogFragment.java +++ b/apps/TestingCamera/src/com/android/testingcamera/SnapshotDialogFragment.java @@ -41,9 +41,7 @@ public class SnapshotDialogFragment extends DialogFragment implements View.OnCli return view; } - @Override public void onClick(View v) { - // TODO Auto-generated method stub this.dismiss(); } diff --git a/apps/TestingCamera/src/com/android/testingcamera/TestingCamera.java b/apps/TestingCamera/src/com/android/testingcamera/TestingCamera.java index 5cf7a5e..d3403c7 100644 --- a/apps/TestingCamera/src/com/android/testingcamera/TestingCamera.java +++ b/apps/TestingCamera/src/com/android/testingcamera/TestingCamera.java @@ -22,13 +22,17 @@ import android.app.FragmentManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.hardware.Camera; +import android.hardware.Camera.Parameters; import android.media.CamcorderProfile; +import android.media.MediaRecorder; import android.os.Bundle; +import android.os.Environment; import android.view.View; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View.OnClickListener; import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; @@ -37,19 +41,30 @@ import android.widget.Spinner; import android.widget.CompoundButton; import android.widget.TextView; import android.widget.ToggleButton; +import android.text.Layout; +import android.text.method.ScrollingMovementMethod; import android.util.Log; +import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.FieldPosition; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.TreeSet; /** * A simple test application for the camera API. * * The goal of this application is to allow all camera API features to be - * excercised, and all information provided by the API to be shown. + * exercised, and all information provided by the API to be shown. */ public class TestingCamera extends Activity implements SurfaceHolder.Callback { @@ -61,33 +76,46 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { private Button mInfoButton; private Spinner mPreviewSizeSpinner; private ToggleButton mPreviewToggle; + private Spinner mAutofocusModeSpinner; + private Button mAutofocusButton; + private Button mCancelAutofocusButton; private Spinner mSnapshotSizeSpinner; private Button mTakePictureButton; private Spinner mCamcorderProfileSpinner; private ToggleButton mRecordToggle; + private TextView mLogView; + + private Set<View> mPreviewOnlyControls = new HashSet<View>(); + /** Camera state */ private int mCameraId = 0; private Camera mCamera; private Camera.Parameters mParams; private List<Camera.Size> mPreviewSizes; private int mPreviewSize = 0; + private List<String> mAfModes; + private int mAfMode = 0; private List<Camera.Size> mSnapshotSizes; private int mSnapshotSize = 0; private List<CamcorderProfile> mCamcorderProfiles; private int mCamcorderProfile = 0; + private MediaRecorder mRecorder; + private static final int CAMERA_UNINITIALIZED = 0; private static final int CAMERA_OPEN = 1; private static final int CAMERA_PREVIEW = 2; private static final int CAMERA_TAKE_PICTURE = 3; + private static final int CAMERA_RECORD = 4; private int mState = CAMERA_UNINITIALIZED; /** Misc variables */ private static final String TAG = "TestingCamera"; - // Activity methods + /** Activity lifecycle */ + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -109,20 +137,33 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { mPreviewToggle = (ToggleButton) findViewById(R.id.start_preview); mPreviewToggle.setOnClickListener(mPreviewToggleListener); + mAutofocusModeSpinner = (Spinner) findViewById(R.id.af_mode_spinner); + mAutofocusModeSpinner.setOnItemSelectedListener(mAutofocusModeListener); + + mAutofocusButton = (Button) findViewById(R.id.af_button); + mAutofocusButton.setOnClickListener(mAutofocusButtonListener); + mPreviewOnlyControls.add(mAutofocusButton); + + mCancelAutofocusButton = (Button) findViewById(R.id.af_cancel_button); + mCancelAutofocusButton.setOnClickListener(mCancelAutofocusButtonListener); + mPreviewOnlyControls.add(mCancelAutofocusButton); + mSnapshotSizeSpinner = (Spinner) findViewById(R.id.snapshot_size_spinner); mSnapshotSizeSpinner.setOnItemSelectedListener(mSnapshotSizeListener); mTakePictureButton = (Button) findViewById(R.id.take_picture); mTakePictureButton.setOnClickListener(mTakePictureListener); + mPreviewOnlyControls.add(mTakePictureButton); mCamcorderProfileSpinner = (Spinner) findViewById(R.id.camcorder_profile_spinner); mCamcorderProfileSpinner.setOnItemSelectedListener(mCamcorderProfileListener); mRecordToggle = (ToggleButton) findViewById(R.id.start_record); mRecordToggle.setOnClickListener(mRecordToggleListener); + mPreviewOnlyControls.add(mRecordToggle); - // TODO: Implement recording support - mRecordToggle.setVisibility(View.GONE); + mLogView = (TextView) findViewById(R.id.log); + mLogView.setMovementMethod(new ScrollingMovementMethod()); int numCameras = Camera.getNumberOfCameras(); String[] cameraNames = new String[numCameras]; @@ -138,6 +179,7 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { @Override public void onResume() { super.onResume(); + log("onResume: Setting up camera"); mPreviewHolder = null; setUpCamera(); } @@ -145,41 +187,43 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { @Override public void onPause() { super.onPause(); - + log("onPause: Releasing camera"); mCamera.release(); mState = CAMERA_UNINITIALIZED; } - // SurfaceHolder.Callback methods - @Override + /** SurfaceHolder.Callback methods */ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mPreviewHolder != null) return; - Log.d(TAG, "Surface holder available: " + width + " x " + height); + log("Surface holder available: " + width + " x " + height); mPreviewHolder = holder; try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { - Log.e(TAG, "Unable to set up preview!"); + logE("Unable to set up preview!"); } - resizePreview(mPreviewSizes.get(mPreviewSize).width, - mPreviewSizes.get(mPreviewSize).height); } - @Override public void surfaceCreated(SurfaceHolder holder) { } - @Override public void surfaceDestroyed(SurfaceHolder holder) { + mPreviewHolder = null; + } + /** UI controls enable/disable */ + private void enablePreviewOnlyControls(boolean enabled) { + for (View v : mPreviewOnlyControls) { + v.setEnabled(enabled); + } } - // UI listeners + /** UI listeners */ private AdapterView.OnItemSelectedListener mCameraSpinnerListener = new AdapterView.OnItemSelectedListener() { @@ -191,13 +235,12 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { } } - public void onNothingSelected(AdapterView parent) { + public void onNothingSelected(AdapterView<?> parent) { } }; private OnClickListener mInfoButtonListener = new OnClickListener() { - @Override public void onClick(View v) { FragmentManager fm = getFragmentManager(); InfoDialogFragment infoDialog = new InfoDialogFragment(); @@ -208,13 +251,11 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { private AdapterView.OnItemSelectedListener mPreviewSizeListener = new AdapterView.OnItemSelectedListener() { - @Override public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { if (pos == mPreviewSize) return; - Log.d(TAG, "Switching preview sizes"); - if (mState == CAMERA_PREVIEW) { + log("Stopping preview to switch resolutions"); mCamera.stopPreview(); } @@ -223,15 +264,18 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { int height = mPreviewSizes.get(mPreviewSize).height; mParams.setPreviewSize(width, height); + log("Setting preview size to " + width + "x" + height); + mCamera.setParameters(mParams); - resizePreview(width, height); if (mState == CAMERA_PREVIEW) { + log("Restarting preview"); + resizePreview(width, height); mCamera.startPreview(); } } - public void onNothingSelected(AdapterView parent) { + public void onNothingSelected(AdapterView<?> parent) { } }; @@ -240,42 +284,92 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { new View.OnClickListener() { public void onClick(View v) { if (mState == CAMERA_TAKE_PICTURE) { - Log.e(TAG, "Can't change preview state while taking picture!"); + logE("Can't change preview state while taking picture!"); return; } if (mPreviewToggle.isChecked()) { - Log.d(TAG, "Starting preview"); - + log("Starting preview"); + resizePreview(mPreviewSizes.get(mPreviewSize).width, + mPreviewSizes.get(mPreviewSize).height); mCamera.startPreview(); mState = CAMERA_PREVIEW; - - mTakePictureButton.setEnabled(true); + enablePreviewOnlyControls(true); } else { - Log.d(TAG, "Stopping preview"); + log("Stopping preview"); mCamera.stopPreview(); mState = CAMERA_OPEN; - mTakePictureButton.setEnabled(false); + enablePreviewOnlyControls(false); } } }; + private OnItemSelectedListener mAutofocusModeListener = + new OnItemSelectedListener() { + public void onItemSelected(AdapterView<?> parent, + View view, int pos, long id) { + if (pos == mAfMode) return; + + mAfMode = pos; + String focusMode = mAfModes.get(mAfMode); + log("Setting focus mode to " + focusMode); + mParams.setFocusMode(focusMode); + + mCamera.setParameters(mParams); + } + + public void onNothingSelected(AdapterView<?> arg0) { + + } + }; + + private OnClickListener mAutofocusButtonListener = + new View.OnClickListener() { + public void onClick(View v) { + log("Triggering autofocus"); + mCamera.autoFocus(mAutofocusCallback); + } + }; + + private OnClickListener mCancelAutofocusButtonListener = + new View.OnClickListener() { + public void onClick(View v) { + log("Cancelling autofocus"); + mCamera.cancelAutoFocus(); + } + }; + + private Camera.AutoFocusCallback mAutofocusCallback = + new Camera.AutoFocusCallback() { + public void onAutoFocus(boolean success, Camera camera) { + log("Autofocus completed: " + (success ? "success" : "failure") ); + } + }; + + private Camera.AutoFocusMoveCallback mAutofocusMoveCallback = + new Camera.AutoFocusMoveCallback() { + public void onAutoFocusMoving(boolean start, Camera camera) { + log("Autofocus movement: " + (start ? "starting" : "stopped") ); + } + }; + private AdapterView.OnItemSelectedListener mSnapshotSizeListener = - new AdapterView.OnItemSelectedListener() { + new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { if (pos == mSnapshotSize) return; - Log.d(TAG, "Switching snapshot sizes"); mSnapshotSize = pos; int width = mSnapshotSizes.get(mSnapshotSize).width; int height = mSnapshotSizes.get(mSnapshotSize).height; + log("Setting snapshot size to " + width + " x " + height); + mParams.setPictureSize(width, height); mCamera.setParameters(mParams); } - public void onNothingSelected(AdapterView parent) { + public void onNothingSelected(AdapterView<?> parent) { } }; @@ -283,17 +377,15 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { private View.OnClickListener mTakePictureListener = new View.OnClickListener() { public void onClick(View v) { - Log.d(TAG, "Taking picture"); + log("Taking picture"); if (mState == CAMERA_PREVIEW) { mState = CAMERA_TAKE_PICTURE; - - mTakePictureButton.setEnabled(false); - mPreviewToggle.setEnabled(false); + enablePreviewOnlyControls(false); mPreviewToggle.setChecked(false); mCamera.takePicture(mShutterCb, mRawCb, mPostviewCb, mJpegCb); } else { - Log.e(TAG, "Can't take picture while not running preview!"); + logE("Can't take picture while not running preview!"); } } }; @@ -302,41 +394,53 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { - mCamcorderProfile = pos; + if (pos == mCamcorderProfile) return; + + log("Setting camcorder profile to " + ((TextView)view).getText()); + mCamcorderProfile = pos; } - public void onNothingSelected(AdapterView parent) { + public void onNothingSelected(AdapterView<?> parent) { } }; private View.OnClickListener mRecordToggleListener = - new View.OnClickListener() { + new View.OnClickListener() { public void onClick(View v) { + mPreviewToggle.setEnabled(false); + if (mState == CAMERA_PREVIEW) { + startRecording(); + } else if (mState == CAMERA_RECORD) { + stopRecording(); + } else { + logE("Can't toggle recording in current state!"); + } + mPreviewToggle.setEnabled(true); } }; private Camera.ShutterCallback mShutterCb = new Camera.ShutterCallback() { public void onShutter() { - Log.d(TAG, "Shutter cb fired"); + log("Shutter callback received"); } }; private Camera.PictureCallback mRawCb = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { - Log.d(TAG, "Raw cb fired"); + log("Raw callback received"); } }; private Camera.PictureCallback mPostviewCb = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { - Log.d(TAG, "Postview cb fired"); + log("Postview callback received"); } }; private Camera.PictureCallback mJpegCb = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { - Log.d(TAG, "JPEG cb fired"); + log("JPEG picture callback received"); FragmentManager fm = getFragmentManager(); SnapshotDialogFragment snapshotDialog = new SnapshotDialogFragment(); @@ -353,139 +457,176 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { // Internal methods void setUpCamera() { - Log.d(TAG, "Setting up camera " + mCameraId); + log("Setting up camera " + mCameraId); + logIndent(1); if (mState >= CAMERA_OPEN) { - Log.d(TAG, "Closing old camera"); + log("Closing old camera"); mCamera.release(); mState = CAMERA_UNINITIALIZED; } - Log.d(TAG, "Opening camera " + mCameraId); + log("Opening camera " + mCameraId); mCamera = Camera.open(mCameraId); mState = CAMERA_OPEN; mParams = mCamera.getParameters(); // Set up preview size selection - mPreviewSizes = mParams.getSupportedPreviewSizes(); + + log("Configuring camera"); + logIndent(1); + + updatePreviewSizes(mParams); + updateAfModes(mParams); + updateSnapshotSizes(mParams); + updateCamcorderProfile(mCameraId); + + // Update parameters based on above updates + mCamera.setParameters(mParams); + + mCamera.setAutoFocusMoveCallback(mAutofocusMoveCallback); + + if (mPreviewHolder != null) { + log("Setting preview display"); + try { + mCamera.setPreviewDisplay(mPreviewHolder); + } catch(IOException e) { + Log.e(TAG, "Unable to set up preview!"); + } + } + + logIndent(-1); + + mPreviewToggle.setEnabled(true); + mPreviewToggle.setChecked(false); + enablePreviewOnlyControls(false); + + int width = mPreviewSizes.get(mPreviewSize).width; + int height = mPreviewSizes.get(mPreviewSize).height; + resizePreview(width, height); + if (mPreviewToggle.isChecked()) { + log("Starting preview" ); + mCamera.startPreview(); + mState = CAMERA_PREVIEW; + } + logIndent(-1); + } + + private void updateAfModes(Parameters params) { + mAfModes = params.getSupportedFocusModes(); + + mAutofocusModeSpinner.setAdapter( + new ArrayAdapter<String>(this, R.layout.spinner_item, + mAfModes.toArray(new String[0]))); + + mAfMode = 0; + + params.setFocusMode(mAfModes.get(mAfMode)); + + log("Setting AF mode to " + mAfModes.get(mAfMode)); + } + + private void updatePreviewSizes(Camera.Parameters params) { + mPreviewSizes = params.getSupportedPreviewSizes(); String[] availableSizeNames = new String[mPreviewSizes.size()]; int i = 0; for (Camera.Size previewSize: mPreviewSizes) { availableSizeNames[i++] = - Integer.toString(previewSize.width) + " x " + - Integer.toString(previewSize.height); + Integer.toString(previewSize.width) + " x " + + Integer.toString(previewSize.height); } mPreviewSizeSpinner.setAdapter( - new ArrayAdapter<String>( - this, R.layout.spinner_item, availableSizeNames)); + new ArrayAdapter<String>( + this, R.layout.spinner_item, availableSizeNames)); mPreviewSize = 0; int width = mPreviewSizes.get(mPreviewSize).width; int height = mPreviewSizes.get(mPreviewSize).height; - mParams.setPreviewSize(width, height); - - // Set up snapshot size selection + params.setPreviewSize(width, height); + log("Setting preview size to " + width + " x " + height); + } - mSnapshotSizes = mParams.getSupportedPictureSizes(); + private void updateSnapshotSizes(Camera.Parameters params) { + String[] availableSizeNames; + mSnapshotSizes = params.getSupportedPictureSizes(); availableSizeNames = new String[mSnapshotSizes.size()]; - i = 0; + int i = 0; for (Camera.Size snapshotSize : mSnapshotSizes) { availableSizeNames[i++] = - Integer.toString(snapshotSize.width) + " x " + - Integer.toString(snapshotSize.height); + Integer.toString(snapshotSize.width) + " x " + + Integer.toString(snapshotSize.height); } mSnapshotSizeSpinner.setAdapter( - new ArrayAdapter<String>( - this, R.layout.spinner_item, availableSizeNames)); + new ArrayAdapter<String>( + this, R.layout.spinner_item, availableSizeNames)); mSnapshotSize = 0; - width = mSnapshotSizes.get(mSnapshotSize).width; - height = mSnapshotSizes.get(mSnapshotSize).height; - mParams.setPictureSize(width, height); - - // Set up camcorder profile selection - updateCamcorderProfile(mCameraId); - - // Update parameters based on above defaults - - mCamera.setParameters(mParams); - - if (mPreviewHolder != null) { - try { - mCamera.setPreviewDisplay(mPreviewHolder); - } catch(IOException e) { - Log.e(TAG, "Unable to set up preview!"); - } - } - - mPreviewToggle.setEnabled(true); - mPreviewToggle.setChecked(false); - mTakePictureButton.setEnabled(false); - - resizePreview(width, height); - if (mPreviewToggle.isChecked()) { - Log.d(TAG, "Starting preview" ); - mCamera.startPreview(); - mState = CAMERA_PREVIEW; - } + int snapshotWidth = mSnapshotSizes.get(mSnapshotSize).width; + int snapshotHeight = mSnapshotSizes.get(mSnapshotSize).height; + params.setPictureSize(snapshotWidth, snapshotHeight); + log("Setting snapshot size to " + snapshotWidth + " x " + snapshotHeight); } private void updateCamcorderProfile(int cameraId) { // Have to query all of these individually, final int PROFILES[] = new int[] { - CamcorderProfile.QUALITY_1080P, - CamcorderProfile.QUALITY_480P, - CamcorderProfile.QUALITY_720P, - CamcorderProfile.QUALITY_CIF, - CamcorderProfile.QUALITY_HIGH, - CamcorderProfile.QUALITY_LOW, - CamcorderProfile.QUALITY_QCIF, - CamcorderProfile.QUALITY_QVGA, - CamcorderProfile.QUALITY_TIME_LAPSE_1080P, - CamcorderProfile.QUALITY_TIME_LAPSE_480P, - CamcorderProfile.QUALITY_TIME_LAPSE_720P, - CamcorderProfile.QUALITY_TIME_LAPSE_CIF, - CamcorderProfile.QUALITY_TIME_LAPSE_HIGH, - CamcorderProfile.QUALITY_TIME_LAPSE_LOW, - CamcorderProfile.QUALITY_TIME_LAPSE_QCIF, - CamcorderProfile.QUALITY_TIME_LAPSE_QVGA + CamcorderProfile.QUALITY_1080P, + CamcorderProfile.QUALITY_480P, + CamcorderProfile.QUALITY_720P, + CamcorderProfile.QUALITY_CIF, + CamcorderProfile.QUALITY_HIGH, + CamcorderProfile.QUALITY_LOW, + CamcorderProfile.QUALITY_QCIF, + CamcorderProfile.QUALITY_QVGA, + CamcorderProfile.QUALITY_TIME_LAPSE_1080P, + CamcorderProfile.QUALITY_TIME_LAPSE_480P, + CamcorderProfile.QUALITY_TIME_LAPSE_720P, + CamcorderProfile.QUALITY_TIME_LAPSE_CIF, + CamcorderProfile.QUALITY_TIME_LAPSE_HIGH, + CamcorderProfile.QUALITY_TIME_LAPSE_LOW, + CamcorderProfile.QUALITY_TIME_LAPSE_QCIF, + CamcorderProfile.QUALITY_TIME_LAPSE_QVGA }; final String PROFILE_NAMES[] = new String[] { - "1080P", - "480P", - "720P", - "CIF", - "HIGH", - "LOW", - "QCIF", - "QVGA", - "TIME_LAPSE_1080P", - "TIME_LAPSE_480P", - "TIME_LAPSE_720P", - "TIME_LAPSE_CIF", - "TIME_LAPSE_HIGH", - "TIME_LAPSE_LOW", - "TIME_LAPSE_QCIF", - "TIME_LAPSE_QVGA" + "1080P", + "480P", + "720P", + "CIF", + "HIGH", + "LOW", + "QCIF", + "QVGA", + "TIME_LAPSE_1080P", + "TIME_LAPSE_480P", + "TIME_LAPSE_720P", + "TIME_LAPSE_CIF", + "TIME_LAPSE_HIGH", + "TIME_LAPSE_LOW", + "TIME_LAPSE_QCIF", + "TIME_LAPSE_QVGA" }; List<String> availableCamcorderProfileNames = new ArrayList<String>(); mCamcorderProfiles = new ArrayList<CamcorderProfile>(); for (int i = 0; i < PROFILES.length; i++) { - if (CamcorderProfile.hasProfile(cameraId, PROFILES[i])) { - availableCamcorderProfileNames.add(PROFILE_NAMES[i]); - mCamcorderProfiles.add(CamcorderProfile.get(cameraId, PROFILES[i])); - } + if (CamcorderProfile.hasProfile(cameraId, PROFILES[i])) { + availableCamcorderProfileNames.add(PROFILE_NAMES[i]); + mCamcorderProfiles.add(CamcorderProfile.get(cameraId, PROFILES[i])); + } } String[] nameArray = (String[])availableCamcorderProfileNames.toArray(new String[0]); mCamcorderProfileSpinner.setAdapter( - new ArrayAdapter<String>( - this, R.layout.spinner_item, nameArray)); + new ArrayAdapter<String>( + this, R.layout.spinner_item, nameArray)); + + mCamcorderProfile = 0; + log("Setting camcorder profile to " + nameArray[mCamcorderProfile]); + } void resizePreview(int width, int height) { @@ -498,4 +639,161 @@ public class TestingCamera extends Activity implements SurfaceHolder.Callback { } } + + static final int MEDIA_TYPE_IMAGE = 0; + static final int MEDIA_TYPE_VIDEO = 1; + private File getOutputMediaFile(int type){ + // To be safe, you should check that the SDCard is mounted + // using Environment.getExternalStorageState() before doing this. + + String state = Environment.getExternalStorageState(); + if (!Environment.MEDIA_MOUNTED.equals(state)) { + return null; + } + + File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES), "TestingCamera"); + // This location works best if you want the created images to be shared + // between applications and persist after your app has been uninstalled. + + // Create the storage directory if it does not exist + if (! mediaStorageDir.exists()){ + if (! mediaStorageDir.mkdirs()){ + logE("Failed to create directory for pictures/video"); + return null; + } + } + + // Create a media file name + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + File mediaFile; + if (type == MEDIA_TYPE_IMAGE){ + mediaFile = new File(mediaStorageDir.getPath() + File.separator + + "IMG_"+ timeStamp + ".jpg"); + } else if(type == MEDIA_TYPE_VIDEO) { + mediaFile = new File(mediaStorageDir.getPath() + File.separator + + "VID_"+ timeStamp + ".mp4"); + } else { + return null; + } + + return mediaFile; + } + + private void startRecording() { + log("Starting recording"); + logIndent(1); + log("Configuring MediaRecoder"); + mCamera.unlock(); + mRecorder = new MediaRecorder(); + mRecorder.setOnErrorListener(mRecordingErrorListener); + mRecorder.setOnInfoListener(mRecordingInfoListener); + mRecorder.setCamera(mCamera); + mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setProfile(mCamcorderProfiles.get(mCamcorderProfile)); + File outputFile = getOutputMediaFile(MEDIA_TYPE_VIDEO); + log("File name:" + outputFile.toString()); + mRecorder.setOutputFile(outputFile.toString()); + + boolean ready = false; + log("Preparing MediaRecorder"); + try { + mRecorder.prepare(); + ready = true; + } catch (Exception e) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + logE("Exception preparing MediaRecorder:\n" + writer.toString()); + } + + if (ready) { + try { + log("Starting MediaRecorder"); + mRecorder.start(); + mState = CAMERA_RECORD; + log("Recording active"); + } catch (Exception e) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + logE("Exception starting MediaRecorder:\n" + writer.toString()); + } + } else { + mPreviewToggle.setChecked(false); + } + logIndent(-1); + } + + private MediaRecorder.OnErrorListener mRecordingErrorListener = + new MediaRecorder.OnErrorListener() { + public void onError(MediaRecorder mr, int what, int extra) { + logE("MediaRecorder reports error: " + what + ", extra " + + extra); + if (mState == CAMERA_RECORD) { + stopRecording(); + } + } + }; + + private MediaRecorder.OnInfoListener mRecordingInfoListener = + new MediaRecorder.OnInfoListener() { + public void onInfo(MediaRecorder mr, int what, int extra) { + log("MediaRecorder reports info: " + what + ", extra " + + extra); + } + }; + + private void stopRecording() { + log("Stopping recording"); + if (mRecorder != null) { + mRecorder.stop(); + mCamera.lock(); + mState = CAMERA_PREVIEW; + mRecorder.release(); + mRecorder = null; + } else { + logE("Recorder is unexpectedly null!"); + } + } + + private int mLogIndentLevel = 0; + private String mLogIndent = "\t"; + /** Increment or decrement log indentation level */ + private void logIndent(int delta) { + mLogIndentLevel += delta; + if (mLogIndentLevel < 0) mLogIndentLevel = 0; + char[] mLogIndentArray = new char[mLogIndentLevel + 1]; + for (int i = -1; i < mLogIndentLevel; i++) { + mLogIndentArray[i + 1] = '\t'; + } + mLogIndent = new String(mLogIndentArray); + } + + SimpleDateFormat mDateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); + /** Log both to log text view and to device logcat */ + private void log(String logLine) { + Log.d(TAG, logLine); + logAndScrollToBottom(logLine, mLogIndent); + } + + private void logE(String logLine) { + Log.e(TAG, logLine); + logAndScrollToBottom(logLine, mLogIndent + "!!! "); + } + + private void logAndScrollToBottom(String logLine, String logIndent) { + StringBuffer logEntry = new StringBuffer(32); + logEntry.append("\n").append(mDateFormatter.format(new Date())).append(logIndent); + logEntry.append(logLine); + mLogView.append(logEntry); + final Layout layout = mLogView.getLayout(); + if (layout != null){ + int scrollDelta = layout.getLineBottom(mLogView.getLineCount() - 1) + - mLogView.getScrollY() - mLogView.getHeight(); + if(scrollDelta > 0) { + mLogView.scrollBy(0, scrollDelta); + } + } + } + }
\ No newline at end of file |