diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md
index 087c66b7008d..fa8b26132c28 100644
--- a/packages/share/CHANGELOG.md
+++ b/packages/share/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.6.3
+
+* Support the v2 Android embedder.
+* Update to AndroidX.
+* Migrate to using the new e2e test binding.
+* Add a e2e test.
+
## 0.6.2+4
* Define clang module for iOS.
diff --git a/packages/share/android/build.gradle b/packages/share/android/build.gradle
index 3b265e6c5ca7..1461873885ef 100644
--- a/packages/share/android/build.gradle
+++ b/packages/share/android/build.gradle
@@ -45,3 +45,29 @@ android {
disable 'InvalidPackage'
}
}
+
+// TODO(cyanglaz): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348
+afterEvaluate {
+ def containsEmbeddingDependencies = false
+ for (def configuration : configurations.all) {
+ for (def dependency : configuration.dependencies) {
+ if (dependency.group == 'io.flutter' &&
+ dependency.name.startsWith('flutter_embedding') &&
+ dependency.isTransitive())
+ {
+ containsEmbeddingDependencies = true
+ break
+ }
+ }
+ }
+ if (!containsEmbeddingDependencies) {
+ android {
+ dependencies {
+ def lifecycle_version = "1.1.1"
+ api "android.arch.lifecycle:runtime:$lifecycle_version"
+ api "android.arch.lifecycle:common:$lifecycle_version"
+ api "android.arch.lifecycle:common-java8:$lifecycle_version"
+ }
+ }
+ }
+}
diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java b/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java
new file mode 100644
index 000000000000..f7e4d579e7a2
--- /dev/null
+++ b/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java
@@ -0,0 +1,33 @@
+// Copyright 2019 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package io.flutter.plugins.share;
+
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import java.util.Map;
+
+/** Handles the method calls for the plugin. */
+class MethodCallHandler implements MethodChannel.MethodCallHandler {
+
+ private Share share;
+
+ MethodCallHandler(Share share) {
+ this.share = share;
+ }
+
+ @Override
+ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
+ if (call.method.equals("share")) {
+ if (!(call.arguments instanceof Map)) {
+ throw new IllegalArgumentException("Map argument expected");
+ }
+ // Android does not support showing the share sheet at a particular point on screen.
+ share.share((String) call.argument("text"), (String) call.argument("subject"));
+ result.success(null);
+ } else {
+ result.notImplemented();
+ }
+ }
+}
diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java b/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java
new file mode 100644
index 000000000000..8c9e833ee9d3
--- /dev/null
+++ b/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java
@@ -0,0 +1,50 @@
+// Copyright 2019 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package io.flutter.plugins.share;
+
+import android.app.Activity;
+import android.content.Intent;
+
+/** Handles share intent. */
+class Share {
+
+ private Activity activity;
+
+ /**
+ * Constructs a Share object. The {@code activity} is used to start the share intent. It might be
+ * null when constructing the {@link Share} object and set to non-null when an activity is
+ * available using {@link #setActivity(Activity)}.
+ */
+ Share(Activity activity) {
+ this.activity = activity;
+ }
+
+ /**
+ * Sets the activity when an activity is available. When the activity becomes unavailable, use
+ * this method to set it to null.
+ */
+ void setActivity(Activity activity) {
+ this.activity = activity;
+ }
+
+ void share(String text, String subject) {
+ if (text == null || text.isEmpty()) {
+ throw new IllegalArgumentException("Non-empty text expected");
+ }
+
+ Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_TEXT, text);
+ shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ shareIntent.setType("text/plain");
+ Intent chooserIntent = Intent.createChooser(shareIntent, null /* dialog title optional */);
+ if (activity != null) {
+ activity.startActivity(chooserIntent);
+ } else {
+ chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity.startActivity(chooserIntent);
+ }
+ }
+}
diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java
index 60b83e415b70..443f28ede38e 100644
--- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java
+++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java
@@ -4,59 +4,68 @@
package io.flutter.plugins.share;
-import android.content.Intent;
-import io.flutter.plugin.common.MethodCall;
+import android.app.Activity;
+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.Registrar;
-import java.util.Map;
/** Plugin method host for presenting a share sheet via Intent */
-public class SharePlugin implements MethodChannel.MethodCallHandler {
+public class SharePlugin implements FlutterPlugin, ActivityAware {
private static final String CHANNEL = "plugins.flutter.io/share";
+ private MethodCallHandler handler;
+ private Share share;
+ private MethodChannel methodChannel;
public static void registerWith(Registrar registrar) {
- MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL);
- SharePlugin instance = new SharePlugin(registrar);
- channel.setMethodCallHandler(instance);
+ SharePlugin plugin = new SharePlugin();
+ plugin.setUpChannel(registrar.activity(), registrar.messenger());
}
- private final Registrar mRegistrar;
+ @Override
+ public void onAttachedToEngine(FlutterPluginBinding binding) {
+ setUpChannel(null, binding.getFlutterEngine().getDartExecutor());
+ }
+
+ @Override
+ public void onDetachedFromEngine(FlutterPluginBinding binding) {
+ methodChannel.setMethodCallHandler(null);
+ methodChannel = null;
+ share = null;
+ }
+
+ @Override
+ public void onAttachedToActivity(ActivityPluginBinding binding) {
+ share.setActivity(binding.getActivity());
+ }
- private SharePlugin(Registrar registrar) {
- this.mRegistrar = registrar;
+ @Override
+ public void onDetachedFromActivity() {
+ tearDownChannel();
+ }
+
+ @Override
+ public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
+ onAttachedToActivity(binding);
}
@Override
- public void onMethodCall(MethodCall call, MethodChannel.Result result) {
- if (call.method.equals("share")) {
- if (!(call.arguments instanceof Map)) {
- throw new IllegalArgumentException("Map argument expected");
- }
- // Android does not support showing the share sheet at a particular point on screen.
- share((String) call.argument("text"), (String) call.argument("subject"));
- result.success(null);
- } else {
- result.notImplemented();
- }
- }
-
- private void share(String text, String subject) {
- if (text == null || text.isEmpty()) {
- throw new IllegalArgumentException("Non-empty text expected");
- }
-
- Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, text);
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
- shareIntent.setType("text/plain");
- Intent chooserIntent = Intent.createChooser(shareIntent, null /* dialog title optional */);
- if (mRegistrar.activity() != null) {
- mRegistrar.activity().startActivity(chooserIntent);
- } else {
- chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mRegistrar.context().startActivity(chooserIntent);
- }
+ public void onDetachedFromActivityForConfigChanges() {
+ onDetachedFromActivity();
+ }
+
+ private void setUpChannel(Activity activity, BinaryMessenger messenger) {
+ methodChannel = new MethodChannel(messenger, CHANNEL);
+ share = new Share(activity);
+ handler = new MethodCallHandler(share);
+ methodChannel.setMethodCallHandler(handler);
+ }
+
+ private void tearDownChannel() {
+ share.setActivity(null);
+ methodChannel.setMethodCallHandler(null);
}
}
diff --git a/packages/share/example/android/app/src/main/AndroidManifest.xml b/packages/share/example/android/app/src/main/AndroidManifest.xml
index a86d072a6b33..d5e5ec8bf39d 100644
--- a/packages/share/example/android/app/src/main/AndroidManifest.xml
+++ b/packages/share/example/android/app/src/main/AndroidManifest.xml
@@ -4,12 +4,18 @@
-
+
+
diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java
new file mode 100644
index 000000000000..736ac546c55a
--- /dev/null
+++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package io.flutter.plugins.shareexample;
+
+import android.os.Bundle;
+import io.flutter.app.FlutterActivity;
+import io.flutter.plugins.GeneratedPluginRegistrant;
+
+public class EmbeddingV1Activity extends FlutterActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ GeneratedPluginRegistrant.registerWith(this);
+ }
+}
diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java
new file mode 100644
index 000000000000..958541165806
--- /dev/null
+++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java
@@ -0,0 +1,13 @@
+package io.flutter.plugins.shareexample;
+
+import androidx.test.rule.ActivityTestRule;
+import dev.flutter.plugins.e2e.FlutterRunner;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(FlutterRunner.class)
+public class EmbeddingV1ActivityTest {
+ @Rule
+ public ActivityTestRule rule =
+ new ActivityTestRule<>(EmbeddingV1Activity.class);
+}
diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivity.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivity.java
index 89d8bb21073d..3717feb8ca7e 100644
--- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivity.java
+++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivity.java
@@ -1,18 +1,19 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.shareexample;
-import android.os.Bundle;
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.GeneratedPluginRegistrant;
+import io.flutter.embedding.android.FlutterActivity;
+import io.flutter.embedding.engine.FlutterEngine;
+import io.flutter.plugins.share.SharePlugin;
public class MainActivity extends FlutterActivity {
-
+ // TODO(cyanglaz): Remove this once v2 of GeneratedPluginRegistrant rolls to stable.
+ // https://github.com/flutter/flutter/issues/42694
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- GeneratedPluginRegistrant.registerWith(this);
+ public void configureFlutterEngine(FlutterEngine flutterEngine) {
+ super.configureFlutterEngine(flutterEngine);
+ flutterEngine.getPlugins().add(new SharePlugin());
}
}
diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivityTest.java
new file mode 100644
index 000000000000..fcd936a7dd0f
--- /dev/null
+++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/MainActivityTest.java
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package io.flutter.plugins.shareexample;
+
+import androidx.test.rule.ActivityTestRule;
+import dev.flutter.plugins.e2e.FlutterRunner;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(FlutterRunner.class)
+public class MainActivityTest {
+ @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class);
+}
diff --git a/packages/share/example/android/gradle.properties b/packages/share/example/android/gradle.properties
index 8bd86f680510..38c8d4544ff1 100644
--- a/packages/share/example/android/gradle.properties
+++ b/packages/share/example/android/gradle.properties
@@ -1 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
+android.enableR8=true
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/packages/share/example/pubspec.yaml b/packages/share/example/pubspec.yaml
index f28c6dc95d62..4e4fc49dca7a 100644
--- a/packages/share/example/pubspec.yaml
+++ b/packages/share/example/pubspec.yaml
@@ -7,5 +7,15 @@ dependencies:
share:
path: ../
+dev_dependencies:
+ flutter_driver:
+ sdk: flutter
+ e2e: ^0.2.0
+
flutter:
uses-material-design: true
+
+environment:
+ sdk: ">=2.0.0-dev.28.0 <3.0.0"
+ flutter: ">=1.9.1+hotfix.2 <2.0.0"
+
diff --git a/packages/share/example/test_driver/test/share_e2e_test.dart b/packages/share/example/test_driver/test/share_e2e_test.dart
new file mode 100644
index 000000000000..ff6e9ce74ad9
--- /dev/null
+++ b/packages/share/example/test_driver/test/share_e2e_test.dart
@@ -0,0 +1,15 @@
+// Copyright 2019, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+import 'package:flutter_driver/flutter_driver.dart';
+
+Future main() async {
+ final FlutterDriver driver = await FlutterDriver.connect();
+ final String result =
+ await driver.requestData(null, timeout: const Duration(minutes: 1));
+ driver.close();
+ exit(result == 'pass' ? 0 : 1);
+}
diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml
index 800f1b482eed..d569cbff70be 100644
--- a/packages/share/pubspec.yaml
+++ b/packages/share/pubspec.yaml
@@ -3,7 +3,7 @@ description: Flutter plugin for sharing content via the platform share UI, using
the ACTION_SEND intent on Android and UIActivityViewController on iOS.
author: Flutter Team
homepage: https://github.com/flutter/plugins/tree/master/packages/share
-version: 0.6.2+4
+version: 0.6.3
flutter:
plugin:
@@ -21,7 +21,8 @@ dev_dependencies:
mockito: ^3.0.0
flutter_test:
sdk: flutter
+ e2e: ^0.2.0
environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0"
- flutter: ">=1.6.0 <2.0.0"
+ flutter: ">=1.6.7 <2.0.0"
diff --git a/packages/share/test/share_e2e.dart b/packages/share/test/share_e2e.dart
new file mode 100644
index 000000000000..eb990222b009
--- /dev/null
+++ b/packages/share/test/share_e2e.dart
@@ -0,0 +1,15 @@
+// Copyright 2019, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:share/share.dart';
+import 'package:e2e/e2e.dart';
+
+void main() {
+ E2EWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('Can launch share', (WidgetTester tester) async {
+ expect(Share.share('message', subject: 'title'), completes);
+ });
+}