diff --git a/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java b/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java index 45acab0480..0006c35747 100644 --- a/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java +++ b/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java @@ -10898,6 +10898,36 @@ public static boolean checkForPermission(String permission, String description, if(android.os.Build.VERSION.SDK_INT < 23){ return true; } + + if (android.os.Build.VERSION.SDK_INT >= 30 && "android.permission.ACCESS_BACKGROUND_LOCATION".equals(permission)) { + if (android.support.v4.content.ContextCompat.checkSelfPermission(getContext(), permission) == PackageManager.PERMISSION_GRANTED) { + return true; + } + if (getActivity() == null) { + return false; + } + + String prompt = Display.getInstance().getProperty(permission, description); + String title = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.title", "Requires permission"); + String settingsBtn = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.settings", "Settings"); + String cancelBtn = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.cancel", "Cancel"); + + if(Dialog.show(title, prompt, settingsBtn, cancelBtn)){ + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", getContext().getPackageName(), null); + intent.setData(uri); + getActivity().startActivity(intent); + + String explanationTitle = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.explanation_title", "Permission Required"); + String explanationBody = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.explanation_body", "Please enable 'Allow all the time' in the settings, then press OK."); + String okBtn = Display.getInstance().getProperty("android.permission.ACCESS_BACKGROUND_LOCATION.ok", "OK"); + + Dialog.show(explanationTitle, explanationBody, okBtn, null); + return android.support.v4.content.ContextCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED; + } else { + return false; + } + } String prompt = Display.getInstance().getProperty(permission, description); diff --git a/docs/developer-guide/Miscellaneous-Features.asciidoc b/docs/developer-guide/Miscellaneous-Features.asciidoc index e12d071ecc..f15e391d14 100644 --- a/docs/developer-guide/Miscellaneous-Features.asciidoc +++ b/docs/developer-guide/Miscellaneous-Features.asciidoc @@ -450,6 +450,12 @@ LocationManager.getLocationManager() .addGeoFencing(GeofenceListenerImpl.class, gf); ---- +===== Android Background Location Permissions (API 30+) + +On Android 11 (API level 30) and higher, requesting background location permission requires a two-step process. First, foreground location permissions must be granted. Then, the app must request background location access, which will direct the user to the system settings to select "Allow all the time". Codename One handles this flow automatically when you use `LocationManager`. + +For Android 11+ (API 30+), Codename One detects if background location is needed and presents a dialog explaining the requirement before redirecting the user to the app settings. You can customize the permission prompt message using the localization key `android.permission.ACCESS_BACKGROUND_LOCATION`. + [source,java] ---- public class GeofenceListenerImpl implements GeofenceListener {