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 f5fe7a45a..476f28a49 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 @@ -3,6 +3,7 @@ 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; @@ -59,6 +60,8 @@ public class ActivityHostApiImpl implements private final AlarmManagerFlutterApiImpl alarmManagerFlutterApi; + private final PackageManagerFlutterApiImpl packageManagerFlutterApi; + /** * Callbacks to complete a pending permission request. *

@@ -84,11 +87,13 @@ public class ActivityHostApiImpl implements public ActivityHostApiImpl( @NonNull PowerManagerFlutterApiImpl powerManagerFlutterApi, @NonNull AlarmManagerFlutterApiImpl alarmManagerFlutterApi, + @NonNull PackageManagerFlutterApiImpl packageManagerFlutterApi, @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager ) { - this.alarmManagerFlutterApi = alarmManagerFlutterApi; this.powerManagerFlutterApi = powerManagerFlutterApi; + this.alarmManagerFlutterApi = alarmManagerFlutterApi; + this.packageManagerFlutterApi = packageManagerFlutterApi; this.binaryMessenger = binaryMessenger; this.instanceManager = instanceManager; } @@ -249,4 +254,19 @@ public boolean onActivityResult( 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/ContextHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java index a4c8df5ed..4be9cfffa 100644 --- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java @@ -3,6 +3,7 @@ import android.app.AlarmManager; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.PowerManager; import androidx.annotation.NonNull; @@ -32,6 +33,8 @@ public class ContextHostApiImpl implements ContextHostApi { private final AlarmManagerFlutterApiImpl alarmManagerFlutterApi; + private final PackageManagerFlutterApiImpl packageManagerFlutterApi; + /** * Constructs an {@link ContextHostApiImpl}. * @@ -41,11 +44,13 @@ public class ContextHostApiImpl implements ContextHostApi { public ContextHostApiImpl( @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; } @@ -104,4 +109,19 @@ public void startActivity( final UUID systemServiceUuid = instanceManager.getIdentifierForStrongReference(systemService); return systemServiceUuid.toString(); } + + @Override + @NonNull public String getPackageManager( + @NonNull String instanceId + ) { + final UUID instanceUuid = UUID.fromString(instanceId); + final Context context = instanceManager.getInstance(instanceUuid); + + final PackageManager packageManager = context.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/PackageManagerFlutterApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PackageManagerFlutterApiImpl.java new file mode 100644 index 000000000..0b9b0534c --- /dev/null +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PackageManagerFlutterApiImpl.java @@ -0,0 +1,66 @@ +package com.baseflow.permissionhandler; + +import android.content.pm.PackageManager; + +import androidx.annotation.NonNull; + +import com.baseflow.instancemanager.InstanceManager; +import com.baseflow.permissionhandler.PermissionHandlerPigeon.PackageManagerFlutterApi; + +import java.util.UUID; + +import io.flutter.plugin.common.BinaryMessenger; + +/** + * Flutter API implementation for `PackageManager`. + * + *

This class may handle adding native instances that are attached to a Dart instance or passing + * arguments of callbacks methods to a Dart instance. + */ +public class PackageManagerFlutterApiImpl { + // To ease adding additional methods, this value is added prematurely. + @SuppressWarnings({"unused", "FieldCanBeLocal"}) + private final BinaryMessenger binaryMessenger; + + private final InstanceManager instanceManager; + + private final PackageManagerFlutterApi api; + + /** + * Constructs a {@link PackageManagerFlutterApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public PackageManagerFlutterApiImpl( + @NonNull BinaryMessenger binaryMessenger, + @NonNull InstanceManager instanceManager + ) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + api = new PackageManagerFlutterApi(binaryMessenger); + } + + /** + * Stores the `PackageManager` instance and notifies Dart to create and store a new + * `PackageManager` instance that is attached to this one. If `instance` has already been added, + * this method does nothing. + */ + public void create(@NonNull PackageManager instance) { + if (!instanceManager.containsInstance(instance)) { + final UUID packageManagerInstanceUuid = instanceManager.addHostCreatedInstance(instance); + api.create(packageManagerInstanceUuid.toString(), reply -> {}); + } + } + + /** + * Disposes of the `PackageManager` instance in the instance manager and notifies Dart to do the + * same. If `instance` was already disposed, this method does nothing. + */ + public void dispose(PackageManager instance) { + final UUID packageManagerInstanceUuid = instanceManager.getIdentifierForStrongReference(instance); + if (packageManagerInstanceUuid != null) { + api.dispose(packageManagerInstanceUuid.toString(), reply -> {}); + } + } +} diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PackageManagerHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PackageManagerHostApiImpl.java new file mode 100644 index 000000000..22f8edb4d --- /dev/null +++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PackageManagerHostApiImpl.java @@ -0,0 +1,52 @@ +package com.baseflow.permissionhandler; + +import android.content.pm.PackageManager; +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import com.baseflow.instancemanager.InstanceManager; +import com.baseflow.permissionhandler.PermissionHandlerPigeon.PackageManagerHostApi; + +import java.util.UUID; + +import io.flutter.plugin.common.BinaryMessenger; + +/** + * Host API implementation for `PackageManager`. + * + *

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 PackageManagerHostApiImpl implements PackageManagerHostApi { + // To ease adding additional methods, this value is added prematurely. + @SuppressWarnings({"unused", "FieldCanBeLocal"}) + private final BinaryMessenger binaryMessenger; + + private final InstanceManager instanceManager; + + /** + * Constructs an {@link PackageManagerHostApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public PackageManagerHostApiImpl( + @NonNull BinaryMessenger binaryMessenger, + @NonNull InstanceManager instanceManager + ) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @NonNull + @Override + public Boolean canRequestPackageInstalls(@NonNull String instanceId) { + final UUID instanceUuid = UUID.fromString(instanceId); + final PackageManager packageManager = instanceManager.getInstance(instanceUuid); + + return packageManager.canRequestPackageInstalls(); + } +} 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 40c1597cd..bd2d28470 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 @@ -357,6 +357,13 @@ public interface ActivityHostApi { * 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() { @@ -550,6 +557,30 @@ 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); + } + } } } /** @@ -641,6 +672,13 @@ public interface ContextHostApi { */ @NonNull String getSystemService(@NonNull String instanceId, @NonNull String name); + /** + * 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 ContextHostApi. */ static @NonNull MessageCodec getCodec() { @@ -737,6 +775,30 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable ContextHos 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<>( + binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ContextHostApi.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; @@ -1323,4 +1385,102 @@ public void dispose(@NonNull String instanceIdArg, @NonNull Reply callback channelReply -> callback.reply(null)); } } + /** + * Host API for `PackageManager`. + * + * 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/content/pm/PackageManager. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ + public interface PackageManagerHostApi { + /** + * 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(). + */ + @NonNull + Boolean canRequestPackageInstalls(@NonNull String instanceId); + + /** The codec used by PackageManagerHostApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /**Sets up an instance of `PackageManagerHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PackageManagerHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PackageManagerHostApi.canRequestPackageInstalls", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + String instanceIdArg = (String) args.get(0); + try { + Boolean output = api.canRequestPackageInstalls(instanceIdArg); + wrapped.add(0, output); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + /** + * Flutter API for `PackageManager`. + * + * This class may handle instantiating and adding Dart instances that are + * attached to a native instance or receiving callback methods from an + * overridden native class. + * + * See https://developer.android.com/reference/kotlin/android/content/pm/PackageManager. + * + * Generated class from Pigeon that represents Flutter messages that can be called from Java. + */ + public static class PackageManagerFlutterApi { + private final @NonNull BinaryMessenger binaryMessenger; + + public PackageManagerFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + @SuppressWarnings("UnknownNullness") + public interface Reply { + void reply(T reply); + } + /** The codec used by PackageManagerFlutterApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /** Create a new Dart instance and add it to the `InstanceManager`. */ + public void create(@NonNull String instanceIdArg, @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.create", getCodec()); + channel.send( + new ArrayList(Collections.singletonList(instanceIdArg)), + channelReply -> callback.reply(null)); + } + /** Dispose of the Dart instance and remove it from the `InstanceManager`. */ + public void dispose(@NonNull String instanceIdArg, @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.dispose", getCodec()); + channel.send( + new ArrayList(Collections.singletonList(instanceIdArg)), + channelReply -> callback.reply(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 f76c52c66..012b91b14 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 @@ -15,6 +15,7 @@ import com.baseflow.permissionhandler.PermissionHandlerPigeon.BuildVersionHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.ContextHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.IntentHostApi; +import com.baseflow.permissionhandler.PermissionHandlerPigeon.PackageManagerHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.PowerManagerHostApi; import com.baseflow.permissionhandler.PermissionHandlerPigeon.UriHostApi; @@ -67,10 +68,15 @@ private void setUp( final AlarmManagerHostApi alarmManagerHostApi = new AlarmManagerHostApiImpl(binaryMessenger, instanceManager); AlarmManagerHostApi.setup(binaryMessenger, alarmManagerHostApi); + final PackageManagerFlutterApiImpl packageManagerFlutterApi = new PackageManagerFlutterApiImpl(binaryMessenger, instanceManager); + final PackageManagerHostApi packageManagerHostApi = new PackageManagerHostApiImpl(binaryMessenger, instanceManager); + PackageManagerHostApi.setup(binaryMessenger, packageManagerHostApi); + activityFlutterApi = new ActivityFlutterApiImpl(binaryMessenger, instanceManager); activityHostApi = new ActivityHostApiImpl( powerManagerFlutterApi, alarmManagerFlutterApi, + packageManagerFlutterApi, binaryMessenger, instanceManager ); @@ -80,6 +86,7 @@ private void setUp( final ContextHostApiImpl contextHostApi = new ContextHostApiImpl( powerManagerFlutterApi, alarmManagerFlutterApi, + packageManagerFlutterApi, binaryMessenger, instanceManager ); 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 727f522cd..7c59d83db 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/activity.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/activity.dart @@ -62,7 +62,7 @@ class Activity extends JavaObject { ); } - /// Determine whether the application has been granted a particular permission. + /// 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( @@ -81,9 +81,9 @@ class Activity extends JavaObject { /// and /// https://developer.android.com/reference/androidx/core/app/ActivityCompat.OnRequestPermissionsResultCallback. Future requestPermissions( - List permissions, + List permissions, { int? requestCode, - ) { + }) { return _hostApi.requestPermissionsFromInstance( this, permissions, @@ -91,7 +91,7 @@ class Activity extends JavaObject { ); } - /// Launch a new activity. + /// Launches a new activity. /// /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). Future startActivity( @@ -116,9 +116,9 @@ class Activity extends JavaObject { /// /// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int). Future startActivityForResult( - Intent intent, + Intent intent, { int? requestCode, - ) { + }) { return _hostApi.startActivityForResultFromInstance( this, intent, @@ -126,7 +126,7 @@ class Activity extends JavaObject { ); } - /// Return the handle to a system-level service by name. + /// Returns the handle to a system-level service by name. /// /// The class of the returned object varies by the requested name. /// @@ -141,6 +141,15 @@ class Activity extends JavaObject { 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 2f54ba902..445cf2782 100644 --- a/permission_handler_android/lib/src/android_object_mirrors/context.dart +++ b/permission_handler_android/lib/src/android_object_mirrors/context.dart @@ -38,7 +38,7 @@ class Context extends JavaObject { /// receiving intents at a time of your choosing. static const String alarmService = 'alarm'; - /// Determine whether the application has been granted a particular permission. + /// Determines whether the application has been granted a particular permission. /// /// See https://developer.android.com/reference/android/content/Context#checkSelfPermission(java.lang.String). Future checkSelfPermission( @@ -50,7 +50,7 @@ class Context extends JavaObject { ); } - /// Launch a new activity. + /// Launches a new activity. /// /// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent). Future startActivity( @@ -71,7 +71,7 @@ class Context extends JavaObject { ); } - /// Return the handle to a system-level service by name. + /// Returns the handle to a system-level service by name. /// /// The class of the returned object varies by the requested name. /// @@ -84,4 +84,13 @@ class Context extends JavaObject { 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, + ); + } } 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 c0e6e5895..56c466c33 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 @@ -1,10 +1,26 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_instance_manager/flutter_instance_manager.dart'; + +import '../android_permission_handler_api_impls.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 /// through Context#getPackageManager. /// /// See https://developer.android.com/reference/android/content/pm/PackageManager. -class PackageManager { - const PackageManager._(); +class PackageManager extends JavaObject { + /// Instantiates an [PackageManager] without creating and attaching to an + /// instance of the associated native class. + PackageManager.detached({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : _hostApi = PackageManagerHostApiImpl( + binaryMessenger: binaryMessenger, + instanceManager: instanceManager, + ), + super.detached(); + + final PackageManagerHostApiImpl _hostApi; /// Permission check result: this is returned by checkPermission(String, String) if the permission has not been granted to the given package. /// @@ -15,4 +31,11 @@ class PackageManager { /// /// Constant Value: 0 (0x00000000) static const int permissionGranted = 0; + + /// 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() { + return _hostApi.canRequestPackageInstallsFromInstance(this); + } } 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 7139d1dc3..23f901a40 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 @@ -12,6 +12,7 @@ class AndroidPermissionHandlerFlutterApis { ContextFlutterApiImpl? contextFlutterApi, PowerManagerFlutterApiImpl? powerManagerFlutterApi, AlarmManagerFlutterApiImpl? alarmManagerFlutterApi, + PackageManagerFlutterApiImpl? packageManagerFlutterApi, }) { this.activityFlutterApi = activityFlutterApi ?? ActivityFlutterApiImpl(); this.contextFlutterApi = contextFlutterApi ?? ContextFlutterApiImpl(); @@ -19,6 +20,8 @@ class AndroidPermissionHandlerFlutterApis { powerManagerFlutterApi ?? PowerManagerFlutterApiImpl(); this.alarmManagerFlutterApi = alarmManagerFlutterApi ?? AlarmManagerFlutterApiImpl(); + this.packageManagerFlutterApi = + packageManagerFlutterApi ?? PackageManagerFlutterApiImpl(); } static bool _haveBeenSetUp = false; @@ -44,6 +47,9 @@ class AndroidPermissionHandlerFlutterApis { /// Flutter API for [AlarmManager]. late final AlarmManagerFlutterApiImpl alarmManagerFlutterApi; + /// Flutter API for [PackageManager]. + late final PackageManagerFlutterApiImpl packageManagerFlutterApi; + /// Ensures all the Flutter APIs have been setup to receive calls from native code. void ensureSetUp() { if (!_haveBeenSetUp) { @@ -51,6 +57,7 @@ class AndroidPermissionHandlerFlutterApis { ContextFlutterApi.setup(contextFlutterApi); PowerManagerFlutterApi.setup(powerManagerFlutterApi); AlarmManagerFlutterApi.setup(alarmManagerFlutterApi); + PackageManagerFlutterApi.setup(packageManagerFlutterApi); _haveBeenSetUp = true; } @@ -202,6 +209,20 @@ class ActivityHostApiImpl extends ActivityHostApi { 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. @@ -299,6 +320,20 @@ class ContextHostApiImpl extends ContextHostApi { return instanceManager.getInstanceWithWeakReference(systemServiceId); } + + /// Return PackageManager instance to find global package information. + /// + /// See https://developer.android.com/reference/android/content/Context#getPackageManager(). + Future getPackageManagerFromInstance( + Context context, + ) async { + final String packageManagerId = await getPackageManager( + instanceManager.getIdentifier(context)!, + ); + + return instanceManager.getInstanceWithWeakReference(packageManagerId) + as PackageManager; + } } /// Flutter API implementation of Context. @@ -593,3 +628,58 @@ class AlarmManagerFlutterApiImpl extends AlarmManagerFlutterApi { _instanceManager.remove(instanceId); } } + +/// Host API implementation of PackageManager. +class PackageManagerHostApiImpl extends PackageManagerHostApi { + /// Creates a new instance of [PackageManagerHostApiImpl]. + PackageManagerHostApiImpl({ + 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 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 canRequestPackageInstallsFromInstance( + PackageManager packageManager, + ) { + return canRequestPackageInstalls( + instanceManager.getIdentifier(packageManager)!, + ); + } +} + +/// Flutter API implementation of PackageManager. +class PackageManagerFlutterApiImpl extends PackageManagerFlutterApi { + /// Constructs a new instance of [PackageManagerFlutterApiImpl]. + PackageManagerFlutterApiImpl({ + InstanceManager? instanceManager, + }) : _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager _instanceManager; + + @override + void create(String instanceId) { + final PackageManager packageManager = PackageManager.detached(); + _instanceManager.addHostCreatedInstance( + packageManager, + instanceId, + ); + } + + @override + void dispose(String instanceId) { + _instanceManager.remove(instanceId); + } +} diff --git a/permission_handler_android/lib/src/permission_handler.pigeon.dart b/permission_handler_android/lib/src/permission_handler.pigeon.dart index fdf6d0f19..c7b067120 100644 --- a/permission_handler_android/lib/src/permission_handler.pigeon.dart +++ b/permission_handler_android/lib/src/permission_handler.pigeon.dart @@ -348,6 +348,37 @@ 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`. @@ -554,6 +585,37 @@ class ContextHostApi { return (replyList[0] as String?)!; } } + + /// 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.ContextHostApi.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 `Context`. @@ -1130,3 +1192,113 @@ abstract class AlarmManagerFlutterApi { } } } + +/// Host API for `PackageManager`. +/// +/// 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/content/pm/PackageManager. +class PackageManagerHostApi { + /// Constructor for [PackageManagerHostApi]. 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. + PackageManagerHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + /// 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(String arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.PackageManagerHostApi.canRequestPackageInstalls', + 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 bool?)!; + } + } +} + +/// Flutter API for `PackageManager`. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +/// +/// See https://developer.android.com/reference/kotlin/android/content/pm/PackageManager. +abstract class PackageManagerFlutterApi { + static const MessageCodec codec = StandardMessageCodec(); + + /// Create a new Dart instance and add it to the `InstanceManager`. + void create(String instanceId); + + /// Dispose of the Dart instance and remove it from the `InstanceManager`. + void dispose(String instanceId); + + static void setup(PackageManagerFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.create', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.create 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.PackageManagerFlutterApi.create was null, expected non-null String.'); + api.create(arg_instanceId!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.dispose', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.permission_handler_android.PackageManagerFlutterApi.dispose 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.PackageManagerFlutterApi.dispose was null, expected non-null String.'); + api.dispose(arg_instanceId!); + return; + }); + } + } + } +} diff --git a/permission_handler_android/lib/src/permission_handler_android.dart b/permission_handler_android/lib/src/permission_handler_android.dart index b1d5bee7b..cbc15fade 100644 --- a/permission_handler_android/lib/src/permission_handler_android.dart +++ b/permission_handler_android/lib/src/permission_handler_android.dart @@ -109,7 +109,7 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform { }) async { final PermissionRequestResult result = await activity.requestPermissions( permission.manifestStrings, - requestCode, + requestCode: requestCode, ); final List permissions = @@ -143,7 +143,7 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform { 'package:${await _activityManager.applicationContext.getPackageName()}', ), ), - requestCode, + requestCode: requestCode, ); } diff --git a/permission_handler_android/pigeons/android_permission_handler.dart b/permission_handler_android/pigeons/android_permission_handler.dart index ee38f13ec..5cca51b79 100644 --- a/permission_handler_android/pigeons/android_permission_handler.dart +++ b/permission_handler_android/pigeons/android_permission_handler.dart @@ -121,6 +121,13 @@ 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`. @@ -182,6 +189,13 @@ abstract class ContextHostApi { String instanceId, String name, ); + + /// 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 `Context`. @@ -376,3 +390,34 @@ abstract class AlarmManagerFlutterApi { /// Dispose of the Dart instance and remove it from the `InstanceManager`. void dispose(String instanceId); } + +/// Host API for `PackageManager`. +/// +/// 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/content/pm/PackageManager. +@HostApi(dartHostTestHandler: 'PackageManagerTestHostApi') +abstract class PackageManagerHostApi { + /// 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(). + bool canRequestPackageInstalls(String instanceId); +} + +/// Flutter API for `PackageManager`. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +/// +/// See https://developer.android.com/reference/kotlin/android/content/pm/PackageManager. +@FlutterApi() +abstract class PackageManagerFlutterApi { + /// Create a new Dart instance and add it to the `InstanceManager`. + void create(String instanceId); + + /// Dispose of the Dart instance and remove it from the `InstanceManager`. + void dispose(String instanceId); +} diff --git a/permission_handler_android/test/test_permission_handler.pigeon.dart b/permission_handler_android/test/test_permission_handler.pigeon.dart index 451e85149..a260759d7 100644 --- a/permission_handler_android/test/test_permission_handler.pigeon.dart +++ b/permission_handler_android/test/test_permission_handler.pigeon.dart @@ -95,6 +95,11 @@ abstract class ActivityTestHostApi { 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}) { { @@ -284,6 +289,29 @@ 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]; + }); + } + } } } @@ -323,6 +351,11 @@ abstract class ContextTestHostApi { /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String). String getSystemService(String instanceId, String name); + /// 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(ContextTestHostApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -428,6 +461,29 @@ abstract class ContextTestHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.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.ContextHostApi.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.ContextHostApi.getPackageManager was null, expected non-null String.'); + final String output = api.getPackageManager(arg_instanceId!); + return [output]; + }); + } + } } } @@ -831,3 +887,48 @@ abstract class AlarmManagerTestHostApi { } } } + +/// Host API for `PackageManager`. +/// +/// 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/content/pm/PackageManager. +abstract class PackageManagerTestHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = StandardMessageCodec(); + + /// 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(). + bool canRequestPackageInstalls(String instanceId); + + static void setup(PackageManagerTestHostApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.permission_handler_android.PackageManagerHostApi.canRequestPackageInstalls', + 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.PackageManagerHostApi.canRequestPackageInstalls 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.PackageManagerHostApi.canRequestPackageInstalls was null, expected non-null String.'); + final bool output = api.canRequestPackageInstalls(arg_instanceId!); + return [output]; + }); + } + } + } +}