Quick actions initial commit (#112)

* Quick Actions plugin

* Add licensing

* Fix icon refs

* Add licensing and fix usage based on engine update.

* Add Android Support too. Update README

* Remove more comments

* Make analyzer and formatter happy

* Review comments
diff --git a/packages/quick_actions/android/.gitignore b/packages/quick_actions/android/.gitignore
new file mode 100644
index 0000000..5c4ef82
--- /dev/null
+++ b/packages/quick_actions/android/.gitignore
@@ -0,0 +1,12 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+
+/gradle
+/gradlew
+/gradlew.bat
diff --git a/packages/quick_actions/android/build.gradle b/packages/quick_actions/android/build.gradle
new file mode 100644
index 0000000..a66db47
--- /dev/null
+++ b/packages/quick_actions/android/build.gradle
@@ -0,0 +1,32 @@
+group 'io.flutter.plugins.quickactions'
+version '1.0-SNAPSHOT'
+
+buildscript {
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:2.3.0'
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+    }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion '25.0.3'
+
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+}
diff --git a/packages/quick_actions/android/gradle.properties b/packages/quick_actions/android/gradle.properties
new file mode 100644
index 0000000..8bd86f6
--- /dev/null
+++ b/packages/quick_actions/android/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx1536M
diff --git a/packages/quick_actions/android/settings.gradle b/packages/quick_actions/android/settings.gradle
new file mode 100644
index 0000000..7524824
--- /dev/null
+++ b/packages/quick_actions/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'quick_actions'
diff --git a/packages/quick_actions/android/src/main/AndroidManifest.xml b/packages/quick_actions/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7548f28
--- /dev/null
+++ b/packages/quick_actions/android/src/main/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="io.flutter.plugins.quickactions"
+  android:versionCode="1"
+  android:versionName="0.0.1">
+
+  <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25" />
+  <application>
+    <activity android:name=".QuickActionsPlugin$ShortcutHandlerActivity" android:exported="false"/>
+  </application>
+</manifest>
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
new file mode 100644
index 0000000..8e8b8dd
--- /dev/null
+++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java
@@ -0,0 +1,118 @@
+// 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.quickactions;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+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;
+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 */
+@SuppressWarnings("unchecked")
+public class QuickActionsPlugin implements MethodCallHandler {
+  private final Activity activity;
+  // 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 QuickActionsPlugin(Activity activity) {
+    this.activity = activity;
+  }
+
+  /** Plugin registration. */
+  public static void registerWith(Registrar registrar) {
+    if (channel != null) {
+      throw new IllegalStateException("You should not call registerWith more than once.");
+    }
+    channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/quick_actions");
+    channel.setMethodCallHandler(new QuickActionsPlugin(registrar.activity()));
+  }
+
+  @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
+      // lower than API 25 so we chose not to return error. Instead we do nothing.
+      result.success(null);
+      return;
+    }
+    ShortcutManager shortcutManager =
+        (ShortcutManager) activity.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;
+      default:
+        result.notImplemented();
+        return;
+    }
+    result.success(null);
+  }
+
+  @SuppressLint("NewApi")
+  private List<ShortcutInfo> deserializeShortcuts(List<Map<String, String>> shortcuts) {
+    List<ShortcutInfo> shortcutInfos = new ArrayList<>();
+    for (Map<String, String> shortcut : shortcuts) {
+      String icon = shortcut.get("icon");
+      String type = shortcut.get("type");
+      String title = shortcut.get("localizedTitle");
+      ShortcutInfo.Builder shortcutBuilder = new ShortcutInfo.Builder(activity, type);
+      if (icon != null) {
+        int resourceId =
+            activity.getResources().getIdentifier(icon, "drawable", activity.getPackageName());
+        if (resourceId > 0) {
+          shortcutBuilder.setIcon(Icon.createWithResource(activity, resourceId));
+        }
+      }
+      shortcutBuilder.setLongLabel(title);
+      shortcutBuilder.setShortLabel(title);
+      Intent intent = new Intent(activity, ShortcutHandlerActivity.class);
+      intent.setAction("plugins.flutter.io/quick_action");
+      intent.putExtra("type", type);
+      shortcutBuilder.setIntent(intent);
+      shortcutInfos.add(shortcutBuilder.build());
+    }
+    return shortcutInfos;
+  }
+
+  /**
+   * Handle the shortcut and immediately closes the activity.
+   *
+   * <p>Needs to be invokable 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");
+      channel.invokeMethod("launch", type);
+      finish();
+    }
+  }
+}