[local_auth] Fix activity leak in LocalAuthPlugin (#4449)
diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
index 7ed9a7e..a63e22a 100644
--- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
+++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java
@@ -15,6 +15,7 @@
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.biometric.BiometricManager;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Lifecycle;
@@ -337,6 +338,7 @@
@Override
public void onDetachedFromActivityForConfigChanges() {
lifecycle = null;
+ activity = null;
}
@Override
@@ -350,5 +352,11 @@
public void onDetachedFromActivity() {
lifecycle = null;
channel.setMethodCallHandler(null);
+ activity = null;
+ }
+
+ @VisibleForTesting
+ final Activity getActivity() {
+ return activity;
}
}
diff --git a/packages/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java b/packages/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
index 522185f..41868e6 100644
--- a/packages/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
+++ b/packages/local_auth/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java
@@ -4,9 +4,20 @@
package io.flutter.plugins.localauth;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.Activity;
+import android.content.Context;
+import androidx.lifecycle.Lifecycle;
+import io.flutter.embedding.engine.FlutterEngine;
+import io.flutter.embedding.engine.dart.DartExecutor;
+import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding;
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
+import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import org.junit.Test;
@@ -19,4 +30,35 @@
plugin.onMethodCall(new MethodCall("isDeviceSupported", null), mockResult);
verify(mockResult).success(false);
}
+
+ @Test
+ public void onDetachedFromActivity_ShouldReleaseActivity() {
+ final Activity mockActivity = mock(Activity.class);
+ final ActivityPluginBinding mockActivityBinding = mock(ActivityPluginBinding.class);
+ when(mockActivityBinding.getActivity()).thenReturn(mockActivity);
+
+ Context mockContext = mock(Context.class);
+ when(mockActivity.getBaseContext()).thenReturn(mockContext);
+
+ final HiddenLifecycleReference mockLifecycleReference = mock(HiddenLifecycleReference.class);
+ when(mockActivityBinding.getLifecycle()).thenReturn(mockLifecycleReference);
+
+ final Lifecycle mockLifecycle = mock(Lifecycle.class);
+ when(mockLifecycleReference.getLifecycle()).thenReturn(mockLifecycle);
+
+ final FlutterPluginBinding mockPluginBinding = mock(FlutterPluginBinding.class);
+ final FlutterEngine mockFlutterEngine = mock(FlutterEngine.class);
+ when(mockPluginBinding.getFlutterEngine()).thenReturn(mockFlutterEngine);
+
+ DartExecutor mockDartExecutor = mock(DartExecutor.class);
+ when(mockFlutterEngine.getDartExecutor()).thenReturn(mockDartExecutor);
+
+ final LocalAuthPlugin plugin = new LocalAuthPlugin();
+ plugin.onAttachedToEngine(mockPluginBinding);
+ plugin.onAttachedToActivity(mockActivityBinding);
+ assertNotNull(plugin.getActivity());
+
+ plugin.onDetachedFromActivity();
+ assertNull(plugin.getActivity());
+ }
}