mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 09:08:33 +00:00
parent
097f97b5e4
commit
03dc220cea
@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
|
|||||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
@ -236,7 +237,14 @@ public class CameraXFragment extends Fragment implements CameraFragment {
|
|||||||
Animation inAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_in);
|
Animation inAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_in);
|
||||||
Animation outAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_out);
|
Animation outAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.fade_out);
|
||||||
|
|
||||||
camera.setCaptureMode(CameraXView.CaptureMode.MIXED);
|
if (CameraXUtil.isMixedModeSupported(requireContext())) {
|
||||||
|
Log.i(TAG, "Device supports mixed mode recording. [" + CameraXUtil.getLowestSupportedHardwareLevel(requireContext()) + "]");
|
||||||
|
camera.setCaptureMode(CameraXView.CaptureMode.MIXED);
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Device does not support mixed mode recording, falling back to IMAGE [" + CameraXUtil.getLowestSupportedHardwareLevel(requireContext()) + "]");
|
||||||
|
camera.setCaptureMode(CameraXView.CaptureMode.IMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
captureButton.setVideoCaptureListener(new CameraXVideoCaptureHelper(
|
captureButton.setVideoCaptureListener(new CameraXVideoCaptureHelper(
|
||||||
this,
|
this,
|
||||||
captureButton,
|
captureButton,
|
||||||
@ -245,6 +253,9 @@ public class CameraXFragment extends Fragment implements CameraFragment {
|
|||||||
new CameraXVideoCaptureHelper.Callback() {
|
new CameraXVideoCaptureHelper.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onVideoRecordStarted() {
|
public void onVideoRecordStarted() {
|
||||||
|
if (camera.getCaptureMode() == CameraXView.CaptureMode.IMAGE) {
|
||||||
|
camera.setCaptureMode(CameraXView.CaptureMode.VIDEO);
|
||||||
|
}
|
||||||
hideAndDisableControlsForVideoRecording(captureButton, flashButton, flipButton, outAnimation);
|
hideAndDisableControlsForVideoRecording(captureButton, flashButton, flipButton, outAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,6 +331,12 @@ public class CameraXFragment extends Fragment implements CameraFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onCaptureClicked() {
|
private void onCaptureClicked() {
|
||||||
|
if (camera.getCaptureMode() == CameraXView.CaptureMode.VIDEO) {
|
||||||
|
camera.setCaptureMode(CameraXView.CaptureMode.IMAGE);
|
||||||
|
Util.runOnMainDelayed(this::onCaptureClicked, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Stopwatch stopwatch = new Stopwatch("Capture");
|
Stopwatch stopwatch = new Stopwatch("Capture");
|
||||||
|
|
||||||
CameraXSelfieFlashHelper flashHelper = new CameraXSelfieFlashHelper(
|
CameraXSelfieFlashHelper flashHelper = new CameraXSelfieFlashHelper(
|
||||||
|
@ -50,6 +50,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
|||||||
@Override
|
@Override
|
||||||
public void onVideoSaved(@NonNull FileDescriptor fileDescriptor) {
|
public void onVideoSaved(@NonNull FileDescriptor fileDescriptor) {
|
||||||
try {
|
try {
|
||||||
|
isRecording = false;
|
||||||
camera.setZoomLevel(0f);
|
camera.setZoomLevel(0f);
|
||||||
memoryFileDescriptor.seek(0);
|
memoryFileDescriptor.seek(0);
|
||||||
callback.onVideoSaved(fileDescriptor);
|
callback.onVideoSaved(fileDescriptor);
|
||||||
@ -63,6 +64,7 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
|||||||
@NonNull String message,
|
@NonNull String message,
|
||||||
@Nullable Throwable cause)
|
@Nullable Throwable cause)
|
||||||
{
|
{
|
||||||
|
isRecording = false;
|
||||||
callback.onVideoError(cause);
|
callback.onVideoError(cause);
|
||||||
Util.runOnMain(() -> resetCameraSizing());
|
Util.runOnMain(() -> resetCameraSizing());
|
||||||
}
|
}
|
||||||
@ -202,7 +204,6 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
|
|||||||
Log.d(TAG, "onVideoCaptureComplete");
|
Log.d(TAG, "onVideoCaptureComplete");
|
||||||
camera.stopRecording();
|
camera.stopRecording();
|
||||||
|
|
||||||
|
|
||||||
if (cameraMetricsAnimator != null && cameraMetricsAnimator.isRunning()) {
|
if (cameraMetricsAnimator != null && cameraMetricsAnimator.isRunning()) {
|
||||||
cameraMetricsAnimator.reverse();
|
cameraMetricsAnimator.reverse();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
package org.thoughtcrime.securesms.mediasend.camerax;
|
package org.thoughtcrime.securesms.mediasend.camerax;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.BitmapRegionDecoder;
|
import android.graphics.BitmapRegionDecoder;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
|
import android.hardware.camera2.CameraAccessException;
|
||||||
|
import android.hardware.camera2.CameraCharacteristics;
|
||||||
|
import android.hardware.camera2.CameraManager;
|
||||||
|
import android.hardware.camera2.CameraMetadata;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Rational;
|
import android.util.Rational;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
@ -14,6 +19,7 @@ import android.util.Size;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.camera.camera2.impl.compat.CameraManagerCompat;
|
||||||
import androidx.camera.core.CameraX;
|
import androidx.camera.core.CameraX;
|
||||||
import androidx.camera.core.ImageCapture;
|
import androidx.camera.core.ImageCapture;
|
||||||
import androidx.camera.core.ImageProxy;
|
import androidx.camera.core.ImageProxy;
|
||||||
@ -29,6 +35,24 @@ public class CameraXUtil {
|
|||||||
|
|
||||||
private static final String TAG = Log.tag(CameraXUtil.class);
|
private static final String TAG = Log.tag(CameraXUtil.class);
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
private static final int[] CAMERA_HARDWARE_LEVEL_ORDERING = new int[]{CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL};
|
||||||
|
|
||||||
|
@RequiresApi(24)
|
||||||
|
private static final int[] CAMERA_HARDWARE_LEVEL_ORDERING_24 = new int[]{CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3};
|
||||||
|
|
||||||
|
@RequiresApi(28)
|
||||||
|
private static final int[] CAMERA_HARDWARE_LEVEL_ORDERING_28 = new int[]{CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
|
||||||
|
CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3};
|
||||||
|
|
||||||
@SuppressWarnings("SuspiciousNameCombination")
|
@SuppressWarnings("SuspiciousNameCombination")
|
||||||
@RequiresApi(21)
|
@RequiresApi(21)
|
||||||
public static ImageResult toJpeg(@NonNull ImageProxy image, int rotation, boolean flip) throws IOException {
|
public static ImageResult toJpeg(@NonNull ImageProxy image, int rotation, boolean flip) throws IOException {
|
||||||
@ -144,6 +168,61 @@ public class CameraXUtil {
|
|||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
public static boolean isMixedModeSupported(@NonNull Context context) {
|
||||||
|
return getLowestSupportedHardwareLevel(context) != CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
public static int getLowestSupportedHardwareLevel(@NonNull Context context) {
|
||||||
|
CameraManager cameraManager = CameraManagerCompat.from(context).unwrap();
|
||||||
|
|
||||||
|
try {
|
||||||
|
int supported = maxHardwareLevel();
|
||||||
|
|
||||||
|
for (String cameraId : cameraManager.getCameraIdList()) {
|
||||||
|
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
|
||||||
|
Integer hwLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
||||||
|
|
||||||
|
if (hwLevel == null || hwLevel == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
||||||
|
return CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
|
||||||
|
}
|
||||||
|
|
||||||
|
supported = smallerHardwareLevel(supported, hwLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
Log.w(TAG, "Failed to enumerate cameras", e);
|
||||||
|
|
||||||
|
return CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
private static int maxHardwareLevel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= 24) return CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3;
|
||||||
|
else return CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
private static int smallerHardwareLevel(int levelA, int levelB) {
|
||||||
|
|
||||||
|
int[] hardwareInfoOrdering = getHardwareInfoOrdering();
|
||||||
|
for (int hwInfo : hardwareInfoOrdering) {
|
||||||
|
if (levelA == hwInfo || levelB == hwInfo) return hwInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(21)
|
||||||
|
private static int[] getHardwareInfoOrdering() {
|
||||||
|
if (Build.VERSION.SDK_INT >= 28) return CAMERA_HARDWARE_LEVEL_ORDERING_28;
|
||||||
|
else if (Build.VERSION.SDK_INT >= 24) return CAMERA_HARDWARE_LEVEL_ORDERING_24;
|
||||||
|
else return CAMERA_HARDWARE_LEVEL_ORDERING;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ImageResult {
|
public static class ImageResult {
|
||||||
private final byte[] data;
|
private final byte[] data;
|
||||||
private final int width;
|
private final int width;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user