BookmarkUtils.java revision 90b40269a55eb34a2942c6a493819b60a03eb7f1
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
19import android.content.Context;
20import android.content.Intent;
21import android.graphics.Bitmap;
22import android.graphics.BitmapFactory;
23import android.graphics.Canvas;
24import android.graphics.Color;
25import android.graphics.Paint;
26import android.graphics.Path;
27import android.graphics.PorterDuff;
28import android.graphics.PorterDuffXfermode;
29import android.graphics.Rect;
30import android.graphics.RectF;
31import android.net.Uri;
32import android.provider.Browser;
33import android.util.Log;
34
35class BookmarkUtils {
36    private final static String LOGTAG = "BookmarkUtils";
37
38    // XXX: There is no public string defining this intent so if Home changes the value, we
39    // have to update this string.
40    private static final String INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";
41
42    enum BookmarkIconType {
43        ICON_INSTALLABLE_WEB_APP, // Icon for an installable web app (launches WebAppRuntime).
44        ICON_HOME_SHORTCUT        // Icon for a shortcut on the home screen (launches Browser).
45    };
46
47    /**
48     * Creates an icon to be associated with this bookmark. If available, the apple touch icon
49     * will be used, else we draw our own depending on the type of "bookmark" being created.
50     */
51    static Bitmap createIcon(Context context, Bitmap touchIcon, Bitmap favicon,
52            BookmarkIconType type) {
53        int iconDimension = context.getResources().getDimensionPixelSize(
54                android.R.dimen.app_icon_size);
55
56        Bitmap bm = Bitmap.createBitmap(iconDimension, iconDimension, Bitmap.Config.ARGB_8888);
57        Canvas canvas = new Canvas(bm);
58        Rect iconBounds = new Rect(0, 0, bm.getWidth(), bm.getHeight());
59
60        // Use the apple-touch-icon if available
61        if (touchIcon != null) {
62            drawTouchIconToCanvas(touchIcon, canvas, iconBounds);
63        } else {
64            // No touch icon so create our own.
65            // Set the background based on the type of shortcut (either webapp or home shortcut).
66            Bitmap icon = getIconBackground(context, type);
67
68            if (icon != null) {
69                // Now draw the correct icon background into our new bitmap.
70                canvas.drawBitmap(icon, null, iconBounds, null);
71            }
72
73            // If we have a favicon, overlay it in a nice rounded white box on top of the
74            // background.
75            if (favicon != null) {
76                drawFaviconToCanvas(favicon, canvas, iconBounds,
77                        context.getResources().getDisplayMetrics().density);
78            }
79        }
80        return bm;
81    }
82
83    /**
84     * Convenience method for creating an intent that will add a shortcut to the home screen.
85     */
86    static Intent createAddToHomeIntent(Context context, String url, String title,
87            Bitmap touchIcon, Bitmap favicon) {
88        Intent i = new Intent(INSTALL_SHORTCUT);
89        Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
90        long urlHash = url.hashCode();
91        long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
92        shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID, Long.toString(uniqueId));
93        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
94        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
95        i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, touchIcon, favicon,
96                BookmarkIconType.ICON_HOME_SHORTCUT));
97
98        // Do not allow duplicate items
99        i.putExtra("duplicate", false);
100        return i;
101    }
102
103    private static Bitmap getIconBackground(Context context, BookmarkIconType type) {
104        if (type == BookmarkIconType.ICON_HOME_SHORTCUT) {
105            // Want to create a shortcut icon on the homescreen, so the icon
106            // background is the red bookmark.
107            return BitmapFactory.decodeResource(context.getResources(),
108                    R.drawable.ic_launcher_shortcut_browser_bookmark);
109        } else if (type == BookmarkIconType.ICON_INSTALLABLE_WEB_APP) {
110            // Use the web browser icon as the background for the icon for an installable
111            // web app.
112            return BitmapFactory.decodeResource(context.getResources(),
113                    R.drawable.ic_launcher_browser);
114        }
115        return null;
116    }
117
118    private static void drawTouchIconToCanvas(Bitmap touchIcon, Canvas canvas, Rect iconBounds) {
119        Rect src = new Rect(0, 0, touchIcon.getWidth(), touchIcon.getHeight());
120
121        // Paint used for scaling the bitmap and drawing the rounded rect.
122        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
123        paint.setFilterBitmap(true);
124        canvas.drawBitmap(touchIcon, src, iconBounds, paint);
125
126        // Construct a path from a round rect. This will allow drawing with
127        // an inverse fill so we can punch a hole using the round rect.
128        Path path = new Path();
129        path.setFillType(Path.FillType.INVERSE_WINDING);
130        RectF rect = new RectF(iconBounds);
131        rect.inset(1, 1);
132        path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
133
134        // Reuse the paint and clear the outside of the rectangle.
135        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
136        canvas.drawPath(path, paint);
137    }
138
139    private static void drawFaviconToCanvas(Bitmap favicon, Canvas canvas, Rect iconBounds,
140            float density) {
141        // Make a Paint for the white background rectangle and for
142        // filtering the favicon.
143        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
144        p.setStyle(Paint.Style.FILL_AND_STROKE);
145        p.setColor(Color.WHITE);
146
147        // Create a rectangle that is slightly wider than the favicon
148        final float iconSize = 16 * density; // 16x16 favicon
149        final float padding = 2 * density; // white padding around icon
150        final float rectSize = iconSize + 2 * padding;
151        final float x = iconBounds.exactCenterX() - (rectSize / 2);
152        // Note: Subtract 2 dip from the y position since the box is
153        // slightly higher than center. Use padding since it is already
154        // 2 * density.
155        final float y = iconBounds.exactCenterY() - (rectSize / 2) - padding;
156        RectF r = new RectF(x, y, x + rectSize, y + rectSize);
157
158        // Draw a white rounded rectangle behind the favicon
159        canvas.drawRoundRect(r, 2, 2, p);
160
161        // Draw the favicon in the same rectangle as the rounded
162        // rectangle but inset by the padding
163        // (results in a 16x16 favicon).
164        r.inset(padding, padding);
165        canvas.drawBitmap(favicon, null, r, p);
166    }
167
168};
169