From da87d1bf51a038951b273ef116a6633d58bf9446 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 29 Aug 2023 23:25:01 +0700 Subject: [PATCH 1/6] fix: fail to request camera permission in scan receipt screen --- src/CONST.ts | 2 +- .../CameraPermission/index.android.js | 11 ++++++++++ .../CameraPermission/index.ios.js | 11 ++++++++++ .../ReceiptSelector/CameraPermission/index.js | 5 +++++ src/pages/iou/ReceiptSelector/index.native.js | 20 ++++++++++--------- 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.android.js create mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js create mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.js diff --git a/src/CONST.ts b/src/CONST.ts index 4cb4509e96a3..2bf787dcd0f6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -454,7 +454,7 @@ const CONST = { }, RECEIPT: { ICON_SIZE: 164, - PERMISSION_AUTHORIZED: 'authorized', + PERMISSION_GRANTED: 'granted', HAND_ICON_HEIGHT: 152, HAND_ICON_WIDTH: 200, SHUTTER_SIZE: 90, diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js new file mode 100644 index 000000000000..fb1d270fd592 --- /dev/null +++ b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js @@ -0,0 +1,11 @@ +import {PermissionsAndroid} from 'react-native'; + +function requestCameraPermission() { + return PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA); +} + +function getCameraPermissionStatus() { + return PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA); +} + +export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js new file mode 100644 index 000000000000..3c24bfa10d6f --- /dev/null +++ b/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js @@ -0,0 +1,11 @@ +import {check, PERMISSIONS, request} from 'react-native-permissions'; + +function requestCameraPermission() { + return request(PERMISSIONS.IOS.CAMERA); +} + +function getCameraPermissionStatus() { + return check(PERMISSIONS.IOS.CAMERA); +} + +export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.js new file mode 100644 index 000000000000..4357b592d7ef --- /dev/null +++ b/src/pages/iou/ReceiptSelector/CameraPermission/index.js @@ -0,0 +1,5 @@ +function requestCameraPermission() {} + +function getCameraPermissionStatus() {} + +export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index 727cbb05d395..619d7c8945de 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -1,4 +1,4 @@ -import {ActivityIndicator, Alert, AppState, Linking, Text, View} from 'react-native'; +import {ActivityIndicator, Alert, AppState, Linking, PermissionsAndroid, Text, View} from 'react-native'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Camera, useCameraDevices} from 'react-native-vision-camera'; import lodashGet from 'lodash/get'; @@ -21,6 +21,8 @@ import useLocalize from '../../../hooks/useLocalize'; import ONYXKEYS from '../../../ONYXKEYS'; import Log from '../../../libs/Log'; import participantPropTypes from '../../../components/participantPropTypes'; +import * as CameraPermission from './CameraPermission'; +import {RESULTS} from 'react-native-permissions'; const propTypes = { /** React Navigation route */ @@ -113,7 +115,7 @@ function ReceiptSelector(props) { useEffect(() => { const subscription = AppState.addEventListener('change', (nextAppState) => { if (appState.current.match(/inactive|background/) && nextAppState === 'active') { - Camera.getCameraPermissionStatus().then((permissionStatus) => { + CameraPermission.getCameraPermissionStatus().then((permissionStatus) => { setPermissions(permissionStatus); }); } @@ -156,11 +158,11 @@ function ReceiptSelector(props) { }; const askForPermissions = () => { - if (permissions === 'not-determined') { - Camera.requestCameraPermission().then((permissionStatus) => { + if (permissions === 'denied') { + CameraPermission.requestCameraPermission().then((permissionStatus) => { setPermissions(permissionStatus); }); - } else { + } else if (['blocked', 'never_ask_again'].includes(permissions)) { Linking.openSettings(); } }; @@ -219,13 +221,13 @@ function ReceiptSelector(props) { }); }, [flash, iouType, props.iou, props.report, reportID, translate]); - Camera.getCameraPermissionStatus().then((permissionStatus) => { + CameraPermission.getCameraPermissionStatus().then((permissionStatus) => { setPermissions(permissionStatus); }); return ( - {permissions !== CONST.RECEIPT.PERMISSION_AUTHORIZED && ( + {permissions !== CONST.RECEIPT.PERMISSION_GRANTED && ( )} - {permissions === CONST.RECEIPT.PERMISSION_AUTHORIZED && device == null && ( + {permissions === CONST.RECEIPT.PERMISSION_GRANTED && device == null && ( )} - {permissions === CONST.RECEIPT.PERMISSION_AUTHORIZED && device != null && ( + {permissions === CONST.RECEIPT.PERMISSION_GRANTED && device != null && ( Date: Wed, 30 Aug 2023 00:23:05 +0700 Subject: [PATCH 2/6] fix request permission on android --- .../ReceiptSelector/CameraPermission/index.android.js | 7 ++++--- src/pages/iou/ReceiptSelector/index.native.js | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js index fb1d270fd592..ef0d8e4bddd3 100644 --- a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js +++ b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js @@ -1,11 +1,12 @@ -import {PermissionsAndroid} from 'react-native'; +import {check, PERMISSIONS, request} from "react-native-permissions"; function requestCameraPermission() { - return PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA); + return request(PERMISSIONS.ANDROID.CAMERA); } +// Android will never return blocked after a check, you have to request the permission to get the info. function getCameraPermissionStatus() { - return PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA); + return check(PERMISSIONS.ANDROID.CAMERA); } export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index 619d7c8945de..dcc1f24ae673 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -1,4 +1,4 @@ -import {ActivityIndicator, Alert, AppState, Linking, PermissionsAndroid, Text, View} from 'react-native'; +import {ActivityIndicator, Alert, AppState, Linking, Text, View} from 'react-native'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Camera, useCameraDevices} from 'react-native-vision-camera'; import lodashGet from 'lodash/get'; @@ -22,7 +22,6 @@ import ONYXKEYS from '../../../ONYXKEYS'; import Log from '../../../libs/Log'; import participantPropTypes from '../../../components/participantPropTypes'; import * as CameraPermission from './CameraPermission'; -import {RESULTS} from 'react-native-permissions'; const propTypes = { /** React Navigation route */ @@ -161,8 +160,12 @@ function ReceiptSelector(props) { if (permissions === 'denied') { CameraPermission.requestCameraPermission().then((permissionStatus) => { setPermissions(permissionStatus); + // Android will never return blocked after a check, you have to request the permission to get the info. + if (permissionStatus === 'blocked') { + Linking.openSettings(); + } }); - } else if (['blocked', 'never_ask_again'].includes(permissions)) { + } else if (permissions === 'blocked') { Linking.openSettings(); } }; From d16d9792ac04cbe9efe31dc7ac68ab49aa7a4dfd Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 30 Aug 2023 01:42:00 +0700 Subject: [PATCH 3/6] use predefined constants --- .../CameraPermission/index.android.js | 2 +- src/pages/iou/ReceiptSelector/index.native.js | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js index ef0d8e4bddd3..3eb9ef4eea5a 100644 --- a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js +++ b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js @@ -1,4 +1,4 @@ -import {check, PERMISSIONS, request} from "react-native-permissions"; +import {check, PERMISSIONS, request} from 'react-native-permissions'; function requestCameraPermission() { return request(PERMISSIONS.ANDROID.CAMERA); diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index dcc1f24ae673..e2378883a80e 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -6,6 +6,7 @@ import PropTypes from 'prop-types'; import {launchImageLibrary} from 'react-native-image-picker'; import {withOnyx} from 'react-native-onyx'; import {useIsFocused} from '@react-navigation/native'; +import {RESULTS} from 'react-native-permissions'; import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback'; import Icon from '../../../components/Icon'; import * as Expensicons from '../../../components/Icon/Expensicons'; @@ -100,7 +101,8 @@ function ReceiptSelector(props) { const camera = useRef(null); const [flash, setFlash] = useState(false); - const [permissions, setPermissions] = useState('authorized'); + const [permissions, setPermissions] = useState('granted'); + const isAndroidBlockedPermissionRef = useRef(false); const appState = useRef(AppState.currentState); const iouType = lodashGet(props.route, 'params.iouType', ''); @@ -157,16 +159,14 @@ function ReceiptSelector(props) { }; const askForPermissions = () => { - if (permissions === 'denied') { + // Android will never return blocked after a check, you have to request the permission to get the info. + if (permissions === RESULTS.BLOCKED || isAndroidBlockedPermissionRef.current) { + Linking.openSettings(); + } else if (permissions === RESULTS.DENIED) { CameraPermission.requestCameraPermission().then((permissionStatus) => { setPermissions(permissionStatus); - // Android will never return blocked after a check, you have to request the permission to get the info. - if (permissionStatus === 'blocked') { - Linking.openSettings(); - } + isAndroidBlockedPermissionRef.current = permissionStatus === RESULTS.BLOCKED; }); - } else if (permissions === 'blocked') { - Linking.openSettings(); } }; @@ -230,7 +230,7 @@ function ReceiptSelector(props) { return ( - {permissions !== CONST.RECEIPT.PERMISSION_GRANTED && ( + {permissions !== RESULTS.GRANTED && ( )} - {permissions === CONST.RECEIPT.PERMISSION_GRANTED && device == null && ( + {permissions === RESULTS.GRANTED && device == null && ( )} - {permissions === CONST.RECEIPT.PERMISSION_GRANTED && device != null && ( + {permissions === RESULTS.GRANTED && device != null && ( Date: Wed, 30 Aug 2023 04:36:37 +0700 Subject: [PATCH 4/6] add comment --- src/pages/iou/ReceiptSelector/index.native.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index e2378883a80e..5a486f907f37 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -159,7 +159,8 @@ function ReceiptSelector(props) { }; const askForPermissions = () => { - // Android will never return blocked after a check, you have to request the permission to get the info. + // There's no way we can check for the BLOCKED status without requesting the permission first + // https://github.com/zoontek/react-native-permissions/blob/a836e114ce3a180b2b23916292c79841a267d828/README.md?plain=1#L670 if (permissions === RESULTS.BLOCKED || isAndroidBlockedPermissionRef.current) { Linking.openSettings(); } else if (permissions === RESULTS.DENIED) { From fd64c225e605f5d3cfedb08b53f066ed347624a0 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 31 Aug 2023 09:56:39 +0700 Subject: [PATCH 5/6] fix lint --- src/pages/iou/ReceiptSelector/index.native.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index 3893795b97d4..4ccaad40cdb5 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -21,7 +21,6 @@ import Button from '../../../components/Button'; import useLocalize from '../../../hooks/useLocalize'; import ONYXKEYS from '../../../ONYXKEYS'; import Log from '../../../libs/Log'; -import participantPropTypes from '../../../components/participantPropTypes'; import * as CameraPermission from './CameraPermission'; import {iouPropTypes, iouDefaultProps} from '../propTypes'; From 6c0320f20367dd8e472fee7512d673ce1fead53a Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 4 Sep 2023 23:34:16 +0700 Subject: [PATCH 6/6] fix lint --- src/pages/iou/ReceiptSelector/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js index 3b87fe448aef..4ff32d940c9f 100644 --- a/src/pages/iou/ReceiptSelector/index.native.js +++ b/src/pages/iou/ReceiptSelector/index.native.js @@ -1,6 +1,6 @@ import {ActivityIndicator, Alert, AppState, Linking, Text, View} from 'react-native'; import React, {useCallback, useEffect, useRef, useState} from 'react'; -import {Camera, useCameraDevices} from 'react-native-vision-camera'; +import {useCameraDevices} from 'react-native-vision-camera'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import {launchImageLibrary} from 'react-native-image-picker';