diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 3c89003e5d59..d1e6d8db07f3 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.2+2 +* Fix bug that would make the shortcut not open on Android. +* Report shortcut used on Android. +* Improves example. + ## 0.3.2+1 * Update usage example in README. diff --git a/packages/quick_actions/android/src/main/AndroidManifest.xml b/packages/quick_actions/android/src/main/AndroidManifest.xml index 26daac952d28..5b02f6d8aef2 100644 --- a/packages/quick_actions/android/src/main/AndroidManifest.xml +++ b/packages/quick_actions/android/src/main/AndroidManifest.xml @@ -1,12 +1,4 @@ - - - - diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java index 6fb276af0934..3a4ba2410666 100644 --- a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java +++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java @@ -4,15 +4,14 @@ package io.flutter.plugins.quickactions; -import android.annotation.SuppressLint; -import android.app.Activity; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; +import android.content.res.Resources; import android.graphics.drawable.Icon; import android.os.Build; -import android.os.Bundle; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; @@ -23,17 +22,11 @@ import java.util.Map; /** QuickActionsPlugin */ -@SuppressWarnings("unchecked") public class QuickActionsPlugin implements MethodCallHandler { - private final Registrar registrar; - private static final String intentExtraAction = "action"; - private static String launchAction = null; + private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions"; + private static final String EXTRA_ACTION = "some unique action key"; - // Channel is a static field because it needs to be accessible to the - // {@link ShortcutHandlerActivity} which has to be a static class with - // no-args constructor. - // It is also mutable because it is derived from {@link Registrar}. - private static MethodChannel channel; + private final Registrar registrar; private QuickActionsPlugin(Registrar registrar) { this.registrar = registrar; @@ -45,13 +38,11 @@ private QuickActionsPlugin(Registrar registrar) { *

