add a preview image of the last photo taken
This commit is contained in:
parent
2a2a5cc9c6
commit
f4a779db66
|
@ -12,7 +12,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
||||
public class PhotoProcessor extends AsyncTask<byte[], Void, String> {
|
||||
private static final String TAG = PhotoProcessor.class.getSimpleName();
|
||||
private static WeakReference<MainActivity> mActivity;
|
||||
private static Uri mUri;
|
||||
|
@ -23,7 +23,7 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(byte[]... params) {
|
||||
protected String doInBackground(byte[]... params) {
|
||||
FileOutputStream fos = null;
|
||||
String path;
|
||||
try {
|
||||
|
@ -34,7 +34,7 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
}
|
||||
|
||||
if (path.isEmpty()) {
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
|
||||
final File photoFile = new File(path);
|
||||
|
@ -42,7 +42,7 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
fos = new FileOutputStream(photoFile);
|
||||
fos.write(data);
|
||||
fos.close();
|
||||
Utils.scanFile(path, mActivity.get().getApplicationContext());
|
||||
return photoFile.getAbsolutePath();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "PhotoProcessor file not found: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
|
@ -57,19 +57,19 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
protected void onPostExecute(String path) {
|
||||
super.onPostExecute(path);
|
||||
final MediaSavedListener listener = mActivity.get();
|
||||
if (listener != null) {
|
||||
listener.mediaSaved();
|
||||
listener.mediaSaved(path);
|
||||
}
|
||||
}
|
||||
|
||||
public interface MediaSavedListener {
|
||||
void mediaSaved();
|
||||
void mediaSaved(String path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -621,7 +621,7 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
try {
|
||||
mRecorder.stop();
|
||||
final String[] paths = {mCurVideoPath};
|
||||
MediaScannerConnection.scanFile(getContext(), paths, null, mIsVideoCaptureIntent ? this : null);
|
||||
MediaScannerConnection.scanFile(getContext(), paths, null, this);
|
||||
} catch (RuntimeException e) {
|
||||
new File(mCurVideoPath).delete();
|
||||
Utils.showToast(getContext(), R.string.video_saving_error);
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.content.pm.PackageManager;
|
|||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.Camera;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.Display;
|
||||
|
@ -85,11 +84,6 @@ public class Utils {
|
|||
return Environment.getExternalStoragePublicDirectory(type);
|
||||
}
|
||||
|
||||
public static void scanFile(String path, Context context) {
|
||||
final String[] paths = {path};
|
||||
MediaScannerConnection.scanFile(context, paths, null, null);
|
||||
}
|
||||
|
||||
public static String formatSeconds(int duration) {
|
||||
final StringBuilder sb = new StringBuilder(8);
|
||||
final int hours = duration / (60 * 60);
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package com.simplemobiletools.camera.activities;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
@ -41,7 +47,8 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements SensorEventListener, PreviewListener, PhotoProcessor.MediaSavedListener {
|
||||
public class MainActivity extends AppCompatActivity
|
||||
implements SensorEventListener, PreviewListener, PhotoProcessor.MediaSavedListener, MediaScannerConnection.OnScanCompletedListener {
|
||||
@BindView(R.id.viewHolder) RelativeLayout mViewHolder;
|
||||
@BindView(R.id.toggle_camera) ImageView mToggleCameraBtn;
|
||||
@BindView(R.id.toggle_flash) ImageView mToggleFlashBtn;
|
||||
|
@ -49,13 +56,16 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
@BindView(R.id.shutter) ImageView mShutterBtn;
|
||||
@BindView(R.id.video_rec_curr_timer) TextView mRecCurrTimer;
|
||||
@BindView(R.id.about) View mAboutBtn;
|
||||
@BindView(R.id.last_photo_video_preview) ImageView mLastPhotoVideoPreview;
|
||||
|
||||
private static final String TAG = MainActivity.class.getSimpleName();
|
||||
private static final int CAMERA_STORAGE_PERMISSION = 1;
|
||||
private static final int AUDIO_PERMISSION = 2;
|
||||
|
||||
private static SensorManager mSensorManager;
|
||||
private static Preview mPreview;
|
||||
private static Handler mTimerHandler;
|
||||
private static Uri mPreviewUri;
|
||||
|
||||
private static boolean mIsFlashEnabled;
|
||||
private static boolean mIsInPhotoMode;
|
||||
|
@ -153,6 +163,7 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
|
||||
mIsInPhotoMode = true;
|
||||
mTimerHandler = new Handler();
|
||||
setupPreviewImage(true);
|
||||
}
|
||||
|
||||
private boolean hasCameraAndStoragePermission() {
|
||||
|
@ -209,6 +220,25 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.last_photo_video_preview)
|
||||
public void showLastMediaPreview() {
|
||||
if (mPreviewUri == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
final String REVIEW_ACTION = "com.android.camera.action.REVIEW";
|
||||
Intent intent = new Intent(REVIEW_ACTION, mPreviewUri);
|
||||
this.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, mPreviewUri);
|
||||
if (intent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivity(intent);
|
||||
} else {
|
||||
Utils.showToast(getApplicationContext(), R.string.no_gallery_app_available);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.toggle_flash)
|
||||
public void toggleFlash() {
|
||||
if (!checkCameraAvailable()) {
|
||||
|
@ -304,7 +334,7 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
if (mIsInPhotoMode) {
|
||||
initPhotoButtons();
|
||||
} else {
|
||||
initVideoButtons();
|
||||
tryInitVideoButtons();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,11 +343,12 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
mTogglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.videocam));
|
||||
mShutterBtn.setImageDrawable(res.getDrawable(R.mipmap.camera));
|
||||
mPreview.initPhotoMode();
|
||||
setupPreviewImage(true);
|
||||
}
|
||||
|
||||
private void initVideoButtons() {
|
||||
private void tryInitVideoButtons() {
|
||||
if (mPreview.initRecorder()) {
|
||||
setupVideoIcons();
|
||||
initVideoButtons();
|
||||
} else {
|
||||
if (!mIsVideoCaptureIntent) {
|
||||
Utils.showToast(getApplicationContext(), R.string.video_mode_error);
|
||||
|
@ -325,12 +356,88 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
}
|
||||
}
|
||||
|
||||
private void setupVideoIcons() {
|
||||
private void initVideoButtons() {
|
||||
final Resources res = getResources();
|
||||
mTogglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.photo));
|
||||
mToggleCameraBtn.setVisibility(View.VISIBLE);
|
||||
mShutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
|
||||
checkFlash();
|
||||
setupPreviewImage(false);
|
||||
}
|
||||
|
||||
private void setupPreviewImage(boolean isPhoto) {
|
||||
final Uri uri = (isPhoto) ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
final long lastMediaId = getLastMediaId(uri);
|
||||
if (lastMediaId == 0) {
|
||||
return;
|
||||
}
|
||||
final ContentResolver cr = getContentResolver();
|
||||
mPreviewUri = Uri.withAppendedPath(uri, String.valueOf(lastMediaId));
|
||||
Bitmap tmb;
|
||||
|
||||
if (isPhoto) {
|
||||
tmb = MediaStore.Images.Thumbnails.getThumbnail(cr, lastMediaId, MediaStore.Images.Thumbnails.MICRO_KIND, null);
|
||||
final int rotationDegrees = getImageRotation();
|
||||
tmb = rotateThumbnail(tmb, rotationDegrees);
|
||||
} else {
|
||||
tmb = MediaStore.Video.Thumbnails.getThumbnail(cr, lastMediaId, MediaStore.Video.Thumbnails.MICRO_KIND, null);
|
||||
}
|
||||
|
||||
setPreviewImage(tmb);
|
||||
}
|
||||
|
||||
private int getImageRotation() {
|
||||
final String[] projection = {MediaStore.Images.ImageColumns.ORIENTATION};
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int orientationIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);
|
||||
return cursor.getInt(orientationIndex);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Bitmap rotateThumbnail(Bitmap tmb, int degrees) {
|
||||
if (degrees == 0)
|
||||
return tmb;
|
||||
|
||||
final Matrix matrix = new Matrix();
|
||||
matrix.setRotate(degrees, tmb.getWidth() / 2, tmb.getHeight() / 2);
|
||||
return Bitmap.createBitmap(tmb, 0, 0, tmb.getWidth(), tmb.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
private void setPreviewImage(final Bitmap bmp) {
|
||||
if (bmp != null) {
|
||||
mLastPhotoVideoPreview.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mLastPhotoVideoPreview.setImageBitmap(bmp);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private long getLastMediaId(Uri uri) {
|
||||
final String[] projection = {MediaStore.Images.ImageColumns._ID};
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = getContentResolver().query(uri, projection, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int idIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID);
|
||||
return cursor.getLong(idIndex);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void hideNavigationBarIcons() {
|
||||
|
@ -364,6 +471,7 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
super.onResume();
|
||||
if (hasCameraAndStoragePermission()) {
|
||||
resumeCameraItems();
|
||||
setupPreviewImage(mIsInPhotoMode);
|
||||
|
||||
if (mIsVideoCaptureIntent && mIsInPhotoMode) {
|
||||
togglePhotoVideo();
|
||||
|
@ -387,7 +495,7 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
}
|
||||
|
||||
if (!mIsInPhotoMode) {
|
||||
setupVideoIcons();
|
||||
initVideoButtons();
|
||||
}
|
||||
} else {
|
||||
Utils.showToast(getApplicationContext(), R.string.camera_switch_error);
|
||||
|
@ -461,6 +569,7 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
|
||||
@Override
|
||||
public void videoSaved(Uri uri) {
|
||||
setupPreviewImage(mIsInPhotoMode);
|
||||
if (mIsVideoCaptureIntent) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setData(uri);
|
||||
|
@ -471,7 +580,10 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
}
|
||||
|
||||
@Override
|
||||
public void mediaSaved() {
|
||||
public void mediaSaved(String path) {
|
||||
final String[] paths = {path};
|
||||
MediaScannerConnection.scanFile(getApplicationContext(), paths, null, this);
|
||||
|
||||
if (mIsImageCaptureIntent) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
|
@ -485,4 +597,9 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
if (mPreview != null)
|
||||
mPreview.releaseCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanCompleted(String path, Uri uri) {
|
||||
setupPreviewImage(mIsInPhotoMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_margin="@dimen/side_icon_padding"
|
||||
android:layout_marginRight="@dimen/side_icon_padding"
|
||||
android:layout_marginTop="@dimen/side_icon_padding"
|
||||
android:padding="@dimen/side_icon_padding"
|
||||
android:src="@mipmap/about"/>
|
||||
|
||||
|
@ -30,6 +31,15 @@
|
|||
android:padding="@dimen/side_icon_padding"
|
||||
android:src="@mipmap/videocam"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/last_photo_video_preview"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_below="@+id/toggle_photo_video"
|
||||
android:layout_marginRight="@dimen/side_icon_padding"
|
||||
android:padding="@dimen/side_preview_padding"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/btn_holder"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<resources>
|
||||
<dimen name="side_icon_padding">12dp</dimen>
|
||||
<dimen name="icon_size">64dp</dimen>
|
||||
<dimen name="settings_padding">12dp</dimen>
|
||||
<dimen name="social_padding">12dp</dimen>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<dimen name="activity_margin">16dp</dimen>
|
||||
<dimen name="preview_btn_margin">32dp</dimen>
|
||||
<dimen name="side_icon_padding">12dp</dimen>
|
||||
<dimen name="side_preview_padding">8dp</dimen>
|
||||
<dimen name="icon_size">56dp</dimen>
|
||||
<dimen name="settings_padding">8dp</dimen>
|
||||
<dimen name="social_padding">8dp</dimen>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<string name="camera_switch_error">Switching camera failed</string>
|
||||
<string name="no_permissions">Not much to do without accessing your camera and storage</string>
|
||||
<string name="no_audio_permissions">We need the audio permission for recording videos</string>
|
||||
<string name="no_gallery_app_available">No gallery app available</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="settings">Settings</string>
|
||||
|
|
Loading…
Reference in New Issue