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 // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia 15 navigator.getUserMedia || 16 navigator.webkitGetUserMedia || 17 navigator.mozGetUserMedia || 18 function () { 19 const error: any = new Error('Permission unimplemented'); 20 error.code = 0; 21 error.name = 'NotAllowedError'; 22 throw error; 23 }; 24 25 return new Promise((resolve, reject) => { 26 getUserMedia.call(navigator, constraints, resolve, reject); 27 }); 28} 29 30function handleGetUserMediaError({ message }: { message: string }): PermissionResponse { 31 // name: NotAllowedError 32 // code: 0 33 if (message === 'Permission dismissed') { 34 return { 35 status: PermissionStatus.UNDETERMINED, 36 expires: 'never', 37 canAskAgain: true, 38 granted: false, 39 }; 40 } else { 41 return { 42 status: PermissionStatus.DENIED, 43 expires: 'never', 44 canAskAgain: true, 45 granted: false, 46 }; 47 } 48} 49 50async function handleRequestPermissionsAsync(): Promise<PermissionResponse> { 51 try { 52 await getUserMedia({ 53 video: true, 54 }); 55 return { 56 status: PermissionStatus.GRANTED, 57 expires: 'never', 58 canAskAgain: true, 59 granted: true, 60 }; 61 } catch ({ message }) { 62 return handleGetUserMediaError({ message }); 63 } 64} 65 66async function handlePermissionsQueryAsync(): Promise<PermissionResponse> { 67 if (!navigator?.permissions?.query) { 68 throw new UnavailabilityError( 69 'expo-barcode-scanner', 70 'navigator.permissions API is not available' 71 ); 72 } 73 74 const { state } = await navigator.permissions.query({ name: 'camera' }); 75 switch (state) { 76 case 'prompt': 77 return { 78 status: PermissionStatus.UNDETERMINED, 79 expires: 'never', 80 canAskAgain: true, 81 granted: false, 82 }; 83 case 'granted': 84 return { 85 status: PermissionStatus.GRANTED, 86 expires: 'never', 87 canAskAgain: true, 88 granted: true, 89 }; 90 case 'denied': 91 return { 92 status: PermissionStatus.DENIED, 93 expires: 'never', 94 canAskAgain: true, 95 granted: false, 96 }; 97 } 98} 99 100export default { 101 get name(): string { 102 return 'ExpoBarCodeScannerModule'; 103 }, 104 get BarCodeType() { 105 return { 106 code39mod43: 'code39mod43', 107 code138: 'code138', 108 interleaved2of5: 'interleaved2of5', 109 aztec: 'aztec', 110 ean13: 'ean13', 111 ean8: 'ean8', 112 qr: 'qr', 113 pdf417: 'pdf417', 114 upc_e: 'upc_e', 115 datamatrix: 'datamatrix', 116 code39: 'code39', 117 code93: 'code93', 118 itf14: 'itf14', 119 codabar: 'codabar', 120 code128: 'code128', 121 upc_a: 'upc_a', 122 }; 123 }, 124 get Type() { 125 return { front: 'front', back: 'back' }; 126 }, 127 async requestPermissionsAsync(): Promise<PermissionResponse> { 128 return handleRequestPermissionsAsync(); 129 }, 130 async getPermissionsAsync(): Promise<PermissionResponse> { 131 return handlePermissionsQueryAsync(); 132 }, 133}; 134