add retake, send actions and preview

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
Andy Scherzinger 2021-09-15 20:09:15 +02:00
parent 547e9ebf8b
commit 67c421a067
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
4 changed files with 174 additions and 21 deletions

View File

@ -190,6 +190,7 @@ dependencies {
implementation 'androidx.camera:camera-camera2:1.0.1'
implementation 'androidx.camera:camera-lifecycle:1.0.1'
implementation 'androidx.camera:camera-view:1.0.0-alpha20'
implementation "androidx.exifinterface:exifinterface:1.3.3"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

View File

@ -24,12 +24,15 @@ package com.nextcloud.talk.activities;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.util.Size;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.View;
import android.widget.Toast;
import com.google.common.util.concurrent.ListenableFuture;
@ -39,6 +42,8 @@ import com.nextcloud.talk.models.TakePictureViewModel;
import com.nextcloud.talk.utils.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@ -53,6 +58,7 @@ import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.core.content.ContextCompat;
import androidx.exifinterface.media.ExifInterface;
import androidx.lifecycle.ViewModelProvider;
public class TakePhotoActivity extends AppCompatActivity {
@ -99,7 +105,7 @@ public class TakePhotoActivity extends AppCompatActivity {
viewModel.isTorchEnabled()
.observe(
this,
enabled -> camera.getCameraControl().enableTorch(enabled));
enabled -> camera.getCameraControl().enableTorch(enabled));
binding.toggleTorch.setOnClickListener((v) -> viewModel.toggleTorchEnabled());
binding.switchCamera.setOnClickListener((v) -> {
@ -111,6 +117,20 @@ public class TakePhotoActivity extends AppCompatActivity {
imageCapture,
preview);
});
binding.retake.setOnClickListener((v) -> {
Uri uri = (Uri) binding.photoPreview.getTag();
File photoFile = new File(uri.getPath());
if (!photoFile.delete()) {
Log.w(TAG, "Error deleting temp camera image");
}
binding.takePhoto.setEnabled(true);
showCameraElements();
});
binding.send.setOnClickListener((v) -> {
Uri uri = (Uri) binding.photoPreview.getTag();
setResult(RESULT_OK, new Intent().setDataAndType(uri, "image/jpeg"));
finish();
});
} catch (IllegalArgumentException | ExecutionException | InterruptedException e) {
Log.e(TAG, "Error taking picture", e);
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
@ -119,6 +139,28 @@ public class TakePhotoActivity extends AppCompatActivity {
}, ContextCompat.getMainExecutor(this));
}
private void showCameraElements() {
binding.send.setVisibility(View.GONE);
binding.retake.setVisibility(View.GONE);
binding.photoPreview.setVisibility(View.GONE);
binding.preview.setVisibility(View.VISIBLE);
binding.takePhoto.setVisibility(View.VISIBLE);
binding.switchCamera.setVisibility(View.VISIBLE);
binding.toggleTorch.setVisibility(View.VISIBLE);
}
private void showPictureProcessingElements() {
binding.preview.setVisibility(View.GONE);
binding.takePhoto.setVisibility(View.GONE);
binding.switchCamera.setVisibility(View.GONE);
binding.toggleTorch.setVisibility(View.GONE);
binding.send.setVisibility(View.VISIBLE);
binding.retake.setVisibility(View.VISIBLE);
binding.photoPreview.setVisibility(View.VISIBLE);
}
private ImageCapture getImageCapture() {
final ImageCapture imageCapture = new ImageCapture.Builder().setTargetResolution(new Size(720, 1280)).build();
@ -145,7 +187,7 @@ public class TakePhotoActivity extends AppCompatActivity {
binding.takePhoto.setOnClickListener((v) -> {
binding.takePhoto.setEnabled(false);
final String photoFileName = dateFormat.format(new Date())+ ".jpg";
final String photoFileName = dateFormat.format(new Date()) + ".jpg";
try {
final File photoFile = FileUtils.getTempCacheFile(this, "photos/" + photoFileName);
final ImageCapture.OutputFileOptions options =
@ -155,24 +197,33 @@ public class TakePhotoActivity extends AppCompatActivity {
ContextCompat.getMainExecutor(this),
new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
final Uri savedUri = Uri.fromFile(photoFile);
Log.i(TAG, "onImageSaved - savedUri:" + savedUri);
setResult(RESULT_OK, new Intent().setDataAndType(savedUri, "image/jpeg"));
finish();
}
@Override
public void onError(@NonNull ImageCaptureException e) {
Log.e(TAG, "Error", e);
if(!photoFile.delete()) {
Log.w(TAG, "Deleting picture failed");
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
final Uri savedUri = Uri.fromFile(photoFile);
Log.i(TAG, "onImageSaved - savedUri:" + savedUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
try {
binding.photoPreview.setImageBitmap(
BitmapFactory.decodeStream(new FileInputStream(photoFile), null, options));
binding.photoPreview.setRotation(getImageOrientation(photoFile));
binding.photoPreview.setTag(savedUri);
showPictureProcessingElements();
} catch (FileNotFoundException e) {
Log.w(TAG, "Error reading image", e);
}
}
binding.takePhoto.setEnabled(true);
}
});
@Override
public void onError(@NonNull ImageCaptureException e) {
Log.e(TAG, "Error", e);
if (!photoFile.delete()) {
Log.w(TAG, "Deleting picture failed");
}
binding.takePhoto.setEnabled(true);
}
});
} catch (Exception e) {
Toast.makeText(this, R.string.take_photo_error_deleting_picture, Toast.LENGTH_SHORT).show();
}
@ -181,6 +232,36 @@ public class TakePhotoActivity extends AppCompatActivity {
return imageCapture;
}
public int getImageOrientation(File imageFile) {
int rotate = 0;
try {
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
default:
rotate = 0;
break;
}
Log.i(TAG, "ImageOrientation - Exif orientation: " + orientation + " - " + "Rotate value: " + rotate);
} catch (Exception e) {
Log.w(TAG, "Error calculation rotation value");
}
return rotate;
}
private Preview getPreview() {
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(binding.preview.getSurfaceProvider());

View File

@ -0,0 +1,8 @@
<!-- drawable/autorenew.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z" />
</vector>

View File

@ -34,6 +34,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/photo_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:visibility="gone" />
<com.google.android.material.button.MaterialButton
android:id="@+id/toggle_torch"
style="@style/Widget.AppTheme.Button.IconButton"
@ -41,8 +48,8 @@
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="12dp"
android:layout_marginStart="0dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:contentDescription="@string/take_photo_toggle_torch"
android:insetLeft="4dp"
@ -68,9 +75,9 @@
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="12dp"
android:contentDescription="@string/take_photo_switch_camera"
android:insetLeft="4dp"
android:insetTop="4dp"
@ -89,6 +96,34 @@
app:layout_constraintEnd_toStartOf="@+id/toggle_torch"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/retake"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="12dp"
android:contentDescription="@string/take_photo_switch_camera"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:padding="0dp"
android:tint="@android:color/white"
android:visibility="gone"
app:backgroundTint="@color/colorPrimary"
app:cornerRadius="@dimen/button_corner_radius"
app:elevation="0dp"
app:icon="@drawable/ic_autorenew"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/takePhoto"
app:layout_constraintEnd_toStartOf="@id/takePhoto"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/takePhoto"
android:layout_width="wrap_content"
@ -103,4 +138,32 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_baseline_photo_camera_24" />
<com.google.android.material.button.MaterialButton
android:id="@+id/send"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="12dp"
android:contentDescription="@string/take_photo_switch_camera"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:padding="0dp"
android:tint="@android:color/white"
android:visibility="gone"
app:backgroundTint="@color/colorPrimary"
app:cornerRadius="@dimen/button_corner_radius"
app:elevation="0dp"
app:icon="@drawable/ic_send"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/takePhoto"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/takePhoto" />
</androidx.constraintlayout.widget.ConstraintLayout>