From d955c868aab6129a9c0f905a88e95759c4fc56be Mon Sep 17 00:00:00 2001 From: Jeroen Weener Date: Fri, 10 Nov 2023 12:54:00 +0100 Subject: [PATCH] Port `Settings.canDrawOverlays` (#1216) --- .../ActivityHostApiImpl.java | 85 ------- .../PermissionHandlerPigeon.java | 220 +++++------------- .../PermissionHandlerPlugin.java | 7 +- .../SettingsHostApiImpl.java | 55 +++++ .../src/android_object_mirrors/activity.dart | 70 +----- .../src/android_object_mirrors/context.dart | 4 + .../package_manager.dart | 8 +- .../src/android_object_mirrors/settings.dart | 32 +++ .../android_permission_handler_api_impls.dart | 107 +++------ .../lib/src/permission_handler.pigeon.dart | 214 +++++------------ .../pigeons/android_permission_handler.dart | 66 ++---- .../test/test_permission_handler.pigeon.dart | 207 +++++----------- 12 files changed, 341 insertions(+), 734 deletions(-) create mode 100644 permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/SettingsHostApiImpl.java diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java index 476f28a49..96ab6386e 100644 --- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java @@ -1,10 +1,7 @@ package com.baseflow.permissionhandler; import android.app.Activity; -import android.app.AlarmManager; import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.PowerManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -56,12 +53,6 @@ public class ActivityHostApiImpl implements private final InstanceManager instanceManager; - private final PowerManagerFlutterApiImpl powerManagerFlutterApi; - - private final AlarmManagerFlutterApiImpl alarmManagerFlutterApi; - - private final PackageManagerFlutterApiImpl packageManagerFlutterApi; - /** * Callbacks to complete a pending permission request. *

@@ -85,15 +76,9 @@ public class ActivityHostApiImpl implements * @param instanceManager maintains instances stored to communicate with attached Dart objects */ public ActivityHostApiImpl( - @NonNull PowerManagerFlutterApiImpl powerManagerFlutterApi, - @NonNull AlarmManagerFlutterApiImpl alarmManagerFlutterApi, - @NonNull PackageManagerFlutterApiImpl packageManagerFlutterApi, @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager ) { - this.powerManagerFlutterApi = powerManagerFlutterApi; - this.alarmManagerFlutterApi = alarmManagerFlutterApi; - this.packageManagerFlutterApi = packageManagerFlutterApi; this.binaryMessenger = binaryMessenger; this.instanceManager = instanceManager; } @@ -109,17 +94,6 @@ public ActivityHostApiImpl( return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission); } - @Override - @NonNull public Long checkSelfPermission( - @NonNull String activityInstanceId, - @NonNull String permission - ) { - final UUID activityInstanceUuid = UUID.fromString(activityInstanceId); - final Activity activity = instanceManager.getInstance(activityInstanceUuid); - - return (long) ActivityCompat.checkSelfPermission(activity, permission); - } - @Override public void requestPermissions( @NonNull String activityInstanceId, @@ -166,30 +140,6 @@ public boolean onRequestPermissionsResult( return true; } - @Override - public void startActivity( - @NonNull String instanceId, - @NonNull String intentInstanceId - ) { - final UUID instanceUuid = UUID.fromString(instanceId); - final UUID intentInstanceUuid = UUID.fromString(intentInstanceId); - - final Activity activity = instanceManager.getInstance(instanceUuid); - final Intent intent = instanceManager.getInstance(intentInstanceUuid); - - ActivityCompat.startActivity(activity, intent, null); - } - - @Override - @NonNull public String getPackageName( - @NonNull String instanceId - ) { - final UUID instanceUuid = UUID.fromString(instanceId); - final Activity activity = instanceManager.getInstance(instanceUuid); - - return activity.getPackageName(); - } - @Override public void startActivityForResult( @NonNull String instanceId, @@ -234,39 +184,4 @@ public boolean onActivityResult( return true; } - - @Override - @NonNull public String getSystemService( - @NonNull String instanceId, - @NonNull String name - ) { - final UUID instanceUuid = UUID.fromString(instanceId); - final Activity activity = instanceManager.getInstance(instanceUuid); - - final Object systemService = activity.getSystemService(name); - - if (systemService instanceof PowerManager) { - powerManagerFlutterApi.create((PowerManager) systemService); - } else if (systemService instanceof AlarmManager) { - alarmManagerFlutterApi.create((AlarmManager) systemService); - } - - final UUID systemServiceUuid = instanceManager.getIdentifierForStrongReference(systemService); - return systemServiceUuid.toString(); - } - - @Override - @NonNull public String getPackageManager( - @NonNull String instanceId - ) { - final UUID instanceUuid = UUID.fromString(instanceId); - final Activity activity = instanceManager.getInstance(instanceUuid); - - final PackageManager packageManager = activity.getPackageManager(); - - packageManagerFlutterApi.create(packageManager); - - final UUID packageManagerUuid = instanceManager.getIdentifierForStrongReference(packageManager); - return packageManagerUuid.toString(); - } } diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java index bd2d28470..37f993927 100644 --- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java @@ -311,13 +311,6 @@ public interface ActivityHostApi { */ @NonNull Boolean shouldShowRequestPermissionRationale(@NonNull String instanceId, @NonNull String permission); - /** - * Determine whether the application has been granted a particular permission. - * - * See https://developer.android.com/reference/android/app/Activity#checkSelfPermission(java.lang.String). - */ - @NonNull - Long checkSelfPermission(@NonNull String instanceId, @NonNull String permission); /** * Requests permissions to be granted to this application. * @@ -327,43 +320,12 @@ public interface ActivityHostApi { * https://developer.android.com/reference/android/app/Activity#onRequestPermissionsResult(int,%20java.lang.String[],%20int[]). */ void requestPermissions(@NonNull String instanceId, @NonNull List permissions, @Nullable Long requestCode, @NonNull Result result); - /** - * Launch a new activity. - * - * See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - */ - void startActivity(@NonNull String instanceId, @NonNull String intentInstanceId); - /** - * Returns the name of this application's package. - * - * See https://developer.android.com/reference/android/content/Context#getPackageName(). - */ - @NonNull - String getPackageName(@NonNull String instanceId); - /** - * Return the handle to a system-level service by name. - * - * The class of the returned object varies by the requested name. - * - * Returns the instance ID of the service. - * - * See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - */ - @NonNull - String getSystemService(@NonNull String instanceId, @NonNull String name); /** * Start an activity for which the application would like a result when it finished. * * See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). */ void startActivityForResult(@NonNull String instanceId, @NonNull String intentInstanceId, @Nullable Long requestCode, @NonNull Result result); - /** - * Returns the instance ID of a PackageManager instance to find global package information. - * - * See https://developer.android.com/reference/android/content/Context#getPackageManager(). - */ - @NonNull - String getPackageManager(@NonNull String instanceId); /** The codec used by ActivityHostApi. */ static @NonNull MessageCodec getCodec() { @@ -386,31 +348,6 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable ActivityHo Boolean output = api.shouldShowRequestPermissionRationale(instanceIdArg, permissionArg); wrapped.add(0, output); } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - String instanceIdArg = (String) args.get(0); - String permissionArg = (String) args.get(1); - try { - Long output = api.checkSelfPermission(instanceIdArg, permissionArg); - wrapped.add(0, output); - } catch (Throwable exception) { ArrayList wrappedError = wrapError(exception); wrapped = wrappedError; @@ -452,80 +389,6 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - String instanceIdArg = (String) args.get(0); - String intentInstanceIdArg = (String) args.get(1); - try { - api.startActivity(instanceIdArg, intentInstanceIdArg); - wrapped.add(0, null); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - String instanceIdArg = (String) args.get(0); - try { - String output = api.getPackageName(instanceIdArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - String instanceIdArg = (String) args.get(0); - String nameArg = (String) args.get(1); - try { - String output = api.getSystemService(instanceIdArg, nameArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -557,30 +420,6 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageManager", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - String instanceIdArg = (String) args.get(0); - try { - String output = api.getPackageManager(instanceIdArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } } } /** @@ -1483,4 +1322,63 @@ public void dispose(@NonNull String instanceIdArg, @NonNull Reply callback channelReply -> callback.reply(null)); } } + /** + * Host API for `Settings`. + * + * This class may handle instantiating and adding native object instances that + * are attached to a Dart instance or handle method calls on the associated + * native class or an instance of the class. + * + * See https://developer.android.com/reference/kotlin/android/provider/Settings. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ + public interface SettingsHostApi { + /** + * Checks if the specified context can draw on top of other apps. + * + * As of API level 23, an app cannot draw on top of other apps unless it + * declares the [Manifest.permission.systemAlertWindow] permission in its + * manifest, **and** the user specifically grants the app this capability. To + * prompt the user to grant this approval, the app must send an intent with + * the action [Settings.actionManageOverlayPermission], which causes the + * system to display a permission management screen. + * + * See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + */ + @NonNull + Boolean canDrawOverlays(@NonNull String contextInstanceId); + + /** The codec used by SettingsHostApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /**Sets up an instance of `SettingsHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable SettingsHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.permission_handler_android.SettingsHostApi.canDrawOverlays", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + String contextInstanceIdArg = (String) args.get(0); + try { + Boolean output = api.canDrawOverlays(contextInstanceIdArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } } diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java index 012b91b14..bccd87d51 100644 --- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java @@ -17,6 +17,7 @@ import com.baseflow.permissionhandler.PermissionHandlerPigeon.IntentHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.PackageManagerHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.PowerManagerHostApi; +import com.baseflow.permissionhandler.PermissionHandlerPigeon.SettingsHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.UriHostApi; import io.flutter.embedding.engine.plugins.FlutterPlugin; @@ -72,11 +73,11 @@ private void setUp( final PackageManagerHostApi packageManagerHostApi = new PackageManagerHostApiImpl(binaryMessenger, instanceManager); PackageManagerHostApi.setup(binaryMessenger, packageManagerHostApi); + final SettingsHostApi settingsHostApi = new SettingsHostApiImpl(binaryMessenger, instanceManager); + SettingsHostApi.setup(binaryMessenger, settingsHostApi); + activityFlutterApi = new ActivityFlutterApiImpl(binaryMessenger, instanceManager); activityHostApi = new ActivityHostApiImpl( - powerManagerFlutterApi, - alarmManagerFlutterApi, - packageManagerFlutterApi, binaryMessenger, instanceManager ); diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/SettingsHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/SettingsHostApiImpl.java new file mode 100644 index 000000000..c3ac437cb --- /dev/null +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/SettingsHostApiImpl.java @@ -0,0 +1,55 @@ +package com.baseflow.permissionhandler; + +import android.content.Context; +import android.os.Build; +import android.provider.Settings; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import com.baseflow.instancemanager.InstanceManager; +import com.baseflow.permissionhandler.PermissionHandlerPigeon.SettingsHostApi; + +import java.util.UUID; + +import io.flutter.plugin.common.BinaryMessenger; + +/** + * Host API implementation for `Settings`. + * + *

This class may handle instantiating and adding native object instances that are attached to a + * Dart instance or handle method calls on the associated native class or an instance of the class. + */ +public class SettingsHostApiImpl implements SettingsHostApi { + // To ease adding additional methods, this value is added prematurely. + @SuppressWarnings({"unused", "FieldCanBeLocal"}) + private final BinaryMessenger binaryMessenger; + + private final InstanceManager instanceManager; + + /** + * Constructs an {@link SettingsHostApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public SettingsHostApiImpl( + @NonNull BinaryMessenger binaryMessenger, + @NonNull InstanceManager instanceManager + ) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + } + + @RequiresApi(api = Build.VERSION_CODES.M) + @NonNull + @Override + public Boolean canDrawOverlays( + @NonNull String contextInstanceId + ) { + final UUID contextInstanceUuid = UUID.fromString(contextInstanceId); + final Context context = instanceManager.getInstance(contextInstanceUuid); + + return Settings.canDrawOverlays(context); + } +} diff --git a/permission_handler_android/lib/src/android_object_mirrors/activity.dart b/permission_handler_android/lib/src/android_object_mirrors/activity.dart index 7c59d83db..71bef8c9e 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/activity.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/activity.dart @@ -10,7 +10,7 @@ import '../android_permission_handler_api_impls.dart'; /// An activity is a single, focused thing that the user can do. /// /// See https://developer.android.com/reference/android/app/Activity. -class Activity extends JavaObject { +class Activity extends Context { /// Instantiates an [Activity] without creating and attaching to an instance /// of the associated native class. Activity.detached({ @@ -30,10 +30,20 @@ class Activity extends JavaObject { /// Use with [Context.getSystemService] to retrieve a [PowerManager] for /// controlling power management, including "wake locks," which let you keep /// the device on while you're running long tasks. + /// + /// Copy of [Context.powerService], as static fields are not inherited in + /// Dart. + /// + /// See https://developer.android.com/reference/android/content/Context.html#POWER_SERVICE. static const String powerService = 'power'; /// Use with [Context.getSystemService] to retrieve an [AlarmManager] for /// receiving intents at a time of your choosing. + /// + /// Copy of [Context.alarmService], as static fields are not inherited in + /// Dart. + /// + /// See https://developer.android.com/reference/android/content/Context.html#ALARM_SERVICE. static const String alarmService = 'alarm'; /// Standard activity result: operation succeeded. @@ -62,18 +72,6 @@ class Activity extends JavaObject { ); } - /// Determines whether the application has been granted a particular permission. - /// - /// See https://developer.android.com/reference/android/content/ContextWrapper#checkSelfPermission(java.lang.String). - Future checkSelfPermission( - String permission, - ) { - return _hostApi.checkSelfPermissionFromInstance( - this, - permission, - ); - } - /// Requests permissions to be granted to this application. /// /// See @@ -91,27 +89,6 @@ class Activity extends JavaObject { ); } - /// Launches a new activity. - /// - /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - Future startActivity( - Intent intent, - ) { - return _hostApi.startActivityFromInstance( - this, - intent, - ); - } - - /// Returns the name of this application's package. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageName(). - Future getPackageName() { - return _hostApi.getPackageNameFromInstance( - this, - ); - } - /// Start an activity for which the application would like a result when it finished. /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). @@ -125,31 +102,6 @@ class Activity extends JavaObject { requestCode, ); } - - /// Returns the handle to a system-level service by name. - /// - /// The class of the returned object varies by the requested name. - /// - /// Returns the instance ID of the service. - /// - /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - Future getSystemService( - String name, - ) { - return _hostApi.getSystemServiceFromInstance( - this, - name, - ); - } - - /// Returns a PackageManager instance to find global package information. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). - Future getPackageManager() { - return _hostApi.getPackageManagerFromInstance( - this, - ); - } } /// Result of an activity-for-result request. diff --git a/permission_handler_android/lib/src/android_object_mirrors/context.dart b/permission_handler_android/lib/src/android_object_mirrors/context.dart index 445cf2782..6dd2b156b 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/context.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/context.dart @@ -32,10 +32,14 @@ class Context extends JavaObject { /// Use with [Context.getSystemService] to retrieve a [PowerManager] for /// controlling power management, including "wake locks," which let you keep /// the device on while you're running long tasks. + /// + /// See https://developer.android.com/reference/android/content/Context.html#POWER_SERVICE. static const String powerService = 'power'; /// Use with [Context.getSystemService] to retrieve an [AlarmManager] for /// receiving intents at a time of your choosing. + /// + /// See https://developer.android.com/reference/android/content/Context.html#ALARM_SERVICE. static const String alarmService = 'alarm'; /// Determines whether the application has been granted a particular permission. diff --git a/permission_handler_android/lib/src/android_object_mirrors/package_manager.dart b/permission_handler_android/lib/src/android_object_mirrors/package_manager.dart index 56c466c33..205989958 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/package_manager.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/package_manager.dart @@ -2,6 +2,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_instance_manager/flutter_instance_manager.dart'; import '../android_permission_handler_api_impls.dart'; +import 'build.dart'; /// Class for retrieving various kinds of information related to the application /// packages that are currently installed on the device. You can find this class @@ -35,7 +36,12 @@ class PackageManager extends JavaObject { /// Checks whether the calling package is allowed to request package installs through package installer. /// /// See https://developer.android.com/reference/android/content/pm/PackageManager#canRequestPackageInstalls(). - Future canRequestPackageInstalls() { + Future canRequestPackageInstalls() async { + final int sdkVersion = await Build.version.sdkInt; + if (sdkVersion < Build.versionCodes.m) { + return true; + } + return _hostApi.canRequestPackageInstallsFromInstance(this); } } diff --git a/permission_handler_android/lib/src/android_object_mirrors/settings.dart b/permission_handler_android/lib/src/android_object_mirrors/settings.dart index 464c99298..f12e20c2b 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/settings.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/settings.dart @@ -1,9 +1,15 @@ +import '../android_permission_handler_api_impls.dart'; +import 'build.dart'; +import 'context.dart'; + /// The Settings provider contains global system-level device preferences. /// /// See https://developer.android.com/reference/android/provider/Settings. class Settings { const Settings._(); + static final SettingsHostApiImpl _hostApi = SettingsHostApiImpl(); + /// Activity Action: Show screen of details about a particular application. /// /// Constant Value: "android.settings.APPLICATION_DETAILS_SETTINGS". @@ -80,4 +86,30 @@ class Settings { /// See https://developer.android.com/reference/android/provider/Settings#ACTION_MANAGE_OVERLAY_PERMISSION. static const String actionRequestScheduleExactAlarm = 'android.settings.REQUEST_SCHEDULE_EXACT_ALARM'; + + /// Checks if the specified context can draw on top of other apps. + /// + /// As of API level 23, an app cannot draw on top of other apps unless it + /// declares the [Manifest.permission.systemAlertWindow] permission in its + /// manifest, **and** the user specifically grants the app this capability. To + /// prompt the user to grant this approval, the app must send an intent with + /// the action [Settings.actionManageOverlayPermission], which causes the + /// system to display a permission management screen. + /// + /// Always returns true on devices running Android versions older than + /// [Build.versionCodes.m]. + /// + /// See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + static Future canDrawOverlays( + Context context, + ) async { + final int sdkVersion = await Build.version.sdkInt; + if (sdkVersion < Build.versionCodes.m) { + return true; + } + + return _hostApi.canDrawOverlaysFromInstance( + context, + ); + } } diff --git a/permission_handler_android/lib/src/android_permission_handler_api_impls.dart b/permission_handler_android/lib/src/android_permission_handler_api_impls.dart index 23f901a40..8fe03cc8e 100644 --- a/permission_handler_android/lib/src/android_permission_handler_api_impls.dart +++ b/permission_handler_android/lib/src/android_permission_handler_api_impls.dart @@ -97,21 +97,6 @@ class ActivityHostApiImpl extends ActivityHostApi { ); } - /// Determine whether the application has been granted a particular permission. - /// - /// See https://developer.android.com/reference/android/content/ContextWrapper#checkSelfPermission(java.lang.String). - Future checkSelfPermissionFromInstance( - Activity activity, - String permission, - ) async { - final String activityInstanceId = instanceManager.getIdentifier(activity)!; - - return checkSelfPermission( - activityInstanceId, - permission, - ); - } - /// Requests permissions to be granted to this application. /// /// See @@ -137,30 +122,6 @@ class ActivityHostApiImpl extends ActivityHostApi { ); } - /// Launch a new activity. - /// - /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - Future startActivityFromInstance( - Activity activity, - Intent intent, - ) async { - return startActivity( - instanceManager.getIdentifier(activity)!, - instanceManager.getIdentifier(intent)!, - ); - } - - /// Returns the name of this application's package. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageName(). - Future getPackageNameFromInstance( - Activity activity, - ) async { - return getPackageName( - instanceManager.getIdentifier(activity)!, - ); - } - /// Start an activity for which the application would like a result when it finished. /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). @@ -192,37 +153,6 @@ class ActivityHostApiImpl extends ActivityHostApi { requestCode: requestCode, ); } - - /// Return the handle to a system-level service by name. - /// - /// Returns the instance ID of the service. - /// - /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - Future getSystemServiceFromInstance( - Activity activity, - String name, - ) async { - final String systemServiceId = await getSystemService( - instanceManager.getIdentifier(activity)!, - name, - ); - - return instanceManager.getInstanceWithWeakReference(systemServiceId); - } - - /// Return PackageManager instance to find global package information. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). - Future getPackageManagerFromInstance( - Activity activity, - ) async { - final String packageManagerId = await getPackageManager( - instanceManager.getIdentifier(activity)!, - ); - - return instanceManager.getInstanceWithWeakReference(packageManagerId) - as PackageManager; - } } /// Flutter API implementation of Activity. @@ -683,3 +613,40 @@ class PackageManagerFlutterApiImpl extends PackageManagerFlutterApi { _instanceManager.remove(instanceId); } } + +/// Host API implementation of Settings. +class SettingsHostApiImpl extends SettingsHostApi { + /// Creates a new instance of [SettingsHostApiImpl]. + SettingsHostApiImpl({ + this.binaryMessenger, + InstanceManager? instanceManager, + }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager, + super(binaryMessenger: binaryMessenger); + + /// Sends binary data across the Flutter platform barrier. + /// + /// If it is null, the default BinaryMessenger will be used which routes to + /// the host platform. + final BinaryMessenger? binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager instanceManager; + + /// Checks if the specified context can draw on top of other apps. + /// + /// As of API level 23, an app cannot draw on top of other apps unless it + /// declares the [Manifest.permission.systemAlertWindow] permission in its + /// manifest, **and** the user specifically grants the app this capability. To + /// prompt the user to grant this approval, the app must send an intent with + /// the action [Settings.actionManageOverlayPermission], which causes the + /// system to display a permission management screen. + /// + /// See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + Future canDrawOverlaysFromInstance( + Context context, + ) { + return canDrawOverlays( + instanceManager.getIdentifier(context)!, + ); + } +} diff --git a/permission_handler_android/lib/src/permission_handler.pigeon.dart b/permission_handler_android/lib/src/permission_handler.pigeon.dart index c7b067120..4632543da 100644 --- a/permission_handler_android/lib/src/permission_handler.pigeon.dart +++ b/permission_handler_android/lib/src/permission_handler.pigeon.dart @@ -153,38 +153,6 @@ class ActivityHostApi { } } - /// Determine whether the application has been granted a particular permission. - /// - /// See https://developer.android.com/reference/android/app/Activity#checkSelfPermission(java.lang.String). - Future checkSelfPermission( - String arg_instanceId, String arg_permission) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission', - codec, - binaryMessenger: _binaryMessenger); - final List? replyList = await channel - .send([arg_instanceId, arg_permission]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as int?)!; - } - } - /// Requests permissions to be granted to this application. /// /// See @@ -221,101 +189,6 @@ class ActivityHostApi { } } - /// Launch a new activity. - /// - /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - Future startActivity( - String arg_instanceId, String arg_intentInstanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity', - codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_instanceId, arg_intentInstanceId]) - as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; - } - } - - /// Returns the name of this application's package. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageName(). - Future getPackageName(String arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName', - codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_instanceId]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as String?)!; - } - } - - /// Return the handle to a system-level service by name. - /// - /// The class of the returned object varies by the requested name. - /// - /// Returns the instance ID of the service. - /// - /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - Future getSystemService( - String arg_instanceId, String arg_name) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService', - codec, - binaryMessenger: _binaryMessenger); - final List? replyList = await channel - .send([arg_instanceId, arg_name]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as String?)!; - } - } - /// Start an activity for which the application would like a result when it finished. /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). @@ -348,37 +221,6 @@ class ActivityHostApi { return (replyList[0] as ActivityResultPigeon?)!; } } - - /// Returns the instance ID of a PackageManager instance to find global package information. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). - Future getPackageManager(String arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageManager', - codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_instanceId]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as String?)!; - } - } } /// Flutter API for `Activity`. @@ -1302,3 +1144,59 @@ abstract class PackageManagerFlutterApi { } } } + +/// Host API for `Settings`. +/// +/// This class may handle instantiating and adding native object instances that +/// are attached to a Dart instance or handle method calls on the associated +/// native class or an instance of the class. +/// +/// See https://developer.android.com/reference/kotlin/android/provider/Settings. +class SettingsHostApi { + /// Constructor for [SettingsHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + SettingsHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + /// Checks if the specified context can draw on top of other apps. + /// + /// As of API level 23, an app cannot draw on top of other apps unless it + /// declares the [Manifest.permission.systemAlertWindow] permission in its + /// manifest, **and** the user specifically grants the app this capability. To + /// prompt the user to grant this approval, the app must send an intent with + /// the action [Settings.actionManageOverlayPermission], which causes the + /// system to display a permission management screen. + /// + /// See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + Future canDrawOverlays(String arg_contextInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.SettingsHostApi.canDrawOverlays', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_contextInstanceId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as bool?)!; + } + } +} diff --git a/permission_handler_android/pigeons/android_permission_handler.dart b/permission_handler_android/pigeons/android_permission_handler.dart index 5cca51b79..ec68b23c5 100644 --- a/permission_handler_android/pigeons/android_permission_handler.dart +++ b/permission_handler_android/pigeons/android_permission_handler.dart @@ -64,14 +64,6 @@ abstract class ActivityHostApi { String permission, ); - /// Determine whether the application has been granted a particular permission. - /// - /// See https://developer.android.com/reference/android/app/Activity#checkSelfPermission(java.lang.String). - int checkSelfPermission( - String instanceId, - String permission, - ); - /// Requests permissions to be granted to this application. /// /// See @@ -85,33 +77,6 @@ abstract class ActivityHostApi { int? requestCode, ); - /// Launch a new activity. - /// - /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - void startActivity( - String instanceId, - String intentInstanceId, - ); - - /// Returns the name of this application's package. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageName(). - String getPackageName( - String instanceId, - ); - - /// Return the handle to a system-level service by name. - /// - /// The class of the returned object varies by the requested name. - /// - /// Returns the instance ID of the service. - /// - /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - String getSystemService( - String instanceId, - String name, - ); - /// Start an activity for which the application would like a result when it finished. /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). @@ -121,13 +86,6 @@ abstract class ActivityHostApi { String intentInstanceId, int? requestCode, ); - - /// Returns the instance ID of a PackageManager instance to find global package information. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). - String getPackageManager( - String instanceId, - ); } /// Flutter API for `Activity`. @@ -421,3 +379,27 @@ abstract class PackageManagerFlutterApi { /// Dispose of the Dart instance and remove it from the `InstanceManager`. void dispose(String instanceId); } + +/// Host API for `Settings`. +/// +/// This class may handle instantiating and adding native object instances that +/// are attached to a Dart instance or handle method calls on the associated +/// native class or an instance of the class. +/// +/// See https://developer.android.com/reference/kotlin/android/provider/Settings. +@HostApi(dartHostTestHandler: 'SettingsTestHostApi') +abstract class SettingsHostApi { + /// Checks if the specified context can draw on top of other apps. + /// + /// As of API level 23, an app cannot draw on top of other apps unless it + /// declares the [Manifest.permission.systemAlertWindow] permission in its + /// manifest, **and** the user specifically grants the app this capability. To + /// prompt the user to grant this approval, the app must send an intent with + /// the action [Settings.actionManageOverlayPermission], which causes the + /// system to display a permission management screen. + /// + /// See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + bool canDrawOverlays( + String contextInstanceId, + ); +} diff --git a/permission_handler_android/test/test_permission_handler.pigeon.dart b/permission_handler_android/test/test_permission_handler.pigeon.dart index a260759d7..4294aba8a 100644 --- a/permission_handler_android/test/test_permission_handler.pigeon.dart +++ b/permission_handler_android/test/test_permission_handler.pigeon.dart @@ -56,11 +56,6 @@ abstract class ActivityTestHostApi { bool shouldShowRequestPermissionRationale( String instanceId, String permission); - /// Determine whether the application has been granted a particular permission. - /// - /// See https://developer.android.com/reference/android/app/Activity#checkSelfPermission(java.lang.String). - int checkSelfPermission(String instanceId, String permission); - /// Requests permissions to be granted to this application. /// /// See @@ -70,36 +65,12 @@ abstract class ActivityTestHostApi { Future requestPermissions( String instanceId, List permissions, int? requestCode); - /// Launch a new activity. - /// - /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). - void startActivity(String instanceId, String intentInstanceId); - - /// Returns the name of this application's package. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageName(). - String getPackageName(String instanceId); - - /// Return the handle to a system-level service by name. - /// - /// The class of the returned object varies by the requested name. - /// - /// Returns the instance ID of the service. - /// - /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). - String getSystemService(String instanceId, String name); - /// Start an activity for which the application would like a result when it finished. /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). Future startActivityForResult( String instanceId, String intentInstanceId, int? requestCode); - /// Returns the instance ID of a PackageManager instance to find global package information. - /// - /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). - String getPackageManager(String instanceId); - static void setup(ActivityTestHostApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -129,33 +100,6 @@ abstract class ActivityTestHostApi { }); } } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission', - codec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission was null.'); - final List args = (message as List?)!; - final String? arg_instanceId = (args[0] as String?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission was null, expected non-null String.'); - final String? arg_permission = (args[1] as String?); - assert(arg_permission != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission was null, expected non-null String.'); - final int output = - api.checkSelfPermission(arg_instanceId!, arg_permission!); - return [output]; - }); - } - } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.requestPermissions', @@ -185,82 +129,6 @@ abstract class ActivityTestHostApi { }); } } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity', - codec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity was null.'); - final List args = (message as List?)!; - final String? arg_instanceId = (args[0] as String?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity was null, expected non-null String.'); - final String? arg_intentInstanceId = (args[1] as String?); - assert(arg_intentInstanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity was null, expected non-null String.'); - api.startActivity(arg_instanceId!, arg_intentInstanceId!); - return []; - }); - } - } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName', - codec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName was null.'); - final List args = (message as List?)!; - final String? arg_instanceId = (args[0] as String?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName was null, expected non-null String.'); - final String output = api.getPackageName(arg_instanceId!); - return [output]; - }); - } - } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService', - codec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService was null.'); - final List args = (message as List?)!; - final String? arg_instanceId = (args[0] as String?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService was null, expected non-null String.'); - final String? arg_name = (args[1] as String?); - assert(arg_name != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService was null, expected non-null String.'); - final String output = - api.getSystemService(arg_instanceId!, arg_name!); - return [output]; - }); - } - } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivityForResult', @@ -289,29 +157,6 @@ abstract class ActivityTestHostApi { }); } } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageManager', - codec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageManager was null.'); - final List args = (message as List?)!; - final String? arg_instanceId = (args[0] as String?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageManager was null, expected non-null String.'); - final String output = api.getPackageManager(arg_instanceId!); - return [output]; - }); - } - } } } @@ -932,3 +777,55 @@ abstract class PackageManagerTestHostApi { } } } + +/// Host API for `Settings`. +/// +/// This class may handle instantiating and adding native object instances that +/// are attached to a Dart instance or handle method calls on the associated +/// native class or an instance of the class. +/// +/// See https://developer.android.com/reference/kotlin/android/provider/Settings. +abstract class SettingsTestHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = StandardMessageCodec(); + + /// Checks if the specified context can draw on top of other apps. + /// + /// As of API level 23, an app cannot draw on top of other apps unless it + /// declares the [Manifest.permission.systemAlertWindow] permission in its + /// manifest, **and** the user specifically grants the app this capability. To + /// prompt the user to grant this approval, the app must send an intent with + /// the action [Settings.actionManageOverlayPermission], which causes the + /// system to display a permission management screen. + /// + /// See https://developer.android.com/reference/android/provider/Settings#canDrawOverlays(android.content.Context). + bool canDrawOverlays(String contextInstanceId); + + static void setup(SettingsTestHostApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.SettingsHostApi.canDrawOverlays', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.permission_handler_android.SettingsHostApi.canDrawOverlays was null.'); + final List args = (message as List?)!; + final String? arg_contextInstanceId = (args[0] as String?); + assert(arg_contextInstanceId != null, + 'Argument for dev.flutter.pigeon.permission_handler_android.SettingsHostApi.canDrawOverlays was null, expected non-null String.'); + final bool output = api.canDrawOverlays(arg_contextInstanceId!); + return [output]; + }); + } + } + } +}