diff --git a/app/androidutils.cpp b/app/androidutils.cpp index c6fe3c9e6..c7ca6a77b 100644 --- a/app/androidutils.cpp +++ b/app/androidutils.cpp @@ -260,10 +260,11 @@ bool AndroidUtils::requestMediaLocationPermission() { #ifdef ANDROID const double buildVersion = QSysInfo::productVersion().toDouble(); - // ACCESS_MEDIA_LOCATION is a runtime permission without UI dialog (User do not need to click anything to grant it, it is granted automatically) - if ( buildVersion < ANDROID_VERSION_13 ) + // ACCESS_MEDIA_LOCATION was introduced in Android 10 and requires explicit user consent via a runtime permission dialog + if ( buildVersion >= ANDROID_VERSION_10 && !checkAndAcquirePermissions( QStringLiteral( "android.permission.ACCESS_MEDIA_LOCATION" ) ) ) { - return checkAndAcquirePermissions( "android.permission.ACCESS_MEDIA_LOCATION" ); + CoreUtils::log( QStringLiteral( "AndroidUtils" ), QStringLiteral( "Media location permission denied: GPS EXIF data will not be read from gallery-picked photos" ) ); + return false; } #endif return true; @@ -281,7 +282,7 @@ void AndroidUtils::callImagePicker( const QString &targetPath, const QString &co mLastCode = code; mTargetPath = targetPath; - // request media location permission to be able to read EXIF metadata from gallery image (only necessary for android < 14) + // request media location permission to be able to read unredacted EXIF metadata from gallery image // it is not a mandatory permission, so continue even if it is rejected requestMediaLocationPermission(); @@ -309,10 +310,6 @@ void AndroidUtils::callCamera( const QString &targetPath, const QString &code ) mLastCode = code; - // request media location permission to be able to read EXIF metadata from captured image - // it is not a mandatory permission, so continue even if it is rejected - requestMediaLocationPermission(); - const QJniObject activity = QJniObject::fromString( QStringLiteral( "uk.co.lutraconsulting.CameraActivity" ) ); const QJniObject intent = QJniObject( "android/content/Intent", "(Ljava/lang/String;)V", activity.object() ); diff --git a/app/androidutils.h b/app/androidutils.h index b98e7a44f..63a68638a 100644 --- a/app/androidutils.h +++ b/app/androidutils.h @@ -75,6 +75,7 @@ class AndroidUtils: public QObject static constexpr int BLUETOOTH_CODE = 103; static constexpr int ANDROID_VERSION_13 = 13; + static constexpr int ANDROID_VERSION_10 = 10; void handleActivityResult( int receiverRequestCode, int resultCode, const QJniObject &data ) override; #endif diff --git a/app/inputexpressionfunctions.cpp b/app/inputexpressionfunctions.cpp index 5e4cabb9d..efb005322 100644 --- a/app/inputexpressionfunctions.cpp +++ b/app/inputexpressionfunctions.cpp @@ -59,7 +59,12 @@ QVariant ReadExifLatitude::func( const QVariantList &values, const QgsExpression if ( resultString.isEmpty() ) return QVariant(); - return QVariant( InputUtils::convertCoordinateString( resultString ) ); + double lat = InputUtils::convertCoordinateString( resultString ); + QString latRef = AndroidUtils::readExif( filepath, QStringLiteral( "GPSLatitudeRef" ) ); + if ( lat > 0.0 && latRef.startsWith( QLatin1Char( 'S' ), Qt::CaseInsensitive ) ) + lat = -lat; + return QVariant( lat ); + #elif defined( Q_OS_IOS ) double lat = IosUtils::readExif( filepath, GPS_LAT_TAG ).toDouble(); QString latRef = IosUtils::readExif( filepath, QStringLiteral( "GPSLatitudeRef" ) ); @@ -81,7 +86,12 @@ QVariant ReadExifLongitude::func( const QVariantList &values, const QgsExpressio if ( resultString.isEmpty() ) return QVariant(); - return QVariant( InputUtils::convertCoordinateString( resultString ) ); + double lon = InputUtils::convertCoordinateString( resultString ); + QString lonRef = AndroidUtils::readExif( filepath, QStringLiteral( "GPSLongitudeRef" ) ); + if ( lon > 0.0 && lonRef.startsWith( QLatin1Char( 'W' ), Qt::CaseInsensitive ) ) + lon = -lon; + return QVariant( lon ); + #elif defined( Q_OS_IOS ) double lon = IosUtils::readExif( filepath, GPS_LON_TAG ).toDouble(); QString lonRef = IosUtils::readExif( filepath, QStringLiteral( "GPSLongitudeRef" ) );