Bookmarks.java revision 1a805652e389d9404ee0fda7c993a6202332e92b
1e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins/*
2e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * Copyright (C) 2009 The Android Open Source Project
3e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins *
4e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * Licensed under the Apache License, Version 2.0 (the "License");
5e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * you may not use this file except in compliance with the License.
6e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * You may obtain a copy of the License at
7e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins *
8e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins *      http://www.apache.org/licenses/LICENSE-2.0
9e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins *
10e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * Unless required by applicable law or agreed to in writing, software
11e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * distributed under the License is distributed on an "AS IS" BASIS,
12e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * See the License for the specific language governing permissions and
14e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins * limitations under the License.
15e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins */
16e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins
17e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginspackage com.android.browser;
18e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins
19e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.content.ContentResolver;
20e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.content.ContentUris;
21e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.content.ContentValues;
22e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.content.Context;
23e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.database.Cursor;
24aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdochimport android.graphics.Bitmap;
25e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.net.Uri;
268402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamiltonimport android.os.AsyncTask;
2769bd7077becb42438513fa80c98d0b48c8a23a41Jeff Hamiltonimport android.provider.BrowserContract;
281a805652e389d9404ee0fda7c993a6202332e92bJeff Hamiltonimport android.provider.BrowserContract.Combined;
291a805652e389d9404ee0fda7c993a6202332e92bJeff Hamiltonimport android.provider.BrowserContract.Images;
30e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.util.Log;
31e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.webkit.WebIconDatabase;
32e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scrogginsimport android.widget.Toast;
33e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins
34aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdochimport java.io.ByteArrayOutputStream;
35e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins
36e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins/**
37e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins *  This class is purely to have a common place for adding/deleting bookmarks.
38e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins */
39e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins/* package */ class Bookmarks {
40de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    // We only want the user to be able to bookmark content that
41de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    // the browser can handle directly.
42de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    private static final String acceptableBookmarkSchemes[] = {
43de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "http:",
44de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "https:",
45de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "about:",
46de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "data:",
47de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "javascript:",
48de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "file:",
49de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            "content:"
50de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    };
51de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch
522c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins    private final static String LOGTAG = "Bookmarks";
53e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins    /**
54e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  Add a bookmark to the database.
55e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param context Context of the calling Activity.  This is used to make
56e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *          Toast confirming that the bookmark has been added.  If the
57e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *          caller provides null, the Toast will not be shown.
58e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param cr The ContentResolver being used to add the bookmark to the db.
59e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param url URL of the website to be bookmarked.
60e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param name Provided name for the bookmark.
61aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch     *  @param thumbnail A thumbnail for the bookmark.
629c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate     *  @param retainIcon Whether to retain the page's icon in the icon database.
639c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate     *          This will usually be <code>true</code> except when bookmarks are
649c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate     *          added by a settings restore agent.
65e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     */
668402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /* package */ static void addBookmark(Context context, ContentResolver cr, String url,
678402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            String name, Bitmap thumbnail, boolean retainIcon) {
68e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins        // Want to append to the beginning of the list
698402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        ContentValues values = new ContentValues();
702c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        Cursor cursor = null;
712c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        try {
728402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            values.put(BrowserContract.Bookmarks.TITLE, name);
738402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            values.put(BrowserContract.Bookmarks.URL, url);
748402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            values.put(BrowserContract.Bookmarks.IS_FOLDER, 0);
758402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            values.put(BrowserContract.Bookmarks.THUMBNAIL,
768402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                    bitmapToBytes(thumbnail));
778402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            cr.insert(BrowserContract.Bookmarks.CONTENT_URI, values);
782c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        } catch (IllegalStateException e) {
792c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            Log.e(LOGTAG, "addBookmark", e);
802c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        } finally {
812c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            if (cursor != null) cursor.close();
82e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins        }
839c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate        if (retainIcon) {
849c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate            WebIconDatabase.getInstance().retainIconForPageUrl(url);
859c0dd8caacff99ba76bbb9dc2cab156cded505a8Christopher Tate        }
86e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins        if (context != null) {
87e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins            Toast.makeText(context, R.string.added_to_bookmarks,
88e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins                    Toast.LENGTH_LONG).show();
89e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins        }
90e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins    }
91e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins
92e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins    /**
93e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  Remove a bookmark from the database.  If the url is a visited site, it
94e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  will remain in the database, but only as a history item, and not as a
95e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  bookmarked site.
96e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param context Context of the calling Activity.  This is used to make
97e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *          Toast confirming that the bookmark has been removed.  If the
98e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *          caller provides null, the Toast will not be shown.
99e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param cr The ContentResolver being used to remove the bookmark.
100e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     *  @param url URL of the website to be removed.
101e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins     */
102e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins    /* package */ static void removeFromBookmarks(Context context,
103c95261955cf08f30b484b6a229c4bcff42c645ceAndrei Popescu            ContentResolver cr, String url, String title) {
1042c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        Cursor cursor = null;
1052c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        try {
1068ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            cursor = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
1078ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    new String[] { BrowserContract.Bookmarks._ID },
1088ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    BrowserContract.Bookmarks.URL + " = ? AND " +
1098ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                            BrowserContract.Bookmarks.TITLE + " = ?",
1102c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins                    new String[] { url, title },
1112c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins                    null);
1128ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton
1132c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            // Should be in the database no matter what
1148ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            if (!cursor.moveToFirst()) {
1152c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins                throw new AssertionError("URL is not in the database! " + url
1162c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins                        + " " + title);
117e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins            }
1188ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton
1192c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            // Remove from bookmarks
1202c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            WebIconDatabase.getInstance().releaseIconForPageUrl(url);
1218ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
1228ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    cursor.getLong(0));
1238ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            cr.delete(uri, null, null);
1242c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            if (context != null) {
1258ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                Toast.makeText(context, R.string.removed_from_bookmarks, Toast.LENGTH_LONG).show();
1262c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            }
1272c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        } catch (IllegalStateException e) {
1282c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            Log.e(LOGTAG, "removeFromBookmarks", e);
1292c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins        } finally {
1302c0f611fab8c0a24365c0dd5cbf0a90f70f314c8Leon Scroggins            if (cursor != null) cursor.close();
131e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins        }
132e372c02c732cf0881c21eb8423454a555e8fc75cLeon Scroggins    }
133aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch
134aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch    private static byte[] bitmapToBytes(Bitmap bm) {
135aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch        if (bm == null) {
136aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch            return null;
137aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch        }
138aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch
139aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch        final ByteArrayOutputStream os = new ByteArrayOutputStream();
140aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch        bm.compress(Bitmap.CompressFormat.PNG, 100, os);
141aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch        return os.toByteArray();
142aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch    }
143de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch
144de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    /* package */ static boolean urlHasAcceptableScheme(String url) {
145de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch        if (url == null) {
146de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            return false;
147de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch        }
148de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch
149de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch        for (int i = 0; i < acceptableBookmarkSchemes.length; i++) {
150de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            if (url.startsWith(acceptableBookmarkSchemes[i])) {
151de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch                return true;
152de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch            }
153de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch        }
154de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch        return false;
155de353621650d17a412b6ffe2cbf0366db5f11c40Ben Murdoch    }
1568402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1578ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    static final String QUERY_BOOKMARKS_WHERE =
1581a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton            Combined.URL + " == ? OR " +
1591a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton            Combined.URL + " == ? OR " +
1601a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton            Combined.URL + " LIKE ? || '%' OR " +
1611a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton            Combined.URL + " LIKE ? || '%'";
1628ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton
1631a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton    /* package */ static Cursor queryCombinedForUrl(ContentResolver cr,
1648ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            String originalUrl, String url) {
1658402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (cr == null || url == null) {
1668402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            return null;
1678402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1688402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1698402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // If originalUrl is null, just set it to url.
1708402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (originalUrl == null) {
1718402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            originalUrl = url;
1728402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1738402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1748402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // Look for both the original url and the actual url. This takes in to
1758402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // account redirects.
1761a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton        String originalUrlNoQuery = removeQuery(originalUrl);
1771a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton        String urlNoQuery = removeQuery(url);
1788402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        originalUrl = originalUrlNoQuery + '?';
1798402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        url = urlNoQuery + '?';
1808402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1818402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // Use NoQuery to search for the base url (i.e. if the url is
1828402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com)
1838402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // Use url to match the base url with other queries (i.e. if the url is
1848402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // http://www.google.com/m, search for
1858402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        // http://www.google.com/m?some_query)
1861a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton        final String[] selArgs = new String[] { originalUrlNoQuery, urlNoQuery, originalUrl, url };
1871a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton        final String[] projection = new String[] { Combined.URL };
1881a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton        return cr.query(Combined.CONTENT_URI, projection, QUERY_BOOKMARKS_WHERE, selArgs, null);
1898402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
1908402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
1918402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    // Strip the query from the given url.
1928402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    static String removeQuery(String url) {
1938402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (url == null) {
1948402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            return null;
1958402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
1968402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        int query = url.indexOf('?');
1978402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        String noQuery = url;
1988402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        if (query != -1) {
1998402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            noQuery = url.substring(0, query);
2008402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }
2018402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        return noQuery;
2028402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
2038402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton
2048402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    /**
2058402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * Update the bookmark's favicon. This is a convenience method for updating
2068402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * a bookmark favicon for the originalUrl and url of the passed in WebView.
2078402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * @param cr The ContentResolver to use.
2088402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * @param originalUrl The original url before any redirects.
2098402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * @param url The current url.
2108402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     * @param favicon The favicon bitmap to write to the db.
2118402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton     */
2121a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton    /* package */ static void updateFavicon(final ContentResolver cr,
2138402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            final String originalUrl, final String url, final Bitmap favicon) {
2148402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        new AsyncTask<Void, Void, Void>() {
2158402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            @Override
2168402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            protected Void doInBackground(Void... unused) {
2171a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                Cursor cursor = queryCombinedForUrl(cr, originalUrl, url);
2181a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                try {
2191a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                    if (cursor.moveToFirst()) {
2201a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        final ByteArrayOutputStream os = new ByteArrayOutputStream();
2211a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        favicon.compress(Bitmap.CompressFormat.PNG, 100, os);
2221a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton
2231a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        ContentValues values = new ContentValues();
2241a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        values.put(Images.FAVICON, os.toByteArray());
2251a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        values.put(Images.URL, cursor.getString(0));
2261a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton
2271a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        do {
2281a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                            cr.update(Images.CONTENT_URI, values, null, null);
2291a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                        } while (cursor.moveToNext());
2301a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                    }
2311a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                } finally {
2321a805652e389d9404ee0fda7c993a6202332e92bJeff Hamilton                    if (cursor != null) cursor.close();
2338402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                }
2348402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton                return null;
2358402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton            }
2368402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton        }.execute();
2378402962ef58546d3cfd48fbb211b5e36df0f118eJeff Hamilton    }
238aac7aa6fcfcb519755987ec126be066323f589c8Ben Murdoch}
239