aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnirudh Dewani <anirudhd@google.com>2013-09-10 07:31:26 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2013-09-10 07:31:26 -0700
commit86e6edc9f6faa35d841c684286450bc70d190c27 (patch)
treee2a89c3e427d9af663d0399b5aa0f61e7ffa3f7a
parent98b30fb56e0cf321caea1e8a0796cea572bacea7 (diff)
parentd947052240089b1a45d66eeea23e6cf34d94d632 (diff)
downloadandroid-86e6edc9f6faa35d841c684286450bc70d190c27.tar.gz
* commit 'd947052240089b1a45d66eeea23e6cf34d94d632': BasicMediaRecorder initial implementation
-rw-r--r--common/src/com/example/android/common/media/CameraHelper.java182
-rw-r--r--media/MediaRecorder/MediaRecorder/build.gradle10
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/AndroidManifest.xml51
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/java/com/example/android/media/recorder/MainActivity.java237
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 4512 bytes
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 2719 bytes
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6345 bytes
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11620 bytes
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/layout/activity_main.xml24
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/menu/main.xml6
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values-sw600dp/dimens.xml4
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values-sw720dp-land/dimens.xml5
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values-v11/styles.xml11
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values-v14/styles.xml12
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values/dimens.xml5
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values/strings.xml9
-rw-r--r--media/MediaRecorder/MediaRecorder/src/main/res/values/styles.xml20
-rw-r--r--media/MediaRecorder/build.gradle9
-rw-r--r--media/MediaRecorder/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xmedia/MediaRecorder/gradlew164
-rw-r--r--media/MediaRecorder/gradlew.bat90
-rw-r--r--media/MediaRecorder/settings.gradle1
23 files changed, 846 insertions, 0 deletions
diff --git a/common/src/com/example/android/common/media/CameraHelper.java b/common/src/com/example/android/common/media/CameraHelper.java
new file mode 100644
index 00000000..1fa84167
--- /dev/null
+++ b/common/src/com/example/android/common/media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+ public static final int MEDIA_TYPE_IMAGE = 1;
+ public static final int MEDIA_TYPE_VIDEO = 2;
+
+ /**
+ * Iterate over supported camera preview sizes to see which one best fits the
+ * dimensions of the given view while maintaining the aspect ratio. If none can,
+ * be lenient with the aspect ratio.
+ *
+ * @param sizes Supported camera preview sizes.
+ * @param w The width of the view.
+ * @param h The height of the view.
+ * @return Best match camera preview size to fit in the view.
+ */
+ public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+ // Use a very small tolerance because we want an exact match.
+ final double ASPECT_TOLERANCE = 0.1;
+ double targetRatio = (double) w / h;
+ if (sizes == null)
+ return null;
+
+ Camera.Size optimalSize = null;
+
+ // Start with max value and refine as we iterate over available preview sizes. This is the
+ // minimum difference between view and camera height.
+ double minDiff = Double.MAX_VALUE;
+
+ // Target view height
+ int targetHeight = h;
+
+ // Try to find a preview size that matches aspect ratio and the target view size.
+ // Iterate over all available sizes and pick the largest size that can fit in the view and
+ // still maintain the aspect ratio.
+ for (Camera.Size size : sizes) {
+ double ratio = (double) size.width / size.height;
+ if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+ continue;
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+
+ // Cannot find preview size that matches the aspect ratio, ignore the requirement
+ if (optimalSize == null) {
+ minDiff = Double.MAX_VALUE;
+ for (Camera.Size size : sizes) {
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+ }
+ return optimalSize;
+ }
+
+ /**
+ * @return the default camera on the device. Return null if there is no camera on the device.
+ */
+ public static Camera getDefaultCameraInstance() {
+ return Camera.open();
+ }
+
+
+ /**
+ * @return the default rear/back facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultBackFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+ }
+
+ /**
+ * @return the default front facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultFrontFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+ }
+
+
+ /**
+ *
+ * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+ * or Camera.CameraInfo.CAMERA_FACING_BACK.
+ * @return the default camera on the device. Returns null if camera is not available.
+ */
+ @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+ private static Camera getDefaultCamera(int position) {
+ // Find the total number of cameras available
+ int mNumberOfCameras = Camera.getNumberOfCameras();
+
+ // Find the ID of the back-facing ("default") camera
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == position) {
+ return Camera.open(i);
+
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+ * is persistent and available to other applications like gallery.
+ *
+ * @param type Media type. Can be video or image.
+ * @return A file object pointing to the newly created file.
+ */
+ public static File getOutputMediaFile(int type){
+ // To be safe, you should check that the SDCard is mounted
+ // using Environment.getExternalStorageState() before doing this.
+ if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+ return null;
+ }
+
+ File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES), "CameraSample");
+ // 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()) {
+ Log.d("CameraSample", "failed to create directory");
+ 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;
+ }
+
+}
diff --git a/media/MediaRecorder/MediaRecorder/build.gradle b/media/MediaRecorder/MediaRecorder/build.gradle
new file mode 100644
index 00000000..10fb8116
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/build.gradle
@@ -0,0 +1,10 @@
+apply plugin: 'android'
+
+dependencies {
+ compile "com.android.support:support-v4:18.0.+"
+}
+
+android {
+ compileSdkVersion 18
+ buildToolsVersion "18.0.1"
+}
diff --git a/media/MediaRecorder/MediaRecorder/src/main/AndroidManifest.xml b/media/MediaRecorder/MediaRecorder/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..038b1fd1
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.media.recorder"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="14"
+ android:targetSdkVersion="17" />
+
+ <!-- This app records A/V content from camera and stores it to disk -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.RECORD_VIDEO" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-feature android:name="android.hardware.camera" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <!-- Since this sample records video from camera preview, locking the orientation to
+ landscape. Landscape mode offers us more preview space with standard video aspect
+ ratios (width > height) -->
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/java/com/example/android/media/recorder/MainActivity.java b/media/MediaRecorder/MediaRecorder/src/main/java/com/example/android/media/recorder/MainActivity.java
new file mode 100644
index 00000000..d50b53ea
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/java/com/example/android/media/recorder/MainActivity.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.media.recorder;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.media.CamcorderProfile;
+import android.media.MediaRecorder;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.app.Activity;
+import android.util.Log;
+import android.view.Menu;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.Button;
+
+import com.example.android.common.media.CameraHelper;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This activity uses the camera/camcorder as the A/V source for the {@link MediaRecorder} API.
+ * A {@link TextureView} is used as the camera preview which limits the code to API 14+. This
+ * can be easily replaced with a {@link android.view.SurfaceView} to run on older devices.
+ */
+public class MainActivity extends Activity {
+
+ private Camera mCamera;
+ private TextureView mPreview;
+ private MediaRecorder mMediaRecorder;
+
+ private boolean isRecording = false;
+ private static final String TAG = "Recorder";
+ private Button captureButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mPreview = (TextureView) findViewById(R.id.surface_view);
+ captureButton = (Button) findViewById(R.id.button_capture);
+ }
+
+ /**
+ * The capture button controls all user interaction. When recording, the button click
+ * stops recording, releases {@link MediaRecorder} and {@link Camera}. When not recording,
+ * it prepares the {@link MediaRecorder} and starts recording.
+ *
+ * @param view the view generating the event.
+ */
+ public void onCaptureClick(View view) {
+ if (isRecording) {
+ // BEGIN_INCLUDE(stop_release_media_recorder)
+
+ // stop recording and release camera
+ mMediaRecorder.stop(); // stop the recording
+ releaseMediaRecorder(); // release the MediaRecorder object
+ mCamera.lock(); // take camera access back from MediaRecorder
+
+ // inform the user that recording has stopped
+ setCaptureButtonText("Capture");
+ isRecording = false;
+ releaseCamera();
+ // END_INCLUDE(stop_release_media_recorder)
+
+ } else {
+
+ // BEGIN_INCLUDE(prepare_start_media_recorder)
+
+ new MediaPrepareTask().execute(null, null, null);
+
+ // END_INCLUDE(prepare_start_media_recorder)
+
+ }
+ }
+
+ private void setCaptureButtonText(String title) {
+ captureButton.setText(title);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // if we are using MediaRecorder, release it first
+ releaseMediaRecorder();
+ // release the camera immediately on pause event
+ releaseCamera();
+ }
+
+ private void releaseMediaRecorder(){
+ if (mMediaRecorder != null) {
+ // clear recorder configuration
+ mMediaRecorder.reset();
+ // release the recorder object
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ // Lock camera for later use i.e taking it back from MediaRecorder.
+ // MediaRecorder doesn't need it anymore and we will release it if the activity pauses.
+ mCamera.lock();
+ }
+ }
+
+ private void releaseCamera(){
+ if (mCamera != null){
+ // release the camera for other applications
+ mCamera.release();
+ mCamera = null;
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ private boolean prepareVideoRecorder(){
+
+ // BEGIN_INCLUDE (configure_preview)
+ mCamera = CameraHelper.getDefaultCameraInstance();
+
+ // We need to make sure that our preview and recording video size are supported by the
+ // camera. Query camera to find all the sizes and choose the optimal size given the
+ // dimensions of our preview surface.
+ Camera.Parameters parameters = mCamera.getParameters();
+ List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
+ Camera.Size optimalSize = CameraHelper.getOptimalPreviewSize(mSupportedPreviewSizes,
+ mPreview.getWidth(), mPreview.getHeight());
+
+ // Use the same size for recording profile.
+ CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
+ profile.videoFrameWidth = optimalSize.width;
+ profile.videoFrameHeight = optimalSize.height;
+
+ // likewise for the camera object itself.
+ parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
+ mCamera.setParameters(parameters);
+ try {
+ // Requires API level 11+, For backward compatibility use {@link setPreviewDisplay}
+ // with {@link SurfaceView}
+ mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
+ } catch (IOException e) {
+ Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
+ return false;
+ }
+ // END_INCLUDE (configure_preview)
+
+
+ // BEGIN_INCLUDE (configure_media_recorder)
+ mMediaRecorder = new MediaRecorder();
+
+ // Step 1: Unlock and set camera to MediaRecorder
+ mCamera.unlock();
+ mMediaRecorder.setCamera(mCamera);
+
+ // Step 2: Set sources
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT );
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+
+ // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
+ mMediaRecorder.setProfile(profile);
+
+ // Step 4: Set output file
+ mMediaRecorder.setOutputFile(CameraHelper.getOutputMediaFile(
+ CameraHelper.MEDIA_TYPE_VIDEO).toString());
+ // END_INCLUDE (configure_media_recorder)
+
+ // Step 5: Prepare configured MediaRecorder
+ try {
+ mMediaRecorder.prepare();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
+ releaseMediaRecorder();
+ return false;
+ } catch (IOException e) {
+ Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
+ releaseMediaRecorder();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Asynchronous task for preparing the {@link MediaRecorder} since it's a long blocking
+ * operation.
+ */
+ class MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {
+
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ // initialize video camera
+ if (prepareVideoRecorder()) {
+ // Camera is available and unlocked, MediaRecorder is prepared,
+ // now you can start recording
+ mMediaRecorder.start();
+
+ isRecording = true;
+ } else {
+ // prepare didn't work, release the camera
+ releaseMediaRecorder();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (!result) {
+ MainActivity.this.finish();
+ }
+ // inform the user that recording has started
+ setCaptureButtonText("Stop");
+
+ }
+ }
+
+} \ No newline at end of file
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/drawable-hdpi/ic_launcher.png b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..13cd1e8e
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/drawable-mdpi/ic_launcher.png b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..00b2bd9a
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xhdpi/ic_launcher.png b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..953f1cc5
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..f2ccb102
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/layout/activity_main.xml b/media/MediaRecorder/MediaRecorder/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..d53b3764
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/layout/activity_main.xml
@@ -0,0 +1,24 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:orientation="vertical"
+ tools:context=".MainActivity">
+
+ <TextureView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/surface_view" />
+
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/button_capture"
+ android:layout_gravity="bottom"
+ android:onClick="onCaptureClick"
+ android:text="@string/btnCapture"/>
+</FrameLayout>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/menu/main.xml b/media/MediaRecorder/MediaRecorder/src/main/res/menu/main.xml
new file mode 100644
index 00000000..f3b10b6c
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/menu/main.xml
@@ -0,0 +1,6 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/action_settings"
+ android:title="@string/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values-sw600dp/dimens.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 00000000..886b05fa
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,4 @@
+<resources>
+ <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw600dp devices (e.g. 7" tablets) here. -->
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values-sw720dp-land/dimens.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 00000000..00059fc5
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+ <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+ <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values-v11/styles.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values-v11/styles.xml
new file mode 100644
index 00000000..3c02242a
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values-v14/styles.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values-v14/styles.xml
new file mode 100644
index 00000000..a91fd037
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values/dimens.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..47c82246
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values/strings.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values/strings.xml
new file mode 100644
index 00000000..91ab13aa
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">MediaRecorder</string>
+ <string name="action_settings">Settings</string>
+ <string name="hello_world">Hello world!</string>
+ <string name="btnCapture">capture</string>
+
+</resources>
diff --git a/media/MediaRecorder/MediaRecorder/src/main/res/values/styles.xml b/media/MediaRecorder/MediaRecorder/src/main/res/values/styles.xml
new file mode 100644
index 00000000..6ce89c7b
--- /dev/null
+++ b/media/MediaRecorder/MediaRecorder/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
diff --git a/media/MediaRecorder/build.gradle b/media/MediaRecorder/build.gradle
new file mode 100644
index 00000000..bd6967fd
--- /dev/null
+++ b/media/MediaRecorder/build.gradle
@@ -0,0 +1,9 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.5.+'
+ }
+} \ No newline at end of file
diff --git a/media/MediaRecorder/gradle/wrapper/gradle-wrapper.jar b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..8c0fb64a
--- /dev/null
+++ b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..5c22dec0
--- /dev/null
+++ b/media/MediaRecorder/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
diff --git a/media/MediaRecorder/gradlew b/media/MediaRecorder/gradlew
new file mode 100755
index 00000000..91a7e269
--- /dev/null
+++ b/media/MediaRecorder/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/media/MediaRecorder/gradlew.bat b/media/MediaRecorder/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/media/MediaRecorder/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/media/MediaRecorder/settings.gradle b/media/MediaRecorder/settings.gradle
new file mode 100644
index 00000000..3fbbc548
--- /dev/null
+++ b/media/MediaRecorder/settings.gradle
@@ -0,0 +1 @@
+include ':MediaRecorder'