Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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.quickactions;

import android.annotation.TargetApi;
import android.app.Activity;
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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {

private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions";
private static final String EXTRA_ACTION = "some unique action key";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should "some unique action key" be written here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have enough context to give input here. It seems this is introduced in 63609c9
and @collinjackson or @BugsBunnyBR might be able to give some inputs on this.
Anyways, this is not related to this migration. I suggest we create new issue and fix it in a later PR if needs to be fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is just a unique string, the value itself does not matter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BugsBunnyBR We can make the value of the String unambiguous so it is more readable.


private final Context context;
private Activity activity;

MethodCallHandlerImpl(@NonNull Context context, @Nullable Activity activity) {
this.context = context;
this.activity = activity;
}

void setActivity(Activity activity) {
this.activity = activity;
}

@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
// We already know that this functionality does not work for anything
// lower than API 25 so we chose not to return error. Instead we do nothing.
result.success(null);
return;
}
ShortcutManager shortcutManager =
(ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);
switch (call.method) {
case "setShortcutItems":
List<Map<String, String>> serializedShortcuts = call.arguments();
List<ShortcutInfo> shortcuts = deserializeShortcuts(serializedShortcuts);
shortcutManager.setDynamicShortcuts(shortcuts);
break;
case "clearShortcutItems":
shortcutManager.removeAllDynamicShortcuts();
break;
case "getLaunchAction":
if (activity == null) {
result.error(
"quick_action_getlaunchaction_no_activity",
"There is no activity available when launching action",
null);
return;
}
final Intent intent = activity.getIntent();
final String launchAction = intent.getStringExtra(EXTRA_ACTION);
if (launchAction != null && !launchAction.isEmpty()) {
shortcutManager.reportShortcutUsed(launchAction);
intent.removeExtra(EXTRA_ACTION);
}
result.success(launchAction);
return;
default:
result.notImplemented();
return;
}
result.success(null);
}

@TargetApi(Build.VERSION_CODES.N_MR1)
private List<ShortcutInfo> deserializeShortcuts(List<Map<String, String>> shortcuts) {
final List<ShortcutInfo> shortcutInfos = new ArrayList<>();

for (Map<String, String> shortcut : shortcuts) {
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));
}

final ShortcutInfo shortcutInfo =
shortcutBuilder.setLongLabel(title).setShortLabel(title).setIntent(intent).build();
shortcutInfos.add(shortcutInfo);
}
return shortcutInfos;
}

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);

if (resourceId == 0) {
return res.getIdentifier(icon, "mipmap", packageName);
} else {
return resourceId;
}
}

private Intent getIntentToOpenMainActivity(String type) {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,130 +4,70 @@

package io.flutter.plugins.quickactions;

import android.annotation.TargetApi;
import android.app.Activity;
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 io.flutter.plugin.common.MethodCall;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/** QuickActionsPlugin */
public class QuickActionsPlugin implements MethodCallHandler {
public class QuickActionsPlugin implements FlutterPlugin, ActivityAware {
private static final String CHANNEL_ID = "plugins.flutter.io/quick_actions";
private static final String EXTRA_ACTION = "some unique action key";

private final Registrar registrar;

private QuickActionsPlugin(Registrar registrar) {
this.registrar = registrar;
}
MethodChannel channel;
MethodCallHandlerImpl handler;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MethodCallHandlerImpl handler;
private MethodChannel channel;
private MethodCallHandlerImpl handler;


/**
* Plugin registration.
*
* <p>Must be called when the application is created.
*/
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_ID);
channel.setMethodCallHandler(new QuickActionsPlugin(registrar));
QuickActionsPlugin plugin = new QuickActionsPlugin();
plugin.setupChannel(registrar.messenger(), registrar.context(), registrar.activity());
}

@Override
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
// lower than API 25 so we chose not to return error. Instead we do nothing.
result.success(null);
return;
}
Context context = registrar.context();
ShortcutManager shortcutManager =
(ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);
switch (call.method) {
case "setShortcutItems":
List<Map<String, String>> serializedShortcuts = call.arguments();
List<ShortcutInfo> shortcuts = deserializeShortcuts(serializedShortcuts);
shortcutManager.setDynamicShortcuts(shortcuts);
break;
case "clearShortcutItems":
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);
return;
default:
result.notImplemented();
return;
}
result.success(null);
public void onAttachedToEngine(FlutterPluginBinding binding) {
setupChannel(
binding.getFlutterEngine().getDartExecutor(), binding.getApplicationContext(), null);
}

@TargetApi(Build.VERSION_CODES.N_MR1)
private List<ShortcutInfo> deserializeShortcuts(List<Map<String, String>> shortcuts) {
final List<ShortcutInfo> shortcutInfos = new ArrayList<>();
final Context context = registrar.context();

for (Map<String, String> shortcut : shortcuts) {
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));
}
@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
handler = null;
}

final ShortcutInfo shortcutInfo =
shortcutBuilder.setLongLabel(title).setShortLabel(title).setIntent(intent).build();
shortcutInfos.add(shortcutInfo);
}
return shortcutInfos;
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
handler.setActivity(binding.getActivity());
}

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);
@Override
public void onDetachedFromActivity() {
handler.setActivity(null);
}

if (resourceId == 0) {
return res.getIdentifier(icon, "mipmap", packageName);
} else {
return resourceId;
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
onAttachedToActivity(binding);
}

private Intent getIntentToOpenMainActivity(String type) {
final Context context = registrar.context();
final String packageName = context.getPackageName();
@Override
public void onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity();
}

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);
private void setupChannel(
@NonNull BinaryMessenger messenger, @NonNull Context context, @Nullable Activity activity) {
channel = new MethodChannel(messenger, CHANNEL_ID);
handler = new MethodCallHandlerImpl(context, activity);
channel.setMethodCallHandler(handler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@
<application android:name="io.flutter.app.FlutterApplication"
android:label="quick_actions_example"
android:icon="@mipmap/ic_launcher">
<activity android:name=".MainActivity"
<activity android:name=".EmbeddingV1Activity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:exported="true">
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true"/>
</activity>
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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.quickactionsexample;

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);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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.quickactionsexample;

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.quickactions.QuickActionsPlugin;

public class MainActivity extends FlutterActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
flutterEngine.getPlugins().add(new QuickActionsPlugin());
}
}
3 changes: 3 additions & 0 deletions packages/quick_actions/example/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true