Must be called when the application is created. */ public static void registerWith(Registrar registrar) { - channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/quick_actions"); + final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_ID); channel.setMethodCallHandler(new QuickActionsPlugin(registrar)); - launchAction = registrar.activity().getIntent().getStringExtra(intentExtraAction); } @Override - @SuppressLint("NewApi") public void onMethodCall(MethodCall call, Result result) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { // We already know that this functionality does not work for anything @@ -72,8 +63,13 @@ public void onMethodCall(MethodCall call, Result result) { shortcutManager.removeAllDynamicShortcuts(); break; case "getLaunchAction": + final Intent intent = registrar.activity().getIntent(); + final String launchAction = intent.getStringExtra(EXTRA_ACTION); + if (launchAction != null && !launchAction.isEmpty()) { + shortcutManager.reportShortcutUsed(launchAction); + intent.removeExtra(EXTRA_ACTION); + } result.success(launchAction); - launchAction = null; return; default: result.notImplemented(); @@ -82,69 +78,56 @@ public void onMethodCall(MethodCall call, Result result) { result.success(null); } - @SuppressLint("NewApi") + @TargetApi(Build.VERSION_CODES.N_MR1) private List deserializeShortcuts(List> shortcuts) { - List shortcutInfos = new ArrayList<>(); - Context context = registrar.context(); + final List shortcutInfos = new ArrayList<>(); + final Context context = registrar.context(); + for (Map shortcut : shortcuts) { - String icon = shortcut.get("icon"); - String type = shortcut.get("type"); - String title = shortcut.get("localizedTitle"); - ShortcutInfo.Builder shortcutBuilder = new ShortcutInfo.Builder(context, type); - if (icon != null) { - int resourceId = - context.getResources().getIdentifier(icon, "drawable", context.getPackageName()); - if (resourceId > 0) { - shortcutBuilder.setIcon(Icon.createWithResource(context, resourceId)); - } + final String icon = shortcut.get("icon"); + final String type = shortcut.get("type"); + final String title = shortcut.get("localizedTitle"); + final ShortcutInfo.Builder shortcutBuilder = new ShortcutInfo.Builder(context, type); + + final int resourceId = loadResourceId(context, icon); + final Intent intent = getIntentToOpenMainActivity(type); + + if (resourceId > 0) { + shortcutBuilder.setIcon(Icon.createWithResource(context, resourceId)); } - shortcutBuilder.setLongLabel(title); - shortcutBuilder.setShortLabel(title); - Intent intent = new Intent(context, ShortcutHandlerActivity.class); - intent.setAction("plugins.flutter.io/quick_action"); - intent.putExtra("type", type); - shortcutBuilder.setIntent(intent); - shortcutInfos.add(shortcutBuilder.build()); + + final ShortcutInfo shortcutInfo = + shortcutBuilder.setLongLabel(title).setShortLabel(title).setIntent(intent).build(); + shortcutInfos.add(shortcutInfo); } return shortcutInfos; } - /** - * Handle the shortcut and immediately closes the activity. - * - *

Needs to be invocable by Android system; hence it is public. - */ - public static class ShortcutHandlerActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // Get the Intent that started this activity and extract the string - Intent intent = getIntent(); - String type = intent.getStringExtra("type"); - if (channel != null) { - channel.invokeMethod("launch", type); - } else { - startActivity(getIntentToOpenMainActivity(this, type)); - } - finish(); + private int loadResourceId(Context context, String icon) { + if (icon == null) { + return 0; } + final String packageName = context.getPackageName(); + final Resources res = context.getResources(); + final int resourceId = res.getIdentifier(icon, "drawable", packageName); - /** - * Returns Intent to launch the MainActivity. Used to start the app, if one of quick actions was - * called from the background. - */ - private Intent getIntentToOpenMainActivity(Context context, String type) { - Intent launchIntentForPackage = - context - .getPackageManager() - .getLaunchIntentForPackage(context.getApplicationContext().getPackageName()); - if (launchIntentForPackage == null) { - return null; - } else { - launchIntentForPackage.putExtra(intentExtraAction, type); - return launchIntentForPackage; - } + if (resourceId == 0) { + return res.getIdentifier(icon, "mipmap", packageName); + } else { + return resourceId; } } + + private Intent getIntentToOpenMainActivity(String type) { + final Context context = registrar.context(); + final String packageName = context.getPackageName(); + + return context + .getPackageManager() + .getLaunchIntentForPackage(packageName) + .setAction(Intent.ACTION_RUN) + .putExtra(EXTRA_ACTION, type) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + } } diff --git a/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml b/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml index 20b3b96f7e2e..bb7a1351d343 100644 --- a/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml +++ b/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml @@ -1,19 +1,24 @@ + package="io.flutter.plugins.quickactionsexample"> - + - - - - - - - - + + + + + + + + + diff --git a/packages/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml b/packages/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000000..9ed346888001 --- /dev/null +++ b/packages/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/quick_actions/example/android/app/src/main/res/values/styles.xml b/packages/quick_actions/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000000..6c1d1ec695c9 --- /dev/null +++ b/packages/quick_actions/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/quick_actions/example/lib/main.dart b/packages/quick_actions/example/lib/main.dart index 7ca344dd0ab7..dc4dc7a316fe 100644 --- a/packages/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/example/lib/main.dart @@ -10,42 +10,53 @@ void main() { } class MyApp extends StatelessWidget { - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Flutter Quick Actions Demo', theme: ThemeData( primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Flutter Demo Home Page'), + home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - final String title; + MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { + String shortcut = "no action set"; + @override void initState() { super.initState(); + final QuickActions quickActions = QuickActions(); quickActions.initialize((String shortcutType) { - if (shortcutType == 'action_main') { - print('The user tapped on the "Main view" action.'); - } + setState(() { + if (shortcutType != null) shortcut = shortcutType; + }); }); quickActions.setShortcutItems([ + // NOTE: This first action icon will only work on iOS. + // In a real world project keep the same file name for both platforms. const ShortcutItem( - type: 'action_main', localizedTitle: 'Main view', icon: 'AppIcon'), + type: 'action_one', + localizedTitle: 'Action one', + icon: 'AppIcon', + ), + // NOTE: This second action icon will only work on Android. + // In a real world project keep the same file name for both platforms. + const ShortcutItem( + type: 'action_two', + localizedTitle: 'Action two', + icon: 'ic_launcher'), ]); } @@ -53,12 +64,13 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Plugin example app'), + title: Text('$shortcut'), ), body: const Center( - child: Text('On home screen, long press the icon to ' - 'get Main view action. Tapping on that action should print ' - 'a message to the log.')), + child: Text('On home screen, long press the app icon to ' + 'get Action one or Action two options. Tapping on that action should ' + 'set the toolbar title.'), + ), ); } } diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index 3d51d336a14a..bc818e7c80ac 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.3.2+1 +version: 0.3.2+2 flutter: plugin: