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