diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4f9de630..26bcfe37 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
android:name="android.hardware.camera"
android:required="true"/>
+
diff --git a/app/src/main/java/com/simplemobiletools/camera/MainActivity.java b/app/src/main/java/com/simplemobiletools/camera/MainActivity.java
index e405f175..ce68dc2f 100644
--- a/app/src/main/java/com/simplemobiletools/camera/MainActivity.java
+++ b/app/src/main/java/com/simplemobiletools/camera/MainActivity.java
@@ -87,7 +87,15 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
if (isPhoto) {
preview.takePicture();
} else {
-
+ final Resources res = getResources();
+ final boolean isRecording = preview.toggleRecording();
+ if (isRecording) {
+ shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_stop));
+ toggleCameraBtn.setVisibility(View.INVISIBLE);
+ } else {
+ shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
+ toggleCameraBtn.setVisibility(View.VISIBLE);
+ }
}
}
@@ -99,18 +107,27 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
@OnClick(R.id.toggle_videocam)
public void toggleVideo() {
- final Resources res = getResources();
isPhoto = !isPhoto;
+ toggleCameraBtn.setVisibility(View.VISIBLE);
if (isPhoto) {
+ final Resources res = getResources();
togglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.videocam));
shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.camera));
+ preview.initPhotoMode();
} else {
- togglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.photo));
- shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
+ initVideo();
}
}
+ private void initVideo() {
+ final Resources res = getResources();
+ togglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.photo));
+ shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
+ preview.initRecorder();
+ toggleCameraBtn.setVisibility(View.VISIBLE);
+ }
+
private void hideNavigationBarIcons() {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
@@ -130,12 +147,19 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
final Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
}
+
+ if (!isPhoto) {
+ preview.initRecorder();
+ initVideo();
+ }
}
@Override
protected void onPause() {
super.onPause();
- preview.releaseCamera();
+ if (preview != null) {
+ preview.releaseCamera();
+ }
if (sensorManager != null)
sensorManager.unregisterListener(this);
diff --git a/app/src/main/java/com/simplemobiletools/camera/PhotoProcessor.java b/app/src/main/java/com/simplemobiletools/camera/PhotoProcessor.java
index 85f88bc2..f68008e7 100644
--- a/app/src/main/java/com/simplemobiletools/camera/PhotoProcessor.java
+++ b/app/src/main/java/com/simplemobiletools/camera/PhotoProcessor.java
@@ -6,17 +6,13 @@ import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.ExifInterface;
-import android.media.MediaScannerConnection;
import android.os.AsyncTask;
-import android.os.Environment;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
public class PhotoProcessor extends AsyncTask {
private static final String TAG = PhotoProcessor.class.getSimpleName();
@@ -30,12 +26,13 @@ public class PhotoProcessor extends AsyncTask {
@Override
protected Void doInBackground(byte[]... params) {
- final File photoFile = getOutputMediaFile();
- if (photoFile == null) {
+ final String photoPath = Utils.getOutputMediaFile(mContext, true);
+ if (photoPath.isEmpty()) {
return null;
}
try {
+ final File photoFile = new File(photoPath);
final byte[] data = params[0];
final FileOutputStream fos = new FileOutputStream(photoFile);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
@@ -45,7 +42,7 @@ public class PhotoProcessor extends AsyncTask {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
- scanPhoto(photoFile);
+ Utils.scanFile(photoPath, mContext);
} catch (FileNotFoundException e) {
Log.d(TAG, "onPictureTaken file not found: " + e.getMessage());
} catch (IOException e) {
@@ -55,20 +52,6 @@ public class PhotoProcessor extends AsyncTask {
return null;
}
- private static File getOutputMediaFile() {
- final String appName = mContext.getResources().getString(R.string.app_name);
- final File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
-
- if (!mediaStorageDir.exists()) {
- if (!mediaStorageDir.mkdirs()) {
- return null;
- }
- }
-
- final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
- return new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
- }
-
private Bitmap setBitmapRotation(Bitmap bitmap, String path) throws IOException {
final ExifInterface exif = new ExifInterface(path);
final String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
@@ -127,9 +110,4 @@ public class PhotoProcessor extends AsyncTask {
}
return bitmap;
}
-
- private void scanPhoto(File photo) {
- final String[] photoPath = {photo.getAbsolutePath()};
- MediaScannerConnection.scanFile(mContext, photoPath, null, null);
- }
}
diff --git a/app/src/main/java/com/simplemobiletools/camera/Preview.java b/app/src/main/java/com/simplemobiletools/camera/Preview.java
index aa7ddb54..f7432fa0 100644
--- a/app/src/main/java/com/simplemobiletools/camera/Preview.java
+++ b/app/src/main/java/com/simplemobiletools/camera/Preview.java
@@ -4,7 +4,9 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
+import android.media.CamcorderProfile;
import android.media.MediaPlayer;
+import android.media.MediaRecorder;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
@@ -34,6 +36,11 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
private static boolean isFlashEnabled;
private static Camera.Parameters parameters;
+ private static MediaRecorder recorder;
+ private static boolean isRecording;
+ private static boolean isVideoMode;
+ private static String curVideoPath;
+
public Preview(Context context) {
super(context);
}
@@ -68,7 +75,6 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
releaseCamera();
camera = newCamera;
-
if (camera != null) {
parameters = camera.getParameters();
supportedPreviewSizes = parameters.getSupportedPreviewSizes();
@@ -90,6 +96,9 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
setupPreview();
}
}
+
+ if (isVideoMode)
+ initRecorder();
}
public static void setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) {
@@ -141,8 +150,9 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
- if (camera != null)
+ if (camera != null) {
camera.startPreview();
+ }
canTakePicture = true;
}
@@ -200,6 +210,8 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
}
public void releaseCamera() {
+ stopRecording();
+
if (camera != null) {
camera.stopPreview();
camera.release();
@@ -240,6 +252,19 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
if (camera != null) {
camera.stopPreview();
}
+
+ cleanupRecorder();
+ }
+
+ private void cleanupRecorder() {
+ if (recorder != null) {
+ if (isRecording) {
+ recorder.stop();
+ }
+
+ recorder.release();
+ recorder = null;
+ }
}
@Override
@@ -307,4 +332,64 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
public void disableFlash() {
isFlashEnabled = false;
}
+
+ public void initPhotoMode() {
+ isRecording = false;
+ isVideoMode = false;
+ stopRecording();
+ cleanupRecorder();
+ }
+
+ // VIDEO RECORDING
+ public void initRecorder() {
+ isRecording = false;
+ isVideoMode = true;
+ recorder = new MediaRecorder();
+ recorder.setCamera(camera);
+ recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
+ recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
+
+ curVideoPath = Utils.getOutputMediaFile(getContext(), false);
+ if (curVideoPath.isEmpty()) {
+ Utils.showToast(getContext(), R.string.video_creating_error);
+ return;
+ }
+
+ final CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
+ recorder.setProfile(cpHigh);
+ recorder.setOutputFile(curVideoPath);
+ recorder.setPreviewDisplay(surfaceHolder.getSurface());
+ recorder.setOrientationHint(90);
+
+ try {
+ recorder.prepare();
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "initRecorder " + e.getMessage());
+ } catch (IOException e) {
+ Log.e(TAG, "initRecorder " + e.getMessage());
+ }
+ }
+
+ public boolean toggleRecording() {
+ if (isRecording) {
+ stopRecording();
+ initRecorder();
+ } else {
+ camera.lock();
+ camera.unlock();
+ recorder.start();
+ isRecording = true;
+ }
+ return isRecording;
+ }
+
+ private void stopRecording() {
+ if (recorder != null && isRecording) {
+ recorder.stop();
+ recorder = null;
+ }
+
+ isRecording = false;
+ Utils.scanFile(curVideoPath, getContext());
+ }
}
diff --git a/app/src/main/java/com/simplemobiletools/camera/Utils.java b/app/src/main/java/com/simplemobiletools/camera/Utils.java
index a8e34252..5a77d25f 100644
--- a/app/src/main/java/com/simplemobiletools/camera/Utils.java
+++ b/app/src/main/java/com/simplemobiletools/camera/Utils.java
@@ -1,10 +1,17 @@
package com.simplemobiletools.camera;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.Camera;
+import android.media.MediaScannerConnection;
+import android.os.Environment;
import android.widget.Toast;
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.List;
+import java.util.Locale;
public class Utils {
public static Camera.CameraInfo getCameraInfo(int cameraId) {
@@ -36,4 +43,38 @@ public class Utils {
return true;
}
+
+ public static String getOutputMediaFile(Context context, boolean isPhoto) {
+ final File mediaStorageDir = getFolderName(context, isPhoto);
+
+ if (!mediaStorageDir.exists()) {
+ if (!mediaStorageDir.mkdirs()) {
+ return "";
+ }
+ }
+
+ final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
+ if (isPhoto) {
+ return mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg";
+ } else {
+ return mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4";
+ }
+ }
+
+ private static File getFolderName(Context context, boolean isPhoto) {
+ final Resources res = context.getResources();
+ final String appName = res.getString(R.string.app_name);
+ final String sharedPath = new File(Environment.getExternalStorageDirectory(), appName).getAbsolutePath();
+ String typeDirectory = res.getString(R.string.photo_directory);
+ if (!isPhoto) {
+ typeDirectory = res.getString(R.string.video_directory);
+ }
+
+ return new File(sharedPath, typeDirectory);
+ }
+
+ public static void scanFile(String path, Context context) {
+ final String[] paths = {path};
+ MediaScannerConnection.scanFile(context, paths, null, null);
+ }
}
diff --git a/app/src/main/res/mipmap-hdpi/video_stop.png b/app/src/main/res/mipmap-hdpi/video_stop.png
new file mode 100644
index 00000000..72847bb3
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/video_stop.png differ
diff --git a/app/src/main/res/mipmap-mdpi/video_stop.png b/app/src/main/res/mipmap-mdpi/video_stop.png
new file mode 100644
index 00000000..e649243a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/video_stop.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/video_stop.png b/app/src/main/res/mipmap-xhdpi/video_stop.png
new file mode 100644
index 00000000..4726160d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/video_stop.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/video_stop.png b/app/src/main/res/mipmap-xxhdpi/video_stop.png
new file mode 100644
index 00000000..c6896893
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/video_stop.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/video_stop.png b/app/src/main/res/mipmap-xxxhdpi/video_stop.png
new file mode 100644
index 00000000..c3670ced
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/video_stop.png differ
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d416ca48..025402ac 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,6 +1,9 @@
Simple Camera
An error occurred at obtaining the camera
+ An error occurred at creating the video file
+ Simple Videos
+ Simple Photos
About