mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-25 12:17:22 +00:00
Upgrade CameraX to 1.1.0 and fork removal.
This commit is contained in:
committed by
Greyson Parrelli
parent
e3e9f90094
commit
a52b64281c
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.camera.view.video.ExperimentalVideo;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
|
||||
@@ -18,7 +19,7 @@ public interface CameraFragment {
|
||||
|
||||
float PORTRAIT_ASPECT_RATIO = 9 / 16f;
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint({ "RestrictedApi", "UnsafeOptInUsageError" })
|
||||
static Fragment newInstance() {
|
||||
if (CameraXUtil.isSupported()) {
|
||||
return CameraXFragment.newInstance();
|
||||
@@ -27,7 +28,7 @@ public interface CameraFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint({ "RestrictedApi", "UnsafeOptInUsageError" })
|
||||
static Fragment newInstanceForAvatarCapture() {
|
||||
if (CameraXUtil.isSupported()) {
|
||||
return CameraXFragment.newInstanceForAvatarCapture();
|
||||
|
||||
@@ -5,8 +5,11 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Rational;
|
||||
import android.util.Size;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
@@ -18,7 +21,6 @@ import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.RotateAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -28,8 +30,10 @@ import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.core.ImageCaptureException;
|
||||
import androidx.camera.core.ImageProxy;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.camera.view.CameraController;
|
||||
import androidx.camera.view.LifecycleCameraController;
|
||||
import androidx.camera.view.PreviewView;
|
||||
import androidx.camera.view.SignalCameraView;
|
||||
import androidx.camera.view.video.ExperimentalVideo;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
@@ -64,18 +68,23 @@ import io.reactivex.rxjava3.disposables.Disposable;
|
||||
* Camera captured implemented using the CameraX SDK, which uses Camera2 under the hood. Should be
|
||||
* preferred whenever possible.
|
||||
*/
|
||||
@ExperimentalVideo
|
||||
@RequiresApi(21)
|
||||
public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
|
||||
private static final String TAG = Log.tag(CameraXFragment.class);
|
||||
private static final String IS_VIDEO_ENABLED = "is_video_enabled";
|
||||
|
||||
private SignalCameraView camera;
|
||||
private ViewGroup controlsContainer;
|
||||
private Controller controller;
|
||||
private View selfieFlash;
|
||||
private MemoryFileDescriptor videoFileDescriptor;
|
||||
private Disposable mostRecentItemDisposable = Disposable.disposed();
|
||||
|
||||
private static final Rational ASPECT_RATIO_16_9 = new Rational(16, 9);
|
||||
|
||||
private PreviewView previewView;
|
||||
private ViewGroup controlsContainer;
|
||||
private Controller controller;
|
||||
private View selfieFlash;
|
||||
private MemoryFileDescriptor videoFileDescriptor;
|
||||
private LifecycleCameraController cameraController;
|
||||
private Disposable mostRecentItemDisposable = Disposable.disposed();
|
||||
|
||||
private boolean isThumbAvailable;
|
||||
private boolean isMediaSelected;
|
||||
@@ -124,12 +133,18 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
ViewGroup cameraParent = view.findViewById(R.id.camerax_camera_parent);
|
||||
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
|
||||
this.camera = view.findViewById(R.id.camerax_camera);
|
||||
this.previewView = view.findViewById(R.id.camerax_camera);
|
||||
this.controlsContainer = view.findViewById(R.id.camerax_controls_container);
|
||||
|
||||
camera.setScaleType(PreviewView.ScaleType.FIT_CENTER);
|
||||
camera.bindToLifecycle(getViewLifecycleOwner(), this::handleCameraInitializationError);
|
||||
camera.setCameraLensFacing(CameraXUtil.toLensFacing(TextSecurePreferences.getDirectCaptureCameraId(requireContext())));
|
||||
cameraController = new LifecycleCameraController(requireContext());
|
||||
cameraController.bindToLifecycle(getViewLifecycleOwner());
|
||||
cameraController.setCameraSelector(CameraXUtil.toCameraSelector(TextSecurePreferences.getDirectCaptureCameraId(requireContext())));
|
||||
cameraController.setTapToFocusEnabled(true);
|
||||
cameraController.setImageCaptureMode(CameraXUtil.getOptimalCaptureMode());
|
||||
cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE);
|
||||
|
||||
previewView.setScaleType(PreviewView.ScaleType.FIT_CENTER);
|
||||
previewView.setController(cameraController);
|
||||
|
||||
onOrientationChanged(getResources().getConfiguration().orientation);
|
||||
|
||||
@@ -155,7 +170,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
camera.bindToLifecycle(getViewLifecycleOwner(), this::handleCameraInitializationError);
|
||||
cameraController.bindToLifecycle(getViewLifecycleOwner());
|
||||
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
}
|
||||
|
||||
@@ -204,19 +219,17 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
});
|
||||
}
|
||||
|
||||
private void handleCameraInitializationError(Throwable error) {
|
||||
Log.w(TAG, "An error occurred", error);
|
||||
|
||||
Context context = getActivity();
|
||||
if (context != null) {
|
||||
Toast.makeText(context, R.string.CameraFragment__failed_to_open_camera, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void onOrientationChanged(int orientation) {
|
||||
int layout = orientation == Configuration.ORIENTATION_PORTRAIT ? R.layout.camera_controls_portrait
|
||||
: R.layout.camera_controls_landscape;
|
||||
|
||||
int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels);
|
||||
Size size = CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, orientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
CameraController.OutputSize outputSize = new CameraController.OutputSize(size);
|
||||
|
||||
cameraController.setImageCaptureTargetSize(outputSize);
|
||||
cameraController.setVideoCaptureTargetSize(new CameraController.OutputSize(VideoUtil.getVideoRecordingSize()));
|
||||
|
||||
controlsContainer.removeAllViews();
|
||||
controlsContainer.addView(LayoutInflater.from(getContext()).inflate(layout, controlsContainer, false));
|
||||
initControls();
|
||||
@@ -301,15 +314,15 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
onCaptureClicked();
|
||||
});
|
||||
|
||||
camera.setScaleType(PreviewView.ScaleType.FILL_CENTER);
|
||||
previewView.setScaleType(PreviewView.ScaleType.FILL_CENTER);
|
||||
|
||||
ProcessCameraProvider.getInstance(requireContext())
|
||||
.addListener(() -> initializeFlipButton(flipButton, flashButton),
|
||||
Executors.mainThreadExecutor());
|
||||
|
||||
flashButton.setAutoFlashEnabled(camera.hasFlash());
|
||||
flashButton.setFlash(camera.getFlash());
|
||||
flashButton.setOnFlashModeChangedListener(camera::setFlash);
|
||||
flashButton.setAutoFlashEnabled(cameraController.getImageCaptureFlashMode() >= ImageCapture.FLASH_MODE_AUTO);
|
||||
flashButton.setFlash(cameraController.getImageCaptureFlashMode());
|
||||
flashButton.setOnFlashModeChangedListener(cameraController::setImageCaptureFlashMode);
|
||||
|
||||
galleryButton.setOnClickListener(v -> controller.onGalleryClicked());
|
||||
countButton.setOnClickListener(v -> controller.onCameraCountButtonClicked());
|
||||
@@ -322,8 +335,6 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
Animation inAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_in);
|
||||
Animation outAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_out);
|
||||
|
||||
camera.setCaptureMode(SignalCameraView.CaptureMode.MIXED);
|
||||
|
||||
int maxDuration = VideoUtil.getMaxVideoRecordDurationInSeconds(requireContext(), controller.getMediaConstraints());
|
||||
if (controller.getMaxVideoDuration() > 0) {
|
||||
maxDuration = controller.getMaxVideoDuration();
|
||||
@@ -334,7 +345,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
captureButton.setVideoCaptureListener(new CameraXVideoCaptureHelper(
|
||||
this,
|
||||
captureButton,
|
||||
camera,
|
||||
cameraController,
|
||||
previewView,
|
||||
videoFileDescriptor,
|
||||
maxDuration,
|
||||
new CameraXVideoCaptureHelper.Callback() {
|
||||
@@ -432,19 +444,21 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
|
||||
CameraXSelfieFlashHelper flashHelper = new CameraXSelfieFlashHelper(
|
||||
requireActivity().getWindow(),
|
||||
camera,
|
||||
cameraController,
|
||||
selfieFlash
|
||||
);
|
||||
|
||||
camera.takePicture(Executors.mainThreadExecutor(), new ImageCapture.OnImageCapturedCallback() {
|
||||
cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE);
|
||||
cameraController.takePicture(Executors.mainThreadExecutor(), new ImageCapture.OnImageCapturedCallback() {
|
||||
@Override
|
||||
public void onCaptureSuccess(@NonNull ImageProxy image) {
|
||||
flashHelper.endFlash();
|
||||
|
||||
final boolean flip = cameraController.getCameraSelector() == CameraSelector.DEFAULT_FRONT_CAMERA;
|
||||
SimpleTask.run(CameraXFragment.this.getViewLifecycleOwner().getLifecycle(), () -> {
|
||||
stopwatch.split("captured");
|
||||
try {
|
||||
return CameraXUtil.toJpeg(image, camera.getCameraLensFacing() == CameraSelector.LENS_FACING_FRONT);
|
||||
return CameraXUtil.toJpeg(image, flip);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to encode captured image.", e);
|
||||
return null;
|
||||
@@ -492,18 +506,20 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera.hasCameraWithLensFacing(CameraSelector.LENS_FACING_FRONT) && camera.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK)) {
|
||||
if (cameraController.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) && cameraController.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)) {
|
||||
flipButton.setVisibility(View.VISIBLE);
|
||||
flipButton.setOnClickListener(v -> {
|
||||
camera.toggleCamera();
|
||||
TextSecurePreferences.setDirectCaptureCameraId(getContext(), CameraXUtil.toCameraDirectionInt(camera.getCameraLensFacing()));
|
||||
cameraController.setCameraSelector(cameraController.getCameraSelector() == CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
? CameraSelector.DEFAULT_BACK_CAMERA
|
||||
: CameraSelector.DEFAULT_FRONT_CAMERA);
|
||||
TextSecurePreferences.setDirectCaptureCameraId(getContext(), CameraXUtil.toCameraDirectionInt(cameraController.getCameraSelector()));
|
||||
|
||||
Animation animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
|
||||
animation.setDuration(200);
|
||||
animation.setInterpolator(new DecelerateInterpolator());
|
||||
flipButton.startAnimation(animation);
|
||||
flashButton.setAutoFlashEnabled(camera.hasFlash());
|
||||
flashButton.setFlash(camera.getFlash());
|
||||
flashButton.setAutoFlashEnabled(cameraController.getImageCaptureFlashMode() >= ImageCapture.FLASH_MODE_AUTO);
|
||||
flashButton.setFlash(cameraController.getImageCaptureFlashMode());
|
||||
});
|
||||
|
||||
GestureDetector gestureDetector = new GestureDetector(requireContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||
@@ -516,7 +532,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
|
||||
}
|
||||
});
|
||||
|
||||
camera.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
|
||||
previewView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
|
||||
|
||||
} else {
|
||||
flipButton.setVisibility(View.GONE);
|
||||
|
||||
@@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.camera.core.CameraSelector;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.view.SignalCameraView;
|
||||
import androidx.camera.view.CameraController;
|
||||
|
||||
@RequiresApi(21)
|
||||
final class CameraXSelfieFlashHelper {
|
||||
@@ -18,14 +18,14 @@ final class CameraXSelfieFlashHelper {
|
||||
private static final long SELFIE_FLASH_DURATION_MS = 250;
|
||||
|
||||
private final Window window;
|
||||
private final SignalCameraView camera;
|
||||
private final CameraController camera;
|
||||
private final View selfieFlash;
|
||||
|
||||
private float brightnessBeforeFlash;
|
||||
private boolean inFlash;
|
||||
|
||||
CameraXSelfieFlashHelper(@NonNull Window window,
|
||||
@NonNull SignalCameraView camera,
|
||||
@NonNull CameraController camera,
|
||||
@NonNull View selfieFlash)
|
||||
{
|
||||
this.window = window;
|
||||
@@ -64,11 +64,9 @@ final class CameraXSelfieFlashHelper {
|
||||
}
|
||||
|
||||
private boolean shouldUseViewBasedFlash() {
|
||||
Integer cameraLensFacing = camera.getCameraLensFacing();
|
||||
CameraSelector cameraSelector = camera.getCameraSelector() ;
|
||||
|
||||
return camera.getFlash() == ImageCapture.FLASH_MODE_ON &&
|
||||
!camera.hasFlash() &&
|
||||
cameraLensFacing != null &&
|
||||
cameraLensFacing == CameraSelector.LENS_FACING_FRONT;
|
||||
return camera.getImageCaptureFlashMode() == ImageCapture.FLASH_MODE_ON &&
|
||||
cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,13 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.camera.core.VideoCapture;
|
||||
import androidx.camera.view.SignalCameraView;
|
||||
import androidx.camera.core.ZoomState;
|
||||
import androidx.camera.view.CameraController;
|
||||
import androidx.camera.view.PreviewView;
|
||||
import androidx.camera.view.video.ExperimentalVideo;
|
||||
import androidx.camera.view.video.OnVideoSavedCallback;
|
||||
import androidx.camera.view.video.OutputFileOptions;
|
||||
import androidx.camera.view.video.OutputFileResults;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.bumptech.glide.util.Executors;
|
||||
@@ -28,9 +33,11 @@ import org.thoughtcrime.securesms.video.VideoUtil;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RequiresApi(26)
|
||||
@ExperimentalVideo
|
||||
class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener {
|
||||
|
||||
private static final String TAG = CameraXVideoCaptureHelper.class.getName();
|
||||
@@ -38,23 +45,22 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
private static final long VIDEO_SIZE = 10 * 1024 * 1024;
|
||||
|
||||
private final @NonNull Fragment fragment;
|
||||
private final @NonNull SignalCameraView camera;
|
||||
private final @NonNull PreviewView previewView;
|
||||
private final @NonNull CameraController cameraController;
|
||||
private final @NonNull Callback callback;
|
||||
private final @NonNull MemoryFileDescriptor memoryFileDescriptor;
|
||||
private final @NonNull ValueAnimator updateProgressAnimator;
|
||||
private final @NonNull Debouncer debouncer;
|
||||
|
||||
private boolean isRecording;
|
||||
private ValueAnimator cameraMetricsAnimator;
|
||||
|
||||
private final VideoCapture.OnVideoSavedCallback videoSavedListener = new VideoCapture.OnVideoSavedCallback() {
|
||||
private final OnVideoSavedCallback videoSavedListener = new OnVideoSavedCallback() {
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
|
||||
public void onVideoSaved(@NonNull OutputFileResults outputFileResults) {
|
||||
try {
|
||||
isRecording = false;
|
||||
debouncer.clear();
|
||||
camera.setZoomRatio(camera.getMinZoomRatio());
|
||||
cameraController.setZoomRatio(Objects.requireNonNull(cameraController.getZoomState().getValue()).getMinZoomRatio());
|
||||
memoryFileDescriptor.seek(0);
|
||||
callback.onVideoSaved(memoryFileDescriptor.getFileDescriptor());
|
||||
} catch (IOException e) {
|
||||
@@ -65,7 +71,6 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
|
||||
isRecording = false;
|
||||
debouncer.clear();
|
||||
callback.onVideoError(cause);
|
||||
}
|
||||
@@ -73,13 +78,15 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
|
||||
CameraXVideoCaptureHelper(@NonNull Fragment fragment,
|
||||
@NonNull CameraButtonView captureButton,
|
||||
@NonNull SignalCameraView camera,
|
||||
@NonNull CameraController cameraController,
|
||||
@NonNull PreviewView previewView,
|
||||
@NonNull MemoryFileDescriptor memoryFileDescriptor,
|
||||
int maxVideoDurationSec,
|
||||
@NonNull Callback callback)
|
||||
{
|
||||
this.fragment = fragment;
|
||||
this.camera = camera;
|
||||
this.cameraController = cameraController;
|
||||
this.previewView = previewView;
|
||||
this.memoryFileDescriptor = memoryFileDescriptor;
|
||||
this.callback = callback;
|
||||
this.updateProgressAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(TimeUnit.SECONDS.toMillis(maxVideoDurationSec));
|
||||
@@ -94,7 +101,6 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
Log.d(TAG, "onVideoCaptureStarted");
|
||||
|
||||
if (canRecordAudio()) {
|
||||
isRecording = true;
|
||||
beginCameraRecording();
|
||||
} else {
|
||||
displayAudioRecordingPermissionsDialog();
|
||||
@@ -117,13 +123,14 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private void beginCameraRecording() {
|
||||
this.camera.setZoomRatio(this.camera.getMinZoomRatio());
|
||||
this.cameraController.setZoomRatio(Objects.requireNonNull(this.cameraController.getZoomState().getValue()).getMinZoomRatio());
|
||||
callback.onVideoRecordStarted();
|
||||
shrinkCaptureArea();
|
||||
|
||||
VideoCapture.OutputFileOptions options = new VideoCapture.OutputFileOptions.Builder(memoryFileDescriptor.getFileDescriptor()).build();
|
||||
OutputFileOptions options = OutputFileOptions.builder(memoryFileDescriptor.getParcelFileDescriptor()).build();
|
||||
|
||||
camera.startRecording(options, Executors.mainThreadExecutor(), videoSavedListener);
|
||||
cameraController.setEnabledUseCases(CameraController.VIDEO_CAPTURE);
|
||||
cameraController.startRecording(options, Executors.mainThreadExecutor(), videoSavedListener);
|
||||
updateProgressAnimator.start();
|
||||
debouncer.publish(this::onVideoCaptureComplete);
|
||||
}
|
||||
@@ -152,7 +159,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
cameraMetricsAnimator = ValueAnimator.ofFloat(screenSize.getWidth(), targetWidthForAnimation);
|
||||
}
|
||||
|
||||
ViewGroup.LayoutParams params = camera.getLayoutParams();
|
||||
ViewGroup.LayoutParams params = previewView.getLayoutParams();
|
||||
cameraMetricsAnimator.setInterpolator(new LinearInterpolator());
|
||||
cameraMetricsAnimator.setDuration(200);
|
||||
cameraMetricsAnimator.addUpdateListener(animation -> {
|
||||
@@ -161,13 +168,13 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
} else {
|
||||
params.width = Math.round((float) animation.getAnimatedValue());
|
||||
}
|
||||
camera.setLayoutParams(params);
|
||||
previewView.setLayoutParams(params);
|
||||
});
|
||||
cameraMetricsAnimator.start();
|
||||
}
|
||||
|
||||
private Size getScreenSize() {
|
||||
DisplayMetrics metrics = camera.getResources().getDisplayMetrics();
|
||||
DisplayMetrics metrics = previewView.getResources().getDisplayMetrics();
|
||||
return new Size(metrics.widthPixels, metrics.heightPixels);
|
||||
}
|
||||
|
||||
@@ -179,11 +186,11 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
|
||||
@Override
|
||||
public void onVideoCaptureComplete() {
|
||||
isRecording = false;
|
||||
if (!canRecordAudio()) return;
|
||||
|
||||
Log.d(TAG, "onVideoCaptureComplete");
|
||||
camera.stopRecording();
|
||||
cameraController.stopRecording();
|
||||
cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE);
|
||||
|
||||
if (cameraMetricsAnimator != null && cameraMetricsAnimator.isRunning()) {
|
||||
cameraMetricsAnimator.reverse();
|
||||
@@ -195,8 +202,9 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
||||
|
||||
@Override
|
||||
public void onZoomIncremented(float increment) {
|
||||
float range = camera.getMaxZoomRatio() - camera.getMinZoomRatio();
|
||||
camera.setZoomRatio((range * increment) + camera.getMinZoomRatio());
|
||||
ZoomState zoomState = Objects.requireNonNull(cameraController.getZoomState().getValue());
|
||||
float range = zoomState.getMaxZoomRatio() - zoomState.getMinZoomRatio();
|
||||
cameraController.setZoomRatio((range * increment) + zoomState.getMinZoomRatio());
|
||||
}
|
||||
|
||||
static MemoryFileDescriptor createFileDescriptor(@NonNull Context context) throws MemoryFileDescriptor.MemoryFileException {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
|
||||
@@ -14,6 +15,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RequiresApi(21)
|
||||
public final class CameraXFlashToggleView extends AppCompatImageView {
|
||||
|
||||
private static final String STATE_FLASH_INDEX = "flash.toggle.state.flash.index";
|
||||
|
||||
@@ -109,23 +109,26 @@ public class CameraXUtil {
|
||||
return Build.VERSION.SDK_INT >= 21 && !CameraXModelBlacklist.isBlacklisted();
|
||||
}
|
||||
|
||||
public static int toCameraDirectionInt(int facing) {
|
||||
if (facing == CameraSelector.LENS_FACING_FRONT) {
|
||||
@RequiresApi(21)
|
||||
public static int toCameraDirectionInt(CameraSelector cameraSelector) {
|
||||
if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) {
|
||||
return Camera.CameraInfo.CAMERA_FACING_FRONT;
|
||||
} else {
|
||||
return Camera.CameraInfo.CAMERA_FACING_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
public static int toLensFacing(@CameraSelector.LensFacing int cameraDirectionInt) {
|
||||
@RequiresApi(21)
|
||||
public static CameraSelector toCameraSelector(@CameraSelector.LensFacing int cameraDirectionInt) {
|
||||
if (cameraDirectionInt == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
return CameraSelector.LENS_FACING_FRONT;
|
||||
return CameraSelector.DEFAULT_FRONT_CAMERA;
|
||||
} else {
|
||||
return CameraSelector.LENS_FACING_BACK;
|
||||
return CameraSelector.DEFAULT_BACK_CAMERA;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull @ImageCapture.CaptureMode int getOptimalCaptureMode() {
|
||||
@RequiresApi(21)
|
||||
public static @ImageCapture.CaptureMode int getOptimalCaptureMode() {
|
||||
return FastCameraModels.contains(Build.MODEL) ? ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
|
||||
: ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY;
|
||||
}
|
||||
|
||||
@@ -169,6 +169,10 @@ public final class MemoryFileDescriptor implements Closeable {
|
||||
return parcelFileDescriptor.getFileDescriptor();
|
||||
}
|
||||
|
||||
public ParcelFileDescriptor getParcelFileDescriptor() {
|
||||
return parcelFileDescriptor;
|
||||
}
|
||||
|
||||
public void seek(long position) throws IOException {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(getFileDescriptor())) {
|
||||
fileInputStream.getChannel().position(position);
|
||||
|
||||
Reference in New Issue
Block a user