Update shortcut sample

Use favicon as a shortcut icon, if available.

Change-Id: Ic2393e2de6ce9eb39b5d25d0dafd9686416cdfe7
diff --git a/samples/ShortcutSample/AndroidManifest.xml b/samples/ShortcutSample/AndroidManifest.xml
index 88b0544..4fb99b8 100644
--- a/samples/ShortcutSample/AndroidManifest.xml
+++ b/samples/ShortcutSample/AndroidManifest.xml
@@ -19,6 +19,8 @@
 
     <uses-sdk android:minSdkVersion="25" />
 
+    <uses-permission android:name="android.permission.INTERNET" />
+
     <application
         android:label="@string/app_name"
         android:icon="@drawable/app"
diff --git a/samples/ShortcutSample/src/com/example/android/shortcutsample/Main.java b/samples/ShortcutSample/src/com/example/android/shortcutsample/Main.java
index 41f0b2b..3e7f893 100644
--- a/samples/ShortcutSample/src/com/example/android/shortcutsample/Main.java
+++ b/samples/ShortcutSample/src/com/example/android/shortcutsample/Main.java
@@ -19,6 +19,7 @@
 import android.app.ListActivity;
 import android.content.Context;
 import android.content.pm.ShortcutInfo;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -98,13 +99,27 @@
                 .setPositiveButton("Add", (dialog, whichButton) -> {
                     final String url = editUri.getText().toString().trim();
                     if (url.length() > 0) {
-                        mHelper.addWebSiteShortcut(url);
-                        refreshList();
+                        addUriAsync(url);
                     }
                 })
                 .show();
     }
 
+    private void addUriAsync(String uri) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                mHelper.addWebSiteShortcut(uri);
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void aVoid) {
+                refreshList();
+            }
+        }.execute();
+    }
+
     private void refreshList() {
         mAdapter.setShortcuts(mHelper.getShortcuts());
     }
diff --git a/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java b/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java
index 61c4f29..6649f9d 100644
--- a/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java
+++ b/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java
@@ -19,12 +19,19 @@
 import android.content.Intent;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.PersistableBundle;
 import android.util.Log;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -169,8 +176,12 @@
         b.setShortLabel(uri.getHost());
         b.setLongLabel(uri.toString());
 
-        // TODO Fetch the favicon from the URI and sets to the icon.
-        b.setIcon(Icon.createWithResource(mContext, R.drawable.link));
+        Bitmap bmp = fetchFavicon(uri);
+        if (bmp != null) {
+            b.setIcon(Icon.createWithBitmap(bmp));
+        } else {
+            b.setIcon(Icon.createWithResource(mContext, R.drawable.link));
+        }
 
         return b;
     }
@@ -209,4 +220,23 @@
     public void enableShortcut(ShortcutInfo shortcut) {
         mShortcutManager.enableShortcuts(Arrays.asList(shortcut.getId()));
     }
+
+    private Bitmap fetchFavicon(Uri uri) {
+        final Uri iconUri = uri.buildUpon().path("favicon.ico").build();
+        Log.i(TAG, "Fetching favicon from: " + iconUri);
+
+        InputStream is = null;
+        BufferedInputStream bis = null;
+        try
+        {
+            URLConnection conn = new URL(iconUri.toString()).openConnection();
+            conn.connect();
+            is = conn.getInputStream();
+            bis = new BufferedInputStream(is, 8192);
+            return BitmapFactory.decodeStream(bis);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to fetch favicon from " + iconUri, e);
+            return null;
+        }
+    }
 }
diff --git a/samples/ShortcutSample/src/com/example/android/shortcutsample/Utils.java b/samples/ShortcutSample/src/com/example/android/shortcutsample/Utils.java
index 523f4dc..7f03b57 100644
--- a/samples/ShortcutSample/src/com/example/android/shortcutsample/Utils.java
+++ b/samples/ShortcutSample/src/com/example/android/shortcutsample/Utils.java
@@ -16,20 +16,17 @@
 package com.example.android.shortcutsample;
 
 import android.content.Context;
-import android.content.pm.ShortcutInfo;
-import android.os.AsyncTask;
-import android.os.PersistableBundle;
-import android.util.Log;
+import android.os.Handler;
+import android.os.Looper;
 import android.widget.Toast;
 
-import java.util.ArrayList;
-import java.util.List;
-
 public class Utils {
     private Utils() {
     }
 
     public static void showToast(Context context, String message) {
-        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+        new Handler(Looper.getMainLooper()).post(() -> {
+            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+        });
     }
 }