diff --git a/permission_handler_android/example/lib/main.dart b/permission_handler_android/example/lib/main.dart index ce1cef03c..65f5b2199 100644 --- a/permission_handler_android/example/lib/main.dart +++ b/permission_handler_android/example/lib/main.dart @@ -1,5 +1,8 @@ +import 'dart:async'; + import 'package:baseflow_plugin_template/baseflow_plugin_template.dart'; import 'package:flutter/material.dart'; +import 'package:permission_handler_android/permission_handler_android.dart'; import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; void main() { @@ -132,6 +135,9 @@ class _PermissionState extends State { Future requestPermission(Permission permission) async { final status = await _permissionHandler.requestPermissions([permission]); + final a = PermissionHandlerAndroidMirror(); + a.register(onAttachedToActivity: (_) => {}); + setState(() { print(status); _permissionStatus = status[permission] ?? PermissionStatus.denied; diff --git a/permission_handler_android/lib/src/permission_handler_android.dart b/permission_handler_android/lib/src/permission_handler_android.dart index 500b4a96b..b921d2c1c 100644 --- a/permission_handler_android/lib/src/permission_handler_android.dart +++ b/permission_handler_android/lib/src/permission_handler_android.dart @@ -10,6 +10,17 @@ import 'permission_handler_android_mirror.dart'; class PermissionHandlerAndroid extends PermissionHandlerPlatform { PermissionHandlerAndroidMirror? _mirror; + /// The activity that Flutter is attached to. + /// + /// Used for method invocation that require an activity or context. + Activity? _attachedActivity; + + /// Allow overriding the attached activity for testing purposes. + @visibleForTesting + set attachedActivity(Activity? activity) { + _attachedActivity = activity; + } + @visibleForTesting set mirror(PermissionHandlerAndroidMirror mirror) => _mirror = mirror; @@ -20,14 +31,19 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform { factory PermissionHandlerAndroid() { final instance = PermissionHandlerAndroid._(); instance._mirror = PermissionHandlerAndroidMirror(); - instance._mirror!.init(); + instance._mirror!.register( + onAttachedToActivity: (Activity attachedActivity) { + instance._attachedActivity = attachedActivity; + }, + ); return instance; } /// Registers this class as the default instance of [PermissionHandlerPlatform]. static void registerWith() { PermissionHandlerPlatform.setInstanceBuilder( - () => PermissionHandlerAndroid()); + () => PermissionHandlerAndroid(), + ); } /// TODO(jweener): implement this method. @@ -45,14 +61,12 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform { @override Future shouldShowRequestPermissionRationale(Permission permission) { - final Activity? attachedActivity = _mirror!.attachedActivity; - - if (attachedActivity == null) { + if (_attachedActivity == null) { throw Exception('There is no attached activity'); } return ActivityCompat.shouldShowRequestPermissionRationale( - attachedActivity, + _attachedActivity!, // TODO(jweener): replace with Android manifest name for permission once // they have been ported over. 'android.permission.READ_CONTACTS', diff --git a/permission_handler_android/lib/src/permission_handler_android_mirror.dart b/permission_handler_android/lib/src/permission_handler_android_mirror.dart index 80595b4e9..49a9cfbe1 100644 --- a/permission_handler_android/lib/src/permission_handler_android_mirror.dart +++ b/permission_handler_android/lib/src/permission_handler_android_mirror.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_instance_manager/flutter_instance_manager.dart'; import 'package:permission_handler_android/src/permission_handler.pigeon.dart'; import 'android_permission_handler_api_impls.dart'; @@ -11,40 +12,33 @@ import 'android_object_mirrors/activity.dart'; /// void main() { /// // Initialize Android mirror APIs. /// final PermissionHandlerAndroidMirror mirror = PermissionHandlerAndroidMirror(); -/// mirror.init(); +/// final Activity activity = mirror.register((Activity attachedActivity) => this.activity = attachedActivity); +/// } +/// +/// void someMethod() { +/// activity.getSystemService(Context.LOCATION_SERVICE); /// /// ActivityCompat.shouldShowRequestPermissionRationale( -/// mirror.attachedActivity, +/// activity, /// 'permission_name', /// ); /// } /// ``` class PermissionHandlerAndroidMirror { - /// Mirror of the host activity that is needed for some function invocations. - Activity? _attachedActivity; - - /// Allow overriding the attached activity for testing purposes. - @visibleForTesting - set attachedActivity(Activity? activity) { - _attachedActivity = activity; - } - - /// Get the attached activity. - Activity? get attachedActivity => _attachedActivity; - - /// Create a new instance of [PermissionHandlerAndroidMirror]. - /// - /// After constructing this instance, you must call [init] before using it. - PermissionHandlerAndroidMirror(); - - /// Initialize the Flutter APIs. + /// Initialize the Flutter APIs and get the activity that Flutter is attached + /// to via `onAttachedToActivity`. /// /// This method is typically called right after constructing a new instance of /// [PermissionHandlerAndroidMirror]. - void init() { + void register({ + required void Function(Activity attachedActivity) onAttachedToActivity, + @visibleForTesting InstanceManager? instanceManager, + }) { final ActivityFlutterApi activityFlutterApi = ActivityFlutterApiImpl( - onAttachedToActivity: (Activity activity) => _attachedActivity = activity, + onAttachedToActivity: onAttachedToActivity, + instanceManager: instanceManager, ); + ActivityFlutterApi.setup(activityFlutterApi); } } diff --git a/permission_handler_android/test/permission_handler_test.dart b/permission_handler_android/test/permission_handler_test.dart index e671a9281..c711832ce 100644 --- a/permission_handler_android/test/permission_handler_test.dart +++ b/permission_handler_android/test/permission_handler_test.dart @@ -53,9 +53,8 @@ void main() { group('PermissionHandlerAndroid', () { test('shouldShowRequestPermissionRationale', () async { // > Arrange - final InstanceManager instanceManager = InstanceManager( - onWeakReferenceRemoved: (_) {}, - ); + + // Mock method channel on the native side. TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMessageHandler( 'dev.flutter.pigeon.permission_handler_android.ActivityCompatHostApi.shouldShowRequestPermissionRationale', @@ -69,18 +68,29 @@ void main() { return codec.encodeMessage(response); }, ); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + ActivityCompat.api = + ActivityCompatHostApiImpl(instanceManager: instanceManager); + final activity = Activity.detached(); instanceManager.addHostCreatedInstance( activity, 'activity_instance_id', ); - ActivityCompat.api = - ActivityCompatHostApiImpl(instanceManager: instanceManager); + + // Arrange permission handler. final permissionHandler = PermissionHandlerAndroid(); final mirror = PermissionHandlerAndroidMirror(); - mirror.init(); - mirror.attachedActivity = activity; + mirror.register( + onAttachedToActivity: (Activity activity) {}, + instanceManager: instanceManager, + ); permissionHandler.mirror = mirror; + permissionHandler.attachedActivity = activity; // > Act final shouldShowRequestPermissionRationale = await permissionHandler