Allow some time for camera initialization, add log if no device found (#3059)

* Start screen in a loading state for 700ms

One idea I have about the bug is that maybe it takes a few renders to initialize the device. As we are immediately backing out of the screen in case we have no device, maybe just adding a few ms to give the native side time helps.

* If no device is selected log the length of devices available

* Add missing mock
This commit is contained in:
Johannes Klein
2025-08-13 19:20:36 +02:00
committed by GitHub
parent d3086687c2
commit a15e4c7076
5 changed files with 63 additions and 22 deletions

View File

@@ -2,12 +2,14 @@ import {
mockCamera,
mockSortDevices,
mockUseCameraDevice,
mockUseCameraDevices,
mockUseCameraFormat
} from "tests/vision-camera/vision-camera";
export const Camera = mockCamera;
export const sortDevices = mockSortDevices;
export const useCameraDevice = mockUseCameraDevice;
export const useCameraDevices = mockUseCameraDevices;
export const useCameraFormat = mockUseCameraFormat;
export const VisionCameraProxy = {
initFrameProcessorPlugin: jest.fn( )

View File

@@ -1,7 +1,11 @@
import { useNavigation, useRoute } from "@react-navigation/native";
import {
Camera, useCameraDevice
Camera,
useCameraDevice,
useCameraDevices
} from "components/Camera/helpers/visionCameraWrapper";
import { ActivityIndicator } from "components/SharedComponents";
import { View } from "components/styledComponents";
import React, {
useCallback,
useEffect,
@@ -14,6 +18,7 @@ import type {
TakePhotoOptions
} from "react-native-vision-camera";
import fetchAccurateUserLocation from "sharedHelpers/fetchAccurateUserLocation.ts";
import { log } from "sharedHelpers/logger";
import { createSentinelFile, deleteSentinelFile, logStage } from "sharedHelpers/sentinelFiles.ts";
import { useTranslation } from "sharedHooks";
import useLocationPermission from "sharedHooks/useLocationPermission.tsx";
@@ -50,6 +55,8 @@ interface SavePhotoOptions {
export const MAX_PHOTOS_ALLOWED = 20;
const logger = log.extend( "CameraContainer" );
const CameraContainer = ( ) => {
const currentObservation = useStore( state => state.currentObservation );
const setCameraState = useStore( state => state.setCameraState );
@@ -99,6 +106,18 @@ const CameraContainer = ( ) => {
"telephoto-camera"
]
} );
const devices = useCameraDevices( );
const [loadingDevices, setLoadingDevices] = useState( true );
const [timeoutId, setTimeoutId] = useState<undefined | ReturnType<typeof setTimeout> | null>(
undefined
);
if ( timeoutId === undefined ) {
setTimeoutId( setTimeout( () => {
setLoadingDevices( false );
setTimeoutId( null );
}, 700 ) );
}
const hasFlash = device?.hasFlash;
const initialPhotoOptions = {
// We had this set to true in Seek but received many reports of it not respecting OS-wide sound
@@ -278,11 +297,23 @@ const CameraContainer = ( ) => {
}
}, [hasLocationPermissions] );
if ( !device ) {
if ( loadingDevices ) {
return (
<View className="flex-1 bg-black justify-center items-center">
<ActivityIndicator />
</View>
);
}
if ( !loadingDevices && !device ) {
Alert.alert(
t( "No-Camera-Available" ),
t( "Could-not-find-a-camera-on-this-device" )
);
logger.error(
"Camera started but no device was found. Length of the list of all devices: ",
devices.length
);
navigation.goBack();
return null;
}

View File

@@ -10,16 +10,19 @@ import { useFrameProcessor } from "react-native-vision-camera";
import {
mockCamera,
mockUseCameraDevice,
mockUseCameraDevices,
mockUseCameraFormat
} from "tests/vision-camera/vision-camera";
const Camera = mockCamera;
const useCameraDevice = mockUseCameraDevice;
const useCameraDevices = mockUseCameraDevices;
const useCameraFormat = mockUseCameraFormat;
export {
Camera,
useCameraDevice,
useCameraDevices,
useCameraFormat,
useFrameProcessor
};

View File

@@ -3,10 +3,15 @@
import {
Camera,
useCameraDevice,
useCameraDevices,
useCameraFormat,
useFrameProcessor
} from "react-native-vision-camera";
export {
Camera, useCameraDevice, useCameraFormat, useFrameProcessor
Camera,
useCameraDevice,
useCameraDevices,
useCameraFormat,
useFrameProcessor
};

View File

@@ -104,27 +104,27 @@ export class mockCamera extends React.PureComponent {
export const mockSortDevices = ( _left, _right ) => 1;
export const mockUseCameraDevice = _deviceType => {
const device = {
physicalDevices: ["wide-angle-camera"],
hasFlash: true,
hasTorch: true,
id: "1",
isMultiCam: true,
maxZoom: 12.931958198547363,
minZoom: 1,
name: "front (1)",
neutralZoom: 1,
position: "front",
supportsDepthCapture: false,
supportsFocus: true,
supportsLowLightBoost: false,
supportsParallelVideoProcessing: true,
supportsRawCapture: true
};
return device;
const device = {
physicalDevices: ["wide-angle-camera"],
hasFlash: true,
hasTorch: true,
id: "1",
isMultiCam: true,
maxZoom: 12.931958198547363,
minZoom: 1,
name: "front (1)",
neutralZoom: 1,
position: "front",
supportsDepthCapture: false,
supportsFocus: true,
supportsLowLightBoost: false,
supportsParallelVideoProcessing: true,
supportsRawCapture: true
};
export const mockUseCameraDevice = _deviceType => device;
export const mockUseCameraDevices = () => [device];
export const mockUseCameraFormat = _device => {
const format = {
autoFocusSystem: "contrast-detection",