[quick_actions] Android support only calling initialize once (#4204)
Fixes flutter/flutter#87259
diff --git a/packages/quick_actions/quick_actions/CHANGELOG.md b/packages/quick_actions/quick_actions/CHANGELOG.md
index 4f89438..5d040f4 100644
--- a/packages/quick_actions/quick_actions/CHANGELOG.md
+++ b/packages/quick_actions/quick_actions/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.0+5
+
+* Support only calling initialize once.
+
## 0.6.0+4
* Remove references to the Android V1 embedding.
diff --git a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java
index 4652830..2d89352 100644
--- a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java
+++ b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java
@@ -20,9 +20,8 @@
import java.util.Map;
class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
-
+ protected static final String EXTRA_ACTION = "some unique action key";
private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions";
- private static final String EXTRA_ACTION = "some unique action key";
private final Context context;
private Activity activity;
diff --git a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java
index ab34313..b2f80ad 100644
--- a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java
+++ b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java
@@ -6,14 +6,17 @@
import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.PluginRegistry.NewIntentListener;
/** QuickActionsPlugin */
-public class QuickActionsPlugin implements FlutterPlugin, ActivityAware {
+public class QuickActionsPlugin implements FlutterPlugin, ActivityAware, NewIntentListener {
private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions";
private MethodChannel channel;
@@ -43,6 +46,8 @@
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
handler.setActivity(binding.getActivity());
+ binding.addOnNewIntentListener(this);
+ onNewIntent(binding.getActivity().getIntent());
}
@Override
@@ -52,6 +57,7 @@
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
+ binding.removeOnNewIntentListener(this);
onAttachedToActivity(binding);
}
@@ -60,6 +66,19 @@
onDetachedFromActivity();
}
+ @Override
+ public boolean onNewIntent(Intent intent) {
+ // Do nothing for anything lower than API 25 as the functionality isn't supported.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
+ return false;
+ }
+ // Notify the Dart side if the launch intent has the intent extra relevant to quick actions.
+ if (intent.hasExtra(MethodCallHandlerImpl.EXTRA_ACTION) && channel != null) {
+ channel.invokeMethod("launch", intent.getStringExtra(MethodCallHandlerImpl.EXTRA_ACTION));
+ }
+ return false;
+ }
+
private void setupChannel(BinaryMessenger messenger, Context context, Activity activity) {
channel = new MethodChannel(messenger, CHANNEL_ID);
handler = new MethodCallHandlerImpl(context, activity);
diff --git a/packages/quick_actions/quick_actions/android/src/test/java/io/flutter/plugins/quickactions/QuickActionsTest.java b/packages/quick_actions/quick_actions/android/src/test/java/io/flutter/plugins/quickactions/QuickActionsTest.java
index d437444..208a119 100644
--- a/packages/quick_actions/quick_actions/android/src/test/java/io/flutter/plugins/quickactions/QuickActionsTest.java
+++ b/packages/quick_actions/quick_actions/android/src/test/java/io/flutter/plugins/quickactions/QuickActionsTest.java
@@ -4,17 +4,30 @@
package io.flutter.plugins.quickactions;
+import static io.flutter.plugins.quickactions.MethodCallHandlerImpl.EXTRA_ACTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding;
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.StandardMethodCodec;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
+import org.junit.After;
import org.junit.Test;
+import org.mockito.internal.util.reflection.FieldSetter;
public class QuickActionsTest {
private static class TestBinaryMessenger implements BinaryMessenger {
@@ -42,6 +55,10 @@
}
}
+ static final int SUPPORTED_BUILD = 25;
+ static final int UNSUPPORTED_BUILD = 24;
+ static final String SHORTCUT_TYPE = "action_one";
+
@Test
public void canAttachToEngine() {
final TestBinaryMessenger testBinaryMessenger = new TestBinaryMessenger();
@@ -51,4 +68,98 @@
final QuickActionsPlugin plugin = new QuickActionsPlugin();
plugin.onAttachedToEngine(mockPluginBinding);
}
+
+ @Test
+ public void onAttachedToActivity_buildVersionSupported_invokesLaunchMethod()
+ throws NoSuchFieldException, IllegalAccessException {
+ // Arrange
+ final TestBinaryMessenger testBinaryMessenger = new TestBinaryMessenger();
+ final QuickActionsPlugin plugin = new QuickActionsPlugin();
+ setUpMessengerAndFlutterPluginBinding(testBinaryMessenger, plugin);
+ setBuildVersion(SUPPORTED_BUILD);
+ FieldSetter.setField(
+ plugin,
+ QuickActionsPlugin.class.getDeclaredField("handler"),
+ mock(MethodCallHandlerImpl.class));
+ final Intent mockIntent = createMockIntentWithQuickActionExtra();
+ final Activity mockMainActivity = mock(Activity.class);
+ when(mockMainActivity.getIntent()).thenReturn(mockIntent);
+ final ActivityPluginBinding mockActivityPluginBinding = mock(ActivityPluginBinding.class);
+ when(mockActivityPluginBinding.getActivity()).thenReturn(mockMainActivity);
+
+ // Act
+ plugin.onAttachedToActivity(mockActivityPluginBinding);
+
+ // Assert
+ assertNotNull(testBinaryMessenger.lastMethodCall);
+ assertEquals(testBinaryMessenger.lastMethodCall.method, "launch");
+ assertEquals(testBinaryMessenger.lastMethodCall.arguments, SHORTCUT_TYPE);
+ }
+
+ @Test
+ public void onNewIntent_buildVersionUnsupported_doesNotInvokeMethod()
+ throws NoSuchFieldException, IllegalAccessException {
+ // Arrange
+ final TestBinaryMessenger testBinaryMessenger = new TestBinaryMessenger();
+ final QuickActionsPlugin plugin = new QuickActionsPlugin();
+ setUpMessengerAndFlutterPluginBinding(testBinaryMessenger, plugin);
+ setBuildVersion(UNSUPPORTED_BUILD);
+ final Intent mockIntent = createMockIntentWithQuickActionExtra();
+
+ // Act
+ final boolean onNewIntentReturn = plugin.onNewIntent(mockIntent);
+
+ // Assert
+ assertNull(testBinaryMessenger.lastMethodCall);
+ assertFalse(onNewIntentReturn);
+ }
+
+ @Test
+ public void onNewIntent_buildVersionSupported_invokesLaunchMethod()
+ throws NoSuchFieldException, IllegalAccessException {
+ // Arrange
+ final TestBinaryMessenger testBinaryMessenger = new TestBinaryMessenger();
+ final QuickActionsPlugin plugin = new QuickActionsPlugin();
+ setUpMessengerAndFlutterPluginBinding(testBinaryMessenger, plugin);
+ setBuildVersion(SUPPORTED_BUILD);
+ final Intent mockIntent = createMockIntentWithQuickActionExtra();
+
+ // Act
+ final boolean onNewIntentReturn = plugin.onNewIntent(mockIntent);
+
+ // Assert
+ assertNotNull(testBinaryMessenger.lastMethodCall);
+ assertEquals(testBinaryMessenger.lastMethodCall.method, "launch");
+ assertEquals(testBinaryMessenger.lastMethodCall.arguments, SHORTCUT_TYPE);
+ assertFalse(onNewIntentReturn);
+ }
+
+ private void setUpMessengerAndFlutterPluginBinding(
+ TestBinaryMessenger testBinaryMessenger, QuickActionsPlugin plugin) {
+ final FlutterPluginBinding mockPluginBinding = mock(FlutterPluginBinding.class);
+ when(mockPluginBinding.getBinaryMessenger()).thenReturn(testBinaryMessenger);
+ plugin.onAttachedToEngine(mockPluginBinding);
+ }
+
+ private Intent createMockIntentWithQuickActionExtra() {
+ final Intent mockIntent = mock(Intent.class);
+ when(mockIntent.hasExtra(EXTRA_ACTION)).thenReturn(true);
+ when(mockIntent.getStringExtra(EXTRA_ACTION)).thenReturn(QuickActionsTest.SHORTCUT_TYPE);
+ return mockIntent;
+ }
+
+ private void setBuildVersion(int buildVersion)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field buildSdkField = Build.VERSION.class.getField("SDK_INT");
+ buildSdkField.setAccessible(true);
+ final Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(buildSdkField, buildSdkField.getModifiers() & ~Modifier.FINAL);
+ buildSdkField.set(null, buildVersion);
+ }
+
+ @After
+ public void tearDown() throws NoSuchFieldException, IllegalAccessException {
+ setBuildVersion(0);
+ }
}
diff --git a/packages/quick_actions/quick_actions/lib/quick_actions.dart b/packages/quick_actions/quick_actions/lib/quick_actions.dart
index 6907f25..7d3d4ad 100644
--- a/packages/quick_actions/quick_actions/lib/quick_actions.dart
+++ b/packages/quick_actions/quick_actions/lib/quick_actions.dart
@@ -16,7 +16,7 @@
/// Initializes this plugin.
///
- /// Call this once before any further interaction with the the plugin.
+ /// Call this once before any further interaction with the plugin.
Future<void> initialize(QuickActionHandler handler) async =>
QuickActionsPlatform.instance.initialize(handler);
diff --git a/packages/quick_actions/quick_actions/pubspec.yaml b/packages/quick_actions/quick_actions/pubspec.yaml
index 657c2f0..e52ab51 100644
--- a/packages/quick_actions/quick_actions/pubspec.yaml
+++ b/packages/quick_actions/quick_actions/pubspec.yaml
@@ -3,7 +3,7 @@
Quick Actions on iOS and App Shortcuts on Android.
repository: https://github.com/flutter/plugins/tree/master/packages/quick_actions
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+quick_actions%22
-version: 0.6.0+4
+version: 0.6.0+5
environment:
sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart b/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart
index b15fb8b..2e06935 100644
--- a/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart
+++ b/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart
@@ -38,7 +38,7 @@
/// Initializes this plugin.
///
- /// Call this once before any further interaction with the the plugin.
+ /// Call this once before any further interaction with the plugin.
Future<void> initialize(QuickActionHandler handler) async {
throw UnimplementedError("initialize() has not been implemented.");
}