diff --git a/src/components/MapView/GPSMapView.tsx b/src/components/MapView/GPSMapView.tsx index 7910e3d9b759..950bf3932161 100644 --- a/src/components/MapView/GPSMapView.tsx +++ b/src/components/MapView/GPSMapView.tsx @@ -16,7 +16,7 @@ import type {MapState} from '@rnmapbox/maps'; import {useFocusEffect} from '@react-navigation/native'; import Mapbox, {MarkerView} from '@rnmapbox/maps'; -import {getForegroundPermissionsAsync, requestForegroundPermissionsAsync} from 'expo-location'; +import {getForegroundPermissionsAsync} from 'expo-location'; import {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import {useSharedValue} from 'react-native-reanimated'; @@ -55,14 +55,15 @@ function GPSMapView({accessToken, style, mapPadding, styleURL, pitchEnabled, way const [foregroundLocationPermissionsGranted, setForegroundLocationPermissionsGranted] = useState(null); - // Request foreground location permissions if not granted yet to determine if we can use followUserLocation prop on the map camera + // Check (never request) foreground location permissions to determine if we can use the followUserLocation prop on the map camera. + // Requesting here would trigger an OS prompt on open without a prior explicit user action, so we only read the current status. useFocusEffect(() => { if (isOffline) { return; } let ignore = false; - requestForegroundPermissionsAsync().then(({granted}) => { + getForegroundPermissionsAsync().then(({granted}) => { if (ignore) { return; } diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 1d4531771ba3..acba06272d65 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -22,6 +22,7 @@ import type {MapState} from '@rnmapbox/maps'; import {useFocusEffect, useNavigation} from '@react-navigation/native'; import Mapbox, {MarkerView} from '@rnmapbox/maps'; +import {getForegroundPermissionsAsync} from 'expo-location'; import {memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import {useSharedValue} from 'react-native-reanimated'; @@ -114,10 +115,37 @@ function MapView({ return; } - getCurrentPosition((params) => { - const currentCoords = {longitude: params.coords.longitude, latitude: params.coords.latitude}; - setUserLocation(currentCoords); - }, setCurrentPositionToInitialState); + // Only read the device location when permission is ALREADY granted. We never request it here, + // so opening the map cannot trigger an OS permission prompt without a prior explicit user action. + let ignore = false; + getForegroundPermissionsAsync().then(({granted}) => { + if (ignore) { + return; + } + if (!granted) { + // Pass the permission-denied error so any stale cached location is cleared and the map falls back to initialState. + setCurrentPositionToInitialState({ + code: GeolocationErrorCode.PERMISSION_DENIED, + message: 'User denied access to location.', + }); + return; + } + + getCurrentPosition((params) => { + if (ignore) { + return; + } + const currentCoords = { + longitude: params.coords.longitude, + latitude: params.coords.latitude, + }; + setUserLocation(currentCoords); + }, setCurrentPositionToInitialState); + }); + + return () => { + ignore = true; + }; }, [isOffline, shouldPanMapToCurrentPosition, setCurrentPositionToInitialState]), );