1import { PermissionResponse, PermissionStatus, UnavailabilityError } from 'expo-modules-core'; 2 3function getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream> { 4 if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { 5 return navigator.mediaDevices.getUserMedia(constraints); 6 } 7 8 // Some browsers partially implement mediaDevices. We can't just assign an object 9 // with getUserMedia as it would overwrite existing properties. 10 // Here, we will just add the getUserMedia property if it's missing. 11 12 // First get ahold of the legacy getUserMedia, if present 13 const getUserMedia = 14 navigator.getUserMedia || 15 (navigator as any).webkitGetUserMedia || 16 (navigator as any).mozGetUserMedia || 17 function () { 18 const error: any = new Error('Permission unimplemented'); 19 error.code = 0; 20 error.name = 'NotAllowedError'; 21 throw error; 22 }; 23 24 return new Promise((resolve, reject) => { 25 getUserMedia.call(navigator, constraints, resolve, reject); 26 }); 27} 28 29function handleGetUserMediaError({ message }: { message: string }): PermissionResponse { 30 // name: NotAllowedError 31 // code: 0 32 if (message === 'Permission dismissed') { 33 return { 34 status: PermissionStatus.UNDETERMINED, 35 expires: 'never', 36 canAskAgain: true, 37 granted: false, 38 }; 39 } else { 40 return { 41 status: PermissionStatus.DENIED, 42 expires: 'never', 43 canAskAgain: true, 44 granted: false, 45 }; 46 } 47} 48 49async function handleRequestPermissionsAsync(): Promise<PermissionResponse> { 50 try { 51 await getUserMedia({ 52 video: true, 53 }); 54 return { 55 status: PermissionStatus.GRANTED, 56 expires: 'never', 57 canAskAgain: true, 58 granted: true, 59 }; 60 } catch ({ message }) { 61 return handleGetUserMediaError({ message }); 62 } 63} 64 65async function handlePermissionsQueryAsync(): Promise<PermissionResponse> { 66 if (!navigator?.permissions?.query) { 67 throw new UnavailabilityError( 68 'expo-barcode-scanner', 69 'navigator.permissions API is not available' 70 ); 71 } 72 73 const { state } = await navigator.permissions.query({ name: 'camera' }); 74 switch (state) { 75 case 'prompt': 76 return { 77 status: PermissionStatus.UNDETERMINED, 78 expires: 'never', 79 canAskAgain: true, 80 granted: false, 81 }; 82 case 'granted': 83 return { 84 status: PermissionStatus.GRANTED, 85 expires: 'never', 86 canAskAgain: true, 87 granted: true, 88 }; 89 case 'denied': 90 return { 91 status: PermissionStatus.DENIED, 92 expires: 'never', 93 canAskAgain: true, 94 granted: false, 95 }; 96 } 97} 98 99export default { 100 get name(): string { 101 return 'ExpoBarCodeScannerModule'; 102 }, 103 get BarCodeType() { 104 return { 105 code39mod43: 'code39mod43', 106 code138: 'code138', 107 interleaved2of5: 'interleaved2of5', 108 aztec: 'aztec', 109 ean13: 'ean13', 110 ean8: 'ean8', 111 qr: 'qr', 112 pdf417: 'pdf417', 113 upc_e: 'upc_e', 114 datamatrix: 'datamatrix', 115 code39: 'code39', 116 code93: 'code93', 117 itf14: 'itf14', 118 codabar: 'codabar', 119 code128: 'code128', 120 upc_a: 'upc_a', 121 }; 122 }, 123 get Type() { 124 return { front: 'front', back: 'back' }; 125 }, 126 async requestPermissionsAsync(): Promise<PermissionResponse> { 127 return handleRequestPermissionsAsync(); 128 }, 129 async getPermissionsAsync(): Promise<PermissionResponse> { 130 return handlePermissionsQueryAsync(); 131 }, 132}; 133