blob: 62ed7e36d4fee5cdf1afdd4fd2829556b77aa8e4 [file] [log] [blame]
Leon Scrogginse372c022009-06-12 17:07:29 -04001/*
2 * Copyright (C) 2009 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.ContentResolver;
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.content.Context;
23import android.database.Cursor;
Ben Murdochaac7aa62009-09-17 16:57:40 +010024import android.graphics.Bitmap;
Leon Scrogginse372c022009-06-12 17:07:29 -040025import android.net.Uri;
Jeff Hamilton84029622010-08-05 14:29:28 -050026import android.os.AsyncTask;
Leon Scrogginse372c022009-06-12 17:07:29 -040027import android.provider.Browser;
Jeff Hamilton84029622010-08-05 14:29:28 -050028import android.provider.Browser.BookmarkColumns;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050029import android.provider.BrowserContract;
Leon Scrogginse372c022009-06-12 17:07:29 -040030import android.util.Log;
31import android.webkit.WebIconDatabase;
32import android.widget.Toast;
33
Ben Murdochaac7aa62009-09-17 16:57:40 +010034import java.io.ByteArrayOutputStream;
Leon Scrogginse372c022009-06-12 17:07:29 -040035
36/**
37 * This class is purely to have a common place for adding/deleting bookmarks.
38 */
39/* package */ class Bookmarks {
Ben Murdochde353622009-10-12 10:29:00 +010040 // We only want the user to be able to bookmark content that
41 // the browser can handle directly.
42 private static final String acceptableBookmarkSchemes[] = {
43 "http:",
44 "https:",
45 "about:",
46 "data:",
47 "javascript:",
48 "file:",
49 "content:"
50 };
51
Leon Scroggins2c0f6112010-03-12 18:09:39 -050052 private final static String LOGTAG = "Bookmarks";
Leon Scrogginse372c022009-06-12 17:07:29 -040053 /**
54 * Add a bookmark to the database.
55 * @param context Context of the calling Activity. This is used to make
56 * Toast confirming that the bookmark has been added. If the
57 * caller provides null, the Toast will not be shown.
58 * @param cr The ContentResolver being used to add the bookmark to the db.
59 * @param url URL of the website to be bookmarked.
60 * @param name Provided name for the bookmark.
Ben Murdochaac7aa62009-09-17 16:57:40 +010061 * @param thumbnail A thumbnail for the bookmark.
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070062 * @param retainIcon Whether to retain the page's icon in the icon database.
63 * This will usually be <code>true</code> except when bookmarks are
64 * added by a settings restore agent.
Leon Scrogginse372c022009-06-12 17:07:29 -040065 */
Jeff Hamilton84029622010-08-05 14:29:28 -050066 /* package */ static void addBookmark(Context context, ContentResolver cr, String url,
67 String name, Bitmap thumbnail, boolean retainIcon) {
Leon Scrogginse372c022009-06-12 17:07:29 -040068 // Want to append to the beginning of the list
Jeff Hamilton84029622010-08-05 14:29:28 -050069 ContentValues values = new ContentValues();
Leon Scroggins2c0f6112010-03-12 18:09:39 -050070 Cursor cursor = null;
71 try {
Jeff Hamilton84029622010-08-05 14:29:28 -050072 values.put(BrowserContract.Bookmarks.TITLE, name);
73 values.put(BrowserContract.Bookmarks.URL, url);
74 values.put(BrowserContract.Bookmarks.IS_FOLDER, 0);
75 values.put(BrowserContract.Bookmarks.THUMBNAIL,
76 bitmapToBytes(thumbnail));
77 cr.insert(BrowserContract.Bookmarks.CONTENT_URI, values);
Leon Scroggins2c0f6112010-03-12 18:09:39 -050078 } catch (IllegalStateException e) {
79 Log.e(LOGTAG, "addBookmark", e);
80 } finally {
81 if (cursor != null) cursor.close();
Leon Scrogginse372c022009-06-12 17:07:29 -040082 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070083 if (retainIcon) {
84 WebIconDatabase.getInstance().retainIconForPageUrl(url);
85 }
Leon Scrogginse372c022009-06-12 17:07:29 -040086 if (context != null) {
87 Toast.makeText(context, R.string.added_to_bookmarks,
88 Toast.LENGTH_LONG).show();
89 }
90 }
91
92 /**
93 * Remove a bookmark from the database. If the url is a visited site, it
94 * will remain in the database, but only as a history item, and not as a
95 * bookmarked site.
96 * @param context Context of the calling Activity. This is used to make
97 * Toast confirming that the bookmark has been removed. If the
98 * caller provides null, the Toast will not be shown.
99 * @param cr The ContentResolver being used to remove the bookmark.
100 * @param url URL of the website to be removed.
101 */
102 /* package */ static void removeFromBookmarks(Context context,
Andrei Popescuc9526192009-09-23 15:52:16 +0100103 ContentResolver cr, String url, String title) {
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500104 Cursor cursor = null;
105 try {
106 cursor = cr.query(
107 Browser.BOOKMARKS_URI,
108 Browser.HISTORY_PROJECTION,
109 "url = ? AND title = ?",
110 new String[] { url, title },
111 null);
112 boolean first = cursor.moveToFirst();
113 // Should be in the database no matter what
114 if (!first) {
115 throw new AssertionError("URL is not in the database! " + url
116 + " " + title);
Leon Scrogginse372c022009-06-12 17:07:29 -0400117 }
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500118 // Remove from bookmarks
119 WebIconDatabase.getInstance().releaseIconForPageUrl(url);
120 Uri uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
121 cursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX));
122 int numVisits = cursor.getInt(
123 Browser.HISTORY_PROJECTION_VISITS_INDEX);
124 if (0 == numVisits) {
125 cr.delete(uri, null, null);
126 } else {
127 // It is no longer a bookmark, but it is still a visited
128 // site.
129 ContentValues values = new ContentValues();
130 values.put(Browser.BookmarkColumns.BOOKMARK, 0);
131 try {
132 cr.update(uri, values, null, null);
133 } catch (IllegalStateException e) {
134 Log.e("removeFromBookmarks", "no database!");
135 }
136 }
137 if (context != null) {
138 Toast.makeText(context, R.string.removed_from_bookmarks,
139 Toast.LENGTH_LONG).show();
140 }
141 } catch (IllegalStateException e) {
142 Log.e(LOGTAG, "removeFromBookmarks", e);
143 } finally {
144 if (cursor != null) cursor.close();
Leon Scrogginse372c022009-06-12 17:07:29 -0400145 }
Leon Scrogginse372c022009-06-12 17:07:29 -0400146 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100147
148 private static byte[] bitmapToBytes(Bitmap bm) {
149 if (bm == null) {
150 return null;
151 }
152
153 final ByteArrayOutputStream os = new ByteArrayOutputStream();
154 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
155 return os.toByteArray();
156 }
Ben Murdochde353622009-10-12 10:29:00 +0100157
158 /* package */ static boolean urlHasAcceptableScheme(String url) {
159 if (url == null) {
160 return false;
161 }
162
163 for (int i = 0; i < acceptableBookmarkSchemes.length; i++) {
164 if (url.startsWith(acceptableBookmarkSchemes[i])) {
165 return true;
166 }
167 }
168 return false;
169 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500170
171 /* package */ static Cursor queryBookmarksForUrl(ContentResolver cr,
172 String originalUrl, String url, boolean onlyBookmarks) {
173 if (cr == null || url == null) {
174 return null;
175 }
176
177 // If originalUrl is null, just set it to url.
178 if (originalUrl == null) {
179 originalUrl = url;
180 }
181
182 // Look for both the original url and the actual url. This takes in to
183 // account redirects.
184 String originalUrlNoQuery = Bookmarks.removeQuery(originalUrl);
185 String urlNoQuery = Bookmarks.removeQuery(url);
186 originalUrl = originalUrlNoQuery + '?';
187 url = urlNoQuery + '?';
188
189 // Use NoQuery to search for the base url (i.e. if the url is
190 // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com)
191 // Use url to match the base url with other queries (i.e. if the url is
192 // http://www.google.com/m, search for
193 // http://www.google.com/m?some_query)
194 final String[] selArgs = new String[] {
195 originalUrlNoQuery, urlNoQuery, originalUrl, url };
196 String where = BookmarkColumns.URL + " == ? OR "
197 + BookmarkColumns.URL + " == ? OR "
198 + BookmarkColumns.URL + " LIKE ? || '%' OR "
199 + BookmarkColumns.URL + " LIKE ? || '%'";
200 if (onlyBookmarks) {
201 where = "(" + where + ") AND " + BookmarkColumns.BOOKMARK + " == 1";
202 }
203 final String[] projection =
204 new String[] { Browser.BookmarkColumns._ID };
205 return cr.query(Browser.BOOKMARKS_URI, projection, where, selArgs,
206 null);
207 }
208
209 // Strip the query from the given url.
210 static String removeQuery(String url) {
211 if (url == null) {
212 return null;
213 }
214 int query = url.indexOf('?');
215 String noQuery = url;
216 if (query != -1) {
217 noQuery = url.substring(0, query);
218 }
219 return noQuery;
220 }
221
222 /**
223 * Update the bookmark's favicon. This is a convenience method for updating
224 * a bookmark favicon for the originalUrl and url of the passed in WebView.
225 * @param cr The ContentResolver to use.
226 * @param originalUrl The original url before any redirects.
227 * @param url The current url.
228 * @param favicon The favicon bitmap to write to the db.
229 */
230 /* package */ static void updateBookmarkFavicon(final ContentResolver cr,
231 final String originalUrl, final String url, final Bitmap favicon) {
232 new AsyncTask<Void, Void, Void>() {
233 @Override
234 protected Void doInBackground(Void... unused) {
235 final Cursor c =
236 Bookmarks.queryBookmarksForUrl(cr, originalUrl, url, true);
237 if (c == null) {
238 return null;
239 }
240 if (c.moveToFirst()) {
241 ContentValues values = new ContentValues();
242 final ByteArrayOutputStream os =
243 new ByteArrayOutputStream();
244 favicon.compress(Bitmap.CompressFormat.PNG, 100, os);
245 values.put(Browser.BookmarkColumns.FAVICON,
246 os.toByteArray());
247 do {
248 cr.update(ContentUris.withAppendedId(
249 Browser.BOOKMARKS_URI, c.getInt(0)),
250 values, null, null);
251 } while (c.moveToNext());
252 }
253 c.close();
254 return null;
255 }
256 }.execute();
257 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100258}